Contains code from:
coxpcall - Copyright 2005 - Kepler Project (www.keplerproject.org)
ltn12/luasocket - Copyright 2004-2007 Diego Nehab
+axTLS - Copyright 2008 Cameron Rich
mkdir -p dist$(LUA_LIBRARYDIR)
cp src/nixio.so dist$(LUA_LIBRARYDIR)/nixio.so
-$(AXTLS_DIR)/.prepared: $(AXTLS_FILE)
- rm -rf $(AXTLS_DIR)
- tar xvfz $(AXTLS_FILE)
+$(AXTLS_DIR)/.prepared:
+ #rm -rf $(AXTLS_DIR)
+ #tar xvfz $(AXTLS_FILE)
cp axtls-config/{.config,config.h} $(AXTLS_DIR)/config
touch $@
clean: luaclean
rm -f src/*.o src/*.so src/*.a
- rm -rf $(AXTLS_DIR)
+ rm -f $(AXTLS_DIR)/.prepared
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+-include config/.config
+
+ifneq ($(strip $(HAVE_DOT_CONFIG)),y)
+all: menuconfig
+else
+all: target
+endif
+
+include config/makefile.conf
+
+target : $(STAGE) $(TARGET)
+
+# VERSION has to come from the command line
+RELEASE=axTLS-$(VERSION)
+
+# standard version
+target:
+ $(MAKE) -C crypto
+ $(MAKE) -C ssl
+ifdef CONFIG_AXHTTPD
+ $(MAKE) -C httpd
+endif
+ifdef CONFIG_BINDINGS
+ $(MAKE) -C bindings
+endif
+ifdef CONFIG_SAMPLES
+ $(MAKE) -C samples
+endif
+
+$(STAGE) : ssl/version.h
+ @mkdir -p $(STAGE)
+
+# create a version file with something in it.
+ssl/version.h:
+ @echo "#define AXTLS_VERSION \"(no version)\"" > ssl/version.h
+
+$(PREFIX) :
+ @mkdir -p $(PREFIX)/lib
+ @mkdir -p $(PREFIX)/bin
+
+release:
+ $(MAKE) -C config/scripts/config clean
+ -$(MAKE) clean
+ -@rm config/*.msi config/*.back.aip config/config.h config/.config*
+ -@rm www/index.20*
+ -@rm -fr $(STAGE)
+ @echo "#define AXTLS_VERSION \"$(VERSION)\"" > ssl/version.h
+ cd ../; tar cvfz $(RELEASE).tar.gz --wildcards-match-slash --exclude .svn axTLS; cd -;
+
+docs:
+ $(MAKE) -C docsrc doco
+
+# build the Win32 demo release version
+win32_demo:
+ @echo "#define AXTLS_VERSION \"$(VERSION)\"" > ssl/version.h
+ $(MAKE) win32releaseconf
+
+install: $(PREFIX) all
+ cp --no-dereference $(STAGE)/libax* $(PREFIX)/lib
+ chmod 755 $(PREFIX)/lib/libax*
+ifdef CONFIG_SAMPLES
+ install -m 755 $(STAGE)/ax* $(PREFIX)/bin
+endif
+ifdef CONFIG_HTTP_HAS_AUTHORIZATION
+ install -m 755 $(STAGE)/htpasswd $(PREFIX)/bin
+endif
+ifdef CONFIG_PLATFORM_CYGWIN
+ install -m 755 $(STAGE)/cygaxtls.dll $(PREFIX)/bin
+endif
+ifdef CONFIG_PERL_BINDINGS
+ install -m 755 $(STAGE)/axtlsp.pm `perl -e 'use Config; print $$Config{installarchlib};'`
+endif
+ @mkdir -p -m 755 $(PREFIX)/include/axTLS
+ install -m 644 crypto/*.h $(PREFIX)/include/axTLS
+ install -m 644 ssl/*.h $(PREFIX)/include/axTLS
+ -rm $(PREFIX)/include/axTLS/cert.h
+ -rm $(PREFIX)/include/axTLS/private_key.h
+ install -m 644 config/config.h $(PREFIX)/include/axTLS
+
+installclean:
+ -@rm $(PREFIX)/lib/libax* > /dev/null 2>&1
+ -@rm $(PREFIX)/bin/ax* > /dev/null 2>&1
+ -@rm $(PREFIX)/bin/axhttpd* > /dev/null 2>&1
+ -@rm `perl -e 'use Config; print $$Config{installarchlib};'`/axtlsp.pm > /dev/null 2>&1
+
+test:
+ cd $(STAGE); ssltest; ../ssl/test/test_axssl.sh; cd -;
+
+# tidy up things
+clean::
+ @cd crypto; $(MAKE) clean
+ @cd ssl; $(MAKE) clean
+ @cd httpd; $(MAKE) clean
+ @cd samples; $(MAKE) clean
+ @cd docsrc; $(MAKE) clean
+ @cd bindings; $(MAKE) clean
+
+# ---------------------------------------------------------------------------
+# mconf stuff
+# ---------------------------------------------------------------------------
+
+CONFIG_CONFIG_IN = config/Config.in
+CONFIG_DEFCONFIG = config/defconfig
+
+config/scripts/config/conf: config/scripts/config/Makefile
+ $(MAKE) -C config/scripts/config conf
+ -@if [ ! -f config/.config ] ; then \
+ cp $(CONFIG_DEFCONFIG) config/.config; \
+ fi
+
+config/scripts/config/mconf: config/scripts/config/Makefile
+ $(MAKE) -C config/scripts/config ncurses conf mconf
+ -@if [ ! -f config/.config ] ; then \
+ cp $(CONFIG_DEFCONFIG) .config; \
+ fi
+
+cleanconf:
+ $(MAKE) -C config/scripts/config clean
+ @rm -f config/.config
+
+menuconfig: config/scripts/config/mconf
+ @./config/scripts/config/mconf $(CONFIG_CONFIG_IN)
+
+config: config/scripts/config/conf
+ @./config/scripts/config/conf $(CONFIG_CONFIG_IN)
+
+oldconfig: config/scripts/config/conf
+ @./config/scripts/config/conf -o $(CONFIG_CONFIG_IN)
+
+default: config/scripts/config/conf
+ @./config/scripts/config/conf -d $(CONFIG_CONFIG_IN) > /dev/null
+ $(MAKE)
+
+randconfig: config/scripts/config/conf
+ @./config/scripts/config/conf -r $(CONFIG_CONFIG_IN)
+
+allnoconfig: config/scripts/config/conf
+ @./config/scripts/config/conf -n $(CONFIG_CONFIG_IN)
+
+allyesconfig: config/scripts/config/conf
+ @./config/scripts/config/conf -y $(CONFIG_CONFIG_IN)
+
+# The special win32 release configuration
+win32releaseconf: config/scripts/config/conf
+ @./config/scripts/config/conf -D config/win32config $(CONFIG_CONFIG_IN) > /dev/null
+ $(MAKE)
+
+# The special linux release configuration
+linuxconf: config/scripts/config/conf
+ @./config/scripts/config/conf -D config/linuxconfig $(CONFIG_CONFIG_IN) > /dev/null
+ $(MAKE)
--- /dev/null
+
+See www/index.html for the README, CHANGELOG, LICENSE and other notes.
+
--- /dev/null
+libaxtls.so.1.2
\ No newline at end of file
--- /dev/null
+#
+# For a description of the syntax of this configuration file,
+# see scripts/config/Kconfig-language.txt
+#
+menu "Language Bindings"
+
+config CONFIG_BINDINGS
+ bool "Create language bindings"
+ default n
+ help
+ axTLS supports language bindings in C#, VB.NET, Java and Perl.
+
+ Select Y here if you want to build the various language bindings.
+
+config CONFIG_CSHARP_BINDINGS
+ bool "Create C# bindings"
+ default n
+ depends on CONFIG_BINDINGS
+ help
+ Build C# bindings.
+
+ This requires .NET to be installed on Win32 platforms and mono to be
+ installed on all other platforms.
+
+config CONFIG_VBNET_BINDINGS
+ bool "Create VB.NET bindings"
+ default n
+ depends on CONFIG_BINDINGS
+ help
+ Build VB.NET bindings.
+
+ This requires the .NET to be installed and is only built under Win32
+ platforms.
+
+menu ".Net Framework"
+depends on CONFIG_CSHARP_BINDINGS || CONFIG_VBNET_BINDINGS
+config CONFIG_DOT_NET_FRAMEWORK_BASE
+ string "Location of .NET Framework"
+ default "c:\\WINDOWS\\Microsoft.NET\\Framework\\v2.0.50727"
+endmenu
+
+config CONFIG_JAVA_BINDINGS
+ bool "Create Java bindings"
+ default n
+ depends on CONFIG_BINDINGS
+ help
+ Build Java bindings.
+
+ Current Issues (see README):
+ * Needs Java 1.4 or better.
+ * If building under Win32 it will use the Win32 JDK.
+
+menu "Java Home"
+depends on CONFIG_JAVA_BINDINGS
+config CONFIG_JAVA_HOME
+ string "Location of JDK"
+ default "c:\\Program Files\\Java\\jdk1.5.0_06" if CONFIG_PLATFORM_WIN32 || CONFIG_PLATFORM_CYGWIN
+ default "/usr/local/jdk142" if !CONFIG_PLATFORM_WIN32 && !CONFIG_PLATFORM_CYGWIN
+ depends on CONFIG_JAVA_BINDINGS
+ help
+ The location of Sun's JDK.
+endmenu
+
+config CONFIG_PERL_BINDINGS
+ bool "Create Perl bindings"
+ default n
+ depends on CONFIG_BINDINGS
+ help
+ Build Perl bindings.
+
+ Current Issues (see README):
+ * 64 bit versions don't work at present.
+ * libperl.so needs to be in the shared library path.
+
+menu "Perl Home"
+depends on CONFIG_PERL_BINDINGS && CONFIG_PLATFORM_WIN32
+config CONFIG_PERL_CORE
+ string "Location of Perl CORE"
+ default "c:\\perl\\lib\\CORE"
+ help:
+ works with ActiveState
+ "http://www.activestate.com/Products/ActivePerl"
+
+config CONFIG_PERL_LIB
+ string "Name of Perl Library"
+ default "perl58.lib"
+endmenu
+
+config CONFIG_LUA_BINDINGS
+ bool "Create Lua bindings"
+ default n
+ depends on CONFIG_BINDINGS && !CONFIG_PLATFORM_WIN32
+ help
+ Build Lua bindings (see www.lua.org).
+
+menu "Lua Home"
+depends on CONFIG_LUA_BINDINGS
+config CONFIG_LUA_CORE
+ string "Location of Lua CORE"
+ default "/usr/local"
+ help:
+ If the Lua exists on another directory then this needs to be changed
+endmenu
+
+endmenu
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+all:
+
+include ../config/.config
+include ../config/makefile.conf
+
+ifdef CONFIG_CSHARP_BINDINGS
+all: csharp/axInterface.cs
+endif
+
+ifdef CONFIG_VBNET_BINDINGS
+all: vbnet/axInterface.vb
+endif
+
+ifdef CONFIG_JAVA_BINDINGS
+all: java/axtlsj.java
+endif
+
+ifdef CONFIG_PERL_BINDINGS
+all: perl/axTLSp_wrap.c
+endif
+
+ifdef CONFIG_LUA_BINDINGS
+all: lua/axTLSl_wrap.c
+endif
+
+csharp/axInterface.cs: ../ssl/ssl.h
+ @perl ./generate_interface.pl -csharp
+
+vbnet/axInterface.vb: ../ssl/ssl.h
+ @perl ./generate_interface.pl -vbnet
+
+java/axTLSj.i: ../ssl/ssl.h
+ @perl ./generate_SWIG_interface.pl -java
+
+java/axtlsj.java: java/axTLSj.i $(wildcard java/SSL*.java)
+ @cd java; swig -java -package axTLSj axTLSj.i; $(MAKE)
+
+perl/axTLSp.i: ../ssl/ssl.h
+ @perl ./generate_SWIG_interface.pl -perl
+
+perl/axTLSp_wrap.c: perl/axTLSp.i
+ @cd perl; swig -perl5 axTLSp.i; $(MAKE)
+
+lua/axTLSl.i: ../ssl/ssl.h
+ @perl ./generate_SWIG_interface.pl -lua
+
+lua/axTLSl_wrap.c: lua/axTLSl.i
+ @cd lua; swig -lua axTLSl.i; $(MAKE)
+
+clean::
+ $(MAKE) -C csharp clean
+ $(MAKE) -C vbnet clean
+ $(MAKE) -C java clean
+ $(MAKE) -C perl clean
+ $(MAKE) -C lua clean
+
--- /dev/null
+===============================================================================
+= Language Bindings =
+===============================================================================
+
+The tools to generate the various language bindings are done here.
+SWIG 1.3.24 or better is required for creating the Java and Perl bindings.
+
+Perl scripts are used to parse ssl.h and automagically give the appropriate
+bindings.
+
+At present, the four languages supported are:
+
+* C#
+* VB.NET
+* Java
+* Perl
+
+To generate each binding run the following:
+
+C#:
+> generate_interface.pl -csharp
+
+VB.NET:
+> generate_interface.pl -vbnet
+
+
+Java:
+> generate_SWIG_interface.pl -java
+> cd java; swig -java -package axTLSj -noextern axTLSj.i
+
+Perl:
+> generate_SWIG_interface.pl -perl
+> cd perl; swig -noextern -perl axTLSp.i
+
+Java and Perl both create a library each called libaxtlsj.so and libaxtlsp.so
+(or axtlsj.dll and atlsp.dll on Win32 platforms).
+
+Note: the "-noextern" is deprecated in swig 1.3.27 and newer. The "-noextern"
+option was required to get Win32 bindings to work (which is why is has probably
+been deprecated).
+
+Each binding (except for Perl) has an extra helper interface to make life
+easier.
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+include ../../config/.config
+include ../../config/makefile.conf
+
+clean::
+ @rm -f axssl* axInterface.cs
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * A wrapper around the unmanaged interface to give a semi-decent C# API
+ */
+
+using System;
+using System.Runtime.InteropServices;
+using System.Net.Sockets;
+
+/**
+ * @defgroup csharp_api C# API.
+ *
+ * Ensure that the appropriate Dispose() methods are called when finished with
+ * various objects - otherwise memory leaks will result.
+ * @{
+ */
+namespace axTLS
+{
+ /**
+ * @class SSL
+ * @ingroup csharp_api
+ * @brief A representation of an SSL connection.
+ */
+ public class SSL
+ {
+ public IntPtr m_ssl; /**< A pointer to the real SSL type */
+
+ /**
+ * @brief Store the reference to an SSL context.
+ * @param ip [in] A reference to an SSL object.
+ */
+ public SSL(IntPtr ip)
+ {
+ m_ssl = ip;
+ }
+
+ /**
+ * @brief Free any used resources on this connection.
+ *
+ * A "Close Notify" message is sent on this connection (if possible).
+ * It is up to the application to close the socket.
+ */
+ public void Dispose()
+ {
+ axtls.ssl_free(m_ssl);
+ }
+
+ /**
+ * @brief Return the result of a handshake.
+ * @return SSL_OK if the handshake is complete and ok.
+ * @see ssl.h for the error code list.
+ */
+ public int HandshakeStatus()
+ {
+ return axtls.ssl_handshake_status(m_ssl);
+ }
+
+ /**
+ * @brief Return the SSL cipher id.
+ * @return The cipher id which is one of:
+ * - SSL_AES128_SHA (0x2f)
+ * - SSL_AES256_SHA (0x35)
+ * - SSL_RC4_128_SHA (0x05)
+ * - SSL_RC4_128_MD5 (0x04)
+ */
+ public byte GetCipherId()
+ {
+ return axtls.ssl_get_cipher_id(m_ssl);
+ }
+
+ /**
+ * @brief Get the session id for a handshake.
+ *
+ * This will be a 32 byte sequence and is available after the first
+ * handshaking messages are sent.
+ * @return The session id as a 32 byte sequence.
+ * @note A SSLv23 handshake may have only 16 valid bytes.
+ */
+ public byte[] GetSessionId()
+ {
+ IntPtr ptr = axtls.ssl_get_session_id(m_ssl);
+ byte sess_id_size = axtls.ssl_get_session_id_size(m_ssl);
+ byte[] result = new byte[sess_id_size];
+ Marshal.Copy(ptr, result, 0, sess_id_size);
+ return result;
+ }
+
+ /**
+ * @brief Retrieve an X.509 distinguished name component.
+ *
+ * When a handshake is complete and a certificate has been exchanged,
+ * then the details of the remote certificate can be retrieved.
+ *
+ * This will usually be used by a client to check that the server's
+ * common name matches the URL.
+ *
+ * A full handshake needs to occur for this call to work.
+ *
+ * @param component [in] one of:
+ * - SSL_X509_CERT_COMMON_NAME
+ * - SSL_X509_CERT_ORGANIZATION
+ * - SSL_X509_CERT_ORGANIZATIONAL_NAME
+ * - SSL_X509_CA_CERT_COMMON_NAME
+ * - SSL_X509_CA_CERT_ORGANIZATION
+ * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME
+ * @return The appropriate string (or null if not defined)
+ */
+ public string GetCertificateDN(int component)
+ {
+ return axtls.ssl_get_cert_dn(m_ssl, component);
+ }
+ }
+
+ /**
+ * @class SSLUtil
+ * @ingroup csharp_api
+ * @brief Some global helper functions.
+ */
+ public class SSLUtil
+ {
+
+ /**
+ * @brief Return the build mode of the axTLS project.
+ * @return The build mode is one of:
+ * - SSL_BUILD_SERVER_ONLY
+ * - SSL_BUILD_ENABLE_VERIFICATION
+ * - SSL_BUILD_ENABLE_CLIENT
+ * - SSL_BUILD_FULL_MODE
+ */
+ public static int BuildMode()
+ {
+ return axtls.ssl_get_config(axtls.SSL_BUILD_MODE);
+ }
+
+ /**
+ * @brief Return the number of chained certificates that the
+ * client/server supports.
+ * @return The number of supported server certificates.
+ */
+ public static int MaxCerts()
+ {
+ return axtls.ssl_get_config(axtls.SSL_MAX_CERT_CFG_OFFSET);
+ }
+
+ /**
+ * @brief Return the number of CA certificates that the client/server
+ * supports.
+ * @return The number of supported CA certificates.
+ */
+ public static int MaxCACerts()
+ {
+ return axtls.ssl_get_config(axtls.SSL_MAX_CA_CERT_CFG_OFFSET);
+ }
+
+ /**
+ * @brief Indicate if PEM is supported.
+ * @return true if PEM supported.
+ */
+ public static bool HasPEM()
+ {
+ return axtls.ssl_get_config(axtls.SSL_HAS_PEM) > 0 ? true : false;
+ }
+
+ /**
+ * @brief Display the text string of the error.
+ * @param error_code [in] The integer error code.
+ */
+ public static void DisplayError(int error_code)
+ {
+ axtls.ssl_display_error(error_code);
+ }
+
+ /**
+ * @brief Return the version of the axTLS project.
+ */
+ public static string Version()
+ {
+ return axtls.ssl_version();
+ }
+ }
+
+ /**
+ * @class SSLCTX
+ * @ingroup csharp_api
+ * @brief A base object for SSLServer/SSLClient.
+ */
+ public class SSLCTX
+ {
+ /**
+ * @brief A reference to the real client/server context.
+ */
+ protected IntPtr m_ctx;
+
+ /**
+ * @brief Establish a new client/server context.
+ *
+ * This function is called before any client/server SSL connections are
+ * made. If multiple threads are used, then each thread will have its
+ * own SSLCTX context. Any number of connections may be made with a
+ * single context.
+ *
+ * Each new connection will use the this context's private key and
+ * certificate chain. If a different certificate chain is required,
+ * then a different context needs to be be used.
+ *
+ * @param options [in] Any particular options. At present the options
+ * supported are:
+ * - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if
+ * the server authentication fails. The certificate can be
+ * authenticated later with a call to VerifyCert().
+ * - SSL_CLIENT_AUTHENTICATION (server only): Enforce client
+ * authentication i.e. each handshake will include a "certificate
+ * request" message from the server.
+ * - SSL_DISPLAY_BYTES (full mode build only): Display the byte
+ * sequences during the handshake.
+ * - SSL_DISPLAY_STATES (full mode build only): Display the state
+ * changes during the handshake.
+ * - SSL_DISPLAY_CERTS (full mode build only): Display the
+ * certificates that are passed during a handshake.
+ * - SSL_DISPLAY_RSA (full mode build only): Display the RSA key
+ * details that are passed during a handshake.
+ * @param num_sessions [in] The number of sessions to be used for
+ * session caching. If this value is 0, then there is no session
+ * caching.
+ * @return A client/server context.
+ */
+ protected SSLCTX(uint options, int num_sessions)
+ {
+ m_ctx = axtls.ssl_ctx_new(options, num_sessions);
+ }
+
+ /**
+ * @brief Remove a client/server context.
+ *
+ * Frees any used resources used by this context. Each connection will
+ * be sent a "Close Notify" alert (if possible).
+ */
+ public void Dispose()
+ {
+ axtls.ssl_ctx_free(m_ctx);
+ }
+
+ /**
+ * @brief Read the SSL data stream.
+ * @param ssl [in] An SSL object reference.
+ * @param in_data [out] After a successful read, the decrypted data
+ * will be here. It will be null otherwise.
+ * @return The number of decrypted bytes:
+ * - if > 0, then the handshaking is complete and we are returning the
+ * number of decrypted bytes.
+ * - SSL_OK if the handshaking stage is successful (but not yet
+ * complete).
+ * - < 0 if an error.
+ * @see ssl.h for the error code list.
+ * @note Use in_data before doing any successive ssl calls.
+ */
+ public int Read(SSL ssl, out byte[] in_data)
+ {
+ IntPtr ptr = IntPtr.Zero;
+ int ret = axtls.ssl_read(ssl.m_ssl, ref ptr);
+
+ if (ret > axtls.SSL_OK)
+ {
+ in_data = new byte[ret];
+ Marshal.Copy(ptr, in_data, 0, ret);
+ }
+ else
+ {
+ in_data = null;
+ }
+
+ return ret;
+ }
+
+ /**
+ * @brief Write to the SSL data stream.
+ * @param ssl [in] An SSL obect reference.
+ * @param out_data [in] The data to be written
+ * @return The number of bytes sent, or if < 0 if an error.
+ * @see ssl.h for the error code list.
+ */
+ public int Write(SSL ssl, byte[] out_data)
+ {
+ return axtls.ssl_write(ssl.m_ssl, out_data, out_data.Length);
+ }
+
+ /**
+ * @brief Write to the SSL data stream.
+ * @param ssl [in] An SSL obect reference.
+ * @param out_data [in] The data to be written
+ * @param out_len [in] The number of bytes to be written
+ * @return The number of bytes sent, or if < 0 if an error.
+ * @see ssl.h for the error code list.
+ */
+ public int Write(SSL ssl, byte[] out_data, int out_len)
+ {
+ return axtls.ssl_write(ssl.m_ssl, out_data, out_len);
+ }
+
+ /**
+ * @brief Find an ssl object based on a Socket reference.
+ *
+ * Goes through the list of SSL objects maintained in a client/server
+ * context to look for a socket match.
+ * @param s [in] A reference to a <A HREF="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemnetsocketssocketclasstopic.asp">Socket</A> object.
+ * @return A reference to the SSL object. Returns null if the object
+ * could not be found.
+ */
+ public SSL Find(Socket s)
+ {
+ int client_fd = s.Handle.ToInt32();
+ return new SSL(axtls. ssl_find(m_ctx, client_fd));
+ }
+
+ /**
+ * @brief Authenticate a received certificate.
+ *
+ * This call is usually made by a client after a handshake is complete
+ * and the context is in SSL_SERVER_VERIFY_LATER mode.
+ * @param ssl [in] An SSL object reference.
+ * @return SSL_OK if the certificate is verified.
+ */
+ public int VerifyCert(SSL ssl)
+ {
+ return axtls.ssl_verify_cert(ssl.m_ssl);
+ }
+
+ /**
+ * @brief Force the client to perform its handshake again.
+ *
+ * For a client this involves sending another "client hello" message.
+ * For the server is means sending a "hello request" message.
+ *
+ * This is a blocking call on the client (until the handshake
+ * completes).
+ * @param ssl [in] An SSL object reference.
+ * @return SSL_OK if renegotiation instantiation was ok
+ */
+ public int Renegotiate(SSL ssl)
+ {
+ return axtls.ssl_renegotiate(ssl.m_ssl);
+ }
+
+ /**
+ * @brief Load a file into memory that is in binary DER or ASCII PEM
+ * format.
+ *
+ * These are temporary objects that are used to load private keys,
+ * certificates etc into memory.
+ * @param obj_type [in] The format of the file. Can be one of:
+ * - SSL_OBJ_X509_CERT (no password required)
+ * - SSL_OBJ_X509_CACERT (no password required)
+ * - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported)
+ * - SSL_OBJ_P8 (RC4-128 encrypted data supported)
+ * - SSL_OBJ_P12 (RC4-128 encrypted data supported)
+ *
+ * PEM files are automatically detected (if supported).
+ * @param filename [in] The location of a file in DER/PEM format.
+ * @param password [in] The password used. Can be null if not required.
+ * @return SSL_OK if all ok
+ */
+ public int ObjLoad(int obj_type, string filename, string password)
+ {
+ return axtls.ssl_obj_load(m_ctx, obj_type, filename, password);
+ }
+
+ /**
+ * @brief Transfer binary data into the object loader.
+ *
+ * These are temporary objects that are used to load private keys,
+ * certificates etc into memory.
+ * @param obj_type [in] The format of the memory data.
+ * @param data [in] The binary data to be loaded.
+ * @param len [in] The amount of data to be loaded.
+ * @param password [in] The password used. Can be null if not required.
+ * @return SSL_OK if all ok
+ */
+ public int ObjLoad(int obj_type, byte[] data, int len, string password)
+ {
+ return axtls.ssl_obj_memory_load(m_ctx, obj_type,
+ data, len, password);
+ }
+ }
+
+ /**
+ * @class SSLServer
+ * @ingroup csharp_api
+ * @brief The server context.
+ *
+ * All server connections are started within a server context.
+ */
+ public class SSLServer : SSLCTX
+ {
+ /**
+ * @brief Start a new server context.
+ *
+ * @see SSLCTX for details.
+ */
+ public SSLServer(uint options, int num_sessions) :
+ base(options, num_sessions) {}
+
+ /**
+ * @brief Establish a new SSL connection to an SSL client.
+ *
+ * It is up to the application to establish the initial socket
+ * connection.
+ *
+ * Call Dispose() when the connection is to be removed.
+ * @param s [in] A reference to a <A HREF="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemnetsocketssocketclasstopic.asp">Socket</A> object.
+ * @return An SSL object reference.
+ */
+ public SSL Connect(Socket s)
+ {
+ int client_fd = s.Handle.ToInt32();
+ return new SSL(axtls.ssl_server_new(m_ctx, client_fd));
+ }
+ }
+
+ /**
+ * @class SSLClient
+ * @ingroup csharp_api
+ * @brief The client context.
+ *
+ * All client connections are started within a client context.
+ */
+ public class SSLClient : SSLCTX
+ {
+ /**
+ * @brief Start a new client context.
+ *
+ * @see SSLCTX for details.
+ */
+ public SSLClient(uint options, int num_sessions) :
+ base(options, num_sessions) {}
+
+ /**
+ * @brief Establish a new SSL connection to an SSL server.
+ *
+ * It is up to the application to establish the initial socket
+ * connection.
+ *
+ * This is a blocking call - it will finish when the handshake is
+ * complete (or has failed).
+ *
+ * Call Dispose() when the connection is to be removed.
+ * @param s [in] A reference to a <A HREF="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemnetsocketssocketclasstopic.asp">Socket</A> object.
+ * @param session_id [in] A 32 byte session id for session resumption.
+ * This can be null if no session resumption is not required.
+ * @return An SSL object reference. Use SSL.handshakeStatus() to check
+ * if a handshake succeeded.
+ */
+ public SSL Connect(Socket s, byte[] session_id)
+ {
+ int client_fd = s.Handle.ToInt32();
+ byte sess_id_size = (byte)(session_id != null ?
+ session_id.Length : 0);
+ return new SSL(axtls.ssl_client_new(m_ctx, client_fd, session_id,
+ sess_id_size));
+ }
+ }
+}
+/** @} */
--- /dev/null
+#!/usr/bin/perl
+
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#===============================================================
+# Transforms function signature into SWIG format
+sub transformSignature
+{
+ foreach $item (@_)
+ {
+ $line =~ s/STDCALL //g;
+ $line =~ s/EXP_FUNC/extern/g;
+
+ # make API Java more 'byte' friendly
+ $line =~ s/uint32_t/int/g;
+ $line =~ s/const uint8_t \* /const unsigned char \* /g;
+ $line =~ s/\(void\)/()/g;
+ if ($ARGV[0] eq "-java")
+ {
+ $line =~ s/.*ssl_read.*//g;
+ $line =~ s/const uint8_t \*(\w+)/const signed char $1\[\]/g;
+ $line =~ s/uint8_t/signed char/g;
+ }
+ elsif ($ARGV[0] eq "-perl")
+ {
+ $line =~ s/const uint8_t \*(\w+)/const unsigned char $1\[\]/g;
+ $line =~ s/uint8_t/unsigned char/g;
+ }
+ else # lua
+ {
+ $line =~ s/const uint8_t \*session_id/const unsigned char session_id\[\]/g;
+ $line =~ s/const uint8_t \*\w+/unsigned char *INPUT/g;
+ $line =~ s/uint8_t/unsigned char/g;
+ }
+ }
+
+ return $line;
+}
+
+# Parse input file
+sub parseFile
+{
+ foreach $line (@_)
+ {
+ next if $line =~ /ssl_x509_create/; # ignore for now
+
+ # test for a #define
+ if (!$skip && $line =~ m/^#define/)
+ {
+ $splitDefine = 1 if $line =~ m/\\$/;
+ print DATA_OUT $line;
+
+ # check line is not split
+ next if $splitDefine == 1;
+ }
+
+ # pick up second line of #define statement
+ if ($splitDefine)
+ {
+ print DATA_OUT $line;
+
+ # check line is not split
+ $splitDefine = ($line =~ m/\\$/);
+ next;
+ }
+
+ # test for function declaration
+ if (!$skip && $line =~ /EXP_FUNC/ && $line !~/\/\*/)
+ {
+ $line = transformSignature($line);
+ $splitFunctionDeclaration = $line !~ /;/;
+ print DATA_OUT $line;
+ next;
+ }
+
+ if ($splitFunctionDeclaration)
+ {
+ $line = transformSignature($line);
+ $splitFunctionDeclaration = $line !~ /;/;
+ print DATA_OUT $line;
+ next;
+ }
+ }
+}
+
+#===============================================================
+
+# Determine which module to build from cammand-line options
+use strict;
+use Getopt::Std;
+
+my $module;
+my $interfaceFile;
+my $data_file;
+my $skip;
+my $splitLine;
+my @raw_data;
+
+if (not defined $ARGV[0])
+{
+ goto ouch;
+}
+
+if ($ARGV[0] eq "-java")
+{
+ print "Generating Java interface file\n";
+ $module = "axtlsj";
+ $interfaceFile = "java/axTLSj.i";
+}
+elsif ($ARGV[0] eq "-perl")
+{
+ print "Generating Perl interface file\n";
+ $module = "axtlsp";
+ $interfaceFile = "perl/axTLSp.i";
+}
+elsif ($ARGV[0] eq "-lua")
+{
+ print "Generating lua interface file\n";
+ $module = "axtlsl";
+ $interfaceFile = "lua/axTLSl.i";
+}
+else
+{
+ouch:
+ die "Usage: $0 [-java | -perl | -lua]\n";
+}
+
+# Input file required to generate SWIG interface file.
+$data_file = "../ssl/ssl.h";
+
+# Open input files
+open(DATA_IN, $data_file) || die("Could not open file ($data_file)!");
+@raw_data = <DATA_IN>;
+
+# Open output file
+open(DATA_OUT, ">$interfaceFile") || die("Cannot Open File");
+
+#
+# I wish I could say it was easy to generate the Perl/Java/Lua bindings,
+# but each had their own set of challenges... :-(.
+#
+print DATA_OUT << "END";
+%module $module\n
+
+/* include our own header */
+%inline %{
+#include "ssl.h"
+%}
+
+%include "typemaps.i"
+/* Some SWIG magic to make the API a bit more Java friendly */
+#ifdef SWIGJAVA
+
+%apply long { SSL * };
+%apply long { SSL_CTX * };
+%apply long { SSLObjLoader * };
+
+/* allow "unsigned char []" to become "byte[]" */
+%include "arrays_java.i"
+
+/* convert these pointers to use long */
+%apply signed char[] {unsigned char *};
+%apply signed char[] {signed char *};
+
+/* allow ssl_get_session_id() to return "byte[]" */
+%typemap(out) unsigned char * ssl_get_session_id \"if (result) jresult = SWIG_JavaArrayOutSchar(jenv, result, ssl_get_session_id_size((SSL const *)arg1));\"
+
+/* allow ssl_client_new() to have a null session_id input */
+%typemap(in) const signed char session_id[] (jbyte *jarr) {
+ if (jarg3 == NULL)
+ {
+ jresult = (jint)ssl_client_new(arg1,arg2,NULL,0);
+ return jresult;
+ }
+
+ if (!SWIG_JavaArrayInSchar(jenv, &jarr, &arg3, jarg3)) return 0;
+}
+
+/* Lot's of work required for an ssl_read() due to its various custom
+ * requirements.
+ */
+%native (ssl_read) int ssl_read(SSL *ssl, jobject in_data);
+%{
+JNIEXPORT jint JNICALL Java_axTLSj_axtlsjJNI_ssl_1read(JNIEnv *jenv, jclass jcls, jint jarg1, jobject jarg2) {
+ jint jresult = 0 ;
+ SSL *arg1;
+ unsigned char *arg2;
+ jbyte *jarr;
+ int result;
+ JNIEnv e = *jenv;
+ jclass holder_class;
+ jfieldID fid;
+
+ arg1 = (SSL *)jarg1;
+ result = (int)ssl_read(arg1, &arg2);
+
+ /* find the "m_buf" entry in the SSLReadHolder class */
+ if (!(holder_class = e->GetObjectClass(jenv,jarg2)) ||
+ !(fid = e->GetFieldID(jenv,holder_class, "m_buf", "[B")))
+ return SSL_NOT_OK;
+
+ if (result > SSL_OK)
+ {
+ int i;
+
+ /* create a new byte array to hold the read data */
+ jbyteArray jarray = e->NewByteArray(jenv, result);
+
+ /* copy the bytes across to the java byte array */
+ jarr = e->GetByteArrayElements(jenv, jarray, 0);
+ for (i = 0; i < result; i++)
+ jarr[i] = (jbyte)arg2[i];
+
+ /* clean up and set the new m_buf object */
+ e->ReleaseByteArrayElements(jenv, jarray, jarr, 0);
+ e->SetObjectField(jenv, jarg2, fid, jarray);
+ }
+ else /* set to null */
+ e->SetObjectField(jenv, jarg2, fid, NULL);
+
+ jresult = (jint)result;
+ return jresult;
+}
+%}
+
+/* Big hack to get hold of a socket's file descriptor */
+%typemap (jtype) long "Object"
+%typemap (jstype) long "Object"
+%native (getFd) int getFd(long sock);
+%{
+JNIEXPORT jint JNICALL Java_axTLSj_axtlsjJNI_getFd(JNIEnv *env, jclass jcls, jobject sock)
+{
+ JNIEnv e = *env;
+ jfieldID fid;
+ jobject impl;
+ jobject fdesc;
+
+ /* get the SocketImpl from the Socket */
+ if (!(jcls = e->GetObjectClass(env,sock)) ||
+ !(fid = e->GetFieldID(env,jcls,"impl","Ljava/net/SocketImpl;")) ||
+ !(impl = e->GetObjectField(env,sock,fid))) return -1;
+
+ /* get the FileDescriptor from the SocketImpl */
+ if (!(jcls = e->GetObjectClass(env,impl)) ||
+ !(fid = e->GetFieldID(env,jcls,"fd","Ljava/io/FileDescriptor;")) ||
+ !(fdesc = e->GetObjectField(env,impl,fid))) return -1;
+
+ /* get the fd from the FileDescriptor */
+ if (!(jcls = e->GetObjectClass(env,fdesc)) ||
+ !(fid = e->GetFieldID(env,jcls,"fd","I"))) return -1;
+
+ /* return the descriptor */
+ return e->GetIntField(env,fdesc,fid);
+}
+%}
+
+#endif
+
+/* Some SWIG magic to make the API a bit more Perl friendly */
+#ifdef SWIGPERL
+
+/* for ssl_session_id() */
+%typemap(out) const unsigned char * {
+ SV *svs = newSVpv((unsigned char *)\$1, ssl_get_session_id_size((SSL const *)arg1));
+ \$result = newRV(svs);
+ sv_2mortal(\$result);
+ argvi++;
+}
+
+/* for ssl_write() */
+%typemap(in) const unsigned char out_data[] {
+ SV* tempsv;
+ if (!SvROK(\$input))
+ croak("Argument \$argnum is not a reference.");
+ tempsv = SvRV(\$input);
+ if (SvTYPE(tempsv) != SVt_PV)
+ croak("Argument \$argnum is not an string.");
+ \$1 = (unsigned char *)SvPV(tempsv, PL_na);
+}
+
+/* for ssl_read() */
+%typemap(in) unsigned char **in_data (unsigned char *buf) {
+ \$1 = &buf;
+}
+
+%typemap(argout) unsigned char **in_data {
+ if (result > SSL_OK) {
+ SV *svs = newSVpv(*\$1, result);
+ \$result = newRV(svs);
+ sv_2mortal(\$result);
+ argvi++;
+ }
+}
+
+/* for ssl_client_new() */
+%typemap(in) const unsigned char session_id[] {
+ /* check for a reference */
+ if (SvOK(\$input) && SvROK(\$input)) {
+ SV* tempsv = SvRV(\$input);
+ if (SvTYPE(tempsv) != SVt_PV)
+ croak("Argument \$argnum is not an string.");
+ \$1 = (unsigned char *)SvPV(tempsv, PL_na);
+ }
+ else
+ \$1 = NULL;
+}
+
+#endif
+
+/* Some SWIG magic to make the API a bit more Lua friendly */
+#ifdef SWIGLUA
+SWIG_NUMBER_TYPEMAP(unsigned char);
+SWIG_TYPEMAP_NUM_ARR(uchar,unsigned char);
+
+/* for ssl_session_id() */
+%typemap(out) const unsigned char * {
+ int i;
+ lua_newtable(L);
+ for (i = 0; i < ssl_get_session_id_size((SSL const *)arg1); i++){
+ lua_pushnumber(L,(lua_Number)result[i]);
+ lua_rawseti(L,-2,i+1); /* -1 is the number, -2 is the table */
+ }
+ SWIG_arg++;
+}
+
+/* for ssl_read() */
+%typemap(in) unsigned char **in_data (unsigned char *buf) {
+ \$1 = &buf;
+}
+
+%typemap(argout) unsigned char **in_data {
+ if (result > SSL_OK) {
+ int i;
+ lua_newtable(L);
+ for (i = 0; i < result; i++){
+ lua_pushnumber(L,(lua_Number)buf2[i]);
+ lua_rawseti(L,-2,i+1); /* -1 is the number, -2 is the table */
+ }
+ SWIG_arg++;
+ }
+}
+
+/* for ssl_client_new() */
+%typemap(in) const unsigned char session_id[] {
+ if (lua_isnil(L,\$input))
+ \$1 = NULL;
+ else
+ \$1 = SWIG_get_uchar_num_array_fixed(L,\$input, ssl_get_session_id((SSL const *)\$1));
+}
+
+#endif
+
+END
+
+# Initialise loop variables
+$skip = 1;
+$splitLine = 0;
+
+parseFile(@raw_data);
+
+close(DATA_IN);
+close(DATA_OUT);
+
+#===============================================================
+
--- /dev/null
+#!/usr/bin/perl -w
+
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#===============================================================
+# This application transforms ssl.h into interfaces that can be used by
+# other language bindings. It is "SWIG"-like in nature in that various
+# files are generated based on the axTLS API.
+#
+# The file produced is axInterface.? (depending on the file extension).
+#
+#===============================================================
+
+use strict;
+
+my $CSHARP = 0;
+my $VBNET = 1;
+
+my $binding;
+my $skip = 0;
+my $signature_ret_type;
+
+# Transforms function signature into an Interface format
+sub transformSignature
+{
+ my $item;
+ my ($line) = @_;
+
+ foreach $item ($line)
+ {
+ # our very basic preprocessor
+ if ($binding == $CSHARP)
+ {
+ $line =~ s/STDCALL //;
+ $line =~ s/EXP_FUNC/ [DllImport ("axtls")]\n public static extern/;
+ $line =~ s/uint32_t/uint/g;
+ $line =~ s/uint8_t \*\*/ref IntPtr /g;
+ $line =~ s/const uint8_t \* /IntPtr /g;
+ $line =~ s/const uint8_t \*/byte[] /g; # note: subtle diff
+ $line =~ s/uint8_t \* ?/byte[] /g;
+ $line =~ s/uint8_t ?/byte /g;
+ $line =~ s/const char \* ?/string /g;
+ $line =~ s/const SSL_CTX \* ?/IntPtr /g;
+ $line =~ s/SSL_CTX \* ?/IntPtr /g;
+ $line =~ s/SSLObjLoader \* ?/IntPtr /g;
+ $line =~ s/const SSL \* ?/IntPtr /g;
+ $line =~ s/SSL \* ?/IntPtr /g;
+ $line =~ s/\(void\)/()/g;
+ }
+ elsif ($binding == $VBNET)
+ {
+ if ($line =~ /EXP_FUNC/)
+ {
+ # Procedure or function?
+ my $invariant = $line =~ /void /;
+
+ my $proc = $invariant ? "Sub" : "Function";
+ ($signature_ret_type) = $line =~ /EXP_FUNC (.*) STDCALL/;
+ $line =~ s/EXP_FUNC .* STDCALL / <DllImport("axtls")> Public Shared $proc _\n /;
+
+ $signature_ret_type =~ s/const uint8_t \*/As IntPtr/;
+ $signature_ret_type =~ s/const char \*/As String/;
+ $signature_ret_type =~ s/SSL_CTX \*/As IntPtr/;
+ $signature_ret_type =~ s/SSLObjLoader \*/As IntPtr/;
+ $signature_ret_type =~ s/SSL \*/As IntPtr/;
+ $signature_ret_type =~ s/uint8_t/As Byte/;
+ $signature_ret_type =~ s/int/As Integer/;
+ $signature_ret_type =~ s/void//;
+ $signature_ret_type .= "\n End $proc\n\n";
+ }
+
+ $line =~ s/uint32_t (\w+)/ByVal $1 As Integer/g;
+ $line =~ s/int (\w+)/ByVal $1 As Integer/g;
+ $line =~ s/uint8_t \*\* ?(\w+)/ByRef $1 As IntPtr/g;
+ $line =~ s/const uint8_t \* ?(\w+)/ByVal $1() As Byte/g;
+ $line =~ s/uint8_t \* ?(\w+)/ByVal $1() As Byte/g;
+ $line =~ s/uint8_t ?(\w+)/ByVal $1 As Byte/g;
+ $line =~ s/const char \* ?(\w+)/ByVal $1 As String/g;
+ $line =~ s/const SSL_CTX \* ?(\w+)/ByVal $1 As IntPtr/g;
+ $line =~ s/SSL_CTX \* ?(\w+)/ByVal $1 As IntPtr/g;
+ $line =~ s/SSLObjLoader \* ?(\w+)/ByVal $1 As IntPtr/g;
+ $line =~ s/const SSL \* ?(\w+)/ByVal $1 As IntPtr/g;
+ $line =~ s/SSL \* ?(\w+)/ByVal $1 As IntPtr/g;
+ $line =~ s/void \* ?(\w+)/Byval $1 As IntPtr/g;
+ $line =~ s/\(void\)/()/g;
+ $line =~ s/void//g;
+ $line =~ s/;\n/ $signature_ret_type;/;
+ }
+ }
+
+ return $line;
+}
+
+# Parse input file
+sub parseFile
+{
+ my (@file) = @_;
+ my $line;
+ my $splitDefine = 0;
+ my $splitFunctionDeclaration;
+ my $vb_hack = " ";
+ my $vb_line_hack = 0;
+
+ $skip = 0;
+
+ foreach $line (@file)
+ {
+ next if $line =~ /sl_x509_create/; # ignore for now
+
+ # test for a #define
+ if (!$skip && $line =~ m/^#define/)
+ {
+ $splitDefine = 1 if $line =~ m/\\$/;
+
+ if ($binding == $VBNET)
+ {
+ $line =~ s/\|/Or/g;
+ $line =~ s/ 0x/ &H/;
+ }
+
+ my ($name, $value) = $line =~ /#define (\w+) +([^\\]*)[\\]?\n/;
+
+ if (defined $name && defined $value)
+ {
+ # C# constant translation
+ if ($binding == $CSHARP)
+ {
+ $line = " public const int $name = $value";
+ }
+ # VB.NET constant translation
+ elsif ($binding == $VBNET)
+ {
+ $line = " Public Const $name As Integer = $value";
+ }
+ }
+
+ next if $line =~ /#define/; # ignore any other defines
+
+ print DATA_OUT $line;
+
+ # check line is not split
+ next if $splitDefine == 1;
+ print DATA_OUT ";" if $binding == $CSHARP;
+ print DATA_OUT "\n";
+ }
+
+ # pick up second line of #define statement
+ if ($splitDefine)
+ {
+ if ($line !~ /\\$/)
+ {
+ $line =~ s/$/;/ if $binding == $CSHARP; # add the ";"
+ }
+
+ $line =~ s/ ?\| ?/ Or /g
+ if ($binding == $VBNET);
+
+ # check line is not split
+ $splitDefine = ($line =~ m/\\$/);
+
+ # ignore trailing "\"
+ $line =~ s/\\$// if $binding == $CSHARP;
+ $line =~ s/\\$/_/ if $binding == $VBNET;
+ print DATA_OUT $line;
+ next;
+ }
+
+ # test for function declaration
+ if (!$skip && $line =~ /EXP_FUNC/ && $line !~ /\/\*/)
+ {
+ $line = transformSignature($line);
+ $splitFunctionDeclaration = $line !~ /;/;
+ $line =~ s/;// if ($binding == $VBNET);
+ $line =~ s/\n$/ _\n/ if ($binding == $VBNET) &&
+ $splitFunctionDeclaration;
+ print DATA_OUT $line;
+ next;
+ }
+
+ if ($splitFunctionDeclaration)
+ {
+ $line = transformSignature($line);
+ $splitFunctionDeclaration = $line !~ /;/;
+ $line =~ s/;// if ($binding == $VBNET);
+ $line =~ s/\n/ _\n/ if ($binding == $VBNET) &&
+ $splitFunctionDeclaration == 1;
+ print DATA_OUT $line;
+ next;
+ }
+ }
+}
+
+#===============================================================
+
+# Determine which module to build from command-line options
+use strict;
+use Getopt::Std;
+
+my $binding_prefix;
+my $binding_suffix;
+my $data_file;
+my @raw_data;
+
+if (not defined $ARGV[0])
+{
+ goto ouch;
+}
+
+if ($ARGV[0] eq "-csharp")
+{
+ print "Generating C# interface file\n";
+ $binding_prefix = "csharp";
+ $binding_suffix = "cs";
+ $binding = $CSHARP;
+}
+elsif ($ARGV[0] eq "-vbnet")
+{
+ print "Generating VB.NET interface file\n";
+ $binding_prefix = "vbnet";
+ $binding_suffix = "vb";
+ $binding = $VBNET;
+}
+else
+{
+ouch:
+ die "Usage: $0 [-csharp | -vbnet]\n";
+}
+
+my $interfaceFile = "$binding_prefix/axInterface.$binding_suffix";
+
+# Input file required to generate interface file.
+$data_file = "../ssl/ssl.h";
+
+# Open input files
+open(DATA_IN, $data_file) || die("Could not open file ($data_file)!");
+@raw_data = <DATA_IN>;
+
+
+# Open output file
+if ($binding == $CSHARP || $binding == $VBNET)
+{
+ open(DATA_OUT, ">$interfaceFile") || die("Cannot Open File");
+}
+
+# SPEC interface file header
+if ($binding == $CSHARP)
+{
+ # generate the C#/C interface file
+ print DATA_OUT << "END";
+// The C# to C interface definition file for the axTLS project
+// Do not modify - this file is generated
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace axTLS
+{
+ public class axtls
+ {
+END
+}
+elsif ($binding == $VBNET)
+{
+ # generate the VB.NET/C interface file
+ print DATA_OUT << "END";
+' The VB.NET to C interface definition file for the axTLS project
+' Do not modify - this file is generated
+
+Imports System
+Imports System.Runtime.InteropServices
+
+Namespace axTLSvb
+ Public Class axtls
+END
+}
+
+parseFile(@raw_data);
+
+# finish up
+if ($binding == $CSHARP)
+{
+ print DATA_OUT " };\n";
+ print DATA_OUT "};\n";
+}
+elsif ($binding == $VBNET)
+{
+ print DATA_OUT " End Class\nEnd Namespace\n";
+}
+
+close(DATA_IN);
+close(DATA_OUT);
+
+#===============================================================
+
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+AXTLS_HOME=../..
+
+include $(AXTLS_HOME)/config/.config
+include $(AXTLS_HOME)/config/makefile.conf
+include $(AXTLS_HOME)/config/makefile.java.conf
+
+all: lib jar
+
+JAR=$(AXTLS_HOME)/$(STAGE)/axtls.jar
+
+ifdef CONFIG_PLATFORM_WIN32
+TARGET=$(AXTLS_HOME)/$(STAGE)/axtlsj.dll
+else
+TARGET=$(AXTLS_HOME)/$(STAGE)/libaxtlsj.so
+endif
+
+lib: $(TARGET)
+axTLSj_wrap.o : axTLSj_wrap.c
+
+JAVA_FILES= \
+ axtlsjJNI.java \
+ axtlsjConstants.java \
+ axtlsj.java \
+ SSLReadHolder.java \
+ SSL.java \
+ SSLUtil.java \
+ SSLCTX.java \
+ SSLServer.java \
+ SSLClient.java
+
+OBJ=axTLSj_wrap.o
+
+JAVA_CLASSES:=$(JAVA_FILES:%.java=classes/axTLSj/%.class)
+
+ifdef CONFIG_PLATFORM_WIN32
+LDFLAGS += axtls.lib /libpath:"$(AXTLS_HOME)/$(STAGE)"
+
+include $(AXTLS_HOME)/config/makefile.post
+
+$(TARGET) : $(OBJ)
+ $(LD) $(LDFLAGS) $(LDSHARED) /out:$@ $(OBJ)
+else # Not Win32
+
+$(TARGET) : $(OBJ)
+ $(LD) $(LDFLAGS) -L $(AXTLS_HOME)/$(STAGE) $(LDSHARED) -o $@ $(OBJ) -laxtls
+endif
+
+jar: $(OBJ) $(JAR)
+
+# if we are doing the samples then defer creating the jar until then
+$(JAR): $(JAVA_CLASSES)
+ifndef CONFIG_JAVA_SAMPLES
+ jar cvf $@ -C classes axTLSj
+else
+ @if [ ! -f $(JAR) ]; then touch $(JAR); fi
+endif
+
+classes/axTLSj/%.class : %.java
+ javac -d classes -classpath classes $^
+
+clean::
+ @rm -f $(JAR) $(TARGET) SWIG* axtls* *.i *.c
+ @rm -fr classes/*
+
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * A wrapper around the unmanaged interface to give a semi-decent Java API
+ */
+
+package axTLSj;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * @defgroup java_api Java API.
+ *
+ * Ensure that the appropriate dispose() methods are called when finished with
+ * various objects - otherwise memory leaks will result.
+ */
+
+/**
+ * @class SSL
+ * @ingroup java_api
+ * @brief A representation of an SSL connection.
+ *
+ */
+public class SSL
+{
+ public int m_ssl; /**< A pointer to the real SSL type */
+
+ /**
+ * @brief Store the reference to an SSL context.
+ * @param ip [in] A reference to an SSL object.
+ */
+ public SSL(int ip)
+ {
+ m_ssl = ip;
+ }
+
+ /**
+ * @brief Free any used resources on this connection.
+ *
+ * A "Close Notify" message is sent on this connection (if possible). It
+ * is up to the application to close the socket.
+ */
+ public void dispose()
+ {
+ axtlsj.ssl_free(m_ssl);
+ }
+
+ /**
+ * @brief Return the result of a handshake.
+ * @return SSL_OK if the handshake is complete and ok.
+ * @see ssl.h for the error code list.
+ */
+ public int handshakeStatus()
+ {
+ return axtlsj.ssl_handshake_status(m_ssl);
+ }
+
+ /**
+ * @brief Return the SSL cipher id.
+ * @return The cipher id which is one of:
+ * - SSL_AES128_SHA (0x2f)
+ * - SSL_AES256_SHA (0x35)
+ * - SSL_RC4_128_SHA (0x05)
+ * - SSL_RC4_128_MD5 (0x04)
+ */
+ public byte getCipherId()
+ {
+ return axtlsj.ssl_get_cipher_id(m_ssl);
+ }
+
+ /**
+ * @brief Get the session id for a handshake.
+ *
+ * This will be a 32 byte sequence and is available after the first
+ * handshaking messages are sent.
+ * @return The session id as a 32 byte sequence.
+ * @note A SSLv23 handshake may have only 16 valid bytes.
+ */
+ public byte[] getSessionId()
+ {
+ return axtlsj.ssl_get_session_id(m_ssl);
+ }
+
+ /**
+ * @brief Retrieve an X.509 distinguished name component.
+ *
+ * When a handshake is complete and a certificate has been exchanged,
+ * then the details of the remote certificate can be retrieved.
+ *
+ * This will usually be used by a client to check that the server's common
+ * name matches the URL.
+ *
+ * A full handshake needs to occur for this call to work.
+ *
+ * @param component [in] one of:
+ * - SSL_X509_CERT_COMMON_NAME
+ * - SSL_X509_CERT_ORGANIZATION
+ * - SSL_X509_CERT_ORGANIZATIONAL_NAME
+ * - SSL_X509_CA_CERT_COMMON_NAME
+ * - SSL_X509_CA_CERT_ORGANIZATION
+ * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME
+ * @return The appropriate string (or null if not defined)
+ */
+ public String getCertificateDN(int component)
+ {
+ return axtlsj.ssl_get_cert_dn(m_ssl, component);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * A wrapper around the unmanaged interface to give a semi-decent Java API
+ */
+
+package axTLSj;
+
+import java.net.*;
+
+/**
+ * @class SSLCTX
+ * @ingroup java_api
+ * @brief A base object for SSLServer/SSLClient.
+ */
+public class SSLCTX
+{
+ /**
+ * A reference to the real client/server context.
+ */
+ protected int m_ctx;
+
+ /**
+ * @brief Establish a new client/server context.
+ *
+ * This function is called before any client/server SSL connections are
+ * made. If multiple threads are used, then each thread will have its
+ * own SSLCTX context. Any number of connections may be made with a single
+ * context.
+ *
+ * Each new connection will use the this context's private key and
+ * certificate chain. If a different certificate chain is required, then a
+ * different context needs to be be used.
+ *
+ * @param options [in] Any particular options. At present the options
+ * supported are:
+ * - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if the
+ * server authentication fails. The certificate can be authenticated later
+ * with a call to verifyCert().
+ * - SSL_CLIENT_AUTHENTICATION (server only): Enforce client authentication
+ * i.e. each handshake will include a "certificate request" message from
+ * the server.
+ * - SSL_DISPLAY_BYTES (full mode build only): Display the byte sequences
+ * during the handshake.
+ * - SSL_DISPLAY_STATES (full mode build only): Display the state changes
+ * during the handshake.
+ * - SSL_DISPLAY_CERTS (full mode build only): Display the certificates that
+ * are passed during a handshake.
+ * - SSL_DISPLAY_RSA (full mode build only): Display the RSA key details
+ * that are passed during a handshake.
+ *
+ * @param num_sessions [in] The number of sessions to be used for session
+ * caching. If this value is 0, then there is no session caching.
+ *
+ * If this option is null, then the default internal private key/
+ * certificate pair is used (if CONFIG_SSL_USE_DEFAULT_KEY is set).
+ *
+ * The resources used by this object are automatically freed.
+ * @return A client/server context.
+ */
+ protected SSLCTX(int options, int num_sessions)
+ {
+ m_ctx = axtlsj.ssl_ctx_new(options, num_sessions);
+ }
+
+ /**
+ * @brief Remove a client/server context.
+ *
+ * Frees any used resources used by this context. Each connection will be
+ * sent a "Close Notify" alert (if possible).
+ */
+ public void dispose()
+ {
+ axtlsj.ssl_ctx_free(m_ctx);
+ }
+
+ /**
+ * @brief Read the SSL data stream.
+ * @param ssl [in] An SSL object reference.
+ * @param rh [out] After a successful read, the decrypted data can be
+ * retrieved with rh.getData(). It will be null otherwise.
+ * @return The number of decrypted bytes:
+ * - if > 0, then the handshaking is complete and we are returning the
+ * number of decrypted bytes.
+ * - SSL_OK if the handshaking stage is successful (but not yet complete).
+ * - < 0 if an error.
+ * @see ssl.h for the error code list.
+ * @note Use rh before doing any successive ssl calls.
+ */
+ public int read(SSL ssl, SSLReadHolder rh)
+ {
+ return axtlsj.ssl_read(ssl.m_ssl, rh);
+ }
+
+ /**
+ * @brief Write to the SSL data stream.
+ * @param ssl [in] An SSL obect reference.
+ * @param out_data [in] The data to be written
+ * @return The number of bytes sent, or if < 0 if an error.
+ * @see ssl.h for the error code list.
+ */
+ public int write(SSL ssl, byte[] out_data)
+ {
+ return axtlsj.ssl_write(ssl.m_ssl, out_data, out_data.length);
+ }
+
+ /**
+ * @brief Write to the SSL data stream.
+ * @param ssl [in] An SSL obect reference.
+ * @param out_data [in] The data to be written
+ * @param out_len [in] The number of bytes to be written
+ * @return The number of bytes sent, or if < 0 if an error.
+ * @see ssl.h for the error code list.
+ */
+ public int write(SSL ssl, byte[] out_data, int out_len)
+ {
+ return axtlsj.ssl_write(ssl.m_ssl, out_data, out_len);
+ }
+
+ /**
+ * @brief Find an ssl object based on a Socket reference.
+ *
+ * Goes through the list of SSL objects maintained in a client/server
+ * context to look for a socket match.
+ * @param s [in] A reference to a <A HREF="http://java.sun.com/j2se/1.4.2/docs/api">Socket</A> object.
+ * @return A reference to the SSL object. Returns null if the object
+ * could not be found.
+ */
+ public SSL find(Socket s)
+ {
+ int client_fd = axtlsj.getFd(s);
+ return new SSL(axtlsj.ssl_find(m_ctx, client_fd));
+ }
+
+ /**
+ * @brief Authenticate a received certificate.
+ *
+ * This call is usually made by a client after a handshake is complete
+ * and the context is in SSL_SERVER_VERIFY_LATER mode.
+ * @param ssl [in] An SSL object reference.
+ * @return SSL_OK if the certificate is verified.
+ */
+ public int verifyCert(SSL ssl)
+ {
+ return axtlsj.ssl_verify_cert(ssl.m_ssl);
+ }
+
+ /**
+ * @brief Force the client to perform its handshake again.
+ *
+ * For a client this involves sending another "client hello" message.
+ * For the server is means sending a "hello request" message.
+ *
+ * This is a blocking call on the client (until the handshake completes).
+ * @param ssl [in] An SSL object reference.
+ * @return SSL_OK if renegotiation instantiation was ok
+ */
+ public int renegotiate(SSL ssl)
+ {
+ return axtlsj.ssl_renegotiate(ssl.m_ssl);
+ }
+
+ /**
+ * @brief Load a file into memory that is in binary DER or ASCII PEM format.
+ *
+ * These are temporary objects that are used to load private keys,
+ * certificates etc into memory.
+ * @param obj_type [in] The format of the file. Can be one of:
+ * - SSL_OBJ_X509_CERT (no password required)
+ * - SSL_OBJ_X509_CACERT (no password required)
+ * - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported)
+ * - SSL_OBJ_P8 (RC4-128 encrypted data supported)
+ * - SSL_OBJ_P12 (RC4-128 encrypted data supported)
+ *
+ * PEM files are automatically detected (if supported).
+ * @param filename [in] The location of a file in DER/PEM format.
+ * @param password [in] The password used. Can be null if not required.
+ * @return SSL_OK if all ok
+ */
+ public int objLoad(int obj_type, String filename, String password)
+ {
+ return axtlsj.ssl_obj_load(m_ctx, obj_type, filename, password);
+ }
+
+ /**
+ * @brief Transfer binary data into the object loader.
+ *
+ * These are temporary objects that are used to load private keys,
+ * certificates etc into memory.
+ * @param obj_type [in] The format of the memory data.
+ * @param data [in] The binary data to be loaded.
+ * @param len [in] The amount of data to be loaded.
+ * @param password [in] The password used. Can be null if not required.
+ * @return SSL_OK if all ok
+ */
+
+ public int objLoad(int obj_type, byte[] data, int len, String password)
+ {
+ return axtlsj.ssl_obj_memory_load(m_ctx, obj_type, data, len, password);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * A wrapper around the unmanaged interface to give a semi-decent Java API
+ */
+
+package axTLSj;
+
+import java.net.*;
+
+/**
+ * @class SSLClient
+ * @ingroup java_api
+ * @brief The client context.
+ *
+ * All client connections are started within a client context.
+ */
+public class SSLClient extends SSLCTX
+{
+ /**
+ * @brief Start a new client context.
+ *
+ * @see SSLCTX for details.
+ */
+ public SSLClient(int options, int num_sessions)
+ {
+ super(options, num_sessions);
+ }
+
+ /**
+ * @brief Establish a new SSL connection to an SSL server.
+ *
+ * It is up to the application to establish the initial socket connection.
+ *
+ * This is a blocking call - it will finish when the handshake is
+ * complete (or has failed).
+ *
+ * Call dispose() when the connection is to be removed.
+ * @param s [in] A reference to a <A HREF="http://java.sun.com/j2se/1.4.2/docs/api">Socket</A> object.
+ * @param session_id [in] A 32 byte session id for session resumption. This
+ * can be null if no session resumption is not required.
+ * @return An SSL object reference. Use SSL.handshakeStatus() to check
+ * if a handshake succeeded.
+ */
+ public SSL connect(Socket s, byte[] session_id)
+ {
+ int client_fd = axtlsj.getFd(s);
+ byte sess_id_size = (byte)(session_id != null ?
+ session_id.length : 0);
+ return new SSL(axtlsj.ssl_client_new(m_ctx, client_fd, session_id,
+ sess_id_size));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * A wrapper around the unmanaged interface to give a semi-decent Java API
+ */
+
+package axTLSj;
+
+/**
+ * @class SSLReadHolder
+ * @ingroup java_api
+ * @brief A holder for data read in an SSL read.
+ */
+public class SSLReadHolder
+{
+ /**
+ * @brief Contruct a new read holder object.
+ */
+ public SSLReadHolder()
+ {
+ m_buf = null;
+ }
+
+ /**
+ * @brief Retrieve the reference to the read data.
+ */
+ public byte[] getData()
+ {
+ return m_buf;
+ }
+
+ private byte[] m_buf;
+}
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * A wrapper around the unmanaged interface to give a semi-decent Java API
+ */
+
+package axTLSj;
+
+import java.net.*;
+
+/**
+ * @class SSLServer
+ * @ingroup java_api
+ * @brief The server context.
+ *
+ * All server connections are started within a server context.
+ */
+public class SSLServer extends SSLCTX
+{
+ /**
+ * @brief Start a new server context.
+ *
+ * @see SSLCTX for details.
+ */
+ public SSLServer(int options, int num_sessions)
+ {
+ super(options, num_sessions);
+ }
+
+ /**
+ * @brief Establish a new SSL connection to an SSL client.
+ *
+ * It is up to the application to establish the initial socket connection.
+ *
+ * Call dispose() when the connection is to be removed.
+ * @param s [in] A reference to a <A HREF="http://java.sun.com/j2se/1.4.2/docs/api">Socket</A> object.
+ * @return An SSL object reference.
+ */
+ public SSL connect(Socket s)
+ {
+ int client_fd = axtlsj.getFd(s);
+ return new SSL(axtlsj.ssl_server_new(m_ctx, client_fd));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * A wrapper around the unmanaged interface to give a semi-decent Java API
+ */
+
+package axTLSj;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * @class SSLUtil
+ * @ingroup java_api
+ * @brief Some global helper functions.
+ *
+ */
+public class SSLUtil
+{
+ /**
+ * @brief Load up the ddl/shared library
+ */
+ static
+ {
+ System.loadLibrary("axtlsj");
+ }
+
+ /**
+ * @brief Return the build mode of the axTLS project.
+ * @return The build mode is one of:
+ * - SSL_BUILD_SERVER_ONLY
+ * - SSL_BUILD_ENABLE_VERIFICATION
+ * - SSL_BUILD_ENABLE_CLIENT
+ * - SSL_BUILD_FULL_MODE
+ */
+ public static int buildMode()
+ {
+ return axtlsj.ssl_get_config(axtlsj.SSL_BUILD_MODE);
+ }
+
+ /**
+ * @brief Return the number of chained certificates that the client/server
+ * supports.
+ * @return The number of supported client/server certificates.
+ */
+ public static int maxCerts()
+ {
+ return axtlsj.ssl_get_config(axtlsj.SSL_MAX_CERT_CFG_OFFSET);
+ }
+
+ /**
+ * @brief Return the number of CA certificates that the client/server
+ * supports.
+ * @return The number of supported CA certificates.
+ */
+ public static int maxCACerts()
+ {
+ return axtlsj.ssl_get_config(axtlsj.SSL_MAX_CA_CERT_CFG_OFFSET);
+ }
+
+ /**
+ * @brief Indicate if PEM is supported.
+ * @return true if PEM supported.
+ */
+ public static boolean hasPEM()
+ {
+ return axtlsj.ssl_get_config(axtlsj.SSL_HAS_PEM) > 0 ? true : false;
+ }
+
+ /**
+ * @brief Display the text string of the error.
+ * @param error_code [in] The integer error code.
+ * @see ssl.h for the error code list.
+ */
+ public static void displayError(int error_code)
+ {
+ axtlsj.ssl_display_error(error_code);
+ }
+
+ /**
+ * @brief Return the version of the axTLS project.
+ */
+ public static String version()
+ {
+ return axtlsj.ssl_version();
+ }
+}
+
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+AXTLS_HOME=../..
+
+include $(AXTLS_HOME)/config/.config
+include $(AXTLS_HOME)/config/makefile.conf
+
+all: lib
+
+
+ifdef CONFIG_PLATFORM_WIN32
+TARGET=$(AXTLS_HOME)/$(STAGE)/axtlsl.dll
+else
+TARGET=$(CONFIG_LUA_CORE)/lib/lua/5.1/axtlsl.so
+endif
+
+ifneq ($(MAKECMDGOALS), clean)
+
+lib: $(TARGET)
+OBJ:=axTLSl_wrap.o
+include $(AXTLS_HOME)/config/makefile.post
+
+# there are a few static functions that aren't used
+CFLAGS += -funit-at-a-time
+
+$(TARGET) : $(OBJ)
+ $(LD) $(LDFLAGS) $(LDSHARED) -o $@ $^ -L$(AXTLS_HOME)/$(STAGE) -L$(CONFIG_LUA_CORE)/lib -laxtls -llua
+
+CFLAGS += -I $(CONFIG_LUA_CORE)/include
+else
+CFLAGS += /I"`cygpath -w $(CONFIG_LUA_CORE)/include`"
+LDFLAGS += axtls.lib /libpath:"$(AXTLS_HOME)/$(STAGE)"
+
+$(TARGET) : $(OBJ)
+ $(LD) $(LDFLAGS) $(LDSHARED) /out:$@ $(OBJ)
+endif # WIN32
+
+clean::
+ @rm -f $(TARGET) *.i axTLSl* .depend
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+AXTLS_HOME=../..
+
+include $(AXTLS_HOME)/config/.config
+include $(AXTLS_HOME)/config/makefile.conf
+
+all: lib
+
+ifdef CONFIG_PLATFORM_WIN32
+TARGET=$(AXTLS_HOME)/$(STAGE)/axtlsp.dll
+else
+TARGET=$(AXTLS_HOME)/$(STAGE)/libaxtlsp.so
+endif
+
+ifneq ($(MAKECMDGOALS), clean)
+
+ifdef CONFIG_PLATFORM_WIN32
+PERL5_CORE:=$(shell cygpath -w "$(CONFIG_PERL_CORE)")
+else
+PERL5_CORE= $(shell perl -e 'use Config; print $$Config{archlib};')/CORE
+endif
+
+all: test_perl
+
+test_perl:
+ @if ! [ -d "$(PERL5_CORE)" ]; then \
+ echo "*** Error: Perl not installed at $(CONFIG_PERL_CORE) - go to " \
+ "http://www.cpan.org/authors/id/G/GR/GRAHAMC/SiePerl-5.8.0-bin-1.0-Win32.INSTALL.exe" && exit 1; \
+ fi
+
+endif
+
+lib: $(TARGET)
+OBJ:=axTLSp_wrap.o
+include $(AXTLS_HOME)/config/makefile.post
+
+ifndef CONFIG_PLATFORM_WIN32 # Linux/Unix/Cygwin
+
+#
+# Could have used libperl.a, but it increases the library to over 1MB, so just
+# use libperl.so. But this needs to be in the shared library path for things to
+# work.
+#
+$(TARGET) : $(OBJ)
+ $(LD) $(LDFLAGS) -L$(AXTLS_HOME)/$(STAGE) -L$(PERL5_CORE) $(LDSHARED) -o $@ $(OBJ) -laxtls -lperl
+ifdef CONFIG_PLATFORM_CYGWIN
+ cd $(AXTLS_HOME)/$(STAGE); ln -sf $(notdir $@) axtlsp.dll
+endif
+ @install axtlsp.pm $(AXTLS_HOME)/$(STAGE)
+
+CFLAGS += -D_GNU_SOURCE -I$(PERL5_CORE)
+else
+CFLAGS += /I"$(PERL5_CORE)"
+LDFLAGS += $(CONFIG_PERL_LIB) /libpath:"$(PERL5_CORE)" axtls.lib /libpath:"$(AXTLS_HOME)/$(STAGE)"
+
+$(TARGET) : $(OBJ)
+ $(LD) $(LDFLAGS) $(LDSHARED) /out:$@ $(OBJ)
+ install axtlsp.pm $(AXTLS_HOME)/$(STAGE)
+endif # WIN32
+
+clean::
+ @rm -f $(TARGET) axtls* *.i axTLSp* *.c .depend $(AXTLS_HOME)/$(STAGE)/axtlsp.pm
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+include ../../config/.config
+include ../../config/makefile.conf
+
+clean::
+ @rm -f axssl* axInterface.vb
--- /dev/null
+'
+' Copyright (c) 2007, Cameron Rich
+'
+' All rights reserved.
+'
+' Redistribution and use in source and binary forms, with or without
+' modification, are permitted provided that the following conditions are met:
+'
+' * Redistributions of source code must retain the above copyright notice,
+' this list of conditions and the following disclaimer.
+' * Redistributions in binary form must reproduce the above copyright
+' notice, this list of conditions and the following disclaimer in the
+' documentation and/or other materials provided with the distribution.
+' * Neither the name of the axTLS project nor the names of its
+' contributors may be used to endorse or promote products derived
+' from this software without specific prior written permission.
+'
+' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+' CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+' TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+' OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+' NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+' THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'
+
+'
+' A wrapper around the unmanaged Integererface to give a semi-decent VB.NET API
+'
+
+Imports System
+Imports System.Runtime.InteropServices
+Imports System.Net.Sockets
+Imports axTLSvb
+
+Namespace axTLSvb
+ Public Class SSL
+ Public m_ssl As IntPtr
+
+ Public Sub New(ByRef ip As IntPtr)
+ m_ssl = ip
+ End Sub
+
+ Public Sub Dispose()
+ axtls.ssl_free(m_ssl)
+ End Sub
+
+ Public Function HandshakeStatus() As Integer
+ Return axtls.ssl_handshake_status(m_ssl)
+ End Function
+
+ Public Function GetCipherId() As Byte
+ Return axtls.ssl_get_cipher_id(m_ssl)
+ End Function
+
+ Public Function GetSessionId() As Byte()
+ Dim ptr As IntPtr = axtls.ssl_get_session_id(m_ssl)
+ Dim sess_id_size As Integer = axtls.ssl_get_session_id_size(m_ssl)
+ Dim result(sess_id_size-1) As Byte
+ Marshal.Copy(ptr, result, 0, sess_id_size)
+ Return result
+ End Function
+
+ Public Function GetCertificateDN(component As Integer) As String
+ Return axtls.ssl_get_cert_dn(m_ssl, component)
+ End Function
+ End Class
+
+ Public Class SSLUtil
+ Private dummy As Integer ' need something here
+
+ Public Shared Function BuildMode() As Integer
+ Return axtls.ssl_get_config(axtls.SSL_BUILD_MODE)
+ End Function
+
+ Public Shared Function MaxCerts() As Integer
+ Return axtls.ssl_get_config(axtls.SSL_MAX_CERT_CFG_OFFSET)
+ End Function
+
+ Public Shared Function MaxCACerts() As Integer
+ Return axtls.ssl_get_config(axtls.SSL_MAX_CA_CERT_CFG_OFFSET)
+ End Function
+
+ Public Shared Function HasPEM() As Boolean
+ If axtls.ssl_get_config(axtls.SSL_HAS_PEM) > 0 Then
+ Return True
+ Else
+ Return False
+ End If
+ End Function
+
+ Public Shared Sub DisplayError(ByVal error_code As Integer)
+ axtls.ssl_display_error(error_code)
+ End Sub
+
+ Public Shared Function Version() As String
+ Return axtls.ssl_version()
+ End Function
+ End Class
+
+ Public Class SSLCTX
+ Protected m_ctx As IntPtr
+
+ Protected Sub New(ByVal options As Integer, _
+ ByVal num_sessions As Integer)
+ m_ctx = axtls.ssl_ctx_new(options, num_sessions)
+ End Sub
+
+ Public Sub Dispose()
+ axtls.ssl_ctx_free(m_ctx)
+ End Sub
+
+ Public Function Read(ByVal ssl As SSL, ByRef in_data As Byte()) As Integer
+ Dim ptr As IntPtr = IntPtr.Zero
+ Dim ret as Integer = axtls.ssl_read(ssl.m_ssl, ptr)
+
+ If ret > axtls.SSL_OK Then
+ ReDim in_data(ret)
+ Marshal.Copy(ptr, in_data, 0, ret)
+ Else
+ in_data = Nothing
+ End If
+
+ Return ret
+ End Function
+
+ Public Function Write(ByVal ssl As SSL, _
+ ByVal data As Byte(), len As Integer) As Integer
+ Return axtls.ssl_write(ssl.m_ssl, data, len)
+ End Function
+
+ Public Function Find(ByVal s As Socket) As SSL
+ Dim client_fd As Integer = s.Handle.ToInt32()
+ Return New SSL(axtls.ssl_find(m_ctx, client_fd))
+ End Function
+
+ Public Function VerifyCert(ByVal ssl As SSL) As Integer
+ Return axtls.ssl_verify_cert(ssl.m_ssl)
+ End Function
+
+ Public Function Renegotiate(ByVal ssl As SSL) As Integer
+ Return axtls.ssl_renegotiate(ssl.m_ssl)
+ End Function
+
+ Public Function ObjLoad(ByVal obj_type As Integer, _
+ ByVal filename As String, _
+ password As String) As Integer
+ Return axtls.ssl_obj_load(m_ctx, obj_type, filename, password)
+ End Function
+
+ Public Function ObjLoad(ByVal obj_type As Integer, _
+ ByVal data As Byte(), ByVal len As Integer, _
+ password As String) As Integer
+ Return axtls.ssl_obj_memory_load( _
+ m_ctx, obj_type, data, len, password)
+ End Function
+ End Class
+
+ Public Class SSLServer
+ Inherits SSLCTX
+
+ Public Sub New(ByVal options As Integer, _
+ ByVal num_sessions As Integer)
+ MyBase.New(options, num_sessions)
+ End Sub
+
+ Public Function Connect(ByVal s As Socket) As SSL
+ Dim client_fd As Integer = s.Handle.ToInt32()
+ Return New SSL(axtls.ssl_server_new(m_ctx, client_fd))
+ End Function
+ End Class
+
+ Public Class SSLClient
+ Inherits SSLCTX
+
+ Public Sub New(ByVal options As Integer, _
+ ByVal num_sessions As Integer)
+ MyBase.New(options, num_sessions)
+ End Sub
+
+ Public Function Connect(ByVal s As Socket, _
+ ByVal session_id As Byte()) As SSL
+ Dim client_fd As Integer = s.Handle.ToInt32()
+ Dim sess_id_size As Byte
+ If session_id is Nothing Then
+ sess_id_size = 0
+ Else
+ sess_id_size = session_id.Length
+ End If
+
+ Return New SSL(axtls.ssl_client_new(m_ctx, client_fd, session_id, _
+ sess_id_size))
+ End Function
+
+ End Class
+End Namespace
--- /dev/null
+#
+# Automatically generated make config: don't edit
+#
+HAVE_DOT_CONFIG=y
+CONFIG_PLATFORM_LINUX=y
+# CONFIG_PLATFORM_CYGWIN is not set
+# CONFIG_PLATFORM_WIN32 is not set
+
+#
+# General Configuration
+#
+PREFIX="/usr"
+# CONFIG_DEBUG is not set
+CONFIG_STRIP_UNWANTED_SECTIONS=y
+# CONFIG_VISUAL_STUDIO_7_0 is not set
+# CONFIG_VISUAL_STUDIO_8_0 is not set
+CONFIG_VISUAL_STUDIO_7_0_BASE=""
+CONFIG_VISUAL_STUDIO_8_0_BASE=""
+CONFIG_EXTRA_CFLAGS_OPTIONS="-fpic"
+CONFIG_EXTRA_LDFLAGS_OPTIONS=""
+
+#
+# SSL Library
+#
+# CONFIG_SSL_SERVER_ONLY is not set
+# CONFIG_SSL_CERT_VERIFICATION is not set
+CONFIG_SSL_ENABLE_CLIENT=y
+# CONFIG_SSL_FULL_MODE is not set
+# CONFIG_SSL_SKELETON_MODE is not set
+# CONFIG_SSL_PROT_LOW is not set
+CONFIG_SSL_PROT_MEDIUM=y
+# CONFIG_SSL_PROT_HIGH is not set
+CONFIG_SSL_USE_DEFAULT_KEY=y
+CONFIG_SSL_PRIVATE_KEY_LOCATION=""
+CONFIG_SSL_PRIVATE_KEY_PASSWORD=""
+CONFIG_SSL_X509_CERT_LOCATION=""
+CONFIG_SSL_GENERATE_X509_CERT=y
+CONFIG_SSL_X509_COMMON_NAME=""
+CONFIG_SSL_X509_ORGANIZATION_NAME=""
+CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME=""
+CONFIG_SSL_ENABLE_V23_HANDSHAKE=y
+CONFIG_SSL_HAS_PEM=y
+# CONFIG_SSL_USE_PKCS12 is not set
+CONFIG_SSL_EXPIRY_TIME=24
+CONFIG_X509_MAX_CA_CERTS=4
+CONFIG_SSL_MAX_CERTS=2
+CONFIG_SSL_CTX_MUTEXING=y
+CONFIG_USE_DEV_URANDOM=y
+# CONFIG_WIN32_USE_CRYPTO_LIB is not set
+# CONFIG_OPENSSL_COMPATIBLE is not set
+# CONFIG_PERFORMANCE_TESTING is not set
+# CONFIG_SSL_TEST is not set
+# CONFIG_AXHTTPD is not set
+# CONFIG_HTTP_STATIC_BUILD is not set
+CONFIG_HTTP_PORT=0
+CONFIG_HTTP_HTTPS_PORT=0
+CONFIG_HTTP_SESSION_CACHE_SIZE=0
+CONFIG_HTTP_WEBROOT=""
+CONFIG_HTTP_TIMEOUT=0
+# CONFIG_HTTP_HAS_CGI is not set
+CONFIG_HTTP_CGI_EXTENSIONS=""
+# CONFIG_HTTP_ENABLE_LUA is not set
+CONFIG_HTTP_LUA_PREFIX=""
+CONFIG_HTTP_LUA_CGI_LAUNCHER=""
+# CONFIG_HTTP_BUILD_LUA is not set
+# CONFIG_HTTP_DIRECTORIES is not set
+# CONFIG_HTTP_HAS_AUTHORIZATION is not set
+# CONFIG_HTTP_HAS_IPV6 is not set
+# CONFIG_HTTP_ENABLE_DIFFERENT_USER is not set
+CONFIG_HTTP_USER=""
+# CONFIG_HTTP_VERBOSE is not set
+# CONFIG_HTTP_IS_DAEMON is not set
+
+#
+# Language Bindings
+#
+# CONFIG_BINDINGS is not set
+# CONFIG_CSHARP_BINDINGS is not set
+# CONFIG_VBNET_BINDINGS is not set
+CONFIG_DOT_NET_FRAMEWORK_BASE=""
+# CONFIG_JAVA_BINDINGS is not set
+CONFIG_JAVA_HOME=""
+# CONFIG_PERL_BINDINGS is not set
+CONFIG_PERL_CORE=""
+CONFIG_PERL_LIB=""
+# CONFIG_LUA_BINDINGS is not set
+CONFIG_LUA_CORE=""
+
+#
+# Samples
+#
+# CONFIG_SAMPLES is not set
+# CONFIG_C_SAMPLES is not set
+# CONFIG_CSHARP_SAMPLES is not set
+# CONFIG_VBNET_SAMPLES is not set
+# CONFIG_JAVA_SAMPLES is not set
+# CONFIG_PERL_SAMPLES is not set
+# CONFIG_LUA_SAMPLES is not set
+
+#
+# BigInt Options
+#
+# CONFIG_BIGINT_CLASSICAL is not set
+# CONFIG_BIGINT_MONTGOMERY is not set
+CONFIG_BIGINT_BARRETT=y
+CONFIG_BIGINT_CRT=y
+# CONFIG_BIGINT_KARATSUBA is not set
+MUL_KARATSUBA_THRESH=0
+SQU_KARATSUBA_THRESH=0
+CONFIG_BIGINT_SLIDING_WINDOW=y
+CONFIG_BIGINT_SQUARE=y
+# CONFIG_BIGINT_CHECK_ON is not set
--- /dev/null
+#
+# For a description of the syntax of this configuration file,
+# see scripts/config/Kconfig-language.txt
+#
+
+mainmenu "axTLS Configuration"
+
+config HAVE_DOT_CONFIG
+ bool
+ default y
+
+choice
+ prompt "Platform"
+ default CONFIG_PLATFORM_LINUX
+
+config CONFIG_PLATFORM_LINUX
+ bool "Linux"
+
+config CONFIG_PLATFORM_CYGWIN
+ bool "Cygwin"
+
+config CONFIG_PLATFORM_WIN32
+ bool "Win32"
+
+endchoice
+
+menu "General Configuration"
+
+config PREFIX
+ string "axTLS installation prefix"
+ depends on !CONFIG_PLATFORM_WIN32
+ default "/usr/local"
+ help
+ Define your directory to install axTLS files/subdirs in.
+
+config CONFIG_DEBUG
+ bool "Build axTLS with Debugging symbols"
+ default n
+ help
+ Say Y here if you wish to compile axTLS with debugging symbols.
+ This will allow you to use a debugger to examine axTLS internals.
+ This increases the size of the binary considerably and should only be
+ used when doing development.
+ If you are doing development and want to debug axTLS, answer Y.
+
+ Most people should answer N.
+
+config CONFIG_STRIP_UNWANTED_SECTIONS
+ depends on !CONFIG_PLATFORM_WIN32 && !CONFIG_DEBUG
+ bool "Strip unwanted sections from elf binaries"
+ default y
+ help
+ Strip unwanted sections from the resulting binaries
+
+menu "Microsoft Compiler Options"
+depends on CONFIG_PLATFORM_WIN32
+
+choice
+ prompt "Compiler"
+ depends on CONFIG_PLATFORM_WIN32
+ default CONFIG_VISUAL_STUDIO_7_0
+
+config CONFIG_VISUAL_STUDIO_7_0
+ bool "Visual Studio 7.0 (2003)"
+ help
+ Use Microsoft's Visual Studio 2003 platform.
+
+config CONFIG_VISUAL_STUDIO_8_0
+ bool "Visual Studio 8.0 (2005)"
+ help
+ Use Microsoft's Visual Studio 2005 platform.
+
+endchoice
+
+config CONFIG_VISUAL_STUDIO_7_0_BASE
+ string "Base"
+ depends on CONFIG_VISUAL_STUDIO_7_0
+ default "c:\\Program Files\\Microsoft Visual Studio .NET 2003"
+
+config CONFIG_VISUAL_STUDIO_8_0_BASE
+ string "Base"
+ depends on CONFIG_VISUAL_STUDIO_8_0
+ default "c:\\Program Files\\Microsoft Visual Studio 8"
+
+endmenu
+
+config CONFIG_EXTRA_CFLAGS_OPTIONS
+ string "Any extra CFLAGS options for the compiler?"
+ help
+ Do you want to pass any extra CFLAGS options to the compiler as
+ you build axTLS? If so, this is the option for you... For
+ example, if you want to add some simple compiler switches (like
+ -march=i686), or check for warnings using -Werror, just those
+ options here.
+
+config CONFIG_EXTRA_LDFLAGS_OPTIONS
+ string "Any extra LDFLAGS options for the compiler?"
+ help
+ Do you want to pass any extra LDFLAGS options to the compiler?
+
+endmenu
+
+source ssl/Config.in
+config CONFIG_AXHTTPD
+ bool "Enable HTTP/HTTPS Web Server"
+ default y
+ help
+ Build the AXHTTPD web server
+
+source httpd/Config.in
+source bindings/Config.in
+source samples/Config.in
+source ssl/BigIntConfig.in
+
--- /dev/null
+<jmeterTestPlan version="1.2" properties="1.8">
+ <hashTree>
+ <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="axhttpd Test Plan" enabled="true">
+ <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+ <collectionProp name="Arguments.arguments"/>
+ </elementProp>
+ <stringProp name="TestPlan.user_define_classpath"></stringProp>
+ <boolProp name="TestPlan.serialize_threadgroups">true</boolProp>
+ <boolProp name="TestPlan.functional_mode">false</boolProp>
+ <stringProp name="TestPlan.comments"></stringProp>
+ </TestPlan>
+ <hashTree>
+ <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Test 1" enabled="true">
+ <longProp name="ThreadGroup.start_time">1152004173000</longProp>
+ <stringProp name="ThreadGroup.delay"></stringProp>
+ <stringProp name="ThreadGroup.duration"></stringProp>
+ <stringProp name="ThreadGroup.num_threads">16</stringProp>
+ <boolProp name="ThreadGroup.scheduler">false</boolProp>
+ <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
+ <stringProp name="LoopController.loops">10</stringProp>
+ <boolProp name="LoopController.continue_forever">false</boolProp>
+ </elementProp>
+ <longProp name="ThreadGroup.end_time">1152004173000</longProp>
+ <stringProp name="ThreadGroup.on_sample_error">stopthread</stringProp>
+ <stringProp name="ThreadGroup.ramp_time">0</stringProp>
+ </ThreadGroup>
+ <hashTree>
+ <HTTPSampler guiclass="HttpTestSampleGui" testclass="HTTPSampler" testname="Normal" enabled="true">
+ <stringProp name="HTTPSampler.path">/index.html</stringProp>
+ <stringProp name="HTTPSampler.method">GET</stringProp>
+ <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+ <stringProp name="HTTPSampler.protocol"></stringProp>
+ <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+ <stringProp name="HTTPSampler.port">80</stringProp>
+ <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+ <collectionProp name="Arguments.arguments"/>
+ </elementProp>
+ <stringProp name="HTTPSampler.mimetype"></stringProp>
+ <stringProp name="HTTPSampler.FILE_FIELD"></stringProp>
+ <stringProp name="HTTPSampler.monitor">false</stringProp>
+ <stringProp name="HTTPSampler.domain">127.0.0.1</stringProp>
+ <stringProp name="HTTPSampler.FILE_NAME"></stringProp>
+ <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+ </HTTPSampler>
+ <hashTree/>
+ </hashTree>
+ <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Test 2" enabled="true">
+ <longProp name="ThreadGroup.start_time">1152004173000</longProp>
+ <stringProp name="ThreadGroup.delay"></stringProp>
+ <stringProp name="ThreadGroup.duration"></stringProp>
+ <stringProp name="ThreadGroup.num_threads">16</stringProp>
+ <boolProp name="ThreadGroup.scheduler">false</boolProp>
+ <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
+ <stringProp name="LoopController.loops">10</stringProp>
+ <boolProp name="LoopController.continue_forever">false</boolProp>
+ </elementProp>
+ <longProp name="ThreadGroup.end_time">1152004173000</longProp>
+ <stringProp name="ThreadGroup.on_sample_error">stopthread</stringProp>
+ <stringProp name="ThreadGroup.ramp_time">0</stringProp>
+ </ThreadGroup>
+ <hashTree>
+ <HTTPSampler guiclass="HttpTestSampleGui" testclass="HTTPSampler" testname="RC4" enabled="true">
+ <stringProp name="HTTPSampler.path">/index.html</stringProp>
+ <stringProp name="HTTPSampler.method">GET</stringProp>
+ <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+ <stringProp name="HTTPSampler.protocol">HTTPS</stringProp>
+ <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+ <stringProp name="HTTPSampler.port">443</stringProp>
+ <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+ <collectionProp name="Arguments.arguments"/>
+ </elementProp>
+ <stringProp name="HTTPSampler.mimetype"></stringProp>
+ <stringProp name="HTTPSampler.FILE_FIELD"></stringProp>
+ <stringProp name="HTTPSampler.monitor">false</stringProp>
+ <stringProp name="HTTPSampler.domain">127.0.0.1</stringProp>
+ <stringProp name="HTTPSampler.FILE_NAME"></stringProp>
+ <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+ </HTTPSampler>
+ <hashTree/>
+ </hashTree>
+ <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Test 3" enabled="true">
+ <longProp name="ThreadGroup.start_time">1152004173000</longProp>
+ <stringProp name="ThreadGroup.delay"></stringProp>
+ <stringProp name="ThreadGroup.duration"></stringProp>
+ <stringProp name="ThreadGroup.num_threads">16</stringProp>
+ <boolProp name="ThreadGroup.scheduler">false</boolProp>
+ <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
+ <stringProp name="LoopController.loops">10</stringProp>
+ <boolProp name="LoopController.continue_forever">false</boolProp>
+ </elementProp>
+ <longProp name="ThreadGroup.end_time">1152004173000</longProp>
+ <stringProp name="ThreadGroup.on_sample_error">stopthread</stringProp>
+ <stringProp name="ThreadGroup.ramp_time">0</stringProp>
+ </ThreadGroup>
+ <hashTree>
+ <HTTPSampler guiclass="HttpTestSampleGui" testclass="HTTPSampler" testname="AES128" enabled="true">
+ <stringProp name="HTTPSampler.path">/index.html</stringProp>
+ <stringProp name="HTTPSampler.method">GET</stringProp>
+ <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+ <stringProp name="HTTPSampler.protocol">HTTPS</stringProp>
+ <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+ <stringProp name="HTTPSampler.port">2443</stringProp>
+ <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+ <collectionProp name="Arguments.arguments"/>
+ </elementProp>
+ <stringProp name="HTTPSampler.mimetype"></stringProp>
+ <stringProp name="HTTPSampler.FILE_FIELD"></stringProp>
+ <stringProp name="HTTPSampler.monitor">false</stringProp>
+ <stringProp name="HTTPSampler.domain">127.0.0.1</stringProp>
+ <stringProp name="HTTPSampler.FILE_NAME"></stringProp>
+ <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+ </HTTPSampler>
+ <hashTree/>
+ </hashTree>
+ <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Test 4" enabled="true">
+ <longProp name="ThreadGroup.start_time">1152004173000</longProp>
+ <stringProp name="ThreadGroup.delay"></stringProp>
+ <stringProp name="ThreadGroup.duration"></stringProp>
+ <stringProp name="ThreadGroup.num_threads">16</stringProp>
+ <boolProp name="ThreadGroup.scheduler">false</boolProp>
+ <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
+ <stringProp name="LoopController.loops">10</stringProp>
+ <boolProp name="LoopController.continue_forever">false</boolProp>
+ </elementProp>
+ <longProp name="ThreadGroup.end_time">1152004173000</longProp>
+ <stringProp name="ThreadGroup.on_sample_error">stopthread</stringProp>
+ <stringProp name="ThreadGroup.ramp_time">0</stringProp>
+ </ThreadGroup>
+ <hashTree>
+ <HTTPSampler guiclass="HttpTestSampleGui" testclass="HTTPSampler" testname="AES256" enabled="true">
+ <stringProp name="HTTPSampler.path">/index.html</stringProp>
+ <stringProp name="HTTPSampler.method">GET</stringProp>
+ <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+ <stringProp name="HTTPSampler.protocol">HTTPS</stringProp>
+ <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+ <stringProp name="HTTPSampler.port">3443</stringProp>
+ <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+ <collectionProp name="Arguments.arguments"/>
+ </elementProp>
+ <stringProp name="HTTPSampler.mimetype"></stringProp>
+ <stringProp name="HTTPSampler.FILE_FIELD"></stringProp>
+ <stringProp name="HTTPSampler.monitor">false</stringProp>
+ <stringProp name="HTTPSampler.domain">127.0.0.1</stringProp>
+ <stringProp name="HTTPSampler.FILE_NAME"></stringProp>
+ <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+ </HTTPSampler>
+ <hashTree/>
+ </hashTree>
+ <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Test 5" enabled="true">
+ <longProp name="ThreadGroup.start_time">1152004173000</longProp>
+ <stringProp name="ThreadGroup.delay"></stringProp>
+ <stringProp name="ThreadGroup.duration"></stringProp>
+ <stringProp name="ThreadGroup.num_threads">16</stringProp>
+ <boolProp name="ThreadGroup.scheduler">false</boolProp>
+ <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
+ <stringProp name="LoopController.loops">10</stringProp>
+ <boolProp name="LoopController.continue_forever">false</boolProp>
+ </elementProp>
+ <longProp name="ThreadGroup.end_time">1152004173000</longProp>
+ <stringProp name="ThreadGroup.on_sample_error">stopthread</stringProp>
+ <stringProp name="ThreadGroup.ramp_time">0</stringProp>
+ </ThreadGroup>
+ <hashTree>
+ <HTTPSampler guiclass="HttpTestSampleGui" testclass="HTTPSampler" testname="Skeleton (RC4)" enabled="true">
+ <stringProp name="HTTPSampler.path">/index.html</stringProp>
+ <stringProp name="HTTPSampler.method">GET</stringProp>
+ <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+ <stringProp name="HTTPSampler.protocol">HTTPS</stringProp>
+ <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+ <stringProp name="HTTPSampler.port">1443</stringProp>
+ <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+ <collectionProp name="Arguments.arguments"/>
+ </elementProp>
+ <stringProp name="HTTPSampler.mimetype"></stringProp>
+ <stringProp name="HTTPSampler.FILE_FIELD"></stringProp>
+ <stringProp name="HTTPSampler.monitor">false</stringProp>
+ <stringProp name="HTTPSampler.domain">127.0.0.1</stringProp>
+ <stringProp name="HTTPSampler.FILE_NAME"></stringProp>
+ <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+ </HTTPSampler>
+ <hashTree/>
+ </hashTree>
+ <ResultCollector guiclass="StatGraphVisualizer" testclass="ResultCollector" testname="Aggregate Graph" enabled="true">
+ <objProp>
+ <value class="SampleSaveConfiguration">
+ <time>true</time>
+ <latency>true</latency>
+ <timestamp>true</timestamp>
+ <success>true</success>
+ <label>true</label>
+ <code>true</code>
+ <message>true</message>
+ <threadName>true</threadName>
+ <dataType>true</dataType>
+ <encoding>false</encoding>
+ <assertions>true</assertions>
+ <subresults>true</subresults>
+ <responseData>false</responseData>
+ <samplerData>false</samplerData>
+ <xml>false</xml>
+ <fieldNames>false</fieldNames>
+ <responseHeaders>false</responseHeaders>
+ <requestHeaders>false</requestHeaders>
+ <responseDataOnError>false</responseDataOnError>
+ <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
+ <assertionsResultsToSave>0</assertionsResultsToSave>
+ </value>
+ <name>saveConfig</name>
+ </objProp>
+ <stringProp name="filename"></stringProp>
+ <boolProp name="ResultCollector.error_logging">false</boolProp>
+ </ResultCollector>
+ <hashTree/>
+ <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="false">
+ <objProp>
+ <value class="SampleSaveConfiguration">
+ <time>true</time>
+ <latency>true</latency>
+ <timestamp>true</timestamp>
+ <success>true</success>
+ <label>true</label>
+ <code>true</code>
+ <message>true</message>
+ <threadName>true</threadName>
+ <dataType>true</dataType>
+ <encoding>false</encoding>
+ <assertions>true</assertions>
+ <subresults>true</subresults>
+ <responseData>false</responseData>
+ <samplerData>false</samplerData>
+ <xml>false</xml>
+ <fieldNames>false</fieldNames>
+ <responseHeaders>false</responseHeaders>
+ <requestHeaders>false</requestHeaders>
+ <responseDataOnError>false</responseDataOnError>
+ <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
+ <assertionsResultsToSave>0</assertionsResultsToSave>
+ </value>
+ <name>saveConfig</name>
+ </objProp>
+ <stringProp name="filename"></stringProp>
+ <boolProp name="ResultCollector.error_logging">false</boolProp>
+ </ResultCollector>
+ <hashTree/>
+ </hashTree>
+ </hashTree>
+</jmeterTestPlan>
--- /dev/null
+# Rules.make for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under GPLv2, see the file LICENSE in this tarball for details.
+#
+
+# Pull in the user's busybox configuration
+ifeq ($(filter $(noconfig_targets),$(MAKECMDGOALS)),)
+-include $(top_builddir)/.config
+endif
+
+#--------------------------------------------------------
+PROG := busybox
+MAJOR_VERSION :=1
+MINOR_VERSION :=1
+SUBLEVEL_VERSION:=0
+EXTRAVERSION :=
+VERSION :=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBLEVEL_VERSION)$(EXTRAVERSION)
+BUILDTIME := $(shell TZ=UTC date -u "+%Y.%m.%d-%H:%M%z")
+
+
+#--------------------------------------------------------
+# With a modern GNU make(1) (highly recommended, that's what all the
+# developers use), all of the following configuration values can be
+# overridden at the command line. For example:
+# make CROSS=powerpc-linux- top_srcdir="$HOME/busybox" PREFIX=/mnt/app
+#--------------------------------------------------------
+
+# If you are running a cross compiler, you will want to set 'CROSS'
+# to something more interesting... Target architecture is determined
+# by asking the CC compiler what arch it compiles things for, so unless
+# your compiler is broken, you should not need to specify TARGET_ARCH
+CROSS =$(subst ",, $(strip $(CROSS_COMPILER_PREFIX)))
+CC = $(CROSS)gcc
+AR = $(CROSS)ar
+AS = $(CROSS)as
+LD = $(CROSS)ld
+NM = $(CROSS)nm
+STRIP = $(CROSS)strip
+CPP = $(CC) -E
+# MAKEFILES = $(top_builddir)/.config
+RM = rm
+RM_F = $(RM) -f
+LN = ln
+LN_S = $(LN) -s
+MKDIR = mkdir
+MKDIR_P = $(MKDIR) -p
+MV = mv
+CP = cp
+
+
+# What OS are you compiling busybox for? This allows you to include
+# OS specific things, syscall overrides, etc.
+TARGET_OS=linux
+
+# Select the compiler needed to build binaries for your development system
+HOSTCC = gcc
+HOSTCFLAGS= -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+
+# Ensure consistent sort order, 'gcc -print-search-dirs' behavior, etc.
+LC_ALL:= C
+
+# If you want to add some simple compiler switches (like -march=i686),
+# especially from the command line, use this instead of CFLAGS directly.
+# For optimization overrides, it's better still to set OPTIMIZATION.
+CFLAGS_EXTRA=$(subst ",, $(strip $(EXTRA_CFLAGS_OPTIONS)))
+
+# To compile vs some other alternative libc, you may need to use/adjust
+# the following lines to meet your needs...
+#
+# If you are using Red Hat 6.x with the compatible RPMs (for developing under
+# Red Hat 5.x and glibc 2.0) uncomment the following. Be sure to read about
+# using the compatible RPMs (compat-*) at http://www.redhat.com !
+#LIBCDIR:=/usr/i386-glibc20-linux
+#
+# For other libraries, you are on your own. But these may (or may not) help...
+#LDFLAGS+=-nostdlib
+#LIBRARIES:=$(LIBCDIR)/lib/libc.a -lgcc
+#CROSS_CFLAGS+=-nostdinc -I$(LIBCDIR)/include -I$(GCCINCDIR) -funsigned-char
+#GCCINCDIR:=$(shell gcc -print-search-dirs | sed -ne "s/install: \(.*\)/\1include/gp")
+
+WARNINGS=-Wall -Wstrict-prototypes -Wshadow
+CFLAGS=-I$(top_builddir)/include -I$(top_srcdir)/include -I$(srcdir)
+ARFLAGS=cru
+
+
+# gcc centric. Perhaps fiddle with findstring gcc,$(CC) for the rest
+# get the CC MAJOR/MINOR version
+CC_MAJOR:=$(shell printf "%02d" $(shell echo __GNUC__ | $(CC) -E -xc - | tail -n 1))
+CC_MINOR:=$(shell printf "%02d" $(shell echo __GNUC_MINOR__ | $(CC) -E -xc - | tail -n 1))
+
+#--------------------------------------------------------
+export VERSION BUILDTIME HOSTCC HOSTCFLAGS CROSS CC AR AS LD NM STRIP CPP
+ifeq ($(strip $(TARGET_ARCH)),)
+TARGET_ARCH:=$(shell $(CC) -dumpmachine | sed -e s'/-.*//' \
+ -e 's/i.86/i386/' \
+ -e 's/sparc.*/sparc/' \
+ -e 's/arm.*/arm/g' \
+ -e 's/m68k.*/m68k/' \
+ -e 's/ppc/powerpc/g' \
+ -e 's/v850.*/v850/g' \
+ -e 's/sh[234]/sh/' \
+ -e 's/mips-.*/mips/' \
+ -e 's/mipsel-.*/mipsel/' \
+ -e 's/cris.*/cris/' \
+ )
+endif
+
+# A nifty macro to make testing gcc features easier
+check_gcc=$(shell \
+ if [ "$(1)" != "" ]; then \
+ if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; \
+ then echo "$(1)"; else echo "$(2)"; fi \
+ fi)
+
+# Setup some shortcuts so that silent mode is silent like it should be
+ifeq ($(subst s,,$(MAKEFLAGS)),$(MAKEFLAGS))
+export MAKE_IS_SILENT=n
+SECHO=@echo
+else
+export MAKE_IS_SILENT=y
+SECHO=-@false
+endif
+
+CFLAGS+=$(call check_gcc,-funsigned-char,)
+
+#--------------------------------------------------------
+# Arch specific compiler optimization stuff should go here.
+# Unless you want to override the defaults, do not set anything
+# for OPTIMIZATION...
+
+# use '-Os' optimization if available, else use -O2
+OPTIMIZATION:=$(call check_gcc,-Os,-O2)
+
+# Some nice architecture specific optimizations
+ifeq ($(strip $(TARGET_ARCH)),arm)
+ OPTIMIZATION+=-fstrict-aliasing
+endif
+ifeq ($(strip $(TARGET_ARCH)),i386)
+ OPTIMIZATION+=$(call check_gcc,-march=i386,)
+ OPTIMIZATION+=$(call check_gcc,-mpreferred-stack-boundary=2,)
+ OPTIMIZATION+=$(call check_gcc,-falign-functions=0 -falign-jumps=0 -falign-loops=0,\
+ -malign-functions=0 -malign-jumps=0 -malign-loops=0)
+endif
+OPTIMIZATIONS:=$(OPTIMIZATION) -fomit-frame-pointer
+
+#
+#--------------------------------------------------------
+# If you're going to do a lot of builds with a non-vanilla configuration,
+# it makes sense to adjust parameters above, so you can type "make"
+# by itself, instead of following it by the same half-dozen overrides
+# every time. The stuff below, on the other hand, is probably less
+# prone to casual user adjustment.
+#
+
+ifeq ($(strip $(CONFIG_LFS)),y)
+ # For large file summit support
+ CFLAGS+=-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+endif
+ifeq ($(strip $(CONFIG_DMALLOC)),y)
+ # For testing mem leaks with dmalloc
+ CFLAGS+=-DDMALLOC
+ LIBRARIES:=-ldmalloc
+else
+ ifeq ($(strip $(CONFIG_EFENCE)),y)
+ LIBRARIES:=-lefence
+ endif
+endif
+ifeq ($(strip $(CONFIG_DEBUG)),y)
+ CFLAGS +=$(WARNINGS) -g -D_GNU_SOURCE
+ LDFLAGS +=-Wl,-warn-common
+ STRIPCMD:=/bin/true -Not_stripping_since_we_are_debugging
+else
+ CFLAGS+=$(WARNINGS) $(OPTIMIZATIONS) -D_GNU_SOURCE -DNDEBUG
+ LDFLAGS += -Wl,-warn-common
+ STRIPCMD:=$(STRIP) -s --remove-section=.note --remove-section=.comment
+endif
+ifeq ($(strip $(CONFIG_STATIC)),y)
+ LDFLAGS += --static
+endif
+
+ifeq ($(strip $(CONFIG_SELINUX)),y)
+ LIBRARIES += -lselinux
+endif
+
+ifeq ($(strip $(PREFIX)),)
+ PREFIX:=`pwd`/_install
+endif
+
+# Additional complications due to support for pristine source dir.
+# Include files in the build directory should take precedence over
+# the copy in top_srcdir, both during the compilation phase and the
+# shell script that finds the list of object files.
+# Work in progress by <ldoolitt@recycle.lbl.gov>.
+
+
+OBJECTS:=$(APPLET_SOURCES:.c=.o) busybox.o usage.o applets.o
+CFLAGS += $(CROSS_CFLAGS)
+ifdef BB_INIT_SCRIPT
+ CFLAGS += -DINIT_SCRIPT='"$(BB_INIT_SCRIPT)"'
+endif
+
+# Put user-supplied flags at the end, where they
+# have a chance of winning.
+CFLAGS += $(CFLAGS_EXTRA)
+
+#------------------------------------------------------------
+# Installation options
+ifeq ($(strip $(CONFIG_INSTALL_APPLET_HARDLINKS)),y)
+INSTALL_OPTS=--hardlinks
+endif
+ifeq ($(strip $(CONFIG_INSTALL_APPLET_SYMLINKS)),y)
+INSTALL_OPTS=--symlinks
+endif
+ifeq ($(strip $(CONFIG_INSTALL_APPLET_DONT)),y)
+INSTALL_OPTS=
+endif
+
+.PHONY: dummy
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+<DOCUMENT type="Advanced Installer" CreateVersion="3.9" version="6.0.1" modules="freeware" RootPath="." Language="en">\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiPropsComponent">\r
+ <ROW Property="ALLUSERS" Value="2"/>\r
+ <ROW Property="ARPCOMMENTS" Value="This installer database contains the logic and data required to install <product name>." ValueLocId="*"/>\r
+ <ROW Property="ARPPRODUCTICON" Value="controlPanelIcon.exe"/>\r
+ <ROW Property="ARPURLINFOABOUT" Value="http://axtls.cerocclub.com.au"/>\r
+ <ROW Property="BannerBitmap" Value="default_banner.bmp" Type="1"/>\r
+ <ROW Property="DialogBitmap" Value="default_dialog.bmp" Type="1"/>\r
+ <ROW Property="Manufacturer" Value="axTLS" ValueLocId="*"/>\r
+ <ROW Property="ProductCode" Value="1033:{F49FFA19-C243-4627-BE13-7DEDA4E700D0} "/>\r
+ <ROW Property="ProductLanguage" Value="1033"/>\r
+ <ROW Property="ProductName" Value="Axhttpd" ValueLocId="*"/>\r
+ <ROW Property="ProductVersion" Value="1.1.8"/>\r
+ <ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND"/>\r
+ <ROW Property="UpgradeCode" Value="{93E5623E-740C-449C-9770-EDABD392868D}"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiDirsComponent">\r
+ <ROW Directory="APPDIR" Directory_Parent="TARGETDIR" DefaultDir="APPDIR:." IsPseudoRoot="1"/>\r
+ <ROW Directory="New_Folder_DIR" Directory_Parent="APPDIR" DefaultDir="include"/>\r
+ <ROW Directory="SHORTCUTDIR" Directory_Parent="TARGETDIR" DefaultDir="SHORTC~1|SHORTCUTDIR" IsPseudoRoot="1"/>\r
+ <ROW Directory="TARGETDIR" DefaultDir="SourceDir"/>\r
+ <ROW Directory="another_dir_DIR" Directory_Parent="test_dir_DIR" DefaultDir="anothe~1|another_dir"/>\r
+ <ROW Directory="bin_DIR" Directory_Parent="test_dir_DIR" DefaultDir="bin"/>\r
+ <ROW Directory="no_http_DIR" Directory_Parent="test_dir_DIR" DefaultDir="no_http"/>\r
+ <ROW Directory="no_ssl_DIR" Directory_Parent="test_dir_DIR" DefaultDir="no_ssl"/>\r
+ <ROW Directory="test_dir_DIR" Directory_Parent="www_DIR" DefaultDir="test_dir"/>\r
+ <ROW Directory="www_DIR" Directory_Parent="APPDIR" DefaultDir="www"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">\r
+ <ROW Component="another_dir" ComponentId="{3F073789-DB33-40BC-BF88-922C6DF252EC}" Directory_="another_dir_DIR" Attributes="0"/>\r
+ <ROW Component="axhttpd.exe" ComponentId="{0AEFFA20-29FA-4304-8227-F9ED0E6B8A0A}" Directory_="APPDIR" Attributes="0" KeyPath="axhttpd.exe" FullKeyPath="APPDIR\axhttpd.exe"/>\r
+ <ROW Component="axssl.exe" ComponentId="{E1E96774-7BFC-45B9-BA33-FC0C631921FD}" Directory_="APPDIR" Attributes="0" KeyPath="axssl.exe" FullKeyPath="APPDIR\axssl.exe"/>\r
+ <ROW Component="axtls.dll" ComponentId="{4C741E75-A18A-4FC9-972C-C1EF583713EB}" Directory_="APPDIR" Attributes="0" KeyPath="axtls.dll" FullKeyPath="APPDIR\axtls.dll"/>\r
+ <ROW Component="axtls.jar" ComponentId="{796CB0A9-6214-4531-A330-9B37420B7799}" Directory_="APPDIR" Attributes="0" KeyPath="axtls.static.lib" FullKeyPath="APPDIR"/>\r
+ <ROW Component="bigint.h" ComponentId="{FC3E492B-D4F0-41FB-A977-76F6E9FE9FFE}" Directory_="New_Folder_DIR" Attributes="0" KeyPath="bigint.h" FullKeyPath="APPDIR\include"/>\r
+ <ROW Component="favicon.ico" ComponentId="{9A1AB507-100A-470D-A002-CD8262CA4913}" Directory_="www_DIR" Attributes="0" KeyPath="favicon.ico" FullKeyPath="APPDIR\www"/>\r
+ <ROW Component="htaccess" ComponentId="{F53CB1D5-A3B9-4401-B0BA-B6AB1DA860B7}" Directory_="no_ssl_DIR" Attributes="0" KeyPath="htaccess" FullKeyPath="APPDIR\www\test_dir\no_ssl"/>\r
+ <ROW Component="htaccess_1" ComponentId="{953D1999-CC00-4F85-9B48-2CD83ACAE2F9}" Directory_="no_http_DIR" Attributes="0" KeyPath="htaccess_1" FullKeyPath="APPDIR\www\test_dir\no_http"/>\r
+ <ROW Component="htaccess_2" ComponentId="{6F181A8B-B313-47E2-AF79-AABFDBD353D8}" Directory_="bin_DIR" Attributes="0" KeyPath="htaccess_2" FullKeyPath="APPDIR\www\test_dir\bin"/>\r
+ <ROW Component="htpasswd.exe" ComponentId="{9FE1AAD2-4E35-443A-AAE5-3A7D03A52AAA}" Directory_="APPDIR" Attributes="0" KeyPath="htpasswd.exe" FullKeyPath="APPDIR\htpasswd.exe"/>\r
+ <ROW Component="test_dir" ComponentId="{832C9295-CF2A-402E-BB3C-65BCBCBB5971}" Directory_="test_dir_DIR" Attributes="0"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">\r
+ <ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="axhttpd.exe axssl.exe axtls.dll axtls.jar favicon.ico bigint.h htpasswd.exe another_dir htaccess htaccess_2 htaccess_1 test_dir"/>\r
+ <ATTRIBUTE name="CurrentFeature" value="MainFeature"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">\r
+ <ROW File="axhttpd.exe" Component_="axhttpd.exe" FileName="axhttpd.exe" Attributes="0" SourcePath="..\_stage\axhttpd.exe" SelfReg="false" Sequence="1"/>\r
+ <ROW File="axssl.exe" Component_="axssl.exe" FileName="axssl.exe" Attributes="0" SourcePath="..\_stage\axssl.exe" SelfReg="false" Sequence="2"/>\r
+ <ROW File="axtls.dll" Component_="axtls.dll" FileName="axtls.dll" Attributes="0" SourcePath="..\_stage\axtls.dll" SelfReg="false" Sequence="3"/>\r
+ <ROW File="axtls.lib" Component_="axtls.jar" FileName="axtls.lib" Attributes="0" SourcePath="..\_stage\axtls.lib" SelfReg="false" Sequence="4"/>\r
+ <ROW File="axtls.static.lib" Component_="axtls.jar" FileName="axtlss~1.lib|axtls.static.lib" Attributes="0" SourcePath="..\_stage\axtls.static.lib" SelfReg="false" Sequence="5"/>\r
+ <ROW File="bigint.h" Component_="bigint.h" FileName="bigint.h" Attributes="0" SourcePath="..\crypto\bigint.h" SelfReg="false" Sequence="12"/>\r
+ <ROW File="bigint_impl.h" Component_="bigint.h" FileName="bigint~1.h|bigint_impl.h" Attributes="0" SourcePath="..\crypto\bigint_impl.h" SelfReg="false" Sequence="9"/>\r
+ <ROW File="crypto.h" Component_="bigint.h" FileName="crypto.h" Attributes="0" SourcePath="..\crypto\crypto.h" SelfReg="false" Sequence="10"/>\r
+ <ROW File="crypto_misc.h" Component_="bigint.h" FileName="crypto~1.h|crypto_misc.h" Attributes="0" SourcePath="..\ssl\crypto_misc.h" SelfReg="false" Sequence="21"/>\r
+ <ROW File="favicon.ico" Component_="favicon.ico" FileName="favicon.ico" Attributes="0" SourcePath="..\www\favicon.ico" SelfReg="false" Sequence="6"/>\r
+ <ROW File="htaccess" Component_="htaccess" FileName="htacce~1|.htaccess" Attributes="0" SourcePath="..\www\test_dir\no_ssl\.htaccess" SelfReg="false" Sequence="15"/>\r
+ <ROW File="htaccess_1" Component_="htaccess_1" FileName="htacce~1|.htaccess" Attributes="0" SourcePath="..\www\test_dir\no_http\.htaccess" SelfReg="false" Sequence="18"/>\r
+ <ROW File="htaccess_2" Component_="htaccess_2" FileName="htacce~1|.htaccess" Attributes="0" SourcePath="..\www\test_dir\bin\.htaccess" SelfReg="false" Sequence="17"/>\r
+ <ROW File="htpasswd" Component_="htaccess_1" FileName="htpass~1|.htpasswd" Attributes="0" SourcePath="..\www\test_dir\no_http\.htpasswd" SelfReg="false" Sequence="19"/>\r
+ <ROW File="htpasswd.exe" Component_="htpasswd.exe" FileName="htpasswd.exe" Attributes="0" SourcePath="..\_stage\htpasswd.exe" SelfReg="false" Sequence="14"/>\r
+ <ROW File="index.html" Component_="favicon.ico" FileName="index~1.htm|index.html" Attributes="0" SourcePath="..\www\index.html" SelfReg="false" Sequence="7"/>\r
+ <ROW File="index.html_1" Component_="htaccess" FileName="index~1.htm|index.html" Attributes="0" SourcePath="..\www\test_dir\no_ssl\index.html" SelfReg="false" Sequence="16"/>\r
+ <ROW File="index.html_2" Component_="htaccess_1" FileName="index~1.htm|index.html" Attributes="0" SourcePath="..\www\test_dir\no_http\index.html" SelfReg="false" Sequence="20"/>\r
+ <ROW File="os_port.h" Component_="bigint.h" FileName="os_port.h" Attributes="0" SourcePath="..\ssl\os_port.h" SelfReg="false" Sequence="13"/>\r
+ <ROW File="ssl.h" Component_="bigint.h" FileName="ssl.h" Attributes="0" SourcePath="..\ssl\ssl.h" SelfReg="false" Sequence="8"/>\r
+ <ROW File="tls1.h" Component_="bigint.h" FileName="tls1.h" Attributes="0" SourcePath="..\ssl\tls1.h" SelfReg="false" Sequence="11"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.BuildComponent">\r
+ <ROW BuildKey="DefaultBuild" BuildName="DefaultBuild" BuildOrder="1" BuildType="0" InstallationType="4"/>\r
+ <ATTRIBUTE name="CurrentBuild" value="DefaultBuild"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.DictionaryComponent">\r
+ <ROW Path="<ui.ail>"/>\r
+ <ROW Path="<ui_en.ail>"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.FragmentComponent">\r
+ <ROW Fragment="FolderDlg.aip" Path="<FolderDlg.aip>"/>\r
+ <ROW Fragment="StaticUIStrings.aip" Path="<StaticUIStrings.aip>"/>\r
+ <ROW Fragment="UI.aip" Path="<UI.aip>"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiBinaryComponent">\r
+ <ROW Name="aicustact.dll" SourcePath="<aicustact.dll>"/>\r
+ <ROW Name="default_banner.bmp" SourcePath="<default-banner.bmp>"/>\r
+ <ROW Name="default_dialog.bmp" SourcePath="<default-dialog.bmp>"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiControlComponent">\r
+ <ATTRIBUTE name="FixedSizeBitmaps" value="0"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiControlEventComponent">\r
+ <ROW Dialog_="FolderDlg" Control_="Back" Event="NewDialog" Argument="WelcomeDlg" Condition="AI_INSTALL" Ordering="1"/>\r
+ <ROW Dialog_="WelcomeDlg" Control_="Next" Event="NewDialog" Argument="FolderDlg" Condition="AI_INSTALL" Ordering="1"/>\r
+ <ROW Dialog_="VerifyReadyDlg" Control_="Back" Event="NewDialog" Argument="FolderDlg" Condition="AI_INSTALL" Ordering="1"/>\r
+ <ROW Dialog_="FolderDlg" Control_="Next" Event="NewDialog" Argument="VerifyReadyDlg" Condition="AI_INSTALL" Ordering="3"/>\r
+ <ROW Dialog_="MaintenanceTypeDlg" Control_="Back" Event="NewDialog" Argument="MaintenanceWelcomeDlg" Condition="AI_MAINT" Ordering="1"/>\r
+ <ROW Dialog_="MaintenanceWelcomeDlg" Control_="Next" Event="NewDialog" Argument="MaintenanceTypeDlg" Condition="AI_MAINT" Ordering="2"/>\r
+ <ROW Dialog_="VerifyReadyDlg" Control_="Back" Event="NewDialog" Argument="PatchWelcomeDlg" Condition="AI_PATCH" Ordering="1"/>\r
+ <ROW Dialog_="PatchWelcomeDlg" Control_="Next" Event="NewDialog" Argument="VerifyReadyDlg" Condition="AI_PATCH" Ordering="2"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiCreateFolderComponent">\r
+ <ROW Directory_="another_dir_DIR" Component_="another_dir"/>\r
+ <ROW Directory_="test_dir_DIR" Component_="test_dir"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiCustActComponent">\r
+ <ROW Action="AI_DOWNGRADE" Type="19" Target="4010"/>\r
+ <ROW Action="AI_PREPARE_UPGRADE" Type="65" Source="aicustact.dll" Target="PrepareUpgrade"/>\r
+ <ROW Action="AI_RESTORE_LOCATION" Type="65" Source="aicustact.dll" Target="RestoreLocation"/>\r
+ <ROW Action="AI_STORE_LOCATION" Type="51" Source="ARPINSTALLLOCATION" Target="[APPDIR]"/>\r
+ <ROW Action="SET_APPDIR" Type="307" Source="APPDIR" Target="[ProgramFilesFolder][Manufacturer]\[ProductName]" MultiBuildTarget="DefaultBuild:[ProgramFilesFolder][ProductName]"/>\r
+ <ROW Action="SET_SHORTCUTDIR" Type="307" Source="SHORTCUTDIR" Target="[ProgramMenuFolder][ProductName]"/>\r
+ <ROW Action="SET_TARGETDIR_TO_APPDIR" Type="51" Source="TARGETDIR" Target="[APPDIR]"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiIconsComponent">\r
+ <ROW Name="controlPanelIcon.exe" SourcePath="..\..\axhttpd\www\favicon.ico" Index="0"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiInstExSeqComponent">\r
+ <ROW Action="AI_DOWNGRADE" Condition="AI_NEWERPRODUCTFOUND AND (UILevel <> 5)" Sequence="210"/>\r
+ <ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=""" Sequence="740"/>\r
+ <ROW Action="AI_STORE_LOCATION" Condition="Not Installed" Sequence="1545"/>\r
+ <ROW Action="AI_PREPARE_UPGRADE" Condition="AI_UPGRADE="No" AND (Not Installed)" Sequence="1300"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiInstallUISequenceComponent">\r
+ <ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=""" Sequence="740"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiShortsComponent">\r
+ <ROW Shortcut="axhttpd.exe" Directory_="SHORTCUTDIR" Name="axhttpd" Component_="axhttpd.exe" Target="[#axhttpd.exe]" Description="axhttpd.exe" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>\r
+ <ROW Shortcut="axssl_client" Directory_="SHORTCUTDIR" Name="axsslc~1|axssl client" Component_="axssl.exe" Target="[#axssl.exe]" Arguments="s_client" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>\r
+ <ROW Shortcut="axssl_server" Directory_="SHORTCUTDIR" Name="axssls~1|axssl server" Component_="axssl.exe" Target="[#axssl.exe]" Arguments="s_server" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>\r
+ </COMPONENT>\r
+ <COMPONENT cid="caphyon.advinst.msicomp.MsiUpgradeComponent">\r
+ <ROW UpgradeCode="[|UpgradeCode]" VersionMax="[|ProductVersion]" Attributes="1025" ActionProperty="OLDPRODUCTS"/>\r
+ <ROW UpgradeCode="[|UpgradeCode]" VersionMin="[|ProductVersion]" Attributes="2" ActionProperty="AI_NEWERPRODUCTFOUND"/>\r
+ </COMPONENT>\r
+</DOCUMENT>\r
--- /dev/null
+//Microsoft Visual C++ generated resource script.\r
+//\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#define APSTUDIO_HIDDEN_SYMBOLS\r
+#undef APSTUDIO_HIDDEN_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Icon\r
+//\r
+\r
+// Icon with lowest ID value placed first to ensure application icon\r
+// remains consistent on all systems.\r
+\r
+IDI_AXTLS ICON "../www/favicon.ico"\r
+\r
+\r
+#endif\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
--- /dev/null
+/*
+ * Automatically generated header file: don't edit
+ */
+
+#define HAVE_DOT_CONFIG 1
+#define CONFIG_PLATFORM_LINUX 1
+#undef CONFIG_PLATFORM_CYGWIN
+#undef CONFIG_PLATFORM_WIN32
+
+/*
+ * General Configuration
+ */
+#define PREFIX "/usr"
+#undef CONFIG_DEBUG
+#define CONFIG_STRIP_UNWANTED_SECTIONS 1
+#undef CONFIG_VISUAL_STUDIO_7_0
+#undef CONFIG_VISUAL_STUDIO_8_0
+#define CONFIG_VISUAL_STUDIO_7_0_BASE ""
+#define CONFIG_VISUAL_STUDIO_8_0_BASE ""
+#define CONFIG_EXTRA_CFLAGS_OPTIONS "-fpic"
+#define CONFIG_EXTRA_LDFLAGS_OPTIONS ""
+
+/*
+ * SSL Library
+ */
+#undef CONFIG_SSL_SERVER_ONLY
+#undef CONFIG_SSL_CERT_VERIFICATION
+#define CONFIG_SSL_ENABLE_CLIENT 1
+#undef CONFIG_SSL_FULL_MODE
+#undef CONFIG_SSL_SKELETON_MODE
+#undef CONFIG_SSL_PROT_LOW
+#define CONFIG_SSL_PROT_MEDIUM 1
+#undef CONFIG_SSL_PROT_HIGH
+#define CONFIG_SSL_USE_DEFAULT_KEY 1
+#define CONFIG_SSL_PRIVATE_KEY_LOCATION ""
+#define CONFIG_SSL_PRIVATE_KEY_PASSWORD ""
+#define CONFIG_SSL_X509_CERT_LOCATION ""
+#define CONFIG_SSL_GENERATE_X509_CERT 1
+#define CONFIG_SSL_X509_COMMON_NAME ""
+#define CONFIG_SSL_X509_ORGANIZATION_NAME ""
+#define CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME ""
+#define CONFIG_SSL_ENABLE_V23_HANDSHAKE 1
+#define CONFIG_SSL_HAS_PEM 1
+#undef CONFIG_SSL_USE_PKCS12
+#define CONFIG_SSL_EXPIRY_TIME 24
+#define CONFIG_X509_MAX_CA_CERTS 4
+#define CONFIG_SSL_MAX_CERTS 2
+#define CONFIG_SSL_CTX_MUTEXING 1
+#define CONFIG_USE_DEV_URANDOM 1
+#undef CONFIG_WIN32_USE_CRYPTO_LIB
+#undef CONFIG_OPENSSL_COMPATIBLE
+#undef CONFIG_PERFORMANCE_TESTING
+#undef CONFIG_SSL_TEST
+#undef CONFIG_AXHTTPD
+#undef CONFIG_HTTP_STATIC_BUILD
+#define CONFIG_HTTP_PORT
+#define CONFIG_HTTP_HTTPS_PORT
+#define CONFIG_HTTP_SESSION_CACHE_SIZE
+#define CONFIG_HTTP_WEBROOT ""
+#define CONFIG_HTTP_TIMEOUT
+#undef CONFIG_HTTP_HAS_CGI
+#define CONFIG_HTTP_CGI_EXTENSIONS ""
+#undef CONFIG_HTTP_ENABLE_LUA
+#define CONFIG_HTTP_LUA_PREFIX ""
+#define CONFIG_HTTP_LUA_CGI_LAUNCHER ""
+#undef CONFIG_HTTP_BUILD_LUA
+#undef CONFIG_HTTP_DIRECTORIES
+#undef CONFIG_HTTP_HAS_AUTHORIZATION
+#undef CONFIG_HTTP_HAS_IPV6
+#undef CONFIG_HTTP_ENABLE_DIFFERENT_USER
+#define CONFIG_HTTP_USER ""
+#undef CONFIG_HTTP_VERBOSE
+#undef CONFIG_HTTP_IS_DAEMON
+
+/*
+ * Language Bindings
+ */
+#undef CONFIG_BINDINGS
+#undef CONFIG_CSHARP_BINDINGS
+#undef CONFIG_VBNET_BINDINGS
+#define CONFIG_DOT_NET_FRAMEWORK_BASE ""
+#undef CONFIG_JAVA_BINDINGS
+#define CONFIG_JAVA_HOME ""
+#undef CONFIG_PERL_BINDINGS
+#define CONFIG_PERL_CORE ""
+#define CONFIG_PERL_LIB ""
+#undef CONFIG_LUA_BINDINGS
+#define CONFIG_LUA_CORE ""
+
+/*
+ * Samples
+ */
+#undef CONFIG_SAMPLES
+#undef CONFIG_C_SAMPLES
+#undef CONFIG_CSHARP_SAMPLES
+#undef CONFIG_VBNET_SAMPLES
+#undef CONFIG_JAVA_SAMPLES
+#undef CONFIG_PERL_SAMPLES
+#undef CONFIG_LUA_SAMPLES
+
+/*
+ * BigInt Options
+ */
+#undef CONFIG_BIGINT_CLASSICAL
+#undef CONFIG_BIGINT_MONTGOMERY
+#define CONFIG_BIGINT_BARRETT 1
+#define CONFIG_BIGINT_CRT 1
+#undef CONFIG_BIGINT_KARATSUBA
+#define MUL_KARATSUBA_THRESH
+#define SQU_KARATSUBA_THRESH
+#define CONFIG_BIGINT_SLIDING_WINDOW 1
+#define CONFIG_BIGINT_SQUARE 1
+#undef CONFIG_BIGINT_CHECK_ON
--- /dev/null
+#
+# Automatically generated make config: don't edit
+#
+HAVE_DOT_CONFIG=y
+CONFIG_PLATFORM_LINUX=y
+# CONFIG_PLATFORM_CYGWIN is not set
+# CONFIG_PLATFORM_SOLARIS is not set
+# CONFIG_PLATFORM_WIN32 is not set
+
+#
+# General Configuration
+#
+PREFIX="/usr/local"
+# CONFIG_DEBUG is not set
+CONFIG_STRIP_UNWANTED_SECTIONS=y
+# CONFIG_VISUAL_STUDIO_7_0 is not set
+# CONFIG_VISUAL_STUDIO_8_0 is not set
+CONFIG_VISUAL_STUDIO_7_0_BASE=""
+CONFIG_VISUAL_STUDIO_8_0_BASE=""
+CONFIG_EXTRA_CFLAGS_OPTIONS=""
+CONFIG_EXTRA_LDFLAGS_OPTIONS=""
+
+#
+# SSL Library
+#
+# CONFIG_SSL_SERVER_ONLY is not set
+# CONFIG_SSL_CERT_VERIFICATION is not set
+# CONFIG_SSL_ENABLE_CLIENT is not set
+CONFIG_SSL_FULL_MODE=y
+# CONFIG_SSL_SKELETON_MODE is not set
+# CONFIG_SSL_PROT_LOW is not set
+CONFIG_SSL_PROT_MEDIUM=y
+# CONFIG_SSL_PROT_HIGH is not set
+CONFIG_SSL_USE_DEFAULT_KEY=y
+CONFIG_SSL_PRIVATE_KEY_LOCATION=""
+CONFIG_SSL_PRIVATE_KEY_PASSWORD=""
+CONFIG_SSL_X509_CERT_LOCATION=""
+CONFIG_SSL_GENERATE_X509_CERT=y
+CONFIG_SSL_X509_COMMON_NAME=""
+CONFIG_SSL_X509_ORGANIZATION_NAME=""
+CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME=""
+CONFIG_SSL_ENABLE_V23_HANDSHAKE=y
+CONFIG_SSL_HAS_PEM=y
+CONFIG_SSL_USE_PKCS12=y
+CONFIG_SSL_EXPIRY_TIME=24
+CONFIG_X509_MAX_CA_CERTS=4
+CONFIG_SSL_MAX_CERTS=2
+# CONFIG_SSL_CTX_MUTEXING is not set
+CONFIG_USE_DEV_URANDOM=y
+# CONFIG_WIN32_USE_CRYPTO_LIB is not set
+CONFIG_OPENSSL_COMPATIBLE=y
+# CONFIG_PERFORMANCE_TESTING is not set
+# CONFIG_SSL_TEST is not set
+CONFIG_AXHTTPD=y
+
+#
+# Axhttpd Configuration
+#
+# CONFIG_HTTP_STATIC_BUILD is not set
+CONFIG_HTTP_PORT=80
+CONFIG_HTTP_HTTPS_PORT=443
+CONFIG_HTTP_SESSION_CACHE_SIZE=5
+CONFIG_HTTP_WEBROOT="../www"
+CONFIG_HTTP_TIMEOUT=300
+
+#
+# CGI
+#
+CONFIG_HTTP_HAS_CGI=y
+CONFIG_HTTP_CGI_EXTENSIONS=".lua,.lp"
+CONFIG_HTTP_ENABLE_LUA=y
+CONFIG_HTTP_LUA_PREFIX="/usr/local"
+CONFIG_HTTP_LUA_CGI_LAUNCHER="/bin/cgi"
+# CONFIG_HTTP_BUILD_LUA is not set
+CONFIG_HTTP_DIRECTORIES=y
+CONFIG_HTTP_HAS_AUTHORIZATION=y
+# CONFIG_HTTP_HAS_IPV6 is not set
+# CONFIG_HTTP_VERBOSE is not set
+# CONFIG_HTTP_IS_DAEMON is not set
+
+#
+# Language Bindings
+#
+CONFIG_BINDINGS=y
+# CONFIG_CSHARP_BINDINGS is not set
+# CONFIG_VBNET_BINDINGS is not set
+CONFIG_DOT_NET_FRAMEWORK_BASE=""
+# CONFIG_JAVA_BINDINGS is not set
+CONFIG_JAVA_HOME=""
+# CONFIG_PERL_BINDINGS is not set
+CONFIG_PERL_CORE=""
+CONFIG_PERL_LIB=""
+# CONFIG_LUA_BINDINGS is not set
+CONFIG_LUA_CORE=""
+
+#
+# Samples
+#
+CONFIG_SAMPLES=y
+CONFIG_C_SAMPLES=y
+# CONFIG_CSHARP_SAMPLES is not set
+# CONFIG_VBNET_SAMPLES is not set
+# CONFIG_JAVA_SAMPLES is not set
+# CONFIG_PERL_SAMPLES is not set
+# CONFIG_LUA_SAMPLES is not set
+
+#
+# BigInt Options
+#
+# CONFIG_BIGINT_CLASSICAL is not set
+# CONFIG_BIGINT_MONTGOMERY is not set
+CONFIG_BIGINT_BARRETT=y
+CONFIG_BIGINT_CRT=y
+# CONFIG_BIGINT_KARATSUBA is not set
+MUL_KARATSUBA_THRESH=0
+SQU_KARATSUBA_THRESH=0
+CONFIG_BIGINT_SLIDING_WINDOW=y
+CONFIG_BIGINT_SQUARE=y
+# CONFIG_BIGINT_CHECK_ON is not set
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# A standard makefile for all makefiles
+#
+
+# All executables and libraries go here
+STAGE=./_stage
+
+ifneq ($(MAKECMDGOALS), clean)
+
+# Give an initial rule
+all:
+
+# Win32
+ifdef CONFIG_PLATFORM_WIN32
+
+ifdef CONFIG_VISUAL_STUDIO_7_0
+CONFIG_VISUAL_STUDIO_7_0_BASE_UNIX:=$(shell cygpath -u $(CONFIG_VISUAL_STUDIO_7_0_BASE))
+export INCLUDE=$(shell echo "$(CONFIG_VISUAL_STUDIO_7_0_BASE)\vc7\include;$(CONFIG_VISUAL_STUDIO_7_0_BASE)\vc7\platformsdk\include")
+export LIB=$(shell echo "$(CONFIG_VISUAL_STUDIO_7_0_BASE)\vc7\\platformsdk\lib;$(CONFIG_VISUAL_STUDIO_7_0_BASE)\vc7\lib")
+PATH:=$(CONFIG_VISUAL_STUDIO_7_0_BASE_UNIX)/vc7/bin:$(CONFIG_VISUAL_STUDIO_7_0_BASE_UNIX)/common7/ide:$(PATH)
+else
+ifdef CONFIG_VISUAL_STUDIO_8_0
+CONFIG_VISUAL_STUDIO_8_0_BASE_UNIX:=$(shell cygpath -u $(CONFIG_VISUAL_STUDIO_8_0_BASE))
+export INCLUDE=$(shell echo "$(CONFIG_VISUAL_STUDIO_8_0_BASE)\vc\include;$(CONFIG_VISUAL_STUDIO_8_0_BASE)\vc\platformsdk\include")
+export LIB=$(shell echo "$(CONFIG_VISUAL_STUDIO_8_0_BASE)\vc\platformsdk\lib;$(CONFIG_VISUAL_STUDIO_8_0_BASE)\vc\lib")
+PATH:=$(CONFIG_VISUAL_STUDIO_8_0_BASE_UNIX)/vc/bin:$(CONFIG_VISUAL_STUDIO_8_0_BASE_UNIX)/common7/ide:$(PATH)
+stuff:
+ @echo $(INCLUDE)
+endif
+endif
+
+CC=cl.exe
+LD=link.exe
+AXTLS_INCLUDE=$(shell cygpath -w $(AXTLS_HOME))
+CFLAGS+=/nologo /W3 /D"WIN32" /D"_MBCS" /D"_CONSOLE" /D"_CRT_SECURE_NO_DEPRECATE" /FD /I"$(AXTLS_INCLUDE)crypto" /I"$(AXTLS_INCLUDE)ssl" /I"$(AXTLS_INCLUDE)config" /c
+LDFLAGS=/nologo /subsystem:console /machine:I386
+LDSHARED = /dll
+AR=lib /nologo
+
+ifdef CONFIG_DEBUG
+ CFLAGS += /Gm /Zi /Od /D "_DEBUG"
+ LDFLAGS += /debug /incremental:yes
+else
+ CFLAGS += /O2 /D "NDEBUG"
+ LDFLAGS += /incremental:no
+endif
+
+else # Not Win32
+
+-include .depend
+
+CFLAGS += -I$(AXTLS_HOME)/config -I$(AXTLS_HOME)/ssl -I$(AXTLS_HOME)/crypto
+LD=$(CC)
+STRIP=strip
+
+# Solaris
+ifdef CONFIG_PLATFORM_SOLARIS
+CFLAGS += -DCONFIG_PLATFORM_SOLARIS
+LDFLAGS += -lsocket -lnsl -lc
+LDSHARED = -G
+# Linux/Cygwin
+else
+CFLAGS += -Wall -Wstrict-prototypes -Wshadow
+LDSHARED = -shared
+
+# Linux
+ifndef CONFIG_PLATFORM_CYGWIN
+# CFLAGS += -fPIC
+
+# Cygwin
+else
+CFLAGS += -DCONFIG_PLATFORM_CYGWIN
+LDFLAGS += -enable-auto-import
+endif
+endif
+
+ifdef CONFIG_DEBUG
+CFLAGS += -g
+else
+LDFLAGS += -s
+ifdef CONFIG_PLATFORM_SOLARIS
+CFLAGS += -O
+else
+CFLAGS += -O3
+endif
+
+endif # CONFIG_DEBUG
+endif # WIN32
+
+CFLAGS+=$(subst ",, $(strip $(CONFIG_EXTRA_CFLAGS_OPTIONS)))
+LDFLAGS+=$(subst ",, $(strip $(CONFIG_EXTRA_LDFLAGS_OPTIONS)))
+
+endif # not 'clean'
+
+clean::
+ -@rm -f *.o *.obj core* *.out *~ \.depend vc*0*
+
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+ifneq ($(MAKECMDGOALS), clean)
+
+ifdef CONFIG_PLATFORM_WIN32
+GO_DOT_NET=y
+endif
+
+ifdef CONFIG_PLATFORM_CYGWIN
+GO_DOT_NET=y
+endif
+
+ifdef GO_DOT_NET
+all: test_dot_net_location
+
+# find out where the C# compiler is
+CONFIG_DOT_NET_FRAMEWORK_BASE:=$(shell cygpath -u $(CONFIG_DOT_NET_FRAMEWORK_BASE))
+
+test_dot_net_location:
+ @if ! [ -d "$(CONFIG_DOT_NET_FRAMEWORK_BASE)" ]; then \
+ echo "*** Error: .NET path of $(CONFIG_DOT_NET_FRAMEWORK_BASE) doesn't exist" && exit 1; \
+ fi
+
+PATH:=$(CONFIG_DOT_NET_FRAMEWORK_BASE):$(PATH)
+
+else # Linux?
+all: test_mcs
+
+test_mcs:
+ @if ! mcs --about > /dev/null 2>&1; then \
+ echo "Mono not installed! - go " \
+ "to http://www.mono-project.com/Main_Page" && exit 1; \
+ fi
+
+endif # Linux
+
+endif # not 'clean'
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+ifneq ($(MAKECMDGOALS), clean)
+
+ifdef CONFIG_PLATFORM_CYGWIN
+CFLAGS += -I"$(CONFIG_JAVA_HOME)/include"
+CFLAGS += -I"$(CONFIG_JAVA_HOME)/include/win32"
+JAVA_BIN:=$(CONFIG_JAVA_HOME)/bin
+else
+
+ifdef CONFIG_PLATFORM_WIN32
+CFLAGS += /I"$(shell cygpath -w $(CONFIG_JAVA_HOME)/include)"
+CFLAGS += /I"$(shell cygpath -w $(CONFIG_JAVA_HOME)/include/win32)"
+JAVA_BIN:=$(shell cygpath -u $(CONFIG_JAVA_HOME)/bin)
+else # Linux
+CFLAGS += -I$(CONFIG_JAVA_HOME)/include
+
+ifdef CONFIG_PLATFORM_SOLARIS
+CFLAGS += -I$(CONFIG_JAVA_HOME)/include/solaris
+else
+CFLAGS += -I$(CONFIG_JAVA_HOME)/include/linux
+endif
+
+JAVA_BIN:=$(CONFIG_JAVA_HOME)/bin
+endif
+endif
+
+PATH:=$(JAVA_BIN):$(PATH)
+
+endif # not 'clean'
--- /dev/null
+
+ifneq ($(MAKECMDGOALS), clean)
+ifndef CONFIG_PLATFORM_WIN32
+ifndef CONFIG_PLATFORM_SOLARIS
+# do dependencies
+-include .depend
+all : .depend
+.depend: $(wildcard *.c)
+ @$(CC) $(CFLAGS) -MM $^ > $@
+endif # 'not' solaris
+endif # 'not' win32
+
+ifdef CONFIG_PLATFORM_WIN32
+OBJ:=$(OBJ:.o=.obj)
+%.obj : %.c
+ $(CC) $(CFLAGS) $<
+endif # win32
+
+endif # end of 'not' clean
--- /dev/null
+Introduction
+------------
+
+The configuration database is collection of configuration options
+organized in a tree structure:
+
+ +- Code maturity level options
+ | +- Prompt for development and/or incomplete code/drivers
+ +- General setup
+ | +- Networking support
+ | +- System V IPC
+ | +- BSD Process Accounting
+ | +- Sysctl support
+ +- Loadable module support
+ | +- Enable loadable module support
+ | +- Set version information on all module symbols
+ | +- Kernel module loader
+ +- ...
+
+Every entry has its own dependencies. These dependencies are used
+to determine the visible of an entry. Any child entry is only
+visible if its parent entry is also visible.
+
+Menu entries
+------------
+
+Most entries define a config option, all other entries help to organize
+them. A single configuration option is defined like this:
+
+config MODVERSIONS
+ bool "Set version information on all module symbols"
+ depends MODULES
+ help
+ Usually, modules have to be recompiled whenever you switch to a new
+ kernel. ...
+
+Every line starts with a key word and can be followed by multiple
+arguments. "config" starts a new config entry. The following lines
+define attributes for this config option. Attributes can be the type of
+the config option, input prompt, dependencies, help text and default
+values. A config option can be defined multiple times with the same
+name, but every definition can have only a single input prompt and the
+type must not conflict.
+
+Menu attributes
+---------------
+
+A menu entry can have a number of attributes. Not all of them are
+applicable everywhere (see syntax).
+
+- type definition: "bool"/"tristate"/"string"/"hex"/"integer"
+ Every config option must have a type. There are only two basic types:
+ tristate and string, the other types base on these two. The type
+ definition optionally accepts an input prompt, so these two examples
+ are equivalent:
+
+ bool "Networking support"
+ and
+ bool
+ prompt "Networking support"
+
+- input prompt: "prompt" <prompt> ["if" <expr>]
+ Every menu entry can have at most one prompt, which is used to display
+ to the user. Optionally dependencies only for this prompt can be added
+ with "if".
+
+- default value: "default" <symbol> ["if" <expr>]
+ A config option can have any number of default values. If multiple
+ default values are visible, only the first defined one is active.
+ Default values are not limited to the menu entry, where they are
+ defined, this means the default can be defined somewhere else or be
+ overriden by an earlier definition.
+ The default value is only assigned to the config symbol if no other
+ value was set by the user (via the input prompt above). If an input
+ prompt is visible the default value is presented to the user and can
+ be overridden by him.
+ Optionally dependencies only for this default value can be added with
+ "if".
+
+- dependencies: "depends on"/"requires" <expr>
+ This defines a dependency for this menu entry. If multiple
+ dependencies are defined they are connected with '&&'. Dependencies
+ are applied to all other options within this menu entry (which also
+ accept "if" expression), so these two examples are equivalent:
+
+ bool "foo" if BAR
+ default y if BAR
+ and
+ depends on BAR
+ bool "foo"
+ default y
+
+- help text: "help"
+ This defines a help text. The end of the help text is determined by
+ the level indentation, this means it ends at the first line which has
+ a smaller indentation than the first line of the help text.
+
+
+Menu dependencies
+-----------------
+
+Dependencies define the visibility of a menu entry and can also reduce
+the input range of tristate symbols. The tristate logic used in the
+expressions uses one more state than normal boolean logic to express the
+module state. Dependency expressions have the following syntax:
+
+<expr> ::= <symbol> (1)
+ <symbol> '=' <symbol> (2)
+ <symbol> '!=' <symbol> (3)
+ '(' <expr> ')' (4)
+ '!' <expr> (5)
+ <expr> '||' <expr> (6)
+ <expr> '&&' <expr> (7)
+
+Expressions are listed in decreasing order of precedence.
+
+(1) Convert the symbol into an expression. Boolean and tristate symbols
+ are simply converted into the respective expression values. All
+ other symbol types result in 'n'.
+(2) If the values of both symbols are equal, it returns 'y',
+ otherwise 'n'.
+(3) If the values of both symbols are equal, it returns 'n',
+ otherwise 'y'.
+(4) Returns the value of the expression. Used to override precedence.
+(5) Returns the result of (2-/expr/).
+(6) Returns the result of min(/expr/, /expr/).
+(7) Returns the result of max(/expr/, /expr/).
+
+An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2
+respectively for calculations). A menu entry becomes visible when it's
+expression evaluates to 'm' or 'y'.
+
+There are two type of symbols: constant and nonconstant symbols.
+Nonconstant symbols are the most common ones and are defined with the
+'config' statement. Nonconstant symbols consist entirely of alphanumeric
+characters or underscores.
+Constant symbols are only part of expressions. Constant symbols are
+always surrounded by single or double quotes. Within the quote any
+other character is allowed and the quotes can be escaped using '\'.
+
+Menu structure
+--------------
+
+The position of a menu entry in the tree is determined in two ways. First
+it can be specified explicitely:
+
+menu "Network device support"
+ depends NET
+
+config NETDEVICES
+ ...
+
+endmenu
+
+All entries within the "menu" ... "endmenu" block become a submenu of
+"Network device support". All subentries inherit the dependencies from
+the menu entry, e.g. this means the dependency "NET" is added to the
+dependency list of the config option NETDEVICES.
+
+The other way to generate the menu structure is done by analyzing the
+dependencies. If a menu entry somehow depends on the previous entry, it
+can be made a submenu of it. First the the previous (parent) symbol must
+be part of the dependency list and then one of these two condititions
+must be true:
+- the child entry must become invisible, if the parent is set to 'n'
+- the child entry must only be visible, if the parent is visible
+
+config MODULES
+ bool "Enable loadable module support"
+
+config MODVERSIONS
+ bool "Set version information on all module symbols"
+ depends MODULES
+
+comment "module support disabled"
+ depends !MODULES
+
+MODVERSIONS directly depends on MODULES, this means it's only visible if
+MODULES is different from 'n'. The comment on the other hand is always
+visible when MODULES it's visible (the (empty) dependency of MODULES is
+also part of the comment dependencies).
+
+
+Kconfig syntax
+--------------
+
+The configuration file describes a series of menu entries, where every
+line starts with a keyword (except help texts). The following keywords
+end a menu entry:
+- config
+- choice/endchoice
+- comment
+- menu/endmenu
+- if/endif
+- source
+The first four also start the definition of a menu entry.
+
+config:
+
+ "config" <symbol>
+ <config options>
+
+This defines a config symbol <symbol> and accepts any of above
+attributes as options.
+
+choices:
+
+ "choice"
+ <choice options>
+ <choice block>
+ "endchoice"
+
+This defines a choice group and accepts any of above attributes as
+options. A choice can only be of type bool or tristate, while a boolean
+choice only allows a single config entry to be selected, a tristate
+choice also allows any number of config entries to be set to 'm'. This
+can be used if multiple drivers for a single hardware exists and only a
+single driver can be compiled/loaded into the kernel, but all drivers
+can be compiled as modules.
+A choice accepts another option "optional", which allows to set the
+choice to 'n' and no entry needs to be selected.
+
+comment:
+
+ "comment" <prompt>
+ <comment options>
+
+This defines a comment which is displayed to the user during the
+configuration process and is also echoed to the output files. The only
+possible options are dependencies.
+
+menu:
+
+ "menu" <prompt>
+ <menu options>
+ <menu block>
+ "endmenu"
+
+This defines a menu block, see "Menu structure" above for more
+information. The only possible options are dependencies.
+
+if:
+
+ "if" <expr>
+ <if block>
+ "endif"
+
+This defines an if block. The dependency expression <expr> is appended
+to all enclosed menu entries.
+
+source:
+
+ "source" <prompt>
+
+This reads the specified configuration file. This file is always parsed.
--- /dev/null
+# Makefile for axTLS
+#
+# Copyright (C) 2002 Erik Andersen <andersen@codepoet.org>
+
+top_srcdir=../..
+top_builddir=../..
+srcdir=$(top_srcdir)/scripts/config
+include $(top_srcdir)/Rules.mak
+
+all: ncurses conf mconf
+
+ifeq ($(shell uname),SunOS)
+LIBS = -lcurses
+else
+LIBS = -lncurses
+endif
+ifeq (/usr/include/ncurses/ncurses.h, $(wildcard /usr/include/ncurses/ncurses.h))
+ HOSTNCURSES += -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"
+else
+ifeq (/usr/include/ncurses/curses.h, $(wildcard /usr/include/ncurses/curses.h))
+ HOSTNCURSES += -I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"
+else
+ifeq (/usr/local/include/ncurses/ncurses.h, $(wildcard /usr/local/include/ncurses/ncurses.h))
+ HOSTCFLAGS += -I/usr/local/include/ncurses -DCURSES_LOC="<ncurses.h>"
+else
+ifeq (/usr/local/include/ncurses/curses.h, $(wildcard /usr/local/include/ncurses/curses.h))
+ HOSTCFLAGS += -I/usr/local/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"
+else
+ifeq (/usr/include/ncurses.h, $(wildcard /usr/include/ncurses.h))
+ HOSTNCURSES += -DCURSES_LOC="<ncurses.h>"
+else
+ HOSTNCURSES += -DCURSES_LOC="<curses.h>"
+endif
+endif
+endif
+endif
+endif
+
+CONF_SRC = conf.c
+MCONF_SRC = mconf.c
+LXD_SRC = lxdialog/checklist.c lxdialog/menubox.c lxdialog/textbox.c \
+ lxdialog/yesno.c lxdialog/inputbox.c lxdialog/util.c \
+ lxdialog/msgbox.c
+
+SHARED_SRC = zconf.tab.c
+SHARED_DEPS := $(srcdir)/lkc.h $(srcdir)/lkc_proto.h \
+ lkc_defs.h $(srcdir)/expr.h zconf.tab.h
+CONF_OBJS = $(patsubst %.c,%.o, $(CONF_SRC))
+MCONF_OBJS = $(patsubst %.c,%.o, $(MCONF_SRC) $(LXD_SRC))
+SHARED_OBJS = $(patsubst %.c,%.o, $(SHARED_SRC))
+
+conf: $(CONF_OBJS) $(SHARED_OBJS)
+ $(HOSTCC) $(NATIVE_LDFLAGS) $^ -o $@
+
+mconf: $(MCONF_OBJS) $(SHARED_OBJS)
+ $(HOSTCC) $(NATIVE_LDFLAGS) $^ -o $@ $(LIBS)
+
+$(CONF_OBJS): %.o : $(srcdir)/%.c $(SHARED_DEPS)
+ $(HOSTCC) $(HOSTCFLAGS) -I. -c $< -o $@
+
+$(MCONF_OBJS): %.o : $(srcdir)/%.c $(SHARED_DEPS)
+ @[ -d $(@D) ] || mkdir -v $(@D)
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTNCURSES) -I. -c $< -o $@
+
+lkc_defs.h: $(srcdir)/lkc_proto.h
+ @sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+
+###
+# The following requires flex/bison
+# By default we use the _shipped versions, uncomment the
+# following line if you are modifying the flex/bison src.
+#LKC_GENPARSER := 1
+
+ifdef LKC_GENPARSER
+
+%.tab.c %.tab.h: $(srcdir)/%.y
+ bison -t -d -v -b $* -p $(notdir $*) $<
+
+lex.%.c: $(srcdir)/%.l
+ flex -P$(notdir $*) -o$@ $<
+else
+
+lex.zconf.o: lex.zconf.c $(SHARED_DEPS)
+ $(HOSTCC) $(HOSTCFLAGS) -I$(srcdir) -c $< -o $@
+
+lex.zconf.c: $(srcdir)/lex.zconf.c_shipped
+ cp $< $@
+
+zconf.tab.c: $(srcdir)/zconf.tab.c_shipped
+ cp $< $@
+
+zconf.tab.h: $(srcdir)/zconf.tab.h_shipped
+ cp $< $@
+endif
+
+zconf.tab.o: zconf.tab.c lex.zconf.c $(srcdir)/confdata.c $(srcdir)/expr.c \
+ $(srcdir)/symbol.c $(srcdir)/menu.c $(SHARED_DEPS)
+ $(HOSTCC) $(HOSTCFLAGS) -I$(srcdir) -I. -c $< -o $@
+
+.PHONY: ncurses
+
+ncurses:
+ @echo "main() {}" > lxtemp.c
+ @if $(HOSTCC) lxtemp.c $(LIBS) ; then \
+ rm -f lxtemp.c a.out; \
+ else \
+ rm -f lxtemp.c; \
+ echo -e "\007" ;\
+ echo ">> Unable to find the Ncurses libraries." ;\
+ echo ">>" ;\
+ echo ">> You must have Ncurses installed in order" ;\
+ echo ">> to use 'make menuconfig'" ;\
+ echo ;\
+ exit 1 ;\
+ fi
+
+clean:
+ rm -f *.o *~ ../../*~ core *.exe $(TARGETS) $(MCONF_OBJS) $(CONF_OBJS)
+ rm -f conf conf.exe mconf mconf.exe zconf.tab.c zconf.tab.h lex.zconf.c lkc_defs.h
+ rm -f ../..config.h
+
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum {
+ ask_all,
+ ask_new,
+ ask_silent,
+ set_default,
+ set_yes,
+ set_mod,
+ set_no,
+ set_random
+} input_mode = ask_all;
+char *defconfig_file;
+
+static int indent = 1;
+static int valid_stdin = 1;
+static int conf_cnt;
+static char line[128];
+static struct menu *rootEntry;
+
+static char nohelp_text[] = "Sorry, no help available for this option yet.\n";
+
+static void strip(char *str)
+{
+ char *p = str;
+ int l;
+
+ while ((isspace(*p)))
+ p++;
+ l = strlen(p);
+ if (p != str)
+ memmove(str, p, l + 1);
+ if (!l)
+ return;
+ p = str + l - 1;
+ while ((isspace(*p)))
+ *p-- = 0;
+}
+
+static void check_stdin(void)
+{
+ if (!valid_stdin && input_mode == ask_silent) {
+ printf("aborted!\n\n");
+ printf("Console input/output is redirected. ");
+ printf("Run 'make oldconfig' to update configuration.\n\n");
+ exit(1);
+ }
+}
+
+static void conf_askvalue(struct symbol *sym, const char *def)
+{
+ enum symbol_type type = sym_get_type(sym);
+ tristate val;
+
+ if (!sym_has_value(sym))
+ printf("(NEW) ");
+
+ line[0] = '\n';
+ line[1] = 0;
+
+ if (!sym_is_changable(sym)) {
+ printf("%s\n", def);
+ line[0] = '\n';
+ line[1] = 0;
+ return;
+ }
+
+ switch (input_mode) {
+ case ask_new:
+ case ask_silent:
+ if (sym_has_value(sym)) {
+ printf("%s\n", def);
+ return;
+ }
+ check_stdin();
+ case ask_all:
+ fflush(stdout);
+ fgets(line, 128, stdin);
+ return;
+ case set_default:
+ printf("%s\n", def);
+ return;
+ default:
+ break;
+ }
+
+ switch (type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ printf("%s\n", def);
+ return;
+ default:
+ ;
+ }
+ switch (input_mode) {
+ case set_yes:
+ if (sym_tristate_within_range(sym, yes)) {
+ line[0] = 'y';
+ line[1] = '\n';
+ line[2] = 0;
+ break;
+ }
+ case set_mod:
+ if (type == S_TRISTATE) {
+ if (sym_tristate_within_range(sym, mod)) {
+ line[0] = 'm';
+ line[1] = '\n';
+ line[2] = 0;
+ break;
+ }
+ } else {
+ if (sym_tristate_within_range(sym, yes)) {
+ line[0] = 'y';
+ line[1] = '\n';
+ line[2] = 0;
+ break;
+ }
+ }
+ case set_no:
+ if (sym_tristate_within_range(sym, no)) {
+ line[0] = 'n';
+ line[1] = '\n';
+ line[2] = 0;
+ break;
+ }
+ case set_random:
+ do {
+ val = (tristate)(random() % 3);
+ } while (!sym_tristate_within_range(sym, val));
+ switch (val) {
+ case no: line[0] = 'n'; break;
+ case mod: line[0] = 'm'; break;
+ case yes: line[0] = 'y'; break;
+ }
+ line[1] = '\n';
+ line[2] = 0;
+ break;
+ default:
+ break;
+ }
+ printf("%s", line);
+}
+
+int conf_string(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ const char *def, *help;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", menu->prompt->text);
+ printf("(%s) ", sym->name);
+ def = sym_get_string_value(sym);
+ if (sym_get_string_value(sym))
+ printf("[%s] ", def);
+ conf_askvalue(sym, def);
+ switch (line[0]) {
+ case '\n':
+ break;
+ case '?':
+ /* print help */
+ if (line[1] == '\n') {
+ help = nohelp_text;
+ if (menu->sym->help)
+ help = menu->sym->help;
+ printf("\n%s\n", menu->sym->help);
+ def = NULL;
+ break;
+ }
+ default:
+ line[strlen(line)-1] = 0;
+ def = line;
+ }
+ if (def && sym_set_string_value(sym, def))
+ return 0;
+ }
+}
+
+static int conf_sym(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ int type;
+ tristate oldval, newval;
+ const char *help;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", menu->prompt->text);
+ if (sym->name)
+ printf("(%s) ", sym->name);
+ type = sym_get_type(sym);
+ putchar('[');
+ oldval = sym_get_tristate_value(sym);
+ switch (oldval) {
+ case no:
+ putchar('N');
+ break;
+ case mod:
+ putchar('M');
+ break;
+ case yes:
+ putchar('Y');
+ break;
+ }
+ if (oldval != no && sym_tristate_within_range(sym, no))
+ printf("/n");
+ if (oldval != mod && sym_tristate_within_range(sym, mod))
+ printf("/m");
+ if (oldval != yes && sym_tristate_within_range(sym, yes))
+ printf("/y");
+ if (sym->help)
+ printf("/?");
+ printf("] ");
+ conf_askvalue(sym, sym_get_string_value(sym));
+ strip(line);
+
+ switch (line[0]) {
+ case 'n':
+ case 'N':
+ newval = no;
+ if (!line[1] || !strcmp(&line[1], "o"))
+ break;
+ continue;
+ case 'm':
+ case 'M':
+ newval = mod;
+ if (!line[1])
+ break;
+ continue;
+ case 'y':
+ case 'Y':
+ newval = yes;
+ if (!line[1] || !strcmp(&line[1], "es"))
+ break;
+ continue;
+ case 0:
+ newval = oldval;
+ break;
+ case '?':
+ goto help;
+ default:
+ continue;
+ }
+ if (sym_set_tristate_value(sym, newval))
+ return 0;
+help:
+ help = nohelp_text;
+ if (sym->help)
+ help = sym->help;
+ printf("\n%s\n", help);
+ }
+}
+
+static int conf_choice(struct menu *menu)
+{
+ struct symbol *sym, *def_sym;
+ struct menu *child;
+ int type;
+ bool is_new;
+
+ sym = menu->sym;
+ type = sym_get_type(sym);
+ is_new = !sym_has_value(sym);
+ if (sym_is_changable(sym)) {
+ conf_sym(menu);
+ sym_calc_value(sym);
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ return 0;
+ case yes:
+ break;
+ }
+ } else {
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+ return 0;
+ case yes:
+ break;
+ }
+ }
+
+ while (1) {
+ int cnt, def;
+
+ printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+ def_sym = sym_get_choice_value(sym);
+ cnt = def = 0;
+ line[0] = '0';
+ line[1] = 0;
+ for (child = menu->list; child; child = child->next) {
+ if (!menu_is_visible(child))
+ continue;
+ if (!child->sym) {
+ printf("%*c %s\n", indent, '*', menu_get_prompt(child));
+ continue;
+ }
+ cnt++;
+ if (child->sym == def_sym) {
+ def = cnt;
+ printf("%*c", indent, '>');
+ } else
+ printf("%*c", indent, ' ');
+ printf(" %d. %s", cnt, menu_get_prompt(child));
+ if (child->sym->name)
+ printf(" (%s)", child->sym->name);
+ if (!sym_has_value(child->sym))
+ printf(" (NEW)");
+ printf("\n");
+ }
+ printf("%*schoice", indent - 1, "");
+ if (cnt == 1) {
+ printf("[1]: 1\n");
+ goto conf_childs;
+ }
+ printf("[1-%d", cnt);
+ if (sym->help)
+ printf("?");
+ printf("]: ");
+ switch (input_mode) {
+ case ask_new:
+ case ask_silent:
+ if (!is_new) {
+ cnt = def;
+ printf("%d\n", cnt);
+ break;
+ }
+ check_stdin();
+ case ask_all:
+ fflush(stdout);
+ fgets(line, 128, stdin);
+ strip(line);
+ if (line[0] == '?') {
+ printf("\n%s\n", menu->sym->help ?
+ menu->sym->help : nohelp_text);
+ continue;
+ }
+ if (!line[0])
+ cnt = def;
+ else if (isdigit(line[0]))
+ cnt = atoi(line);
+ else
+ continue;
+ break;
+ case set_random:
+ def = (random() % cnt) + 1;
+ case set_default:
+ case set_yes:
+ case set_mod:
+ case set_no:
+ cnt = def;
+ printf("%d\n", cnt);
+ break;
+ }
+
+ conf_childs:
+ for (child = menu->list; child; child = child->next) {
+ if (!child->sym || !menu_is_visible(child))
+ continue;
+ if (!--cnt)
+ break;
+ }
+ if (!child)
+ continue;
+ if (line[strlen(line) - 1] == '?') {
+ printf("\n%s\n", child->sym->help ?
+ child->sym->help : nohelp_text);
+ continue;
+ }
+ sym_set_choice_value(sym, child->sym);
+ if (child->list) {
+ indent += 2;
+ conf(child->list);
+ indent -= 2;
+ }
+ return 1;
+ }
+}
+
+static void conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (prop) {
+ const char *prompt;
+
+ switch (prop->type) {
+ case P_MENU:
+ if (input_mode == ask_silent && rootEntry != menu) {
+ check_conf(menu);
+ return;
+ }
+ case P_COMMENT:
+ prompt = menu_get_prompt(menu);
+ if (prompt)
+ printf("%*c\n%*c %s\n%*c\n",
+ indent, '*',
+ indent, '*', prompt,
+ indent, '*');
+ default:
+ ;
+ }
+ }
+
+ if (!sym)
+ goto conf_childs;
+
+ if (sym_is_choice(sym)) {
+ conf_choice(menu);
+ if (sym->curr.tri != mod)
+ return;
+ goto conf_childs;
+ }
+
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ conf_string(menu);
+ break;
+ default:
+ conf_sym(menu);
+ break;
+ }
+
+conf_childs:
+ if (sym)
+ indent += 2;
+ for (child = menu->list; child; child = child->next)
+ conf(child);
+ if (sym)
+ indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ if (sym) {
+ if (sym_is_changable(sym) && !sym_has_value(sym)) {
+ if (!conf_cnt++)
+ printf("*\n* Restart config...\n*\n");
+ rootEntry = menu_get_parent_menu(menu);
+ conf(rootEntry);
+ }
+ if (sym_is_choice(sym) && sym_get_tristate_value(sym) != mod)
+ return;
+ }
+
+ for (child = menu->list; child; child = child->next)
+ check_conf(child);
+}
+
+int main(int ac, char **av)
+{
+ int i = 1;
+ const char *name;
+ struct stat tmpstat;
+
+ if (ac > i && av[i][0] == '-') {
+ switch (av[i++][1]) {
+ case 'o':
+ input_mode = ask_new;
+ break;
+ case 's':
+ input_mode = ask_silent;
+ valid_stdin = isatty(0) && isatty(1) && isatty(2);
+ break;
+ case 'd':
+ input_mode = set_default;
+ break;
+ case 'D':
+ input_mode = set_default;
+ defconfig_file = av[i++];
+ if (!defconfig_file) {
+ printf("%s: No default config file specified\n",
+ av[0]);
+ exit(1);
+ }
+ break;
+ case 'n':
+ input_mode = set_no;
+ break;
+ case 'm':
+ input_mode = set_mod;
+ break;
+ case 'y':
+ input_mode = set_yes;
+ break;
+ case 'r':
+ input_mode = set_random;
+ srandom(time(NULL));
+ break;
+ case 'h':
+ case '?':
+ printf("%s [-o|-s] config\n", av[0]);
+ exit(0);
+ }
+ }
+ name = av[i];
+ if (!name) {
+ printf("%s: configuration file missing\n", av[0]);
+ }
+ conf_parse(name);
+ //zconfdump(stdout);
+ switch (input_mode) {
+ case set_default:
+ if (!defconfig_file)
+ defconfig_file = conf_get_default_confname();
+ if (conf_read(defconfig_file)) {
+ printf("***\n"
+ "*** Can't find default configuration \"%s\"!\n"
+ "***\n", defconfig_file);
+ exit(1);
+ }
+ break;
+ case ask_silent:
+ if (stat(".config", &tmpstat)) {
+ printf("***\n"
+ "*** You have not yet configured axTLS!\n"
+ "***\n"
+ "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
+ "*** \"make menuconfig\" or \"make config\").\n"
+ "***\n");
+ exit(1);
+ }
+ case ask_all:
+ case ask_new:
+ conf_read(NULL);
+ break;
+ default:
+ break;
+ }
+
+ if (input_mode != ask_silent) {
+ rootEntry = &rootmenu;
+ conf(&rootmenu);
+ if (input_mode == ask_all) {
+ input_mode = ask_silent;
+ valid_stdin = 1;
+ }
+ }
+ do {
+ conf_cnt = 0;
+ check_conf(&rootmenu);
+ } while (conf_cnt);
+ if (conf_write(NULL)) {
+ fprintf(stderr, "\n*** Error during writing of the axTLS configuration.\n\n");
+ return 1;
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <sys/stat.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+const char conf_def_filename[] = "config/.config";
+
+const char conf_defname[] = "config/defconfig";
+
+const char *conf_confnames[] = {
+ "config/.config",
+ conf_defname,
+ NULL,
+};
+
+static char *conf_expand_value(const char *in)
+{
+ struct symbol *sym;
+ const char *src;
+ static char res_value[SYMBOL_MAXLENGTH];
+ char *dst, name[SYMBOL_MAXLENGTH];
+
+ res_value[0] = 0;
+ dst = name;
+ while ((src = strchr(in, '$'))) {
+ strncat(res_value, in, src - in);
+ src++;
+ dst = name;
+ while (isalnum(*src) || *src == '_')
+ *dst++ = *src++;
+ *dst = 0;
+ sym = sym_lookup(name, 0);
+ sym_calc_value(sym);
+ strcat(res_value, sym_get_string_value(sym));
+ in = src;
+ }
+ strcat(res_value, in);
+
+ return res_value;
+}
+
+char *conf_get_default_confname(void)
+{
+ struct stat buf;
+ static char fullname[PATH_MAX+1];
+ char *env, *name;
+
+ name = conf_expand_value(conf_defname);
+ env = getenv(SRCTREE);
+ if (env) {
+ sprintf(fullname, "%s/%s", env, name);
+ if (!stat(fullname, &buf))
+ return fullname;
+ }
+ return name;
+}
+
+int conf_read(const char *name)
+{
+ FILE *in = NULL;
+ char line[1024];
+ char *p, *p2;
+ int lineno = 0;
+ struct symbol *sym;
+ struct property *prop;
+ struct expr *e;
+ int i;
+
+ if (name) {
+ in = zconf_fopen(name);
+ } else {
+ const char **names = conf_confnames;
+ while ((name = *names++)) {
+ name = conf_expand_value(name);
+ in = zconf_fopen(name);
+ if (in) {
+ printf("#\n"
+ "# using defaults found in %s\n"
+ "#\n", name);
+ break;
+ }
+ }
+ }
+
+ if (!in)
+ return 1;
+
+ for_all_symbols(i, sym) {
+ sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
+ sym->flags &= ~SYMBOL_VALID;
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ if (sym->user.val)
+ free(sym->user.val);
+ default:
+ sym->user.val = NULL;
+ sym->user.tri = no;
+ }
+ }
+
+ while (fgets(line, sizeof(line), in)) {
+ lineno++;
+ sym = NULL;
+ switch (line[0]) {
+ case '#':
+ if (line[1]!=' ')
+ continue;
+ p = strchr(line + 2, ' ');
+ if (!p)
+ continue;
+ *p++ = 0;
+ if (strncmp(p, "is not set", 10))
+ continue;
+ sym = sym_find(line + 2);
+ if (!sym) {
+ fprintf(stderr, "%s:%d: trying to assign nonexistent symbol %s\n", name, lineno, line + 2);
+ break;
+ }
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ sym->user.tri = no;
+ sym->flags &= ~SYMBOL_NEW;
+ break;
+ default:
+ ;
+ }
+ break;
+
+ case 'A' ... 'Z':
+ p = strchr(line, '=');
+ if (!p)
+ continue;
+ *p++ = 0;
+ p2 = strchr(p, '\n');
+ if (p2)
+ *p2 = 0;
+ sym = sym_find(line);
+ if (!sym) {
+ fprintf(stderr, "%s:%d: trying to assign nonexistent symbol %s\n", name, lineno, line);
+ break;
+ }
+ switch (sym->type) {
+ case S_TRISTATE:
+ if (p[0] == 'm') {
+ sym->user.tri = mod;
+ sym->flags &= ~SYMBOL_NEW;
+ break;
+ }
+ case S_BOOLEAN:
+ if (p[0] == 'y') {
+ sym->user.tri = yes;
+ sym->flags &= ~SYMBOL_NEW;
+ break;
+ }
+ if (p[0] == 'n') {
+ sym->user.tri = no;
+ sym->flags &= ~SYMBOL_NEW;
+ break;
+ }
+ break;
+ case S_STRING:
+ if (*p++ != '"')
+ break;
+ for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+ if (*p2 == '"') {
+ *p2 = 0;
+ break;
+ }
+ memmove(p2, p2 + 1, strlen(p2));
+ }
+ if (!p2) {
+ fprintf(stderr, "%s:%d: invalid string found\n", name, lineno);
+ exit(1);
+ }
+ case S_INT:
+ case S_HEX:
+ if (sym_string_valid(sym, p)) {
+ sym->user.val = strdup(p);
+ sym->flags &= ~SYMBOL_NEW;
+ } else {
+ fprintf(stderr, "%s:%d: symbol value '%s' invalid for %s\n", name, lineno, p, sym->name);
+ exit(1);
+ }
+ break;
+ default:
+ ;
+ }
+ break;
+ case '\n':
+ break;
+ default:
+ continue;
+ }
+ if (sym && sym_is_choice_value(sym)) {
+ struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+ switch (sym->user.tri) {
+ case no:
+ break;
+ case mod:
+ if (cs->user.tri == yes)
+ /* warn? */;
+ break;
+ case yes:
+ if (cs->user.tri != no)
+ /* warn? */;
+ cs->user.val = sym;
+ break;
+ }
+ cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
+ cs->flags &= ~SYMBOL_NEW;
+ }
+ }
+ fclose(in);
+
+ if (modules_sym)
+ sym_calc_value(modules_sym);
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+ if (sym->visible == no)
+ sym->flags |= SYMBOL_NEW;
+ switch (sym->type) {
+ case S_STRING:
+ case S_INT:
+ case S_HEX:
+ if (!sym_string_within_range(sym, sym->user.val))
+ sym->flags |= SYMBOL_NEW;
+ default:
+ break;
+ }
+ }
+ if (!sym_is_choice(sym))
+ continue;
+ prop = sym_get_choice_prop(sym);
+ for (e = prop->expr; e; e = e->left.expr)
+ if (e->right.sym->visible != no)
+ sym->flags |= e->right.sym->flags & SYMBOL_NEW;
+ }
+
+ sym_change_count = 1;
+
+ return 0;
+}
+
+struct menu *next_menu(struct menu *menu)
+{
+ if (menu->list) return menu->list;
+ do {
+ if (menu->next) {
+ menu = menu->next;
+ break;
+ }
+ } while ((menu = menu->parent));
+
+ return menu;
+}
+
+#define SYMBOL_FORCEWRITE (1<<31)
+
+int conf_write(const char *name)
+{
+ FILE *out, *out_h;
+ struct symbol *sym;
+ struct menu *menu;
+ const char *basename;
+ char dirname[128], tmpname[128], newname[128];
+ int type, l;
+ const char *str;
+
+ dirname[0] = 0;
+ if (name && name[0]) {
+ struct stat st;
+ char *slash;
+
+ if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
+ strcpy(dirname, name);
+ strcat(dirname, "/");
+ basename = conf_def_filename;
+ } else if ((slash = strrchr(name, '/'))) {
+ int size = slash - name + 1;
+ memcpy(dirname, name, size);
+ dirname[size] = 0;
+ if (slash[1])
+ basename = slash + 1;
+ else
+ basename = conf_def_filename;
+ } else
+ basename = name;
+ } else
+ basename = conf_def_filename;
+
+ sprintf(newname, "config/%s.tmpconfig.%d", dirname, (int)getpid());
+ out = fopen(newname, "w");
+ if (!out)
+ return 1;
+ out_h = NULL;
+ if (!name) {
+ out_h = fopen("config/.tmpconfig.h", "w");
+ if (!out_h)
+ return 1;
+ }
+ fprintf(out, "#\n"
+ "# Automatically generated make config: don't edit\n"
+ "#\n");
+ if (out_h) {
+ fprintf(out_h, "/*\n"
+ " * Automatically generated header file: don't edit\n"
+ " */\n\n");
+#if 0
+ "/* Version Number */\n"
+ "#define BB_VER \"%s\"\n"
+ "#define BB_BT \"%s\"\n",
+ getenv("VERSION"),
+ getenv("BUILDTIME"));
+ if (getenv("EXTRA_VERSION"))
+ fprintf(out_h, "#define BB_EXTRA_VERSION \"%s\"\n",
+ getenv("EXTRA_VERSION"));
+ fprintf(out_h, "\n");
+#endif
+ }
+
+ if (!sym_change_count)
+ sym_clear_all_valid();
+
+ /* Force write of all non-duplicate symbols. */
+
+ /* Write out everything by default. */
+ for(menu = rootmenu.list; menu; menu = next_menu(menu))
+ if (menu->sym) menu->sym->flags |= SYMBOL_FORCEWRITE;
+
+ menu = rootmenu.list;
+ while (menu) {
+ sym = menu->sym;
+ if (!sym) {
+ if (!menu_is_visible(menu))
+ goto next;
+ str = menu_get_prompt(menu);
+ fprintf(out, "\n"
+ "#\n"
+ "# %s\n"
+ "#\n", str);
+ if (out_h)
+ fprintf(out_h, "\n"
+ "/*\n"
+ " * %s\n"
+ " */\n", str);
+ } else if (!(sym->flags & SYMBOL_CHOICE)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_FORCEWRITE))
+ goto next;
+
+ sym->flags &= ~SYMBOL_FORCEWRITE;
+ type = sym->type;
+ if (type == S_TRISTATE) {
+ sym_calc_value(modules_sym);
+ if (modules_sym->curr.tri == no)
+ type = S_BOOLEAN;
+ }
+ switch (type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ fprintf(out, "# %s is not set\n", sym->name);
+ if (out_h)
+ fprintf(out_h, "#undef %s\n", sym->name);
+ break;
+ case mod:
+#if 0
+ fprintf(out, "%s=m\n", sym->name);
+ if (out_h)
+ fprintf(out_h, "#define %s_MODULE 1\n", sym->name);
+#endif
+ break;
+ case yes:
+ fprintf(out, "%s=y\n", sym->name);
+ if (out_h)
+ fprintf(out_h, "#define %s 1\n", sym->name);
+ break;
+ }
+ break;
+ case S_STRING:
+ // fix me
+ str = sym_get_string_value(sym);
+ fprintf(out, "%s=\"", sym->name);
+ if (out_h)
+ fprintf(out_h, "#define %s \"", sym->name);
+ do {
+ l = strcspn(str, "\"\\");
+ if (l) {
+ fwrite(str, l, 1, out);
+ if (out_h)
+ fwrite(str, l, 1, out_h);
+ }
+ str += l;
+ while (*str == '\\' || *str == '"') {
+ fprintf(out, "\\%c", *str);
+ if (out_h)
+ fprintf(out_h, "\\%c", *str);
+ str++;
+ }
+ } while (*str);
+ fputs("\"\n", out);
+ if (out_h)
+ fputs("\"\n", out_h);
+ break;
+ case S_HEX:
+ str = sym_get_string_value(sym);
+ if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
+ fprintf(out, "%s=%s\n", sym->name, *str ? str : "0");
+ if (out_h)
+ fprintf(out_h, "#define %s 0x%s\n", sym->name, str);
+ break;
+ }
+ case S_INT:
+ str = sym_get_string_value(sym);
+ fprintf(out, "%s=%s\n", sym->name, *str ? str : "0");
+ if (out_h)
+ fprintf(out_h, "#define %s %s\n", sym->name, str);
+ break;
+ }
+ }
+next:
+ menu = next_menu(menu);
+ }
+ fclose(out);
+ if (out_h) {
+ fclose(out_h);
+ rename("config/.tmpconfig.h", "config/config.h");
+ file_write_dep(NULL);
+ }
+ if (!name || basename != conf_def_filename) {
+ if (!name)
+ name = conf_def_filename;
+ sprintf(tmpname, "%s.old", name);
+ rename(name, tmpname);
+ }
+ sprintf(tmpname, "%s%s", dirname, basename);
+ if (rename(newname, tmpname))
+ return 1;
+
+ sym_change_count = 0;
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define DEBUG_EXPR 0
+
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+ struct expr *e = malloc(sizeof(*e));
+ memset(e, 0, sizeof(*e));
+ e->type = E_SYMBOL;
+ e->left.sym = sym;
+ return e;
+}
+
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
+{
+ struct expr *e = malloc(sizeof(*e));
+ memset(e, 0, sizeof(*e));
+ e->type = type;
+ e->left.expr = ce;
+ return e;
+}
+
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
+{
+ struct expr *e = malloc(sizeof(*e));
+ memset(e, 0, sizeof(*e));
+ e->type = type;
+ e->left.expr = e1;
+ e->right.expr = e2;
+ return e;
+}
+
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
+{
+ struct expr *e = malloc(sizeof(*e));
+ memset(e, 0, sizeof(*e));
+ e->type = type;
+ e->left.sym = s1;
+ e->right.sym = s2;
+ return e;
+}
+
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
+{
+ if (!e1)
+ return e2;
+ return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
+}
+
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
+{
+ if (!e1)
+ return e2;
+ return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
+}
+
+struct expr *expr_copy(struct expr *org)
+{
+ struct expr *e;
+
+ if (!org)
+ return NULL;
+
+ e = malloc(sizeof(*org));
+ memcpy(e, org, sizeof(*org));
+ switch (org->type) {
+ case E_SYMBOL:
+ e->left = org->left;
+ break;
+ case E_NOT:
+ e->left.expr = expr_copy(org->left.expr);
+ break;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ e->left.sym = org->left.sym;
+ e->right.sym = org->right.sym;
+ break;
+ case E_AND:
+ case E_OR:
+ case E_CHOICE:
+ e->left.expr = expr_copy(org->left.expr);
+ e->right.expr = expr_copy(org->right.expr);
+ break;
+ default:
+ printf("can't copy type %d\n", e->type);
+ free(e);
+ e = NULL;
+ break;
+ }
+
+ return e;
+}
+
+void expr_free(struct expr *e)
+{
+ if (!e)
+ return;
+
+ switch (e->type) {
+ case E_SYMBOL:
+ break;
+ case E_NOT:
+ expr_free(e->left.expr);
+ return;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ break;
+ case E_OR:
+ case E_AND:
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ break;
+ default:
+ printf("how to free type %d?\n", e->type);
+ break;
+ }
+ free(e);
+}
+
+static int trans_count;
+
+#define e1 (*ep1)
+#define e2 (*ep2)
+
+static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+ if (e1->type == type) {
+ __expr_eliminate_eq(type, &e1->left.expr, &e2);
+ __expr_eliminate_eq(type, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ __expr_eliminate_eq(type, &e1, &e2->left.expr);
+ __expr_eliminate_eq(type, &e1, &e2->right.expr);
+ return;
+ }
+ if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+ e1->left.sym == e2->left.sym && (e1->left.sym->flags & (SYMBOL_YES|SYMBOL_NO)))
+ return;
+ if (!expr_eq(e1, e2))
+ return;
+ trans_count++;
+ expr_free(e1); expr_free(e2);
+ switch (type) {
+ case E_OR:
+ e1 = expr_alloc_symbol(&symbol_no);
+ e2 = expr_alloc_symbol(&symbol_no);
+ break;
+ case E_AND:
+ e1 = expr_alloc_symbol(&symbol_yes);
+ e2 = expr_alloc_symbol(&symbol_yes);
+ break;
+ default:
+ ;
+ }
+}
+
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
+{
+ if (!e1 || !e2)
+ return;
+ switch (e1->type) {
+ case E_OR:
+ case E_AND:
+ __expr_eliminate_eq(e1->type, ep1, ep2);
+ default:
+ ;
+ }
+ if (e1->type != e2->type) switch (e2->type) {
+ case E_OR:
+ case E_AND:
+ __expr_eliminate_eq(e2->type, ep1, ep2);
+ default:
+ ;
+ }
+ e1 = expr_eliminate_yn(e1);
+ e2 = expr_eliminate_yn(e2);
+}
+
+#undef e1
+#undef e2
+
+int expr_eq(struct expr *e1, struct expr *e2)
+{
+ int res, old_count;
+
+ if (e1->type != e2->type)
+ return 0;
+ switch (e1->type) {
+ case E_EQUAL:
+ case E_UNEQUAL:
+ return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
+ case E_SYMBOL:
+ return e1->left.sym == e2->left.sym;
+ case E_NOT:
+ return expr_eq(e1->left.expr, e2->left.expr);
+ case E_AND:
+ case E_OR:
+ e1 = expr_copy(e1);
+ e2 = expr_copy(e2);
+ old_count = trans_count;
+ expr_eliminate_eq(&e1, &e2);
+ res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+ e1->left.sym == e2->left.sym);
+ expr_free(e1);
+ expr_free(e2);
+ trans_count = old_count;
+ return res;
+ case E_CHOICE:
+ case E_RANGE:
+ case E_NONE:
+ /* panic */;
+ }
+
+ if (DEBUG_EXPR) {
+ expr_fprint(e1, stdout);
+ printf(" = ");
+ expr_fprint(e2, stdout);
+ printf(" ?\n");
+ }
+
+ return 0;
+}
+
+struct expr *expr_eliminate_yn(struct expr *e)
+{
+ struct expr *tmp;
+
+ if (e) switch (e->type) {
+ case E_AND:
+ e->left.expr = expr_eliminate_yn(e->left.expr);
+ e->right.expr = expr_eliminate_yn(e->right.expr);
+ if (e->left.expr->type == E_SYMBOL) {
+ if (e->left.expr->left.sym == &symbol_no) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ e->right.expr = NULL;
+ return e;
+ } else if (e->left.expr->left.sym == &symbol_yes) {
+ free(e->left.expr);
+ tmp = e->right.expr;
+ *e = *(e->right.expr);
+ free(tmp);
+ return e;
+ }
+ }
+ if (e->right.expr->type == E_SYMBOL) {
+ if (e->right.expr->left.sym == &symbol_no) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ e->right.expr = NULL;
+ return e;
+ } else if (e->right.expr->left.sym == &symbol_yes) {
+ free(e->right.expr);
+ tmp = e->left.expr;
+ *e = *(e->left.expr);
+ free(tmp);
+ return e;
+ }
+ }
+ break;
+ case E_OR:
+ e->left.expr = expr_eliminate_yn(e->left.expr);
+ e->right.expr = expr_eliminate_yn(e->right.expr);
+ if (e->left.expr->type == E_SYMBOL) {
+ if (e->left.expr->left.sym == &symbol_no) {
+ free(e->left.expr);
+ tmp = e->right.expr;
+ *e = *(e->right.expr);
+ free(tmp);
+ return e;
+ } else if (e->left.expr->left.sym == &symbol_yes) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ e->right.expr = NULL;
+ return e;
+ }
+ }
+ if (e->right.expr->type == E_SYMBOL) {
+ if (e->right.expr->left.sym == &symbol_no) {
+ free(e->right.expr);
+ tmp = e->left.expr;
+ *e = *(e->left.expr);
+ free(tmp);
+ return e;
+ } else if (e->right.expr->left.sym == &symbol_yes) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ e->right.expr = NULL;
+ return e;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ return e;
+}
+
+/*
+ * bool FOO!=n => FOO
+ */
+struct expr *expr_trans_bool(struct expr *e)
+{
+ if (!e)
+ return NULL;
+ switch (e->type) {
+ case E_AND:
+ case E_OR:
+ case E_NOT:
+ e->left.expr = expr_trans_bool(e->left.expr);
+ e->right.expr = expr_trans_bool(e->right.expr);
+ break;
+ case E_UNEQUAL:
+ // FOO!=n -> FOO
+ if (e->left.sym->type == S_TRISTATE) {
+ if (e->right.sym == &symbol_no) {
+ e->type = E_SYMBOL;
+ e->right.sym = NULL;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ return e;
+}
+
+/*
+ * e1 || e2 -> ?
+ */
+struct expr *expr_join_or(struct expr *e1, struct expr *e2)
+{
+ struct expr *tmp;
+ struct symbol *sym1, *sym2;
+
+ if (expr_eq(e1, e2))
+ return expr_copy(e1);
+ if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+ return NULL;
+ if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+ return NULL;
+ if (e1->type == E_NOT) {
+ tmp = e1->left.expr;
+ if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+ return NULL;
+ sym1 = tmp->left.sym;
+ } else
+ sym1 = e1->left.sym;
+ if (e2->type == E_NOT) {
+ if (e2->left.expr->type != E_SYMBOL)
+ return NULL;
+ sym2 = e2->left.expr->left.sym;
+ } else
+ sym2 = e2->left.sym;
+ if (sym1 != sym2)
+ return NULL;
+ if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+ return NULL;
+ if (sym1->type == S_TRISTATE) {
+ if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+ (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
+ // (a='y') || (a='m') -> (a!='n')
+ return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
+ }
+ if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
+ // (a='y') || (a='n') -> (a!='m')
+ return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
+ }
+ if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+ ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
+ // (a='m') || (a='n') -> (a!='y')
+ return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
+ }
+ }
+ if (sym1->type == S_BOOLEAN && sym1 == sym2) {
+ if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
+ (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
+ return expr_alloc_symbol(&symbol_yes);
+ }
+
+ if (DEBUG_EXPR) {
+ printf("optimize (");
+ expr_fprint(e1, stdout);
+ printf(") || (");
+ expr_fprint(e2, stdout);
+ printf(")?\n");
+ }
+ return NULL;
+}
+
+struct expr *expr_join_and(struct expr *e1, struct expr *e2)
+{
+ struct expr *tmp;
+ struct symbol *sym1, *sym2;
+
+ if (expr_eq(e1, e2))
+ return expr_copy(e1);
+ if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+ return NULL;
+ if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+ return NULL;
+ if (e1->type == E_NOT) {
+ tmp = e1->left.expr;
+ if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+ return NULL;
+ sym1 = tmp->left.sym;
+ } else
+ sym1 = e1->left.sym;
+ if (e2->type == E_NOT) {
+ if (e2->left.expr->type != E_SYMBOL)
+ return NULL;
+ sym2 = e2->left.expr->left.sym;
+ } else
+ sym2 = e2->left.sym;
+ if (sym1 != sym2)
+ return NULL;
+ if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+ return NULL;
+
+ if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
+ (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
+ // (a) && (a='y') -> (a='y')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+ if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
+ (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
+ // (a) && (a!='n') -> (a)
+ return expr_alloc_symbol(sym1);
+
+ if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
+ (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
+ // (a) && (a!='m') -> (a='y')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+ if (sym1->type == S_TRISTATE) {
+ if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
+ // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+ sym2 = e1->right.sym;
+ if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+ return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+ : expr_alloc_symbol(&symbol_no);
+ }
+ if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
+ // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+ sym2 = e2->right.sym;
+ if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+ return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+ : expr_alloc_symbol(&symbol_no);
+ }
+ if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
+ // (a!='y') && (a!='n') -> (a='m')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
+
+ if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+ (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
+ // (a!='y') && (a!='m') -> (a='n')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
+
+ if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+ ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
+ // (a!='m') && (a!='n') -> (a='m')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+ if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
+ (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
+ (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
+ (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
+ return NULL;
+ }
+
+ if (DEBUG_EXPR) {
+ printf("optimize (");
+ expr_fprint(e1, stdout);
+ printf(") && (");
+ expr_fprint(e2, stdout);
+ printf(")?\n");
+ }
+ return NULL;
+}
+
+static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+ struct expr *tmp;
+
+ if (e1->type == type) {
+ expr_eliminate_dups1(type, &e1->left.expr, &e2);
+ expr_eliminate_dups1(type, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ expr_eliminate_dups1(type, &e1, &e2->left.expr);
+ expr_eliminate_dups1(type, &e1, &e2->right.expr);
+ return;
+ }
+ if (e1 == e2)
+ return;
+
+ switch (e1->type) {
+ case E_OR: case E_AND:
+ expr_eliminate_dups1(e1->type, &e1, &e1);
+ default:
+ ;
+ }
+
+ switch (type) {
+ case E_OR:
+ tmp = expr_join_or(e1, e2);
+ if (tmp) {
+ expr_free(e1); expr_free(e2);
+ e1 = expr_alloc_symbol(&symbol_no);
+ e2 = tmp;
+ trans_count++;
+ }
+ break;
+ case E_AND:
+ tmp = expr_join_and(e1, e2);
+ if (tmp) {
+ expr_free(e1); expr_free(e2);
+ e1 = expr_alloc_symbol(&symbol_yes);
+ e2 = tmp;
+ trans_count++;
+ }
+ break;
+ default:
+ ;
+ }
+#undef e1
+#undef e2
+}
+
+static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+ struct expr *tmp, *tmp1, *tmp2;
+
+ if (e1->type == type) {
+ expr_eliminate_dups2(type, &e1->left.expr, &e2);
+ expr_eliminate_dups2(type, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ expr_eliminate_dups2(type, &e1, &e2->left.expr);
+ expr_eliminate_dups2(type, &e1, &e2->right.expr);
+ }
+ if (e1 == e2)
+ return;
+
+ switch (e1->type) {
+ case E_OR:
+ expr_eliminate_dups2(e1->type, &e1, &e1);
+ // (FOO || BAR) && (!FOO && !BAR) -> n
+ tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+ tmp2 = expr_copy(e2);
+ tmp = expr_extract_eq_and(&tmp1, &tmp2);
+ if (expr_is_yes(tmp1)) {
+ expr_free(e1);
+ e1 = expr_alloc_symbol(&symbol_no);
+ trans_count++;
+ }
+ expr_free(tmp2);
+ expr_free(tmp1);
+ expr_free(tmp);
+ break;
+ case E_AND:
+ expr_eliminate_dups2(e1->type, &e1, &e1);
+ // (FOO && BAR) || (!FOO || !BAR) -> y
+ tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+ tmp2 = expr_copy(e2);
+ tmp = expr_extract_eq_or(&tmp1, &tmp2);
+ if (expr_is_no(tmp1)) {
+ expr_free(e1);
+ e1 = expr_alloc_symbol(&symbol_yes);
+ trans_count++;
+ }
+ expr_free(tmp2);
+ expr_free(tmp1);
+ expr_free(tmp);
+ break;
+ default:
+ ;
+ }
+#undef e1
+#undef e2
+}
+
+struct expr *expr_eliminate_dups(struct expr *e)
+{
+ int oldcount;
+ if (!e)
+ return e;
+
+ oldcount = trans_count;
+ while (1) {
+ trans_count = 0;
+ switch (e->type) {
+ case E_OR: case E_AND:
+ expr_eliminate_dups1(e->type, &e, &e);
+ expr_eliminate_dups2(e->type, &e, &e);
+ default:
+ ;
+ }
+ if (!trans_count)
+ break;
+ e = expr_eliminate_yn(e);
+ }
+ trans_count = oldcount;
+ return e;
+}
+
+struct expr *expr_transform(struct expr *e)
+{
+ struct expr *tmp;
+
+ if (!e)
+ return NULL;
+ switch (e->type) {
+ case E_EQUAL:
+ case E_UNEQUAL:
+ case E_SYMBOL:
+ case E_CHOICE:
+ break;
+ default:
+ e->left.expr = expr_transform(e->left.expr);
+ e->right.expr = expr_transform(e->right.expr);
+ }
+
+ switch (e->type) {
+ case E_EQUAL:
+ if (e->left.sym->type != S_BOOLEAN)
+ break;
+ if (e->right.sym == &symbol_no) {
+ e->type = E_NOT;
+ e->left.expr = expr_alloc_symbol(e->left.sym);
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_mod) {
+ printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_yes) {
+ e->type = E_SYMBOL;
+ e->right.sym = NULL;
+ break;
+ }
+ break;
+ case E_UNEQUAL:
+ if (e->left.sym->type != S_BOOLEAN)
+ break;
+ if (e->right.sym == &symbol_no) {
+ e->type = E_SYMBOL;
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_mod) {
+ printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_yes) {
+ e->type = E_NOT;
+ e->left.expr = expr_alloc_symbol(e->left.sym);
+ e->right.sym = NULL;
+ break;
+ }
+ break;
+ case E_NOT:
+ switch (e->left.expr->type) {
+ case E_NOT:
+ // !!a -> a
+ tmp = e->left.expr->left.expr;
+ free(e->left.expr);
+ free(e);
+ e = tmp;
+ e = expr_transform(e);
+ break;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ // !a='x' -> a!='x'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
+ break;
+ case E_OR:
+ // !(a || b) -> !a && !b
+ tmp = e->left.expr;
+ e->type = E_AND;
+ e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+ tmp->type = E_NOT;
+ tmp->right.expr = NULL;
+ e = expr_transform(e);
+ break;
+ case E_AND:
+ // !(a && b) -> !a || !b
+ tmp = e->left.expr;
+ e->type = E_OR;
+ e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+ tmp->type = E_NOT;
+ tmp->right.expr = NULL;
+ e = expr_transform(e);
+ break;
+ case E_SYMBOL:
+ if (e->left.expr->left.sym == &symbol_yes) {
+ // !'y' -> 'n'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ break;
+ }
+ if (e->left.expr->left.sym == &symbol_mod) {
+ // !'m' -> 'm'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_mod;
+ break;
+ }
+ if (e->left.expr->left.sym == &symbol_no) {
+ // !'n' -> 'y'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ break;
+ }
+ break;
+ default:
+ ;
+ }
+ break;
+ default:
+ ;
+ }
+ return e;
+}
+
+int expr_contains_symbol(struct expr *dep, struct symbol *sym)
+{
+ if (!dep)
+ return 0;
+
+ switch (dep->type) {
+ case E_AND:
+ case E_OR:
+ return expr_contains_symbol(dep->left.expr, sym) ||
+ expr_contains_symbol(dep->right.expr, sym);
+ case E_SYMBOL:
+ return dep->left.sym == sym;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ return dep->left.sym == sym ||
+ dep->right.sym == sym;
+ case E_NOT:
+ return expr_contains_symbol(dep->left.expr, sym);
+ default:
+ ;
+ }
+ return 0;
+}
+
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
+{
+ if (!dep)
+ return false;
+
+ switch (dep->type) {
+ case E_AND:
+ return expr_depends_symbol(dep->left.expr, sym) ||
+ expr_depends_symbol(dep->right.expr, sym);
+ case E_SYMBOL:
+ return dep->left.sym == sym;
+ case E_EQUAL:
+ if (dep->left.sym == sym) {
+ if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
+ return true;
+ }
+ break;
+ case E_UNEQUAL:
+ if (dep->left.sym == sym) {
+ if (dep->right.sym == &symbol_no)
+ return true;
+ }
+ break;
+ default:
+ ;
+ }
+ return false;
+}
+
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
+{
+ struct expr *tmp = NULL;
+ expr_extract_eq(E_AND, &tmp, ep1, ep2);
+ if (tmp) {
+ *ep1 = expr_eliminate_yn(*ep1);
+ *ep2 = expr_eliminate_yn(*ep2);
+ }
+ return tmp;
+}
+
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2)
+{
+ struct expr *tmp = NULL;
+ expr_extract_eq(E_OR, &tmp, ep1, ep2);
+ if (tmp) {
+ *ep1 = expr_eliminate_yn(*ep1);
+ *ep2 = expr_eliminate_yn(*ep2);
+ }
+ return tmp;
+}
+
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+ if (e1->type == type) {
+ expr_extract_eq(type, ep, &e1->left.expr, &e2);
+ expr_extract_eq(type, ep, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ expr_extract_eq(type, ep, ep1, &e2->left.expr);
+ expr_extract_eq(type, ep, ep1, &e2->right.expr);
+ return;
+ }
+ if (expr_eq(e1, e2)) {
+ *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1;
+ expr_free(e2);
+ if (type == E_AND) {
+ e1 = expr_alloc_symbol(&symbol_yes);
+ e2 = expr_alloc_symbol(&symbol_yes);
+ } else if (type == E_OR) {
+ e1 = expr_alloc_symbol(&symbol_no);
+ e2 = expr_alloc_symbol(&symbol_no);
+ }
+ }
+#undef e1
+#undef e2
+}
+
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
+{
+ struct expr *e1, *e2;
+
+ if (!e) {
+ e = expr_alloc_symbol(sym);
+ if (type == E_UNEQUAL)
+ e = expr_alloc_one(E_NOT, e);
+ return e;
+ }
+ switch (e->type) {
+ case E_AND:
+ e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+ e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+ if (sym == &symbol_yes)
+ e = expr_alloc_two(E_AND, e1, e2);
+ if (sym == &symbol_no)
+ e = expr_alloc_two(E_OR, e1, e2);
+ if (type == E_UNEQUAL)
+ e = expr_alloc_one(E_NOT, e);
+ return e;
+ case E_OR:
+ e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+ e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+ if (sym == &symbol_yes)
+ e = expr_alloc_two(E_OR, e1, e2);
+ if (sym == &symbol_no)
+ e = expr_alloc_two(E_AND, e1, e2);
+ if (type == E_UNEQUAL)
+ e = expr_alloc_one(E_NOT, e);
+ return e;
+ case E_NOT:
+ return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
+ case E_UNEQUAL:
+ case E_EQUAL:
+ if (type == E_EQUAL) {
+ if (sym == &symbol_yes)
+ return expr_copy(e);
+ if (sym == &symbol_mod)
+ return expr_alloc_symbol(&symbol_no);
+ if (sym == &symbol_no)
+ return expr_alloc_one(E_NOT, expr_copy(e));
+ } else {
+ if (sym == &symbol_yes)
+ return expr_alloc_one(E_NOT, expr_copy(e));
+ if (sym == &symbol_mod)
+ return expr_alloc_symbol(&symbol_yes);
+ if (sym == &symbol_no)
+ return expr_copy(e);
+ }
+ break;
+ case E_SYMBOL:
+ return expr_alloc_comp(type, e->left.sym, sym);
+ case E_CHOICE:
+ case E_RANGE:
+ case E_NONE:
+ /* panic */;
+ }
+ return NULL;
+}
+
+tristate expr_calc_value(struct expr *e)
+{
+ tristate val1, val2;
+ const char *str1, *str2;
+
+ if (!e)
+ return yes;
+
+ switch (e->type) {
+ case E_SYMBOL:
+ sym_calc_value(e->left.sym);
+ return e->left.sym->curr.tri;
+ case E_AND:
+ val1 = expr_calc_value(e->left.expr);
+ val2 = expr_calc_value(e->right.expr);
+ return E_AND(val1, val2);
+ case E_OR:
+ val1 = expr_calc_value(e->left.expr);
+ val2 = expr_calc_value(e->right.expr);
+ return E_OR(val1, val2);
+ case E_NOT:
+ val1 = expr_calc_value(e->left.expr);
+ return E_NOT(val1);
+ case E_EQUAL:
+ sym_calc_value(e->left.sym);
+ sym_calc_value(e->right.sym);
+ str1 = sym_get_string_value(e->left.sym);
+ str2 = sym_get_string_value(e->right.sym);
+ return !strcmp(str1, str2) ? yes : no;
+ case E_UNEQUAL:
+ sym_calc_value(e->left.sym);
+ sym_calc_value(e->right.sym);
+ str1 = sym_get_string_value(e->left.sym);
+ str2 = sym_get_string_value(e->right.sym);
+ return !strcmp(str1, str2) ? no : yes;
+ default:
+ printf("expr_calc_value: %d?\n", e->type);
+ return no;
+ }
+}
+
+int expr_compare_type(enum expr_type t1, enum expr_type t2)
+{
+#if 0
+ return 1;
+#else
+ if (t1 == t2)
+ return 0;
+ switch (t1) {
+ case E_EQUAL:
+ case E_UNEQUAL:
+ if (t2 == E_NOT)
+ return 1;
+ case E_NOT:
+ if (t2 == E_AND)
+ return 1;
+ case E_AND:
+ if (t2 == E_OR)
+ return 1;
+ case E_OR:
+ if (t2 == E_CHOICE)
+ return 1;
+ case E_CHOICE:
+ if (t2 == 0)
+ return 1;
+ default:
+ return -1;
+ }
+ printf("[%dgt%d?]", t1, t2);
+ return 0;
+#endif
+}
+
+void expr_print(struct expr *e, void (*fn)(void *, const char *), void *data, int prevtoken)
+{
+ if (!e) {
+ fn(data, "y");
+ return;
+ }
+
+ if (expr_compare_type(prevtoken, e->type) > 0)
+ fn(data, "(");
+ switch (e->type) {
+ case E_SYMBOL:
+ if (e->left.sym->name)
+ fn(data, e->left.sym->name);
+ else
+ fn(data, "<choice>");
+ break;
+ case E_NOT:
+ fn(data, "!");
+ expr_print(e->left.expr, fn, data, E_NOT);
+ break;
+ case E_EQUAL:
+ fn(data, e->left.sym->name);
+ fn(data, "=");
+ fn(data, e->right.sym->name);
+ break;
+ case E_UNEQUAL:
+ fn(data, e->left.sym->name);
+ fn(data, "!=");
+ fn(data, e->right.sym->name);
+ break;
+ case E_OR:
+ expr_print(e->left.expr, fn, data, E_OR);
+ fn(data, " || ");
+ expr_print(e->right.expr, fn, data, E_OR);
+ break;
+ case E_AND:
+ expr_print(e->left.expr, fn, data, E_AND);
+ fn(data, " && ");
+ expr_print(e->right.expr, fn, data, E_AND);
+ break;
+ case E_CHOICE:
+ fn(data, e->right.sym->name);
+ if (e->left.expr) {
+ fn(data, " ^ ");
+ expr_print(e->left.expr, fn, data, E_CHOICE);
+ }
+ break;
+ case E_RANGE:
+ fn(data, "[");
+ fn(data, e->left.sym->name);
+ fn(data, " ");
+ fn(data, e->right.sym->name);
+ fn(data, "]");
+ break;
+ default:
+ {
+ char buf[32];
+ sprintf(buf, "<unknown type %d>", e->type);
+ fn(data, buf);
+ break;
+ }
+ }
+ if (expr_compare_type(prevtoken, e->type) > 0)
+ fn(data, ")");
+}
+
+static void expr_print_file_helper(void *data, const char *str)
+{
+ fwrite(str, strlen(str), 1, data);
+}
+
+void expr_fprint(struct expr *e, FILE *out)
+{
+ expr_print(e, expr_print_file_helper, out, E_NONE);
+}
+
+static void expr_print_gstr_helper(void *data, const char *str)
+{
+ str_append((struct gstr*)data, str);
+}
+
+void expr_gstr_print(struct expr *e, struct gstr *gs)
+{
+ expr_print(e, expr_print_gstr_helper, gs, E_NONE);
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef EXPR_H
+#define EXPR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+struct file {
+ struct file *next;
+ struct file *parent;
+ char *name;
+ int lineno;
+ int flags;
+};
+
+#define FILE_BUSY 0x0001
+#define FILE_SCANNED 0x0002
+#define FILE_PRINTED 0x0004
+
+typedef enum tristate {
+ no, mod, yes
+} tristate;
+
+enum expr_type {
+ E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL, E_RANGE
+};
+
+union expr_data {
+ struct expr *expr;
+ struct symbol *sym;
+};
+
+struct expr {
+ enum expr_type type;
+ union expr_data left, right;
+};
+
+#define E_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2))
+#define E_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2))
+#define E_NOT(dep) (2-(dep))
+
+struct expr_value {
+ struct expr *expr;
+ tristate tri;
+};
+
+struct symbol_value {
+ void *val;
+ tristate tri;
+};
+
+enum symbol_type {
+ S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
+};
+
+struct symbol {
+ struct symbol *next;
+ char *name;
+ char *help;
+ enum symbol_type type;
+ struct symbol_value curr, user;
+ tristate visible;
+ int flags;
+ struct property *prop;
+ struct expr *dep, *dep2;
+ struct expr_value rev_dep;
+};
+
+#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
+
+#define SYMBOL_YES 0x0001
+#define SYMBOL_MOD 0x0002
+#define SYMBOL_NO 0x0004
+#define SYMBOL_CONST 0x0007
+#define SYMBOL_CHECK 0x0008
+#define SYMBOL_CHOICE 0x0010
+#define SYMBOL_CHOICEVAL 0x0020
+#define SYMBOL_PRINTED 0x0040
+#define SYMBOL_VALID 0x0080
+#define SYMBOL_OPTIONAL 0x0100
+#define SYMBOL_WRITE 0x0200
+#define SYMBOL_CHANGED 0x0400
+#define SYMBOL_NEW 0x0800
+#define SYMBOL_AUTO 0x1000
+#define SYMBOL_CHECKED 0x2000
+#define SYMBOL_CHECK_DONE 0x4000
+#define SYMBOL_WARNED 0x8000
+
+#define SYMBOL_MAXLENGTH 256
+#define SYMBOL_HASHSIZE 257
+#define SYMBOL_HASHMASK 0xff
+
+enum prop_type {
+ P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, P_SELECT, P_RANGE
+};
+
+struct property {
+ struct property *next;
+ struct symbol *sym;
+ enum prop_type type;
+ const char *text;
+ struct expr_value visible;
+ struct expr *expr;
+ struct menu *menu;
+ struct file *file;
+ int lineno;
+};
+
+#define for_all_properties(sym, st, tok) \
+ for (st = sym->prop; st; st = st->next) \
+ if (st->type == (tok))
+#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
+#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
+#define for_all_prompts(sym, st) \
+ for (st = sym->prop; st; st = st->next) \
+ if (st->text)
+
+struct menu {
+ struct menu *next;
+ struct menu *parent;
+ struct menu *list;
+ struct symbol *sym;
+ struct property *prompt;
+ struct expr *dep;
+ unsigned int flags;
+ //char *help;
+ struct file *file;
+ int lineno;
+ void *data;
+};
+
+#define MENU_CHANGED 0x0001
+#define MENU_ROOT 0x0002
+
+#ifndef SWIG
+
+extern struct file *file_list;
+extern struct file *current_file;
+struct file *lookup_file(const char *name);
+
+extern struct symbol symbol_yes, symbol_no, symbol_mod;
+extern struct symbol *modules_sym;
+extern int cdebug;
+struct expr *expr_alloc_symbol(struct symbol *sym);
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
+struct expr *expr_copy(struct expr *org);
+void expr_free(struct expr *e);
+int expr_eq(struct expr *e1, struct expr *e2);
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
+tristate expr_calc_value(struct expr *e);
+struct expr *expr_eliminate_yn(struct expr *e);
+struct expr *expr_trans_bool(struct expr *e);
+struct expr *expr_eliminate_dups(struct expr *e);
+struct expr *expr_transform(struct expr *e);
+int expr_contains_symbol(struct expr *dep, struct symbol *sym);
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+
+void expr_fprint(struct expr *e, FILE *out);
+struct gstr; /* forward */
+void expr_gstr_print(struct expr *e, struct gstr *gs);
+
+static inline int expr_is_yes(struct expr *e)
+{
+ return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
+}
+
+static inline int expr_is_no(struct expr *e)
+{
+ return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXPR_H */
--- /dev/null
+
+#line 3 "lex.zconf.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 31
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#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 zconfrestart(zconfin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int zconfleng;
+
+extern FILE *zconfin, *zconfout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up zconftext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up zconftext 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).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+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;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* 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 zconfrestart()), so that the user can continue scanning by
+ * just pointing zconfin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* 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".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when zconftext is formed. */
+static char yy_hold_char;
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+int zconfleng;
+
+/* 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 zconfwrap()'s to do buffer switches
+ * instead of setting up a fresh zconfin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void zconfrestart (FILE *input_file );
+void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size );
+void zconf_delete_buffer (YY_BUFFER_STATE b );
+void zconf_flush_buffer (YY_BUFFER_STATE b );
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer );
+void zconfpop_buffer_state (void );
+
+static void zconfensure_buffer_stack (void );
+static void zconf_load_buffer_state (void );
+static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len );
+
+void *zconfalloc (yy_size_t );
+void *zconfrealloc (void *,yy_size_t );
+void zconffree (void * );
+
+#define yy_new_buffer zconf_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ zconfensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ zconfensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define zconfwrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int zconflineno;
+
+int zconflineno = 1;
+
+extern char *zconftext;
+#define yytext_ptr zconftext
+static yyconst flex_int16_t yy_nxt[][38] =
+ {
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+ },
+
+ {
+ 11, 12, 13, 14, 12, 12, 15, 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
+ },
+
+ {
+ 11, 12, 13, 14, 12, 12, 15, 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
+ },
+
+ {
+ 11, 16, 16, 17, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 18, 16, 16, 18, 18, 19, 20,
+ 21, 22, 18, 18, 23, 24, 18, 25, 18, 26,
+ 27, 18, 28, 29, 30, 18, 18, 16
+ },
+
+ {
+ 11, 16, 16, 17, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 18, 16, 16, 18, 18, 19, 20,
+ 21, 22, 18, 18, 23, 24, 18, 25, 18, 26,
+ 27, 18, 28, 29, 30, 18, 18, 16
+
+ },
+
+ {
+ 11, 31, 32, 33, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31
+ },
+
+ {
+ 11, 31, 32, 33, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31
+ },
+
+ {
+ 11, 34, 34, 35, 34, 36, 34, 34, 36, 34,
+ 34, 34, 34, 34, 34, 37, 34, 34, 34, 34,
+
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34
+ },
+
+ {
+ 11, 34, 34, 35, 34, 36, 34, 34, 36, 34,
+ 34, 34, 34, 34, 34, 37, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34
+ },
+
+ {
+ 11, 38, 38, 39, 40, 41, 42, 43, 41, 44,
+ 45, 46, 47, 47, 48, 49, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 50, 47, 47, 47, 51,
+ 47, 47, 47, 47, 47, 47, 47, 52
+
+ },
+
+ {
+ 11, 38, 38, 39, 40, 41, 42, 43, 41, 44,
+ 45, 46, 47, 47, 48, 49, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 50, 47, 47, 47, 51,
+ 47, 47, 47, 47, 47, 47, 47, 52
+ },
+
+ {
+ -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+ -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+ -11, -11, -11, -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, -12, -12, -12, -12, -12
+ },
+
+ {
+ 11, -13, 53, 54, -13, -13, 55, -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
+ },
+
+ {
+ 11, -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
+
+ },
+
+ {
+ 11, 56, 56, 57, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56
+ },
+
+ {
+ 11, -16, -16, -16, -16, -16, -16, -16, -16, -16,
+ -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
+ -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
+ -16, -16, -16, -16, -16, -16, -16, -16
+ },
+
+ {
+ 11, -17, -17, -17, -17, -17, -17, -17, -17, -17,
+ -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
+
+ -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
+ -17, -17, -17, -17, -17, -17, -17, -17
+ },
+
+ {
+ 11, -18, -18, -18, -18, -18, -18, -18, -18, -18,
+ -18, -18, -18, 58, -18, -18, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -18
+ },
+
+ {
+ 11, -19, -19, -19, -19, -19, -19, -19, -19, -19,
+ -19, -19, -19, 58, -19, -19, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 59,
+ 58, 58, 58, 58, 58, 58, 58, -19
+
+ },
+
+ {
+ 11, -20, -20, -20, -20, -20, -20, -20, -20, -20,
+ -20, -20, -20, 58, -20, -20, 58, 58, 58, 58,
+ 58, 58, 58, 58, 60, 58, 58, 58, 58, 61,
+ 58, 58, 58, 58, 58, 58, 58, -20
+ },
+
+ {
+ 11, -21, -21, -21, -21, -21, -21, -21, -21, -21,
+ -21, -21, -21, 58, -21, -21, 58, 58, 58, 58,
+ 58, 62, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -21
+ },
+
+ {
+ 11, -22, -22, -22, -22, -22, -22, -22, -22, -22,
+ -22, -22, -22, 58, -22, -22, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 63, 58,
+ 58, 58, 58, 58, 58, 58, 58, -22
+ },
+
+ {
+ 11, -23, -23, -23, -23, -23, -23, -23, -23, -23,
+ -23, -23, -23, 58, -23, -23, 58, 58, 58, 58,
+ 58, 64, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -23
+ },
+
+ {
+ 11, -24, -24, -24, -24, -24, -24, -24, -24, -24,
+ -24, -24, -24, 58, -24, -24, 58, 58, 58, 58,
+ 58, 58, 65, 58, 58, 58, 58, 58, 66, 58,
+ 58, 58, 58, 58, 58, 58, 58, -24
+
+ },
+
+ {
+ 11, -25, -25, -25, -25, -25, -25, -25, -25, -25,
+ -25, -25, -25, 58, -25, -25, 58, 67, 58, 58,
+ 58, 68, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -25
+ },
+
+ {
+ 11, -26, -26, -26, -26, -26, -26, -26, -26, -26,
+ -26, -26, -26, 58, -26, -26, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 69, 58, 58, 58, 58, 58, 58, -26
+ },
+
+ {
+ 11, -27, -27, -27, -27, -27, -27, -27, -27, -27,
+ -27, -27, -27, 58, -27, -27, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 70, 58, 58, 58, 58, -27
+ },
+
+ {
+ 11, -28, -28, -28, -28, -28, -28, -28, -28, -28,
+ -28, -28, -28, 58, -28, -28, 58, 71, 58, 58,
+ 58, 72, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -28
+ },
+
+ {
+ 11, -29, -29, -29, -29, -29, -29, -29, -29, -29,
+ -29, -29, -29, 58, -29, -29, 58, 58, 58, 58,
+ 58, 73, 58, 58, 58, 58, 58, 58, 58, 74,
+ 58, 58, 58, 58, 75, 58, 58, -29
+
+ },
+
+ {
+ 11, -30, -30, -30, -30, -30, -30, -30, -30, -30,
+ -30, -30, -30, 58, -30, -30, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 76, 58, 58, 58, 58, -30
+ },
+
+ {
+ 11, 77, 77, -31, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77
+ },
+
+ {
+ 11, -32, 78, 79, -32, -32, -32, -32, -32, -32,
+ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,
+
+ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,
+ -32, -32, -32, -32, -32, -32, -32, -32
+ },
+
+ {
+ 11, 80, -33, -33, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80
+ },
+
+ {
+ 11, 81, 81, 82, 81, -34, 81, 81, -34, 81,
+ 81, 81, 81, 81, 81, -34, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81
+
+ },
+
+ {
+ 11, -35, -35, -35, -35, -35, -35, -35, -35, -35,
+ -35, -35, -35, -35, -35, -35, -35, -35, -35, -35,
+ -35, -35, -35, -35, -35, -35, -35, -35, -35, -35,
+ -35, -35, -35, -35, -35, -35, -35, -35
+ },
+
+ {
+ 11, -36, -36, -36, -36, -36, -36, -36, -36, -36,
+ -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
+ -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
+ -36, -36, -36, -36, -36, -36, -36, -36
+ },
+
+ {
+ 11, 83, 83, 84, 83, 83, 83, 83, 83, 83,
+ 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+
+ 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+ 83, 83, 83, 83, 83, 83, 83, 83
+ },
+
+ {
+ 11, -38, -38, -38, -38, -38, -38, -38, -38, -38,
+ -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
+ -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
+ -38, -38, -38, -38, -38, -38, -38, -38
+ },
+
+ {
+ 11, -39, -39, -39, -39, -39, -39, -39, -39, -39,
+ -39, -39, -39, -39, -39, -39, -39, -39, -39, -39,
+ -39, -39, -39, -39, -39, -39, -39, -39, -39, -39,
+ -39, -39, -39, -39, -39, -39, -39, -39
+
+ },
+
+ {
+ 11, -40, -40, -40, -40, -40, -40, -40, -40, -40,
+ -40, -40, -40, -40, 85, -40, -40, -40, -40, -40,
+ -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
+ -40, -40, -40, -40, -40, -40, -40, -40
+ },
+
+ {
+ 11, -41, -41, -41, -41, -41, -41, -41, -41, -41,
+ -41, -41, -41, -41, -41, -41, -41, -41, -41, -41,
+ -41, -41, -41, -41, -41, -41, -41, -41, -41, -41,
+ -41, -41, -41, -41, -41, -41, -41, -41
+ },
+
+ {
+ 11, 86, 86, -42, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86
+ },
+
+ {
+ 11, -43, -43, -43, -43, -43, -43, 87, -43, -43,
+ -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
+ -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
+ -43, -43, -43, -43, -43, -43, -43, -43
+ },
+
+ {
+ 11, -44, -44, -44, -44, -44, -44, -44, -44, -44,
+ -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
+ -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
+ -44, -44, -44, -44, -44, -44, -44, -44
+
+ },
+
+ {
+ 11, -45, -45, -45, -45, -45, -45, -45, -45, -45,
+ -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,
+ -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,
+ -45, -45, -45, -45, -45, -45, -45, -45
+ },
+
+ {
+ 11, -46, -46, -46, -46, -46, -46, -46, -46, -46,
+ -46, 88, 89, 89, -46, -46, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, -46
+ },
+
+ {
+ 11, -47, -47, -47, -47, -47, -47, -47, -47, -47,
+ -47, 89, 89, 89, -47, -47, 89, 89, 89, 89,
+
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, -47
+ },
+
+ {
+ 11, -48, -48, -48, -48, -48, -48, -48, -48, -48,
+ -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
+ -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
+ -48, -48, -48, -48, -48, -48, -48, -48
+ },
+
+ {
+ 11, -49, -49, 90, -49, -49, -49, -49, -49, -49,
+ -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
+ -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
+ -49, -49, -49, -49, -49, -49, -49, -49
+
+ },
+
+ {
+ 11, -50, -50, -50, -50, -50, -50, -50, -50, -50,
+ -50, 89, 89, 89, -50, -50, 89, 89, 89, 89,
+ 89, 89, 91, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, -50
+ },
+
+ {
+ 11, -51, -51, -51, -51, -51, -51, -51, -51, -51,
+ -51, 89, 89, 89, -51, -51, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 92, 89,
+ 89, 89, 89, 89, 89, 89, 89, -51
+ },
+
+ {
+ 11, -52, -52, -52, -52, -52, -52, -52, -52, -52,
+ -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
+
+ -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
+ -52, -52, -52, -52, -52, -52, -52, 93
+ },
+
+ {
+ 11, -53, 53, 54, -53, -53, 55, -53, -53, -53,
+ -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
+ -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
+ -53, -53, -53, -53, -53, -53, -53, -53
+ },
+
+ {
+ 11, -54, -54, -54, -54, -54, -54, -54, -54, -54,
+ -54, -54, -54, -54, -54, -54, -54, -54, -54, -54,
+ -54, -54, -54, -54, -54, -54, -54, -54, -54, -54,
+ -54, -54, -54, -54, -54, -54, -54, -54
+
+ },
+
+ {
+ 11, 56, 56, 57, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56
+ },
+
+ {
+ 11, 56, 56, 57, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56
+ },
+
+ {
+ 11, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+
+ -57, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, -57, -57, -57, -57, -57, -57, -57
+ },
+
+ {
+ 11, -58, -58, -58, -58, -58, -58, -58, -58, -58,
+ -58, -58, -58, 58, -58, -58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -58
+ },
+
+ {
+ 11, -59, -59, -59, -59, -59, -59, -59, -59, -59,
+ -59, -59, -59, 58, -59, -59, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 94,
+ 58, 58, 58, 58, 58, 58, 58, -59
+
+ },
+
+ {
+ 11, -60, -60, -60, -60, -60, -60, -60, -60, -60,
+ -60, -60, -60, 58, -60, -60, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 95,
+ 58, 58, 58, 58, 58, 58, 58, -60
+ },
+
+ {
+ 11, -61, -61, -61, -61, -61, -61, -61, -61, -61,
+ -61, -61, -61, 58, -61, -61, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 96, 97, 58,
+ 58, 58, 58, 58, 58, 58, 58, -61
+ },
+
+ {
+ 11, -62, -62, -62, -62, -62, -62, -62, -62, -62,
+ -62, -62, -62, 58, -62, -62, 58, 58, 58, 58,
+
+ 58, 58, 98, 58, 58, 58, 58, 58, 58, 58,
+ 99, 58, 58, 58, 58, 58, 58, -62
+ },
+
+ {
+ 11, -63, -63, -63, -63, -63, -63, -63, -63, -63,
+ -63, -63, -63, 58, -63, -63, 58, 100, 58, 58,
+ 101, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -63
+ },
+
+ {
+ 11, -64, -64, -64, -64, -64, -64, -64, -64, -64,
+ -64, -64, -64, 58, -64, -64, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 102, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 103, -64
+
+ },
+
+ {
+ 11, -65, -65, -65, -65, -65, -65, -65, -65, -65,
+ -65, -65, -65, 58, -65, -65, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -65
+ },
+
+ {
+ 11, -66, -66, -66, -66, -66, -66, -66, -66, -66,
+ -66, -66, -66, 58, -66, -66, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 104, 58, 58, -66
+ },
+
+ {
+ 11, -67, -67, -67, -67, -67, -67, -67, -67, -67,
+ -67, -67, -67, 58, -67, -67, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 105, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -67
+ },
+
+ {
+ 11, -68, -68, -68, -68, -68, -68, -68, -68, -68,
+ -68, -68, -68, 58, -68, -68, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 106, 58,
+ 58, 58, 58, 58, 58, 58, 58, -68
+ },
+
+ {
+ 11, -69, -69, -69, -69, -69, -69, -69, -69, -69,
+ -69, -69, -69, 58, -69, -69, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 107, 58, 58, -69
+
+ },
+
+ {
+ 11, -70, -70, -70, -70, -70, -70, -70, -70, -70,
+ -70, -70, -70, 58, -70, -70, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 108,
+ 58, 58, 58, 58, 58, 58, 58, -70
+ },
+
+ {
+ 11, -71, -71, -71, -71, -71, -71, -71, -71, -71,
+ -71, -71, -71, 58, -71, -71, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 109, 58,
+ 58, 58, 58, 58, 58, 58, 58, -71
+ },
+
+ {
+ 11, -72, -72, -72, -72, -72, -72, -72, -72, -72,
+ -72, -72, -72, 58, -72, -72, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 110, 58, 58, 58, 58, 58, -72
+ },
+
+ {
+ 11, -73, -73, -73, -73, -73, -73, -73, -73, -73,
+ -73, -73, -73, 58, -73, -73, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 111, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -73
+ },
+
+ {
+ 11, -74, -74, -74, -74, -74, -74, -74, -74, -74,
+ -74, -74, -74, 58, -74, -74, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 112, 58, -74
+
+ },
+
+ {
+ 11, -75, -75, -75, -75, -75, -75, -75, -75, -75,
+ -75, -75, -75, 58, -75, -75, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 113, 58, 58, 58, 58, -75
+ },
+
+ {
+ 11, -76, -76, -76, -76, -76, -76, -76, -76, -76,
+ -76, -76, -76, 58, -76, -76, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 114, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -76
+ },
+
+ {
+ 11, 77, 77, -77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77
+ },
+
+ {
+ 11, -78, 78, 79, -78, -78, -78, -78, -78, -78,
+ -78, -78, -78, -78, -78, -78, -78, -78, -78, -78,
+ -78, -78, -78, -78, -78, -78, -78, -78, -78, -78,
+ -78, -78, -78, -78, -78, -78, -78, -78
+ },
+
+ {
+ 11, 80, -79, -79, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80
+
+ },
+
+ {
+ 11, -80, -80, -80, -80, -80, -80, -80, -80, -80,
+ -80, -80, -80, -80, -80, -80, -80, -80, -80, -80,
+ -80, -80, -80, -80, -80, -80, -80, -80, -80, -80,
+ -80, -80, -80, -80, -80, -80, -80, -80
+ },
+
+ {
+ 11, 81, 81, 82, 81, -81, 81, 81, -81, 81,
+ 81, 81, 81, 81, 81, -81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81
+ },
+
+ {
+ 11, -82, -82, -82, -82, -82, -82, -82, -82, -82,
+ -82, -82, -82, -82, -82, -82, -82, -82, -82, -82,
+
+ -82, -82, -82, -82, -82, -82, -82, -82, -82, -82,
+ -82, -82, -82, -82, -82, -82, -82, -82
+ },
+
+ {
+ 11, -83, -83, 84, -83, -83, -83, -83, -83, -83,
+ -83, -83, -83, -83, -83, -83, -83, -83, -83, -83,
+ -83, -83, -83, -83, -83, -83, -83, -83, -83, -83,
+ -83, -83, -83, -83, -83, -83, -83, -83
+ },
+
+ {
+ 11, -84, -84, -84, -84, -84, -84, -84, -84, -84,
+ -84, -84, -84, -84, -84, -84, -84, -84, -84, -84,
+ -84, -84, -84, -84, -84, -84, -84, -84, -84, -84,
+ -84, -84, -84, -84, -84, -84, -84, -84
+
+ },
+
+ {
+ 11, -85, -85, -85, -85, -85, -85, -85, -85, -85,
+ -85, -85, -85, -85, -85, -85, -85, -85, -85, -85,
+ -85, -85, -85, -85, -85, -85, -85, -85, -85, -85,
+ -85, -85, -85, -85, -85, -85, -85, -85
+ },
+
+ {
+ 11, 86, 86, -86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86
+ },
+
+ {
+ 11, -87, -87, -87, -87, -87, -87, -87, -87, -87,
+ -87, -87, -87, -87, -87, -87, -87, -87, -87, -87,
+
+ -87, -87, -87, -87, -87, -87, -87, -87, -87, -87,
+ -87, -87, -87, -87, -87, -87, -87, -87
+ },
+
+ {
+ 11, -88, -88, -88, -88, -88, -88, -88, -88, -88,
+ -88, 115, 89, 89, -88, -88, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, -88
+ },
+
+ {
+ 11, -89, -89, -89, -89, -89, -89, -89, -89, -89,
+ -89, 89, 89, 89, -89, -89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, -89
+
+ },
+
+ {
+ 11, -90, -90, -90, -90, -90, -90, -90, -90, -90,
+ -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,
+ -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,
+ -90, -90, -90, -90, -90, -90, -90, -90
+ },
+
+ {
+ 11, -91, -91, -91, -91, -91, -91, -91, -91, -91,
+ -91, 89, 89, 89, -91, -91, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, -91
+ },
+
+ {
+ 11, -92, -92, -92, -92, -92, -92, -92, -92, -92,
+ -92, 89, 89, 89, -92, -92, 89, 89, 89, 89,
+
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, -92
+ },
+
+ {
+ 11, -93, -93, -93, -93, -93, -93, -93, -93, -93,
+ -93, -93, -93, -93, -93, -93, -93, -93, -93, -93,
+ -93, -93, -93, -93, -93, -93, -93, -93, -93, -93,
+ -93, -93, -93, -93, -93, -93, -93, -93
+ },
+
+ {
+ 11, -94, -94, -94, -94, -94, -94, -94, -94, -94,
+ -94, -94, -94, 58, -94, -94, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 116, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -94
+
+ },
+
+ {
+ 11, -95, -95, -95, -95, -95, -95, -95, -95, -95,
+ -95, -95, -95, 58, -95, -95, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 117, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -95
+ },
+
+ {
+ 11, -96, -96, -96, -96, -96, -96, -96, -96, -96,
+ -96, -96, -96, 58, -96, -96, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 118, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -96
+ },
+
+ {
+ 11, -97, -97, -97, -97, -97, -97, -97, -97, -97,
+ -97, -97, -97, 58, -97, -97, 58, 58, 58, 58,
+
+ 58, 58, 119, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -97
+ },
+
+ {
+ 11, -98, -98, -98, -98, -98, -98, -98, -98, -98,
+ -98, -98, -98, 58, -98, -98, 120, 121, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -98
+ },
+
+ {
+ 11, -99, -99, -99, -99, -99, -99, -99, -99, -99,
+ -99, -99, -99, 58, -99, -99, 58, 58, 58, 58,
+ 58, 122, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -99
+
+ },
+
+ {
+ 11, -100, -100, -100, -100, -100, -100, -100, -100, -100,
+ -100, -100, -100, 58, -100, -100, 58, 58, 123, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -100
+ },
+
+ {
+ 11, -101, -101, -101, -101, -101, -101, -101, -101, -101,
+ -101, -101, -101, 58, -101, -101, 58, 58, 58, 124,
+ 58, 58, 58, 58, 58, 125, 58, 126, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -101
+ },
+
+ {
+ 11, -102, -102, -102, -102, -102, -102, -102, -102, -102,
+ -102, -102, -102, 58, -102, -102, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 127, 58, 58, 58, 58, 58, 58, -102
+ },
+
+ {
+ 11, -103, -103, -103, -103, -103, -103, -103, -103, -103,
+ -103, -103, -103, 58, -103, -103, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -103
+ },
+
+ {
+ 11, -104, -104, -104, -104, -104, -104, -104, -104, -104,
+ -104, -104, -104, 58, -104, -104, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -104
+
+ },
+
+ {
+ 11, -105, -105, -105, -105, -105, -105, -105, -105, -105,
+ -105, -105, -105, 58, -105, -105, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 128, 58,
+ 58, 58, 58, 58, 58, 58, 58, -105
+ },
+
+ {
+ 11, -106, -106, -106, -106, -106, -106, -106, -106, -106,
+ -106, -106, -106, 58, -106, -106, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 129, 58, -106
+ },
+
+ {
+ 11, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, 58, -107, -107, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 130, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -107
+ },
+
+ {
+ 11, -108, -108, -108, -108, -108, -108, -108, -108, -108,
+ -108, -108, -108, 58, -108, -108, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 131, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -108
+ },
+
+ {
+ 11, -109, -109, -109, -109, -109, -109, -109, -109, -109,
+ -109, -109, -109, 58, -109, -109, 58, 58, 58, 58,
+ 58, 58, 58, 132, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -109
+
+ },
+
+ {
+ 11, -110, -110, -110, -110, -110, -110, -110, -110, -110,
+ -110, -110, -110, 58, -110, -110, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 133, 58, -110
+ },
+
+ {
+ 11, -111, -111, -111, -111, -111, -111, -111, -111, -111,
+ -111, -111, -111, 58, -111, -111, 58, 58, 58, 58,
+ 58, 134, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -111
+ },
+
+ {
+ 11, -112, -112, -112, -112, -112, -112, -112, -112, -112,
+ -112, -112, -112, 58, -112, -112, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 135, 58, 58, 58, 58, -112
+ },
+
+ {
+ 11, -113, -113, -113, -113, -113, -113, -113, -113, -113,
+ -113, -113, -113, 58, -113, -113, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 136, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -113
+ },
+
+ {
+ 11, -114, -114, -114, -114, -114, -114, -114, -114, -114,
+ -114, -114, -114, 58, -114, -114, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 137, 58, 58, 58, -114
+
+ },
+
+ {
+ 11, -115, -115, -115, -115, -115, -115, -115, -115, -115,
+ -115, 89, 89, 89, -115, -115, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, -115
+ },
+
+ {
+ 11, -116, -116, -116, -116, -116, -116, -116, -116, -116,
+ -116, -116, -116, 58, -116, -116, 58, 58, 58, 58,
+ 58, 138, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -116
+ },
+
+ {
+ 11, -117, -117, -117, -117, -117, -117, -117, -117, -117,
+ -117, -117, -117, 58, -117, -117, 58, 58, 58, 139,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -117
+ },
+
+ {
+ 11, -118, -118, -118, -118, -118, -118, -118, -118, -118,
+ -118, -118, -118, 58, -118, -118, 58, 58, 58, 58,
+ 58, 140, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -118
+ },
+
+ {
+ 11, -119, -119, -119, -119, -119, -119, -119, -119, -119,
+ -119, -119, -119, 58, -119, -119, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 141, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -119
+
+ },
+
+ {
+ 11, -120, -120, -120, -120, -120, -120, -120, -120, -120,
+ -120, -120, -120, 58, -120, -120, 58, 58, 142, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 143, 58, 58, -120
+ },
+
+ {
+ 11, -121, -121, -121, -121, -121, -121, -121, -121, -121,
+ -121, -121, -121, 58, -121, -121, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 144, 58, -121
+ },
+
+ {
+ 11, -122, -122, -122, -122, -122, -122, -122, -122, -122,
+ -122, -122, -122, 58, -122, -122, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 145, 58,
+ 58, 58, 58, 58, 58, 58, 58, -122
+ },
+
+ {
+ 11, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, 58, -123, -123, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 146, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -123
+ },
+
+ {
+ 11, -124, -124, -124, -124, -124, -124, -124, -124, -124,
+ -124, -124, -124, 58, -124, -124, 58, 58, 58, 58,
+ 58, 58, 58, 58, 147, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -124
+
+ },
+
+ {
+ 11, -125, -125, -125, -125, -125, -125, -125, -125, -125,
+ -125, -125, -125, 58, -125, -125, 58, 58, 58, 58,
+ 58, 58, 148, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -125
+ },
+
+ {
+ 11, -126, -126, -126, -126, -126, -126, -126, -126, -126,
+ -126, -126, -126, 58, -126, -126, 58, 58, 58, 58,
+ 58, 149, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -126
+ },
+
+ {
+ 11, -127, -127, -127, -127, -127, -127, -127, -127, -127,
+ -127, -127, -127, 58, -127, -127, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -127
+ },
+
+ {
+ 11, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, 58, -128, -128, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 150, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -128
+ },
+
+ {
+ 11, -129, -129, -129, -129, -129, -129, -129, -129, -129,
+ -129, -129, -129, 58, -129, -129, 58, 58, 58, 151,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -129
+
+ },
+
+ {
+ 11, -130, -130, -130, -130, -130, -130, -130, -130, -130,
+ -130, -130, -130, 58, -130, -130, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 152,
+ 58, 58, 58, 58, 58, 58, 58, -130
+ },
+
+ {
+ 11, -131, -131, -131, -131, -131, -131, -131, -131, -131,
+ -131, -131, -131, 58, -131, -131, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 153, 58, 58, 58, 58, 58, 58, -131
+ },
+
+ {
+ 11, -132, -132, -132, -132, -132, -132, -132, -132, -132,
+ -132, -132, -132, 58, -132, -132, 58, 58, 58, 58,
+
+ 58, 154, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -132
+ },
+
+ {
+ 11, -133, -133, -133, -133, -133, -133, -133, -133, -133,
+ -133, -133, -133, 58, -133, -133, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 155, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -133
+ },
+
+ {
+ 11, -134, -134, -134, -134, -134, -134, -134, -134, -134,
+ -134, -134, -134, 58, -134, -134, 58, 58, 58, 156,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -134
+
+ },
+
+ {
+ 11, -135, -135, -135, -135, -135, -135, -135, -135, -135,
+ -135, -135, -135, 58, -135, -135, 58, 58, 58, 157,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -135
+ },
+
+ {
+ 11, -136, -136, -136, -136, -136, -136, -136, -136, -136,
+ -136, -136, -136, 58, -136, -136, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 158, 58,
+ 58, 58, 58, 58, 58, 58, 58, -136
+ },
+
+ {
+ 11, -137, -137, -137, -137, -137, -137, -137, -137, -137,
+ -137, -137, -137, 58, -137, -137, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 159, 58, 58, -137
+ },
+
+ {
+ 11, -138, -138, -138, -138, -138, -138, -138, -138, -138,
+ -138, -138, -138, 58, -138, -138, 58, 160, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -138
+ },
+
+ {
+ 11, -139, -139, -139, -139, -139, -139, -139, -139, -139,
+ -139, -139, -139, 58, -139, -139, 58, 58, 58, 58,
+ 58, 161, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -139
+
+ },
+
+ {
+ 11, -140, -140, -140, -140, -140, -140, -140, -140, -140,
+ -140, -140, -140, 58, -140, -140, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 162, 58,
+ 58, 58, 58, 58, 58, 58, 58, -140
+ },
+
+ {
+ 11, -141, -141, -141, -141, -141, -141, -141, -141, -141,
+ -141, -141, -141, 58, -141, -141, 58, 58, 58, 58,
+ 58, 58, 58, 163, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -141
+ },
+
+ {
+ 11, -142, -142, -142, -142, -142, -142, -142, -142, -142,
+ -142, -142, -142, 58, -142, -142, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 164,
+ 58, 58, 58, 58, 58, 58, 58, -142
+ },
+
+ {
+ 11, -143, -143, -143, -143, -143, -143, -143, -143, -143,
+ -143, -143, -143, 58, -143, -143, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 165, 58, 58, 58, 58, -143
+ },
+
+ {
+ 11, -144, -144, -144, -144, -144, -144, -144, -144, -144,
+ -144, -144, -144, 58, -144, -144, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 166, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -144
+
+ },
+
+ {
+ 11, -145, -145, -145, -145, -145, -145, -145, -145, -145,
+ -145, -145, -145, 58, -145, -145, 58, 58, 58, 58,
+ 167, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -145
+ },
+
+ {
+ 11, -146, -146, -146, -146, -146, -146, -146, -146, -146,
+ -146, -146, -146, 58, -146, -146, 58, 58, 58, 58,
+ 58, 168, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -146
+ },
+
+ {
+ 11, -147, -147, -147, -147, -147, -147, -147, -147, -147,
+ -147, -147, -147, 58, -147, -147, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 169,
+ 58, 58, 58, 58, 58, 58, 58, -147
+ },
+
+ {
+ 11, -148, -148, -148, -148, -148, -148, -148, -148, -148,
+ -148, -148, -148, 58, -148, -148, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -148
+ },
+
+ {
+ 11, -149, -149, -149, -149, -149, -149, -149, -149, -149,
+ -149, -149, -149, 58, -149, -149, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 170, 58,
+ 58, 58, 58, 58, 58, 58, 58, -149
+
+ },
+
+ {
+ 11, -150, -150, -150, -150, -150, -150, -150, -150, -150,
+ -150, -150, -150, 58, -150, -150, 58, 58, 58, 58,
+ 58, 171, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -150
+ },
+
+ {
+ 11, -151, -151, -151, -151, -151, -151, -151, -151, -151,
+ -151, -151, -151, 58, -151, -151, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 172,
+ 58, 58, 58, 58, 58, 58, 58, -151
+ },
+
+ {
+ 11, -152, -152, -152, -152, -152, -152, -152, -152, -152,
+ -152, -152, -152, 58, -152, -152, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 173, 58,
+ 58, 58, 58, 58, 58, 58, 58, -152
+ },
+
+ {
+ 11, -153, -153, -153, -153, -153, -153, -153, -153, -153,
+ -153, -153, -153, 58, -153, -153, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 174, 58, 58, -153
+ },
+
+ {
+ 11, -154, -154, -154, -154, -154, -154, -154, -154, -154,
+ -154, -154, -154, 58, -154, -154, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -154
+
+ },
+
+ {
+ 11, -155, -155, -155, -155, -155, -155, -155, -155, -155,
+ -155, -155, -155, 58, -155, -155, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 175, 58, 58, 58, 58, -155
+ },
+
+ {
+ 11, -156, -156, -156, -156, -156, -156, -156, -156, -156,
+ -156, -156, -156, 58, -156, -156, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 176, 58, 58, -156
+ },
+
+ {
+ 11, -157, -157, -157, -157, -157, -157, -157, -157, -157,
+ -157, -157, -157, 58, -157, -157, 58, 58, 58, 58,
+
+ 58, 177, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -157
+ },
+
+ {
+ 11, -158, -158, -158, -158, -158, -158, -158, -158, -158,
+ -158, -158, -158, 58, -158, -158, 58, 58, 58, 58,
+ 58, 58, 58, 178, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -158
+ },
+
+ {
+ 11, -159, -159, -159, -159, -159, -159, -159, -159, -159,
+ -159, -159, -159, 58, -159, -159, 58, 179, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -159
+
+ },
+
+ {
+ 11, -160, -160, -160, -160, -160, -160, -160, -160, -160,
+ -160, -160, -160, 58, -160, -160, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 180, 58,
+ 58, 58, 58, 58, 58, 58, 58, -160
+ },
+
+ {
+ 11, -161, -161, -161, -161, -161, -161, -161, -161, -161,
+ -161, -161, -161, 58, -161, -161, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -161
+ },
+
+ {
+ 11, -162, -162, -162, -162, -162, -162, -162, -162, -162,
+ -162, -162, -162, 58, -162, -162, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 181, 58, 58, -162
+ },
+
+ {
+ 11, -163, -163, -163, -163, -163, -163, -163, -163, -163,
+ -163, -163, -163, 58, -163, -163, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -163
+ },
+
+ {
+ 11, -164, -164, -164, -164, -164, -164, -164, -164, -164,
+ -164, -164, -164, 58, -164, -164, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 182,
+ 58, 58, 58, 58, 58, 58, 58, -164
+
+ },
+
+ {
+ 11, -165, -165, -165, -165, -165, -165, -165, -165, -165,
+ -165, -165, -165, 58, -165, -165, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 183, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -165
+ },
+
+ {
+ 11, -166, -166, -166, -166, -166, -166, -166, -166, -166,
+ -166, -166, -166, 58, -166, -166, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 184, 58, 58, -166
+ },
+
+ {
+ 11, -167, -167, -167, -167, -167, -167, -167, -167, -167,
+ -167, -167, -167, 58, -167, -167, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 185, 58, 58, 58, -167
+ },
+
+ {
+ 11, -168, -168, -168, -168, -168, -168, -168, -168, -168,
+ -168, -168, -168, 58, -168, -168, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -168
+ },
+
+ {
+ 11, -169, -169, -169, -169, -169, -169, -169, -169, -169,
+ -169, -169, -169, 58, -169, -169, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 186, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -169
+
+ },
+
+ {
+ 11, -170, -170, -170, -170, -170, -170, -170, -170, -170,
+ -170, -170, -170, 58, -170, -170, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 187, 58, -170
+ },
+
+ {
+ 11, -171, -171, -171, -171, -171, -171, -171, -171, -171,
+ -171, -171, -171, 58, -171, -171, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 188, 58,
+ 58, 58, 58, 58, 58, 58, 58, -171
+ },
+
+ {
+ 11, -172, -172, -172, -172, -172, -172, -172, -172, -172,
+ -172, -172, -172, 58, -172, -172, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 189, 58,
+ 58, 58, 58, 58, 58, 58, 58, -172
+ },
+
+ {
+ 11, -173, -173, -173, -173, -173, -173, -173, -173, -173,
+ -173, -173, -173, 58, -173, -173, 58, 190, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -173
+ },
+
+ {
+ 11, -174, -174, -174, -174, -174, -174, -174, -174, -174,
+ -174, -174, -174, 58, -174, -174, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -174
+
+ },
+
+ {
+ 11, -175, -175, -175, -175, -175, -175, -175, -175, -175,
+ -175, -175, -175, 58, -175, -175, 58, 58, 58, 58,
+ 58, 191, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -175
+ },
+
+ {
+ 11, -176, -176, -176, -176, -176, -176, -176, -176, -176,
+ -176, -176, -176, 58, -176, -176, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -176
+ },
+
+ {
+ 11, -177, -177, -177, -177, -177, -177, -177, -177, -177,
+ -177, -177, -177, 58, -177, -177, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -177
+ },
+
+ {
+ 11, -178, -178, -178, -178, -178, -178, -178, -178, -178,
+ -178, -178, -178, 58, -178, -178, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -178
+ },
+
+ {
+ 11, -179, -179, -179, -179, -179, -179, -179, -179, -179,
+ -179, -179, -179, 58, -179, -179, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 192, 58, 58, -179
+
+ },
+
+ {
+ 11, -180, -180, -180, -180, -180, -180, -180, -180, -180,
+ -180, -180, -180, 58, -180, -180, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -180
+ },
+
+ {
+ 11, -181, -181, -181, -181, -181, -181, -181, -181, -181,
+ -181, -181, -181, 58, -181, -181, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -181
+ },
+
+ {
+ 11, -182, -182, -182, -182, -182, -182, -182, -182, -182,
+ -182, -182, -182, 58, -182, -182, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 193, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -182
+ },
+
+ {
+ 11, -183, -183, -183, -183, -183, -183, -183, -183, -183,
+ -183, -183, -183, 58, -183, -183, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 194, 58, 58, 58, -183
+ },
+
+ {
+ 11, -184, -184, -184, -184, -184, -184, -184, -184, -184,
+ -184, -184, -184, 58, -184, -184, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -184
+
+ },
+
+ {
+ 11, -185, -185, -185, -185, -185, -185, -185, -185, -185,
+ -185, -185, -185, 58, -185, -185, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -185
+ },
+
+ {
+ 11, -186, -186, -186, -186, -186, -186, -186, -186, -186,
+ -186, -186, -186, 58, -186, -186, 58, 58, 58, 195,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -186
+ },
+
+ {
+ 11, -187, -187, -187, -187, -187, -187, -187, -187, -187,
+ -187, -187, -187, 58, -187, -187, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -187
+ },
+
+ {
+ 11, -188, -188, -188, -188, -188, -188, -188, -188, -188,
+ -188, -188, -188, 58, -188, -188, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 196, 58, -188
+ },
+
+ {
+ 11, -189, -189, -189, -189, -189, -189, -189, -189, -189,
+ -189, -189, -189, 58, -189, -189, 58, 58, 58, 58,
+ 58, 58, 197, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -189
+
+ },
+
+ {
+ 11, -190, -190, -190, -190, -190, -190, -190, -190, -190,
+ -190, -190, -190, 58, -190, -190, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 198, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -190
+ },
+
+ {
+ 11, -191, -191, -191, -191, -191, -191, -191, -191, -191,
+ -191, -191, -191, 58, -191, -191, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 199, 58, 58, 58, -191
+ },
+
+ {
+ 11, -192, -192, -192, -192, -192, -192, -192, -192, -192,
+ -192, -192, -192, 58, -192, -192, 58, 58, 58, 58,
+
+ 58, 200, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -192
+ },
+
+ {
+ 11, -193, -193, -193, -193, -193, -193, -193, -193, -193,
+ -193, -193, -193, 58, -193, -193, 58, 58, 58, 58,
+ 58, 201, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -193
+ },
+
+ {
+ 11, -194, -194, -194, -194, -194, -194, -194, -194, -194,
+ -194, -194, -194, 58, -194, -194, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 202, 58, 58, -194
+
+ },
+
+ {
+ 11, -195, -195, -195, -195, -195, -195, -195, -195, -195,
+ -195, -195, -195, 58, -195, -195, 58, 58, 58, 58,
+ 58, 203, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -195
+ },
+
+ {
+ 11, -196, -196, -196, -196, -196, -196, -196, -196, -196,
+ -196, -196, -196, 58, -196, -196, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -196
+ },
+
+ {
+ 11, -197, -197, -197, -197, -197, -197, -197, -197, -197,
+ -197, -197, -197, 58, -197, -197, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 204, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -197
+ },
+
+ {
+ 11, -198, -198, -198, -198, -198, -198, -198, -198, -198,
+ -198, -198, -198, 58, -198, -198, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -198
+ },
+
+ {
+ 11, -199, -199, -199, -199, -199, -199, -199, -199, -199,
+ -199, -199, -199, 58, -199, -199, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -199
+
+ },
+
+ {
+ 11, -200, -200, -200, -200, -200, -200, -200, -200, -200,
+ -200, -200, -200, 58, -200, -200, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -200
+ },
+
+ {
+ 11, -201, -201, -201, -201, -201, -201, -201, -201, -201,
+ -201, -201, -201, 58, -201, -201, 58, 205, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -201
+ },
+
+ {
+ 11, -202, -202, -202, -202, -202, -202, -202, -202, -202,
+ -202, -202, -202, 58, -202, -202, 58, 206, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -202
+ },
+
+ {
+ 11, -203, -203, -203, -203, -203, -203, -203, -203, -203,
+ -203, -203, -203, 58, -203, -203, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -203
+ },
+
+ {
+ 11, -204, -204, -204, -204, -204, -204, -204, -204, -204,
+ -204, -204, -204, 58, -204, -204, 58, 58, 58, 58,
+ 58, 58, 58, 207, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -204
+
+ },
+
+ {
+ 11, -205, -205, -205, -205, -205, -205, -205, -205, -205,
+ -205, -205, -205, 58, -205, -205, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 208, 58,
+ 58, 58, 58, 58, 58, 58, 58, -205
+ },
+
+ {
+ 11, -206, -206, -206, -206, -206, -206, -206, -206, -206,
+ -206, -206, -206, 58, -206, -206, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 209, 58, 58, -206
+ },
+
+ {
+ 11, -207, -207, -207, -207, -207, -207, -207, -207, -207,
+ -207, -207, -207, 58, -207, -207, 58, 58, 58, 58,
+
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -207
+ },
+
+ {
+ 11, -208, -208, -208, -208, -208, -208, -208, -208, -208,
+ -208, -208, -208, 58, -208, -208, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -208
+ },
+
+ {
+ 11, -209, -209, -209, -209, -209, -209, -209, -209, -209,
+ -209, -209, -209, 58, -209, -209, 58, 58, 58, 58,
+ 58, 210, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -209
+
+ },
+
+ {
+ 11, -210, -210, -210, -210, -210, -210, -210, -210, -210,
+ -210, -210, -210, 58, -210, -210, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, -210
+ },
+
+ } ;
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up zconftext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ zconfleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 64
+#define YY_END_OF_BUFFER 65
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[211] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 65, 5, 4, 3, 2, 36, 37, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 63, 60, 62, 55, 59, 58, 57, 53, 48, 42,
+ 47, 51, 53, 40, 41, 50, 50, 43, 53, 50,
+ 50, 53, 4, 3, 2, 2, 1, 35, 35, 35,
+ 35, 35, 35, 35, 16, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 63, 60, 62, 61,
+ 55, 54, 57, 56, 44, 51, 38, 50, 50, 52,
+ 45, 46, 39, 35, 35, 35, 35, 35, 35, 35,
+
+ 35, 35, 30, 29, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 49, 25, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 15, 35, 7, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 17, 35, 35,
+ 35, 35, 35, 34, 35, 35, 35, 35, 35, 35,
+ 10, 35, 13, 35, 35, 35, 35, 33, 35, 35,
+ 35, 35, 35, 22, 35, 32, 9, 31, 35, 26,
+ 12, 35, 35, 21, 18, 35, 8, 35, 35, 35,
+ 35, 35, 27, 35, 35, 6, 35, 20, 19, 23,
+
+ 35, 35, 11, 35, 35, 35, 14, 28, 35, 24
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 5, 6, 1, 1, 7, 8, 9,
+ 10, 1, 1, 1, 11, 12, 12, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 1, 1, 1,
+ 14, 1, 1, 1, 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,
+ 1, 15, 1, 1, 16, 1, 17, 18, 19, 20,
+
+ 21, 22, 23, 24, 25, 13, 13, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 13, 13, 36,
+ 13, 13, 1, 37, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+extern int zconf_flex_debug;
+int zconf_flex_debug = 0;
+
+/* 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 *zconftext;
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE 16
+
+char *text;
+static char *text_ptr;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static struct buffer *zconf_endfile(void);
+
+void new_string(void)
+{
+ text = malloc(START_STRSIZE);
+ text_asize = START_STRSIZE;
+ text_ptr = text;
+ text_size = 0;
+ *text_ptr = 0;
+}
+
+void append_string(const char *str, int size)
+{
+ int new_size = text_size + size + 1;
+ if (new_size > text_asize) {
+ text = realloc(text, new_size);
+ text_asize = new_size;
+ text_ptr = text + text_size;
+ }
+ memcpy(text_ptr, str, size);
+ text_ptr += size;
+ text_size += size;
+ *text_ptr = 0;
+}
+
+void alloc_string(const char *str, int size)
+{
+ text = malloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+
+#define INITIAL 0
+#define COMMAND 1
+#define HELP 2
+#define STRING 3
+#define PARAM 4
+
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int zconfwrap (void );
+#else
+extern int zconfwrap (void );
+#endif
+#endif
+
+ static void yyunput (int c,char *buf_ptr );
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#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( zconftext, zconfleng, 1, zconfout )
+#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) \
+ errno=0; \
+ while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(zconfin); \
+ }\
+\
+
+#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
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int zconflex (void);
+
+#define YY_DECL int zconflex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after zconftext and zconfleng
+ * 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
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+ int str = 0;
+ int ts, i;
+
+ if ( (yy_init) )
+ {
+ (yy_init) = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! zconfin )
+ zconfin = stdin;
+
+ if ( ! zconfout )
+ zconfout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ zconfensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ zconf_create_buffer(zconfin,YY_BUF_SIZE );
+ }
+
+ zconf_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of zconftext. */
+ *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:
+ while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 )
+ ++yy_cp;
+
+ yy_current_state = -yy_current_state;
+
+yy_find_action:
+ 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 1:
+/* rule 1 can match eol */
+YY_RULE_SETUP
+current_file->lineno++;
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+
+ YY_BREAK
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+current_file->lineno++; return T_EOL;
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+ BEGIN(COMMAND);
+}
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{
+ unput(zconftext[0]);
+ BEGIN(COMMAND);
+}
+ YY_BREAK
+
+case 6:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_MAINMENU;
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_MENU;
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_ENDMENU;
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_SOURCE;
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_CHOICE;
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_ENDCHOICE;
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_COMMENT;
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_CONFIG;
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_MENUCONFIG;
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_HELP;
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_IF;
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_ENDIF;
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_DEPENDS;
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_REQUIRES;
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_OPTIONAL;
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_DEFAULT;
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_PROMPT;
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_TRISTATE;
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_DEF_TRISTATE;
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_BOOLEAN;
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_BOOLEAN;
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_DEF_BOOLEAN;
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_DEF_BOOLEAN;
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_INT;
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_HEX;
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_STRING;
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_SELECT;
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_SELECT;
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+BEGIN(PARAM); return T_RANGE;
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+{
+ alloc_string(zconftext, zconfleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+
+ YY_BREAK
+case 37:
+/* rule 37 can match eol */
+YY_RULE_SETUP
+current_file->lineno++; BEGIN(INITIAL);
+ YY_BREAK
+
+case 38:
+YY_RULE_SETUP
+return T_AND;
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+return T_OR;
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+return T_OPEN_PAREN;
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+return T_CLOSE_PAREN;
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+return T_NOT;
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+return T_EQUAL;
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+return T_UNEQUAL;
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+return T_IF;
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+return T_ON;
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+{
+ str = zconftext[0];
+ new_string();
+ BEGIN(STRING);
+ }
+ YY_BREAK
+case 48:
+/* rule 48 can match eol */
+YY_RULE_SETUP
+BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+/* ignore */
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+{
+ alloc_string(zconftext, zconfleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+/* comment */
+ YY_BREAK
+case 52:
+/* rule 52 can match eol */
+YY_RULE_SETUP
+current_file->lineno++;
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+
+ YY_BREAK
+case YY_STATE_EOF(PARAM):
+{
+ BEGIN(INITIAL);
+ }
+ YY_BREAK
+
+case 54:
+/* rule 54 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+ append_string(zconftext, zconfleng);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+{
+ append_string(zconftext, zconfleng);
+ }
+ YY_BREAK
+case 56:
+/* rule 56 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+ append_string(zconftext + 1, zconfleng - 1);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+{
+ append_string(zconftext + 1, zconfleng - 1);
+ }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+{
+ if (str == zconftext[0]) {
+ BEGIN(PARAM);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(zconftext, 1);
+ }
+ YY_BREAK
+case 59:
+/* rule 59 can match eol */
+YY_RULE_SETUP
+{
+ printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+ current_file->lineno++;
+ BEGIN(INITIAL);
+ return T_EOL;
+ }
+ YY_BREAK
+case YY_STATE_EOF(STRING):
+{
+ BEGIN(INITIAL);
+ }
+ YY_BREAK
+
+case 60:
+YY_RULE_SETUP
+{
+ ts = 0;
+ for (i = 0; i < zconfleng; i++) {
+ if (zconftext[i] == '\t')
+ ts = (ts & ~7) + 8;
+ else
+ ts++;
+ }
+ last_ts = ts;
+ if (first_ts) {
+ if (ts < first_ts) {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ ts -= first_ts;
+ while (ts > 8) {
+ append_string(" ", 8);
+ ts -= 8;
+ }
+ append_string(" ", ts);
+ }
+ }
+ YY_BREAK
+case 61:
+/* rule 61 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+ current_file->lineno++;
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ YY_BREAK
+case 62:
+/* rule 62 can match eol */
+YY_RULE_SETUP
+{
+ current_file->lineno++;
+ append_string("\n", 1);
+ }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+{
+ append_string(zconftext, zconfleng);
+ if (!first_ts)
+ first_ts = last_ts;
+ }
+ YY_BREAK
+case YY_STATE_EOF(HELP):
+{
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ YY_BREAK
+
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMAND):
+{
+ if (current_buf) {
+ zconf_endfile();
+ return T_EOF;
+ }
+ fclose(zconfin);
+ yyterminate();
+}
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+
+ 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_LVALUE->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 zconfin at a new source and called
+ * zconflex(). 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_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin;
+ YY_CURRENT_BUFFER_LVALUE->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_LVALUE->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 ( zconfwrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * zconftext, 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_LVALUE->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 zconflex */
+
+/* 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 (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->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_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->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_LVALUE->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_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* 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. */
+ zconfrealloc((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_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->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;
+ zconfrestart(zconfin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->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 (void)
+{
+ 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 )
+ {
+ yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
+ }
+
+ 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 );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+
+ yy_current_state = yy_nxt[yy_current_state][1];
+ yy_is_jam = (yy_current_state <= 0);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ static void yyunput (int c, register char * yy_bp )
+{
+ register char *yy_cp;
+
+ yy_cp = (yy_c_buf_p);
+
+ /* undo effects of setting up zconftext */
+ *yy_cp = (yy_hold_char);
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->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_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->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;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#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_LVALUE->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. */
+ zconfrestart(zconfin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( zconfwrap( ) )
+ 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 zconftext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void zconfrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ zconfensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ zconf_create_buffer(zconfin,YY_BUF_SIZE );
+ }
+
+ zconf_init_buffer(YY_CURRENT_BUFFER,input_file );
+ zconf_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * zconfpop_buffer_state();
+ * zconfpush_buffer_state(new_buffer);
+ */
+ zconfensure_buffer_stack ();
+ 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_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ zconf_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (zconfwrap()) processing, but the only time this flag
+ * is looked at is after zconfwrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void zconf_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE zconf_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_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 *) zconfalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ zconf_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with zconf_create_buffer()
+ *
+ */
+ void zconf_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ zconffree((void *) b->yy_ch_buf );
+
+ zconffree((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a zconfrestart() or at EOF.
+ */
+ static void zconf_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ zconf_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then zconf_init_buffer was _probably_
+ * called from zconfrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void zconf_flush_buffer (YY_BUFFER_STATE b )
+{
+ 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 )
+ zconf_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ zconfensure_buffer_stack();
+
+ /* This block is copied from zconf_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from zconf_switch_to_buffer. */
+ zconf_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void zconfpop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ zconf_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ zconf_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void zconfensure_buffer_stack (void)
+{
+ int num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size )
+{
+ 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) zconfalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_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;
+
+ zconf_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to zconflex() will
+ * scan from a @e copy of @a str.
+ * @param str a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * zconf_scan_bytes() instead.
+ */
+YY_BUFFER_STATE zconf_scan_string (yyconst char * str )
+{
+
+ return zconf_scan_bytes(str,strlen(str) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char * bytes, int len )
+{
+ 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 *) zconfalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = zconf_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in zconf_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;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (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 zconftext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ zconftext[zconfleng] = (yy_hold_char); \
+ (yy_c_buf_p) = zconftext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ zconfleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int zconfget_lineno (void)
+{
+
+ return zconflineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *zconfget_in (void)
+{
+ return zconfin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *zconfget_out (void)
+{
+ return zconfout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int zconfget_leng (void)
+{
+ return zconfleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *zconfget_text (void)
+{
+ return zconftext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void zconfset_lineno (int line_number )
+{
+
+ zconflineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see zconf_switch_to_buffer
+ */
+void zconfset_in (FILE * in_str )
+{
+ zconfin = in_str ;
+}
+
+void zconfset_out (FILE * out_str )
+{
+ zconfout = out_str ;
+}
+
+int zconfget_debug (void)
+{
+ return zconf_flex_debug;
+}
+
+void zconfset_debug (int bdebug )
+{
+ zconf_flex_debug = bdebug ;
+}
+
+/* zconflex_destroy is for both reentrant and non-reentrant scanners. */
+int zconflex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ zconf_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ zconfpop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ zconffree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *zconfalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *zconfrealloc (void * ptr, yy_size_t size )
+{
+ /* 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 );
+}
+
+void zconffree (void * ptr )
+{
+ free( (char *) ptr ); /* see zconfrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef yytext_ptr
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+void zconf_starthelp(void)
+{
+ new_string();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ zconflval.string = text;
+ BEGIN(INITIAL);
+}
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+ char *env, fullname[PATH_MAX+1];
+ FILE *f;
+
+ f = fopen(name, "r");
+ if (!f && name[0] != '/') {
+ env = getenv(SRCTREE);
+ if (env) {
+ sprintf(fullname, "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ zconfin = zconf_fopen(name);
+ if (!zconfin) {
+ printf("can't find file %s\n", name);
+ exit(1);
+ }
+
+ current_buf = malloc(sizeof(*current_buf));
+ memset(current_buf, 0, sizeof(*current_buf));
+
+ current_file = file_lookup(name);
+ current_file->lineno = 1;
+ current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct file *file = file_lookup(name);
+ struct buffer *buf = malloc(sizeof(*buf));
+ memset(buf, 0, sizeof(*buf));
+
+ current_buf->state = YY_CURRENT_BUFFER;
+ zconfin = zconf_fopen(name);
+ if (!zconfin) {
+ printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
+ exit(1);
+ }
+ zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
+ buf->parent = current_buf;
+ current_buf = buf;
+
+ if (file->flags & FILE_BUSY) {
+ printf("recursive scan (%s)?\n", name);
+ exit(1);
+ }
+ if (file->flags & FILE_SCANNED) {
+ printf("file %s already scanned?\n", name);
+ exit(1);
+ }
+ file->flags |= FILE_BUSY;
+ file->lineno = 1;
+ file->parent = current_file;
+ current_file = file;
+}
+
+static struct buffer *zconf_endfile(void)
+{
+ struct buffer *parent;
+
+ current_file->flags |= FILE_SCANNED;
+ current_file->flags &= ~FILE_BUSY;
+ current_file = current_file->parent;
+
+ parent = current_buf->parent;
+ if (parent) {
+ fclose(zconfin);
+ zconf_delete_buffer(YY_CURRENT_BUFFER);
+ zconf_switch_to_buffer(parent->state);
+ }
+ free(current_buf);
+ current_buf = parent;
+
+ return parent;
+}
+
+int zconf_lineno(void)
+{
+ if (current_buf)
+ return current_file->lineno - 1;
+ else
+ return 0;
+}
+
+char *zconf_curname(void)
+{
+ if (current_buf)
+ return current_file->name;
+ else
+ return "<none>";
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef LKC_H
+#define LKC_H
+
+#include "expr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef LKC_DIRECT_LINK
+#define P(name,type,arg) extern type name arg
+#else
+#include "lkc_defs.h"
+#define P(name,type,arg) extern type (*name ## _p) arg
+#endif
+#include "lkc_proto.h"
+#undef P
+
+#define SRCTREE "srctree"
+
+int zconfparse(void);
+void zconfdump(FILE *out);
+
+extern int zconfdebug;
+void zconf_starthelp(void);
+FILE *zconf_fopen(const char *name);
+void zconf_initscan(const char *name);
+void zconf_nextfile(const char *name);
+int zconf_lineno(void);
+char *zconf_curname(void);
+
+/* confdata.c */
+extern const char conf_def_filename[];
+extern char conf_filename[];
+
+char *conf_get_default_confname(void);
+
+/* kconfig_load.c */
+void kconfig_load(void);
+
+/* menu.c */
+void menu_init(void);
+void menu_add_menu(void);
+void menu_end_menu(void);
+void menu_add_entry(struct symbol *sym);
+void menu_end_entry(void);
+void menu_add_dep(struct expr *dep);
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
+void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_finalize(struct menu *parent);
+void menu_set_type(int type);
+
+/* util.c */
+struct file *file_lookup(const char *name);
+int file_write_dep(const char *name);
+
+struct gstr {
+ size_t len;
+ char *s;
+};
+struct gstr str_new(void);
+struct gstr str_assign(const char *s);
+void str_free(struct gstr *gs);
+void str_append(struct gstr *gs, const char *s);
+void str_printf(struct gstr *gs, const char *fmt, ...);
+const char *str_get(struct gstr *gs);
+
+/* symbol.c */
+void sym_init(void);
+void sym_clear_all_valid(void);
+void sym_set_changed(struct symbol *sym);
+struct symbol *sym_check_deps(struct symbol *sym);
+struct property *prop_alloc(enum prop_type type, struct symbol *sym);
+struct symbol *prop_get_symbol(struct property *prop);
+
+static inline tristate sym_get_tristate_value(struct symbol *sym)
+{
+ return sym->curr.tri;
+}
+
+
+static inline struct symbol *sym_get_choice_value(struct symbol *sym)
+{
+ return (struct symbol *)sym->curr.val;
+}
+
+static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
+{
+ return sym_set_tristate_value(chval, yes);
+}
+
+static inline bool sym_is_choice(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_CHOICE ? true : false;
+}
+
+static inline bool sym_is_choice_value(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_CHOICEVAL ? true : false;
+}
+
+static inline bool sym_is_optional(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_OPTIONAL ? true : false;
+}
+
+static inline bool sym_has_value(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_NEW ? false : true;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LKC_H */
--- /dev/null
+
+/* confdata.c */
+P(conf_parse,void,(const char *name));
+P(conf_read,int,(const char *name));
+P(conf_write,int,(const char *name));
+
+/* menu.c */
+P(rootmenu,struct menu,);
+
+P(menu_is_visible,bool,(struct menu *menu));
+P(menu_get_prompt,const char *,(struct menu *menu));
+P(menu_get_root_menu,struct menu *,(struct menu *menu));
+P(menu_get_parent_menu,struct menu *,(struct menu *menu));
+
+/* symbol.c */
+P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
+P(sym_change_count,int,);
+
+P(sym_lookup,struct symbol *,(const char *name, int isconst));
+P(sym_find,struct symbol *,(const char *name));
+P(sym_re_search,struct symbol **,(const char *pattern));
+P(sym_type_name,const char *,(enum symbol_type type));
+P(sym_calc_value,void,(struct symbol *sym));
+P(sym_get_type,enum symbol_type,(struct symbol *sym));
+P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
+P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
+P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
+P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
+P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
+P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
+P(sym_is_changable,bool,(struct symbol *sym));
+P(sym_get_choice_prop,struct property *,(struct symbol *sym));
+P(sym_get_default_prop,struct property *,(struct symbol *sym));
+P(sym_get_string_value,const char *,(struct symbol *sym));
+
+P(prop_get_type_name,const char *,(enum prop_type type));
+
+/* expr.c */
+P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2));
+P(expr_print,void,(struct expr *e, void (*fn)(void *, const char *), void *data, int prevtoken));
--- /dev/null
+This is NOT the official version of dialog. This version has been
+significantly modified from the original. It is for use by the Linux
+kernel configuration script. Please do not bother Savio Lam with
+questions about this program.
--- /dev/null
+/*
+ * checklist.c -- implements the checklist box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
+ * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static int list_width, check_x, item_x, checkflag;
+
+/*
+ * Print list item
+ */
+static void
+print_item (WINDOW * win, const char *item, int status,
+ int choice, int selected)
+{
+ int i;
+
+ /* Clear 'residue' of last item */
+ wattrset (win, menubox_attr);
+ wmove (win, choice, 0);
+ for (i = 0; i < list_width; i++)
+ waddch (win, ' ');
+
+ wmove (win, choice, check_x);
+ wattrset (win, selected ? check_selected_attr : check_attr);
+ if (checkflag == FLAG_CHECK)
+ wprintw (win, "[%c]", status ? 'X' : ' ');
+ else
+ wprintw (win, "(%c)", status ? 'X' : ' ');
+
+ wattrset (win, selected ? tag_selected_attr : tag_attr);
+ mvwaddch(win, choice, item_x, item[0]);
+ wattrset (win, selected ? item_selected_attr : item_attr);
+ waddstr (win, (char *)item+1);
+ if (selected) {
+ wmove (win, choice, check_x+1);
+ wrefresh (win);
+ }
+}
+
+/*
+ * Print the scroll indicators.
+ */
+static void
+print_arrows (WINDOW * win, int choice, int item_no, int scroll,
+ int y, int x, int height)
+{
+ wmove(win, y, x);
+
+ if (scroll > 0) {
+ wattrset (win, uarrow_attr);
+ waddch (win, ACS_UARROW);
+ waddstr (win, "(-)");
+ }
+ else {
+ wattrset (win, menubox_attr);
+ waddch (win, ACS_HLINE);
+ waddch (win, ACS_HLINE);
+ waddch (win, ACS_HLINE);
+ waddch (win, ACS_HLINE);
+ }
+
+ y = y + height + 1;
+ wmove(win, y, x);
+
+ if ((height < item_no) && (scroll + choice < item_no - 1)) {
+ wattrset (win, darrow_attr);
+ waddch (win, ACS_DARROW);
+ waddstr (win, "(+)");
+ }
+ else {
+ wattrset (win, menubox_border_attr);
+ waddch (win, ACS_HLINE);
+ waddch (win, ACS_HLINE);
+ waddch (win, ACS_HLINE);
+ waddch (win, ACS_HLINE);
+ }
+}
+
+/*
+ * Display the termination buttons
+ */
+static void
+print_buttons( WINDOW *dialog, int height, int width, int selected)
+{
+ int x = width / 2 - 11;
+ int y = height - 2;
+
+ print_button (dialog, "Select", y, x, selected == 0);
+ print_button (dialog, " Help ", y, x + 14, selected == 1);
+
+ wmove(dialog, y, x+1 + 14*selected);
+ wrefresh (dialog);
+}
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ * The `flag' parameter is used to select between radiolist and checklist.
+ */
+int
+dialog_checklist (const char *title, const char *prompt, int height, int width,
+ int list_height, int item_no, struct dialog_list_item ** items,
+ int flag)
+
+{
+ int i, x, y, box_x, box_y;
+ int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status;
+ WINDOW *dialog, *list;
+
+ checkflag = flag;
+
+ /* Allocate space for storing item on/off status */
+ if ((status = malloc (sizeof (int) * item_no)) == NULL) {
+ endwin ();
+ fprintf (stderr,
+ "\nCan't allocate memory in dialog_checklist().\n");
+ exit (-1);
+ }
+
+ /* Initializes status */
+ for (i = 0; i < item_no; i++) {
+ status[i] = (items[i]->selected == 1); /* ON */
+ if ((!choice && status[i]) || items[i]->selected == 2) /* SELECTED */
+ choice = i + 1;
+ }
+ if (choice)
+ choice--;
+
+ max_choice = MIN (list_height, item_no);
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - height) / 2;
+
+ draw_shadow (stdscr, y, x, height, width);
+
+ dialog = newwin (height, width, y, x);
+ keypad (dialog, TRUE);
+
+ draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
+ wattrset (dialog, border_attr);
+ mvwaddch (dialog, height-3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch (dialog, ACS_HLINE);
+ wattrset (dialog, dialog_attr);
+ waddch (dialog, ACS_RTEE);
+
+ if (title != NULL && strlen(title) >= width-2 ) {
+ /* truncate long title -- mec */
+ char * title2 = malloc(width-2+1);
+ memcpy( title2, title, width-2 );
+ title2[width-2] = '\0';
+ title = title2;
+ }
+
+ if (title != NULL) {
+ wattrset (dialog, title_attr);
+ mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
+ waddstr (dialog, (char *)title);
+ waddch (dialog, ' ');
+ }
+
+ wattrset (dialog, dialog_attr);
+ print_autowrap (dialog, prompt, width - 2, 1, 3);
+
+ list_width = width - 6;
+ box_y = height - list_height - 5;
+ box_x = (width - list_width) / 2 - 1;
+
+ /* create new window for the list */
+ list = subwin (dialog, list_height, list_width, y+box_y+1, x+box_x+1);
+
+ keypad (list, TRUE);
+
+ /* draw a box around the list items */
+ draw_box (dialog, box_y, box_x, list_height + 2, list_width + 2,
+ menubox_border_attr, menubox_attr);
+
+ /* Find length of longest item in order to center checklist */
+ check_x = 0;
+ for (i = 0; i < item_no; i++)
+ check_x = MAX (check_x, + strlen (items[i]->name) + 4);
+
+ check_x = (list_width - check_x) / 2;
+ item_x = check_x + 4;
+
+ if (choice >= list_height) {
+ scroll = choice - list_height + 1;
+ choice -= scroll;
+ }
+
+ /* Print the list */
+ for (i = 0; i < max_choice; i++) {
+ print_item (list, items[scroll + i]->name,
+ status[i+scroll], i, i == choice);
+ }
+
+ print_arrows(dialog, choice, item_no, scroll,
+ box_y, box_x + check_x + 5, list_height);
+
+ print_buttons(dialog, height, width, 0);
+
+ wnoutrefresh (list);
+ wnoutrefresh (dialog);
+ doupdate ();
+
+ while (key != ESC) {
+ key = wgetch (dialog);
+
+ for (i = 0; i < max_choice; i++)
+ if (toupper(key) == toupper(items[scroll + i]->name[0]))
+ break;
+
+
+ if ( i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+ key == '+' || key == '-' ) {
+ if (key == KEY_UP || key == '-') {
+ if (!choice) {
+ if (!scroll)
+ continue;
+ /* Scroll list down */
+ if (list_height > 1) {
+ /* De-highlight current first item */
+ print_item (list, items[scroll]->name,
+ status[scroll], 0, FALSE);
+ scrollok (list, TRUE);
+ wscrl (list, -1);
+ scrollok (list, FALSE);
+ }
+ scroll--;
+ print_item (list, items[scroll]->name,
+ status[scroll], 0, TRUE);
+ wnoutrefresh (list);
+
+ print_arrows(dialog, choice, item_no, scroll,
+ box_y, box_x + check_x + 5, list_height);
+
+ wrefresh (dialog);
+
+ continue; /* wait for another key press */
+ } else
+ i = choice - 1;
+ } else if (key == KEY_DOWN || key == '+') {
+ if (choice == max_choice - 1) {
+ if (scroll + choice >= item_no - 1)
+ continue;
+ /* Scroll list up */
+ if (list_height > 1) {
+ /* De-highlight current last item before scrolling up */
+ print_item (list, items[scroll + max_choice - 1]->name,
+ status[scroll + max_choice - 1],
+ max_choice - 1, FALSE);
+ scrollok (list, TRUE);
+ scroll (list);
+ scrollok (list, FALSE);
+ }
+ scroll++;
+ print_item (list, items[scroll + max_choice - 1]->name,
+ status[scroll + max_choice - 1],
+ max_choice - 1, TRUE);
+ wnoutrefresh (list);
+
+ print_arrows(dialog, choice, item_no, scroll,
+ box_y, box_x + check_x + 5, list_height);
+
+ wrefresh (dialog);
+
+ continue; /* wait for another key press */
+ } else
+ i = choice + 1;
+ }
+ if (i != choice) {
+ /* De-highlight current item */
+ print_item (list, items[scroll + choice]->name,
+ status[scroll + choice], choice, FALSE);
+ /* Highlight new item */
+ choice = i;
+ print_item (list, items[scroll + choice]->name,
+ status[scroll + choice], choice, TRUE);
+ wnoutrefresh (list);
+ wrefresh (dialog);
+ }
+ continue; /* wait for another key press */
+ }
+ switch (key) {
+ case 'H':
+ case 'h':
+ case '?':
+ for (i = 0; i < item_no; i++)
+ items[i]->selected = 0;
+ items[scroll + choice]->selected = 1;
+ delwin (dialog);
+ free (status);
+ return 1;
+ case TAB:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ button = ((key == KEY_LEFT ? --button : ++button) < 0)
+ ? 1 : (button > 1 ? 0 : button);
+
+ print_buttons(dialog, height, width, button);
+ wrefresh (dialog);
+ break;
+ case 'S':
+ case 's':
+ case ' ':
+ case '\n':
+ if (!button) {
+ if (flag == FLAG_CHECK) {
+ status[scroll + choice] = !status[scroll + choice];
+ wmove (list, choice, check_x);
+ wattrset (list, check_selected_attr);
+ wprintw (list, "[%c]", status[scroll + choice] ? 'X' : ' ');
+ } else {
+ if (!status[scroll + choice]) {
+ for (i = 0; i < item_no; i++)
+ status[i] = 0;
+ status[scroll + choice] = 1;
+ for (i = 0; i < max_choice; i++)
+ print_item (list, items[scroll + i]->name,
+ status[scroll + i], i, i == choice);
+ }
+ }
+ wnoutrefresh (list);
+ wrefresh (dialog);
+
+ for (i = 0; i < item_no; i++) {
+ items[i]->selected = status[i];
+ }
+ } else {
+ for (i = 0; i < item_no; i++)
+ items[i]->selected = 0;
+ items[scroll + choice]->selected = 1;
+ }
+ delwin (dialog);
+ free (status);
+ return button;
+ case 'X':
+ case 'x':
+ key = ESC;
+ case ESC:
+ break;
+ }
+
+ /* Now, update everything... */
+ doupdate ();
+ }
+
+
+ delwin (dialog);
+ free (status);
+ return -1; /* ESC pressed */
+}
--- /dev/null
+/*
+ * colors.h -- color attribute definitions
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * Default color definitions
+ *
+ * *_FG = foreground
+ * *_BG = background
+ * *_HL = highlight?
+ */
+#define SCREEN_FG COLOR_CYAN
+#define SCREEN_BG COLOR_BLUE
+#define SCREEN_HL TRUE
+
+#define SHADOW_FG COLOR_BLACK
+#define SHADOW_BG COLOR_BLACK
+#define SHADOW_HL TRUE
+
+#define DIALOG_FG COLOR_BLACK
+#define DIALOG_BG COLOR_WHITE
+#define DIALOG_HL FALSE
+
+#define TITLE_FG COLOR_YELLOW
+#define TITLE_BG COLOR_WHITE
+#define TITLE_HL TRUE
+
+#define BORDER_FG COLOR_WHITE
+#define BORDER_BG COLOR_WHITE
+#define BORDER_HL TRUE
+
+#define BUTTON_ACTIVE_FG COLOR_WHITE
+#define BUTTON_ACTIVE_BG COLOR_BLUE
+#define BUTTON_ACTIVE_HL TRUE
+
+#define BUTTON_INACTIVE_FG COLOR_BLACK
+#define BUTTON_INACTIVE_BG COLOR_WHITE
+#define BUTTON_INACTIVE_HL FALSE
+
+#define BUTTON_KEY_ACTIVE_FG COLOR_WHITE
+#define BUTTON_KEY_ACTIVE_BG COLOR_BLUE
+#define BUTTON_KEY_ACTIVE_HL TRUE
+
+#define BUTTON_KEY_INACTIVE_FG COLOR_RED
+#define BUTTON_KEY_INACTIVE_BG COLOR_WHITE
+#define BUTTON_KEY_INACTIVE_HL FALSE
+
+#define BUTTON_LABEL_ACTIVE_FG COLOR_YELLOW
+#define BUTTON_LABEL_ACTIVE_BG COLOR_BLUE
+#define BUTTON_LABEL_ACTIVE_HL TRUE
+
+#define BUTTON_LABEL_INACTIVE_FG COLOR_BLACK
+#define BUTTON_LABEL_INACTIVE_BG COLOR_WHITE
+#define BUTTON_LABEL_INACTIVE_HL TRUE
+
+#define INPUTBOX_FG COLOR_BLACK
+#define INPUTBOX_BG COLOR_WHITE
+#define INPUTBOX_HL FALSE
+
+#define INPUTBOX_BORDER_FG COLOR_BLACK
+#define INPUTBOX_BORDER_BG COLOR_WHITE
+#define INPUTBOX_BORDER_HL FALSE
+
+#define SEARCHBOX_FG COLOR_BLACK
+#define SEARCHBOX_BG COLOR_WHITE
+#define SEARCHBOX_HL FALSE
+
+#define SEARCHBOX_TITLE_FG COLOR_YELLOW
+#define SEARCHBOX_TITLE_BG COLOR_WHITE
+#define SEARCHBOX_TITLE_HL TRUE
+
+#define SEARCHBOX_BORDER_FG COLOR_WHITE
+#define SEARCHBOX_BORDER_BG COLOR_WHITE
+#define SEARCHBOX_BORDER_HL TRUE
+
+#define POSITION_INDICATOR_FG COLOR_YELLOW
+#define POSITION_INDICATOR_BG COLOR_WHITE
+#define POSITION_INDICATOR_HL TRUE
+
+#define MENUBOX_FG COLOR_BLACK
+#define MENUBOX_BG COLOR_WHITE
+#define MENUBOX_HL FALSE
+
+#define MENUBOX_BORDER_FG COLOR_WHITE
+#define MENUBOX_BORDER_BG COLOR_WHITE
+#define MENUBOX_BORDER_HL TRUE
+
+#define ITEM_FG COLOR_BLACK
+#define ITEM_BG COLOR_WHITE
+#define ITEM_HL FALSE
+
+#define ITEM_SELECTED_FG COLOR_WHITE
+#define ITEM_SELECTED_BG COLOR_BLUE
+#define ITEM_SELECTED_HL TRUE
+
+#define TAG_FG COLOR_YELLOW
+#define TAG_BG COLOR_WHITE
+#define TAG_HL TRUE
+
+#define TAG_SELECTED_FG COLOR_YELLOW
+#define TAG_SELECTED_BG COLOR_BLUE
+#define TAG_SELECTED_HL TRUE
+
+#define TAG_KEY_FG COLOR_YELLOW
+#define TAG_KEY_BG COLOR_WHITE
+#define TAG_KEY_HL TRUE
+
+#define TAG_KEY_SELECTED_FG COLOR_YELLOW
+#define TAG_KEY_SELECTED_BG COLOR_BLUE
+#define TAG_KEY_SELECTED_HL TRUE
+
+#define CHECK_FG COLOR_BLACK
+#define CHECK_BG COLOR_WHITE
+#define CHECK_HL FALSE
+
+#define CHECK_SELECTED_FG COLOR_WHITE
+#define CHECK_SELECTED_BG COLOR_BLUE
+#define CHECK_SELECTED_HL TRUE
+
+#define UARROW_FG COLOR_GREEN
+#define UARROW_BG COLOR_WHITE
+#define UARROW_HL TRUE
+
+#define DARROW_FG COLOR_GREEN
+#define DARROW_BG COLOR_WHITE
+#define DARROW_HL TRUE
+
+/* End of default color definitions */
+
+#define C_ATTR(x,y) ((x ? A_BOLD : 0) | COLOR_PAIR((y)))
+#define COLOR_NAME_LEN 10
+#define COLOR_COUNT 8
+
+/*
+ * Global variables
+ */
+
+typedef struct {
+ char name[COLOR_NAME_LEN];
+ int value;
+} color_names_st;
+
+extern color_names_st color_names[];
+extern int color_table[][3];
--- /dev/null
+
+/*
+ * dialog.h -- common declarations for all dialog modules
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef CURSES_LOC
+#ifdef __sun__
+#define CURS_MACROS
+#endif
+#include CURSES_LOC
+
+/*
+ * Colors in ncurses 1.9.9e do not work properly since foreground and
+ * background colors are OR'd rather than separately masked. This version
+ * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
+ * with standard curses. The simplest fix (to make this work with standard
+ * curses) uses the wbkgdset() function, not used in the original hack.
+ * Turn it off if we're building with 1.9.9e, since it just confuses things.
+ */
+#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
+#define OLD_NCURSES 1
+#undef wbkgdset
+#define wbkgdset(w,p) /*nothing*/
+#else
+#define OLD_NCURSES 0
+#endif
+
+#define TR(params) _tracef params
+
+#define ESC 27
+#define TAB 9
+#define MAX_LEN 2048
+#define BUF_SIZE (10*1024)
+#define MIN(x,y) (x < y ? x : y)
+#define MAX(x,y) (x > y ? x : y)
+
+
+#ifndef ACS_ULCORNER
+#define ACS_ULCORNER '+'
+#endif
+#ifndef ACS_LLCORNER
+#define ACS_LLCORNER '+'
+#endif
+#ifndef ACS_URCORNER
+#define ACS_URCORNER '+'
+#endif
+#ifndef ACS_LRCORNER
+#define ACS_LRCORNER '+'
+#endif
+#ifndef ACS_HLINE
+#define ACS_HLINE '-'
+#endif
+#ifndef ACS_VLINE
+#define ACS_VLINE '|'
+#endif
+#ifndef ACS_LTEE
+#define ACS_LTEE '+'
+#endif
+#ifndef ACS_RTEE
+#define ACS_RTEE '+'
+#endif
+#ifndef ACS_UARROW
+#define ACS_UARROW '^'
+#endif
+#ifndef ACS_DARROW
+#define ACS_DARROW 'v'
+#endif
+
+/*
+ * Attribute names
+ */
+#define screen_attr attributes[0]
+#define shadow_attr attributes[1]
+#define dialog_attr attributes[2]
+#define title_attr attributes[3]
+#define border_attr attributes[4]
+#define button_active_attr attributes[5]
+#define button_inactive_attr attributes[6]
+#define button_key_active_attr attributes[7]
+#define button_key_inactive_attr attributes[8]
+#define button_label_active_attr attributes[9]
+#define button_label_inactive_attr attributes[10]
+#define inputbox_attr attributes[11]
+#define inputbox_border_attr attributes[12]
+#define searchbox_attr attributes[13]
+#define searchbox_title_attr attributes[14]
+#define searchbox_border_attr attributes[15]
+#define position_indicator_attr attributes[16]
+#define menubox_attr attributes[17]
+#define menubox_border_attr attributes[18]
+#define item_attr attributes[19]
+#define item_selected_attr attributes[20]
+#define tag_attr attributes[21]
+#define tag_selected_attr attributes[22]
+#define tag_key_attr attributes[23]
+#define tag_key_selected_attr attributes[24]
+#define check_attr attributes[25]
+#define check_selected_attr attributes[26]
+#define uarrow_attr attributes[27]
+#define darrow_attr attributes[28]
+
+/* number of attributes */
+#define ATTRIBUTE_COUNT 29
+
+/*
+ * Global variables
+ */
+extern bool use_colors;
+
+extern chtype attributes[];
+#endif
+
+extern const char *backtitle;
+
+struct dialog_list_item {
+ char *name;
+ int namelen;
+ char *tag;
+ int selected; /* Set to 1 by dialog_*() function. */
+};
+
+/*
+ * Function prototypes
+ */
+
+void init_dialog (void);
+void end_dialog (void);
+void dialog_clear (void);
+#ifdef CURSES_LOC
+void attr_clear (WINDOW * win, int height, int width, chtype attr);
+void color_setup (void);
+void print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x);
+void print_button (WINDOW * win, const char *label, int y, int x, int selected);
+void draw_box (WINDOW * win, int y, int x, int height, int width, chtype box,
+ chtype border);
+void draw_shadow (WINDOW * win, int y, int x, int height, int width);
+#endif
+
+int first_alpha (const char *string, const char *exempt);
+int dialog_yesno (const char *title, const char *prompt, int height, int width);
+int dialog_msgbox (const char *title, const char *prompt, int height,
+ int width, int pause);
+int dialog_textbox (const char *title, const char *file, int height, int width);
+int dialog_menu (const char *title, const char *prompt, int height, int width,
+ int menu_height, const char *choice, int item_no,
+ struct dialog_list_item ** items);
+int dialog_checklist (const char *title, const char *prompt, int height,
+ int width, int list_height, int item_no,
+ struct dialog_list_item ** items, int flag);
+extern unsigned char dialog_input_result[];
+int dialog_inputbox (const char *title, const char *prompt, int height,
+ int width, const char *init);
+
+struct dialog_list_item *first_sel_item(int item_no,
+ struct dialog_list_item ** items);
+
+/*
+ * This is the base for fictitious keys, which activate
+ * the buttons.
+ *
+ * Mouse-generated keys are the following:
+ * -- the first 32 are used as numbers, in addition to '0'-'9'
+ * -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
+ * -- uppercase chars are used to invoke the button (M_EVENT + 'O')
+ */
+#ifdef CURSES_LOC
+#define M_EVENT (KEY_MAX+1)
+#endif
+
+
+/*
+ * The `flag' parameter in checklist is used to select between
+ * radiolist and checklist
+ */
+#define FLAG_CHECK 1
+#define FLAG_RADIO 0
--- /dev/null
+/*
+ * inputbox.c -- implements the input box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+unsigned char dialog_input_result[MAX_LEN + 1];
+
+/*
+ * Print the termination buttons
+ */
+static void
+print_buttons(WINDOW *dialog, int height, int width, int selected)
+{
+ int x = width / 2 - 11;
+ int y = height - 2;
+
+ print_button (dialog, " Ok ", y, x, selected==0);
+ print_button (dialog, " Help ", y, x + 14, selected==1);
+
+ wmove(dialog, y, x+1+14*selected);
+ wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box for inputing a string
+ */
+int
+dialog_inputbox (const char *title, const char *prompt, int height, int width,
+ const char *init)
+{
+ int i, x, y, box_y, box_x, box_width;
+ int input_x = 0, scroll = 0, key = 0, button = -1;
+ unsigned char *instr = dialog_input_result;
+ WINDOW *dialog;
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - height) / 2;
+
+
+ draw_shadow (stdscr, y, x, height, width);
+
+ dialog = newwin (height, width, y, x);
+ keypad (dialog, TRUE);
+
+ draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
+ wattrset (dialog, border_attr);
+ mvwaddch (dialog, height-3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch (dialog, ACS_HLINE);
+ wattrset (dialog, dialog_attr);
+ waddch (dialog, ACS_RTEE);
+
+ if (title != NULL && strlen(title) >= width-2 ) {
+ /* truncate long title -- mec */
+ char * title2 = malloc(width-2+1);
+ memcpy( title2, title, width-2 );
+ title2[width-2] = '\0';
+ title = title2;
+ }
+
+ if (title != NULL) {
+ wattrset (dialog, title_attr);
+ mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
+ waddstr (dialog, (char *)title);
+ waddch (dialog, ' ');
+ }
+
+ wattrset (dialog, dialog_attr);
+ print_autowrap (dialog, prompt, width - 2, 1, 3);
+
+ /* Draw the input field box */
+ box_width = width - 6;
+ getyx (dialog, y, x);
+ box_y = y + 2;
+ box_x = (width - box_width) / 2;
+ draw_box (dialog, y + 1, box_x - 1, 3, box_width + 2,
+ border_attr, dialog_attr);
+
+ print_buttons(dialog, height, width, 0);
+
+ /* Set up the initial value */
+ wmove (dialog, box_y, box_x);
+ wattrset (dialog, inputbox_attr);
+
+ if (!init)
+ instr[0] = '\0';
+ else
+ strcpy (instr, init);
+
+ input_x = strlen (instr);
+
+ if (input_x >= box_width) {
+ scroll = input_x - box_width + 1;
+ input_x = box_width - 1;
+ for (i = 0; i < box_width - 1; i++)
+ waddch (dialog, instr[scroll + i]);
+ } else
+ waddstr (dialog, instr);
+
+ wmove (dialog, box_y, box_x + input_x);
+
+ wrefresh (dialog);
+
+ while (key != ESC) {
+ key = wgetch (dialog);
+
+ if (button == -1) { /* Input box selected */
+ switch (key) {
+ case TAB:
+ case KEY_UP:
+ case KEY_DOWN:
+ break;
+ case KEY_LEFT:
+ continue;
+ case KEY_RIGHT:
+ continue;
+ case KEY_BACKSPACE:
+ case 127:
+ if (input_x || scroll) {
+ wattrset (dialog, inputbox_attr);
+ if (!input_x) {
+ scroll = scroll < box_width - 1 ?
+ 0 : scroll - (box_width - 1);
+ wmove (dialog, box_y, box_x);
+ for (i = 0; i < box_width; i++)
+ waddch (dialog, instr[scroll + input_x + i] ?
+ instr[scroll + input_x + i] : ' ');
+ input_x = strlen (instr) - scroll;
+ } else
+ input_x--;
+ instr[scroll + input_x] = '\0';
+ mvwaddch (dialog, box_y, input_x + box_x, ' ');
+ wmove (dialog, box_y, input_x + box_x);
+ wrefresh (dialog);
+ }
+ continue;
+ default:
+ if (key < 0x100 && isprint (key)) {
+ if (scroll + input_x < MAX_LEN) {
+ wattrset (dialog, inputbox_attr);
+ instr[scroll + input_x] = key;
+ instr[scroll + input_x + 1] = '\0';
+ if (input_x == box_width - 1) {
+ scroll++;
+ wmove (dialog, box_y, box_x);
+ for (i = 0; i < box_width - 1; i++)
+ waddch (dialog, instr[scroll + i]);
+ } else {
+ wmove (dialog, box_y, input_x++ + box_x);
+ waddch (dialog, key);
+ }
+ wrefresh (dialog);
+ } else
+ flash (); /* Alarm user about overflow */
+ continue;
+ }
+ }
+ }
+ switch (key) {
+ case 'O':
+ case 'o':
+ delwin (dialog);
+ return 0;
+ case 'H':
+ case 'h':
+ delwin (dialog);
+ return 1;
+ case KEY_UP:
+ case KEY_LEFT:
+ switch (button) {
+ case -1:
+ button = 1; /* Indicates "Cancel" button is selected */
+ print_buttons(dialog, height, width, 1);
+ break;
+ case 0:
+ button = -1; /* Indicates input box is selected */
+ print_buttons(dialog, height, width, 0);
+ wmove (dialog, box_y, box_x + input_x);
+ wrefresh (dialog);
+ break;
+ case 1:
+ button = 0; /* Indicates "OK" button is selected */
+ print_buttons(dialog, height, width, 0);
+ break;
+ }
+ break;
+ case TAB:
+ case KEY_DOWN:
+ case KEY_RIGHT:
+ switch (button) {
+ case -1:
+ button = 0; /* Indicates "OK" button is selected */
+ print_buttons(dialog, height, width, 0);
+ break;
+ case 0:
+ button = 1; /* Indicates "Cancel" button is selected */
+ print_buttons(dialog, height, width, 1);
+ break;
+ case 1:
+ button = -1; /* Indicates input box is selected */
+ print_buttons(dialog, height, width, 0);
+ wmove (dialog, box_y, box_x + input_x);
+ wrefresh (dialog);
+ break;
+ }
+ break;
+ case ' ':
+ case '\n':
+ delwin (dialog);
+ return (button == -1 ? 0 : button);
+ case 'X':
+ case 'x':
+ key = ESC;
+ case ESC:
+ break;
+ }
+ }
+
+ delwin (dialog);
+ return -1; /* ESC pressed */
+}
--- /dev/null
+/*
+ * menubox.c -- implements the menu box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Changes by Clifford Wolf (god@clifford.at)
+ *
+ * [ 1998-06-13 ]
+ *
+ * *) A bugfix for the Page-Down problem
+ *
+ * *) Formerly when I used Page Down and Page Up, the cursor would be set
+ * to the first position in the menu box. Now lxdialog is a bit
+ * smarter and works more like other menu systems (just have a look at
+ * it).
+ *
+ * *) Formerly if I selected something my scrolling would be broken because
+ * lxdialog is re-invoked by the Menuconfig shell script, can't
+ * remember the last scrolling position, and just sets it so that the
+ * cursor is at the bottom of the box. Now it writes the temporary file
+ * lxdialog.scrltmp which contains this information. The file is
+ * deleted by lxdialog if the user leaves a submenu or enters a new
+ * one, but it would be nice if Menuconfig could make another "rm -f"
+ * just to be sure. Just try it out - you will recognise a difference!
+ *
+ * [ 1998-06-14 ]
+ *
+ * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
+ * and menus change their size on the fly.
+ *
+ * *) If for some reason the last scrolling position is not saved by
+ * lxdialog, it sets the scrolling so that the selected item is in the
+ * middle of the menu box, not at the bottom.
+ *
+ * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
+ * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
+ * This fixes a bug in Menuconfig where using ' ' to descend into menus
+ * would leave mis-synchronized lxdialog.scrltmp files lying around,
+ * fscanf would read in 'scroll', and eventually that value would get used.
+ */
+
+#include "dialog.h"
+
+static int menu_width, item_x;
+
+/*
+ * Print menu item
+ */
+static void
+print_item (WINDOW * win, const char *item, int choice, int selected, int hotkey)
+{
+ int j;
+ char menu_item[menu_width+1];
+
+ strncpy(menu_item, item, menu_width);
+ menu_item[menu_width] = 0;
+ j = first_alpha(menu_item, "YyNnMmHh");
+
+ /* Clear 'residue' of last item */
+ wattrset (win, menubox_attr);
+ wmove (win, choice, 0);
+#if OLD_NCURSES
+ {
+ int i;
+ for (i = 0; i < menu_width; i++)
+ waddch (win, ' ');
+ }
+#else
+ wclrtoeol(win);
+#endif
+ wattrset (win, selected ? item_selected_attr : item_attr);
+ mvwaddstr (win, choice, item_x, menu_item);
+ if (hotkey) {
+ wattrset (win, selected ? tag_key_selected_attr : tag_key_attr);
+ mvwaddch(win, choice, item_x+j, menu_item[j]);
+ }
+ if (selected) {
+ wmove (win, choice, item_x+1);
+ wrefresh (win);
+ }
+}
+
+/*
+ * Print the scroll indicators.
+ */
+static void
+print_arrows (WINDOW * win, int item_no, int scroll,
+ int y, int x, int height)
+{
+ int cur_y, cur_x;
+
+ getyx(win, cur_y, cur_x);
+
+ wmove(win, y, x);
+
+ if (scroll > 0) {
+ wattrset (win, uarrow_attr);
+ waddch (win, ACS_UARROW);
+ waddstr (win, "(-)");
+ }
+ else {
+ wattrset (win, menubox_attr);
+ waddch (win, ACS_HLINE);
+ waddch (win, ACS_HLINE);
+ waddch (win, ACS_HLINE);
+ waddch (win, ACS_HLINE);
+ }
+
+ y = y + height + 1;
+ wmove(win, y, x);
+
+ if ((height < item_no) && (scroll + height < item_no)) {
+ wattrset (win, darrow_attr);
+ waddch (win, ACS_DARROW);
+ waddstr (win, "(+)");
+ }
+ else {
+ wattrset (win, menubox_border_attr);
+ waddch (win, ACS_HLINE);
+ waddch (win, ACS_HLINE);
+ waddch (win, ACS_HLINE);
+ waddch (win, ACS_HLINE);
+ }
+
+ wmove(win, cur_y, cur_x);
+}
+
+/*
+ * Display the termination buttons.
+ */
+static void
+print_buttons (WINDOW *win, int height, int width, int selected)
+{
+ int x = width / 2 - 16;
+ int y = height - 2;
+
+ print_button (win, "Select", y, x, selected == 0);
+ print_button (win, " Exit ", y, x + 12, selected == 1);
+ print_button (win, " Help ", y, x + 24, selected == 2);
+
+ wmove(win, y, x+1+12*selected);
+ wrefresh (win);
+}
+
+/*
+ * Display a menu for choosing among a number of options
+ */
+int
+dialog_menu (const char *title, const char *prompt, int height, int width,
+ int menu_height, const char *current, int item_no,
+ struct dialog_list_item ** items)
+{
+ int i, j, x, y, box_x, box_y;
+ int key = 0, button = 0, scroll = 0, choice = 0, first_item = 0, max_choice;
+ WINDOW *dialog, *menu;
+ FILE *f;
+
+ max_choice = MIN (menu_height, item_no);
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - height) / 2;
+
+ draw_shadow (stdscr, y, x, height, width);
+
+ dialog = newwin (height, width, y, x);
+ keypad (dialog, TRUE);
+
+ draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
+ wattrset (dialog, border_attr);
+ mvwaddch (dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch (dialog, ACS_HLINE);
+ wattrset (dialog, dialog_attr);
+ wbkgdset (dialog, dialog_attr & A_COLOR);
+ waddch (dialog, ACS_RTEE);
+
+ if (title != NULL && strlen(title) >= width-2 ) {
+ /* truncate long title -- mec */
+ char * title2 = malloc(width-2+1);
+ memcpy( title2, title, width-2 );
+ title2[width-2] = '\0';
+ title = title2;
+ }
+
+ if (title != NULL) {
+ wattrset (dialog, title_attr);
+ mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
+ waddstr (dialog, (char *)title);
+ waddch (dialog, ' ');
+ }
+
+ wattrset (dialog, dialog_attr);
+ print_autowrap (dialog, prompt, width - 2, 1, 3);
+
+ menu_width = width - 6;
+ box_y = height - menu_height - 5;
+ box_x = (width - menu_width) / 2 - 1;
+
+ /* create new window for the menu */
+ menu = subwin (dialog, menu_height, menu_width,
+ y + box_y + 1, x + box_x + 1);
+ keypad (menu, TRUE);
+
+ /* draw a box around the menu items */
+ draw_box (dialog, box_y, box_x, menu_height + 2, menu_width + 2,
+ menubox_border_attr, menubox_attr);
+
+ /*
+ * Find length of longest item in order to center menu.
+ * Set 'choice' to default item.
+ */
+ item_x = 0;
+ for (i = 0; i < item_no; i++) {
+ item_x = MAX (item_x, MIN(menu_width, strlen (items[i]->name) + 2));
+ if (strcmp(current, items[i]->tag) == 0) choice = i;
+ }
+
+ item_x = (menu_width - item_x) / 2;
+
+ /* get the scroll info from the temp file */
+ if ( (f=fopen("lxdialog.scrltmp","r")) != NULL ) {
+ if ( (fscanf(f,"%d\n",&scroll) == 1) && (scroll <= choice) &&
+ (scroll+max_choice > choice) && (scroll >= 0) &&
+ (scroll+max_choice <= item_no) ) {
+ first_item = scroll;
+ choice = choice - scroll;
+ fclose(f);
+ } else {
+ scroll=0;
+ remove("lxdialog.scrltmp");
+ fclose(f);
+ f=NULL;
+ }
+ }
+ if ( (choice >= max_choice) || (f==NULL && choice >= max_choice/2) ) {
+ if (choice >= item_no-max_choice/2)
+ scroll = first_item = item_no-max_choice;
+ else
+ scroll = first_item = choice - max_choice/2;
+ choice = choice - scroll;
+ }
+
+ /* Print the menu */
+ for (i=0; i < max_choice; i++) {
+ print_item (menu, items[first_item + i]->name, i, i == choice,
+ (items[first_item + i]->tag[0] != ':'));
+ }
+
+ wnoutrefresh (menu);
+
+ print_arrows(dialog, item_no, scroll,
+ box_y, box_x+item_x+1, menu_height);
+
+ print_buttons (dialog, height, width, 0);
+ wmove (menu, choice, item_x+1);
+ wrefresh (menu);
+
+ while (key != ESC) {
+ key = wgetch(menu);
+
+ if (key < 256 && isalpha(key)) key = tolower(key);
+
+ if (strchr("ynmh", key))
+ i = max_choice;
+ else {
+ for (i = choice+1; i < max_choice; i++) {
+ j = first_alpha(items[scroll + i]->name, "YyNnMmHh");
+ if (key == tolower(items[scroll + i]->name[j]))
+ break;
+ }
+ if (i == max_choice)
+ for (i = 0; i < max_choice; i++) {
+ j = first_alpha(items[scroll + i]->name, "YyNnMmHh");
+ if (key == tolower(items[scroll + i]->name[j]))
+ break;
+ }
+ }
+
+ if (i < max_choice ||
+ key == KEY_UP || key == KEY_DOWN ||
+ key == '-' || key == '+' ||
+ key == KEY_PPAGE || key == KEY_NPAGE) {
+
+ print_item (menu, items[scroll + choice]->name, choice, FALSE,
+ (items[scroll + choice]->tag[0] != ':'));
+
+ if (key == KEY_UP || key == '-') {
+ if (choice < 2 && scroll) {
+ /* Scroll menu down */
+ scrollok (menu, TRUE);
+ wscrl (menu, -1);
+ scrollok (menu, FALSE);
+
+ scroll--;
+
+ print_item (menu, items[scroll]->name, 0, FALSE,
+ (items[scroll]->tag[0] != ':'));
+ } else
+ choice = MAX(choice - 1, 0);
+
+ } else if (key == KEY_DOWN || key == '+') {
+
+ print_item (menu, items[scroll + choice]->name, choice, FALSE,
+ (items[scroll + choice]->tag[0] != ':'));
+
+ if ((choice > max_choice-3) &&
+ (scroll + max_choice < item_no)
+ ) {
+ /* Scroll menu up */
+ scrollok (menu, TRUE);
+ scroll (menu);
+ scrollok (menu, FALSE);
+
+ scroll++;
+
+ print_item (menu, items[scroll + max_choice - 1]->name,
+ max_choice-1, FALSE,
+ (items[scroll + max_choice - 1]->tag[0] != ':'));
+ } else
+ choice = MIN(choice+1, max_choice-1);
+
+ } else if (key == KEY_PPAGE) {
+ scrollok (menu, TRUE);
+ for (i=0; (i < max_choice); i++) {
+ if (scroll > 0) {
+ wscrl (menu, -1);
+ scroll--;
+ print_item (menu, items[scroll]->name, 0, FALSE,
+ (items[scroll]->tag[0] != ':'));
+ } else {
+ if (choice > 0)
+ choice--;
+ }
+ }
+ scrollok (menu, FALSE);
+
+ } else if (key == KEY_NPAGE) {
+ for (i=0; (i < max_choice); i++) {
+ if (scroll+max_choice < item_no) {
+ scrollok (menu, TRUE);
+ scroll(menu);
+ scrollok (menu, FALSE);
+ scroll++;
+ print_item (menu, items[scroll + max_choice - 1]->name,
+ max_choice-1, FALSE,
+ (items[scroll + max_choice - 1]->tag[0] != ':'));
+ } else {
+ if (choice+1 < max_choice)
+ choice++;
+ }
+ }
+
+ } else
+ choice = i;
+
+ print_item (menu, items[scroll + choice]->name, choice, TRUE,
+ (items[scroll + choice]->tag[0] != ':'));
+
+ print_arrows(dialog, item_no, scroll,
+ box_y, box_x+item_x+1, menu_height);
+
+ wnoutrefresh (dialog);
+ wrefresh (menu);
+
+ continue; /* wait for another key press */
+ }
+
+ switch (key) {
+ case KEY_LEFT:
+ case TAB:
+ case KEY_RIGHT:
+ button = ((key == KEY_LEFT ? --button : ++button) < 0)
+ ? 2 : (button > 2 ? 0 : button);
+
+ print_buttons(dialog, height, width, button);
+ wrefresh (menu);
+ break;
+ case ' ':
+ case 's':
+ case 'y':
+ case 'n':
+ case 'm':
+ case '/':
+ /* save scroll info */
+ if ( (f=fopen("lxdialog.scrltmp","w")) != NULL ) {
+ fprintf(f,"%d\n",scroll);
+ fclose(f);
+ }
+ delwin (dialog);
+ items[scroll + choice]->selected = 1;
+ switch (key) {
+ case 's': return 3;
+ case 'y': return 3;
+ case 'n': return 4;
+ case 'm': return 5;
+ case ' ': return 6;
+ case '/': return 7;
+ }
+ return 0;
+ case 'h':
+ case '?':
+ button = 2;
+ case '\n':
+ delwin (dialog);
+ items[scroll + choice]->selected = 1;
+
+ remove("lxdialog.scrltmp");
+ return button;
+ case 'e':
+ case 'x':
+ key = ESC;
+ case ESC:
+ break;
+ }
+ }
+
+ delwin (dialog);
+ remove("lxdialog.scrltmp");
+ return -1; /* ESC pressed */
+}
--- /dev/null
+/*
+ * msgbox.c -- implements the message box and info box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+/*
+ * Display a message box. Program will pause and display an "OK" button
+ * if the parameter 'pause' is non-zero.
+ */
+int
+dialog_msgbox (const char *title, const char *prompt, int height, int width,
+ int pause)
+{
+ int i, x, y, key = 0;
+ WINDOW *dialog;
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - height) / 2;
+
+ draw_shadow (stdscr, y, x, height, width);
+
+ dialog = newwin (height, width, y, x);
+ keypad (dialog, TRUE);
+
+ draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
+
+ if (title != NULL && strlen(title) >= width-2 ) {
+ /* truncate long title -- mec */
+ char * title2 = malloc(width-2+1);
+ memcpy( title2, title, width-2 );
+ title2[width-2] = '\0';
+ title = title2;
+ }
+
+ if (title != NULL) {
+ wattrset (dialog, title_attr);
+ mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
+ waddstr (dialog, (char *)title);
+ waddch (dialog, ' ');
+ }
+ wattrset (dialog, dialog_attr);
+ print_autowrap (dialog, prompt, width - 2, 1, 2);
+
+ if (pause) {
+ wattrset (dialog, border_attr);
+ mvwaddch (dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch (dialog, ACS_HLINE);
+ wattrset (dialog, dialog_attr);
+ waddch (dialog, ACS_RTEE);
+
+ print_button (dialog, " Ok ",
+ height - 2, width / 2 - 4, TRUE);
+
+ wrefresh (dialog);
+ while (key != ESC && key != '\n' && key != ' ' &&
+ key != 'O' && key != 'o' && key != 'X' && key != 'x')
+ key = wgetch (dialog);
+ } else {
+ key = '\n';
+ wrefresh (dialog);
+ }
+
+ delwin (dialog);
+ return key == ESC ? -1 : 0;
+}
--- /dev/null
+/*
+ * textbox.c -- implements the text box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static void back_lines (int n);
+static void print_page (WINDOW * win, int height, int width);
+static void print_line (WINDOW * win, int row, int width);
+static char *get_line (void);
+static void print_position (WINDOW * win, int height, int width);
+
+static int hscroll, fd, file_size, bytes_read;
+static int begin_reached = 1, end_reached, page_length;
+static char *buf, *page;
+
+/*
+ * Display text from a file in a dialog box.
+ */
+int
+dialog_textbox (const char *title, const char *file, int height, int width)
+{
+ int i, x, y, cur_x, cur_y, fpos, key = 0;
+ int passed_end;
+ char search_term[MAX_LEN + 1];
+ WINDOW *dialog, *text;
+
+ search_term[0] = '\0'; /* no search term entered yet */
+
+ /* Open input file for reading */
+ if ((fd = open (file, O_RDONLY)) == -1) {
+ endwin ();
+ fprintf (stderr,
+ "\nCan't open input file in dialog_textbox().\n");
+ exit (-1);
+ }
+ /* Get file size. Actually, 'file_size' is the real file size - 1,
+ since it's only the last byte offset from the beginning */
+ if ((file_size = lseek (fd, 0, SEEK_END)) == -1) {
+ endwin ();
+ fprintf (stderr, "\nError getting file size in dialog_textbox().\n");
+ exit (-1);
+ }
+ /* Restore file pointer to beginning of file after getting file size */
+ if (lseek (fd, 0, SEEK_SET) == -1) {
+ endwin ();
+ fprintf (stderr, "\nError moving file pointer in dialog_textbox().\n");
+ exit (-1);
+ }
+ /* Allocate space for read buffer */
+ if ((buf = malloc (BUF_SIZE + 1)) == NULL) {
+ endwin ();
+ fprintf (stderr, "\nCan't allocate memory in dialog_textbox().\n");
+ exit (-1);
+ }
+ if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
+ endwin ();
+ fprintf (stderr, "\nError reading file in dialog_textbox().\n");
+ exit (-1);
+ }
+ buf[bytes_read] = '\0'; /* mark end of valid data */
+ page = buf; /* page is pointer to start of page to be displayed */
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - height) / 2;
+
+
+ draw_shadow (stdscr, y, x, height, width);
+
+ dialog = newwin (height, width, y, x);
+ keypad (dialog, TRUE);
+
+ /* Create window for text region, used for scrolling text */
+ text = subwin (dialog, height - 4, width - 2, y + 1, x + 1);
+ wattrset (text, dialog_attr);
+ wbkgdset (text, dialog_attr & A_COLOR);
+
+ keypad (text, TRUE);
+
+ /* register the new window, along with its borders */
+ draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
+
+ wattrset (dialog, border_attr);
+ mvwaddch (dialog, height-3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch (dialog, ACS_HLINE);
+ wattrset (dialog, dialog_attr);
+ wbkgdset (dialog, dialog_attr & A_COLOR);
+ waddch (dialog, ACS_RTEE);
+
+ if (title != NULL && strlen(title) >= width-2 ) {
+ /* truncate long title -- mec */
+ char * title2 = malloc(width-2+1);
+ memcpy( title2, title, width-2 );
+ title2[width-2] = '\0';
+ title = title2;
+ }
+
+ if (title != NULL) {
+ wattrset (dialog, title_attr);
+ mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
+ waddstr (dialog, (char *)title);
+ waddch (dialog, ' ');
+ }
+ print_button (dialog, " Exit ", height - 2, width / 2 - 4, TRUE);
+ wnoutrefresh (dialog);
+ getyx (dialog, cur_y, cur_x); /* Save cursor position */
+
+ /* Print first page of text */
+ attr_clear (text, height - 4, width - 2, dialog_attr);
+ print_page (text, height - 4, width - 2);
+ print_position (dialog, height, width);
+ wmove (dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh (dialog);
+
+ while ((key != ESC) && (key != '\n')) {
+ key = wgetch (dialog);
+ switch (key) {
+ case 'E': /* Exit */
+ case 'e':
+ case 'X':
+ case 'x':
+ delwin (dialog);
+ free (buf);
+ close (fd);
+ return 0;
+ case 'g': /* First page */
+ case KEY_HOME:
+ if (!begin_reached) {
+ begin_reached = 1;
+ /* First page not in buffer? */
+ if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
+ endwin ();
+ fprintf (stderr,
+ "\nError moving file pointer in dialog_textbox().\n");
+ exit (-1);
+ }
+ if (fpos > bytes_read) { /* Yes, we have to read it in */
+ if (lseek (fd, 0, SEEK_SET) == -1) {
+ endwin ();
+ fprintf (stderr, "\nError moving file pointer in "
+ "dialog_textbox().\n");
+ exit (-1);
+ }
+ if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
+ endwin ();
+ fprintf (stderr,
+ "\nError reading file in dialog_textbox().\n");
+ exit (-1);
+ }
+ buf[bytes_read] = '\0';
+ }
+ page = buf;
+ print_page (text, height - 4, width - 2);
+ print_position (dialog, height, width);
+ wmove (dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh (dialog);
+ }
+ break;
+ case 'G': /* Last page */
+ case KEY_END:
+
+ end_reached = 1;
+ /* Last page not in buffer? */
+ if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
+ endwin ();
+ fprintf (stderr,
+ "\nError moving file pointer in dialog_textbox().\n");
+ exit (-1);
+ }
+ if (fpos < file_size) { /* Yes, we have to read it in */
+ if (lseek (fd, -BUF_SIZE, SEEK_END) == -1) {
+ endwin ();
+ fprintf (stderr,
+ "\nError moving file pointer in dialog_textbox().\n");
+ exit (-1);
+ }
+ if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
+ endwin ();
+ fprintf (stderr,
+ "\nError reading file in dialog_textbox().\n");
+ exit (-1);
+ }
+ buf[bytes_read] = '\0';
+ }
+ page = buf + bytes_read;
+ back_lines (height - 4);
+ print_page (text, height - 4, width - 2);
+ print_position (dialog, height, width);
+ wmove (dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh (dialog);
+ break;
+ case 'K': /* Previous line */
+ case 'k':
+ case KEY_UP:
+ if (!begin_reached) {
+ back_lines (page_length + 1);
+
+ /* We don't call print_page() here but use scrolling to ensure
+ faster screen update. However, 'end_reached' and
+ 'page_length' should still be updated, and 'page' should
+ point to start of next page. This is done by calling
+ get_line() in the following 'for' loop. */
+ scrollok (text, TRUE);
+ wscrl (text, -1); /* Scroll text region down one line */
+ scrollok (text, FALSE);
+ page_length = 0;
+ passed_end = 0;
+ for (i = 0; i < height - 4; i++) {
+ if (!i) {
+ /* print first line of page */
+ print_line (text, 0, width - 2);
+ wnoutrefresh (text);
+ } else
+ /* Called to update 'end_reached' and 'page' */
+ get_line ();
+ if (!passed_end)
+ page_length++;
+ if (end_reached && !passed_end)
+ passed_end = 1;
+ }
+
+ print_position (dialog, height, width);
+ wmove (dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh (dialog);
+ }
+ break;
+ case 'B': /* Previous page */
+ case 'b':
+ case KEY_PPAGE:
+ if (begin_reached)
+ break;
+ back_lines (page_length + height - 4);
+ print_page (text, height - 4, width - 2);
+ print_position (dialog, height, width);
+ wmove (dialog, cur_y, cur_x);
+ wrefresh (dialog);
+ break;
+ case 'J': /* Next line */
+ case 'j':
+ case KEY_DOWN:
+ if (!end_reached) {
+ begin_reached = 0;
+ scrollok (text, TRUE);
+ scroll (text); /* Scroll text region up one line */
+ scrollok (text, FALSE);
+ print_line (text, height - 5, width - 2);
+ wnoutrefresh (text);
+ print_position (dialog, height, width);
+ wmove (dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh (dialog);
+ }
+ break;
+ case KEY_NPAGE: /* Next page */
+ case ' ':
+ if (end_reached)
+ break;
+
+ begin_reached = 0;
+ print_page (text, height - 4, width - 2);
+ print_position (dialog, height, width);
+ wmove (dialog, cur_y, cur_x);
+ wrefresh (dialog);
+ break;
+ case '0': /* Beginning of line */
+ case 'H': /* Scroll left */
+ case 'h':
+ case KEY_LEFT:
+ if (hscroll <= 0)
+ break;
+
+ if (key == '0')
+ hscroll = 0;
+ else
+ hscroll--;
+ /* Reprint current page to scroll horizontally */
+ back_lines (page_length);
+ print_page (text, height - 4, width - 2);
+ wmove (dialog, cur_y, cur_x);
+ wrefresh (dialog);
+ break;
+ case 'L': /* Scroll right */
+ case 'l':
+ case KEY_RIGHT:
+ if (hscroll >= MAX_LEN)
+ break;
+ hscroll++;
+ /* Reprint current page to scroll horizontally */
+ back_lines (page_length);
+ print_page (text, height - 4, width - 2);
+ wmove (dialog, cur_y, cur_x);
+ wrefresh (dialog);
+ break;
+ case ESC:
+ break;
+ }
+ }
+
+ delwin (dialog);
+ free (buf);
+ close (fd);
+ return 1; /* ESC pressed */
+}
+
+/*
+ * Go back 'n' lines in text file. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+static void
+back_lines (int n)
+{
+ int i, fpos;
+
+ begin_reached = 0;
+ /* We have to distinguish between end_reached and !end_reached
+ since at end of file, the line is not ended by a '\n'.
+ The code inside 'if' basically does a '--page' to move one
+ character backward so as to skip '\n' of the previous line */
+ if (!end_reached) {
+ /* Either beginning of buffer or beginning of file reached? */
+ if (page == buf) {
+ if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
+ endwin ();
+ fprintf (stderr, "\nError moving file pointer in "
+ "back_lines().\n");
+ exit (-1);
+ }
+ if (fpos > bytes_read) { /* Not beginning of file yet */
+ /* We've reached beginning of buffer, but not beginning of
+ file yet, so read previous part of file into buffer.
+ Note that we only move backward for BUF_SIZE/2 bytes,
+ but not BUF_SIZE bytes to avoid re-reading again in
+ print_page() later */
+ /* Really possible to move backward BUF_SIZE/2 bytes? */
+ if (fpos < BUF_SIZE / 2 + bytes_read) {
+ /* No, move less then */
+ if (lseek (fd, 0, SEEK_SET) == -1) {
+ endwin ();
+ fprintf (stderr, "\nError moving file pointer in "
+ "back_lines().\n");
+ exit (-1);
+ }
+ page = buf + fpos - bytes_read;
+ } else { /* Move backward BUF_SIZE/2 bytes */
+ if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR)
+ == -1) {
+ endwin ();
+ fprintf (stderr, "\nError moving file pointer "
+ "in back_lines().\n");
+ exit (-1);
+ }
+ page = buf + BUF_SIZE / 2;
+ }
+ if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
+ endwin ();
+ fprintf (stderr, "\nError reading file in back_lines().\n");
+ exit (-1);
+ }
+ buf[bytes_read] = '\0';
+ } else { /* Beginning of file reached */
+ begin_reached = 1;
+ return;
+ }
+ }
+ if (*(--page) != '\n') { /* '--page' here */
+ /* Something's wrong... */
+ endwin ();
+ fprintf (stderr, "\nInternal error in back_lines().\n");
+ exit (-1);
+ }
+ }
+ /* Go back 'n' lines */
+ for (i = 0; i < n; i++)
+ do {
+ if (page == buf) {
+ if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
+ endwin ();
+ fprintf (stderr,
+ "\nError moving file pointer in back_lines().\n");
+ exit (-1);
+ }
+ if (fpos > bytes_read) {
+ /* Really possible to move backward BUF_SIZE/2 bytes? */
+ if (fpos < BUF_SIZE / 2 + bytes_read) {
+ /* No, move less then */
+ if (lseek (fd, 0, SEEK_SET) == -1) {
+ endwin ();
+ fprintf (stderr, "\nError moving file pointer "
+ "in back_lines().\n");
+ exit (-1);
+ }
+ page = buf + fpos - bytes_read;
+ } else { /* Move backward BUF_SIZE/2 bytes */
+ if (lseek (fd, -(BUF_SIZE / 2 + bytes_read),
+ SEEK_CUR) == -1) {
+ endwin ();
+ fprintf (stderr, "\nError moving file pointer"
+ " in back_lines().\n");
+ exit (-1);
+ }
+ page = buf + BUF_SIZE / 2;
+ }
+ if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
+ endwin ();
+ fprintf (stderr, "\nError reading file in "
+ "back_lines().\n");
+ exit (-1);
+ }
+ buf[bytes_read] = '\0';
+ } else { /* Beginning of file reached */
+ begin_reached = 1;
+ return;
+ }
+ }
+ } while (*(--page) != '\n');
+ page++;
+}
+
+/*
+ * Print a new page of text. Called by dialog_textbox().
+ */
+static void
+print_page (WINDOW * win, int height, int width)
+{
+ int i, passed_end = 0;
+
+ page_length = 0;
+ for (i = 0; i < height; i++) {
+ print_line (win, i, width);
+ if (!passed_end)
+ page_length++;
+ if (end_reached && !passed_end)
+ passed_end = 1;
+ }
+ wnoutrefresh (win);
+}
+
+/*
+ * Print a new line of text. Called by dialog_textbox() and print_page().
+ */
+static void
+print_line (WINDOW * win, int row, int width)
+{
+ int y, x;
+ char *line;
+
+ line = get_line ();
+ line += MIN (strlen (line), hscroll); /* Scroll horizontally */
+ wmove (win, row, 0); /* move cursor to correct line */
+ waddch (win, ' ');
+ waddnstr (win, line, MIN (strlen (line), width - 2));
+
+ getyx (win, y, x);
+ /* Clear 'residue' of previous line */
+#if OLD_NCURSES
+ {
+ int i;
+ for (i = 0; i < width - x; i++)
+ waddch (win, ' ');
+ }
+#else
+ wclrtoeol(win);
+#endif
+}
+
+/*
+ * Return current line of text. Called by dialog_textbox() and print_line().
+ * 'page' should point to start of current line before calling, and will be
+ * updated to point to start of next line.
+ */
+static char *
+get_line (void)
+{
+ int i = 0, fpos;
+ static char line[MAX_LEN + 1];
+
+ end_reached = 0;
+ while (*page != '\n') {
+ if (*page == '\0') {
+ /* Either end of file or end of buffer reached */
+ if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
+ endwin ();
+ fprintf (stderr, "\nError moving file pointer in "
+ "get_line().\n");
+ exit (-1);
+ }
+ if (fpos < file_size) { /* Not end of file yet */
+ /* We've reached end of buffer, but not end of file yet,
+ so read next part of file into buffer */
+ if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
+ endwin ();
+ fprintf (stderr, "\nError reading file in get_line().\n");
+ exit (-1);
+ }
+ buf[bytes_read] = '\0';
+ page = buf;
+ } else {
+ if (!end_reached)
+ end_reached = 1;
+ break;
+ }
+ } else if (i < MAX_LEN)
+ line[i++] = *(page++);
+ else {
+ /* Truncate lines longer than MAX_LEN characters */
+ if (i == MAX_LEN)
+ line[i++] = '\0';
+ page++;
+ }
+ }
+ if (i <= MAX_LEN)
+ line[i] = '\0';
+ if (!end_reached)
+ page++; /* move pass '\n' */
+
+ return line;
+}
+
+/*
+ * Print current position
+ */
+static void
+print_position (WINDOW * win, int height, int width)
+{
+ int fpos, percent;
+
+ if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
+ endwin ();
+ fprintf (stderr, "\nError moving file pointer in print_position().\n");
+ exit (-1);
+ }
+ wattrset (win, position_indicator_attr);
+ wbkgdset (win, position_indicator_attr & A_COLOR);
+ percent = !file_size ?
+ 100 : ((fpos - bytes_read + page - buf) * 100) / file_size;
+ wmove (win, height - 3, width - 9);
+ wprintw (win, "(%3d%%)", percent);
+}
--- /dev/null
+/*
+ * util.c
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+
+/* use colors by default? */
+bool use_colors = 1;
+
+const char *backtitle = NULL;
+
+const char *dialog_result;
+
+/*
+ * Attribute values, default is for mono display
+ */
+chtype attributes[] =
+{
+ A_NORMAL, /* screen_attr */
+ A_NORMAL, /* shadow_attr */
+ A_NORMAL, /* dialog_attr */
+ A_BOLD, /* title_attr */
+ A_NORMAL, /* border_attr */
+ A_REVERSE, /* button_active_attr */
+ A_DIM, /* button_inactive_attr */
+ A_REVERSE, /* button_key_active_attr */
+ A_BOLD, /* button_key_inactive_attr */
+ A_REVERSE, /* button_label_active_attr */
+ A_NORMAL, /* button_label_inactive_attr */
+ A_NORMAL, /* inputbox_attr */
+ A_NORMAL, /* inputbox_border_attr */
+ A_NORMAL, /* searchbox_attr */
+ A_BOLD, /* searchbox_title_attr */
+ A_NORMAL, /* searchbox_border_attr */
+ A_BOLD, /* position_indicator_attr */
+ A_NORMAL, /* menubox_attr */
+ A_NORMAL, /* menubox_border_attr */
+ A_NORMAL, /* item_attr */
+ A_REVERSE, /* item_selected_attr */
+ A_BOLD, /* tag_attr */
+ A_REVERSE, /* tag_selected_attr */
+ A_BOLD, /* tag_key_attr */
+ A_REVERSE, /* tag_key_selected_attr */
+ A_BOLD, /* check_attr */
+ A_REVERSE, /* check_selected_attr */
+ A_BOLD, /* uarrow_attr */
+ A_BOLD /* darrow_attr */
+};
+
+
+#include "colors.h"
+
+/*
+ * Table of color values
+ */
+int color_table[][3] =
+{
+ {SCREEN_FG, SCREEN_BG, SCREEN_HL},
+ {SHADOW_FG, SHADOW_BG, SHADOW_HL},
+ {DIALOG_FG, DIALOG_BG, DIALOG_HL},
+ {TITLE_FG, TITLE_BG, TITLE_HL},
+ {BORDER_FG, BORDER_BG, BORDER_HL},
+ {BUTTON_ACTIVE_FG, BUTTON_ACTIVE_BG, BUTTON_ACTIVE_HL},
+ {BUTTON_INACTIVE_FG, BUTTON_INACTIVE_BG, BUTTON_INACTIVE_HL},
+ {BUTTON_KEY_ACTIVE_FG, BUTTON_KEY_ACTIVE_BG, BUTTON_KEY_ACTIVE_HL},
+ {BUTTON_KEY_INACTIVE_FG, BUTTON_KEY_INACTIVE_BG, BUTTON_KEY_INACTIVE_HL},
+ {BUTTON_LABEL_ACTIVE_FG, BUTTON_LABEL_ACTIVE_BG, BUTTON_LABEL_ACTIVE_HL},
+ {BUTTON_LABEL_INACTIVE_FG, BUTTON_LABEL_INACTIVE_BG,
+ BUTTON_LABEL_INACTIVE_HL},
+ {INPUTBOX_FG, INPUTBOX_BG, INPUTBOX_HL},
+ {INPUTBOX_BORDER_FG, INPUTBOX_BORDER_BG, INPUTBOX_BORDER_HL},
+ {SEARCHBOX_FG, SEARCHBOX_BG, SEARCHBOX_HL},
+ {SEARCHBOX_TITLE_FG, SEARCHBOX_TITLE_BG, SEARCHBOX_TITLE_HL},
+ {SEARCHBOX_BORDER_FG, SEARCHBOX_BORDER_BG, SEARCHBOX_BORDER_HL},
+ {POSITION_INDICATOR_FG, POSITION_INDICATOR_BG, POSITION_INDICATOR_HL},
+ {MENUBOX_FG, MENUBOX_BG, MENUBOX_HL},
+ {MENUBOX_BORDER_FG, MENUBOX_BORDER_BG, MENUBOX_BORDER_HL},
+ {ITEM_FG, ITEM_BG, ITEM_HL},
+ {ITEM_SELECTED_FG, ITEM_SELECTED_BG, ITEM_SELECTED_HL},
+ {TAG_FG, TAG_BG, TAG_HL},
+ {TAG_SELECTED_FG, TAG_SELECTED_BG, TAG_SELECTED_HL},
+ {TAG_KEY_FG, TAG_KEY_BG, TAG_KEY_HL},
+ {TAG_KEY_SELECTED_FG, TAG_KEY_SELECTED_BG, TAG_KEY_SELECTED_HL},
+ {CHECK_FG, CHECK_BG, CHECK_HL},
+ {CHECK_SELECTED_FG, CHECK_SELECTED_BG, CHECK_SELECTED_HL},
+ {UARROW_FG, UARROW_BG, UARROW_HL},
+ {DARROW_FG, DARROW_BG, DARROW_HL},
+}; /* color_table */
+
+/*
+ * Set window to attribute 'attr'
+ */
+void
+attr_clear (WINDOW * win, int height, int width, chtype attr)
+{
+ int i, j;
+
+ wattrset (win, attr);
+ for (i = 0; i < height; i++) {
+ wmove (win, i, 0);
+ for (j = 0; j < width; j++)
+ waddch (win, ' ');
+ }
+ touchwin (win);
+}
+
+void dialog_clear (void)
+{
+ attr_clear (stdscr, LINES, COLS, screen_attr);
+ /* Display background title if it exists ... - SLH */
+ if (backtitle != NULL) {
+ int i;
+
+ wattrset (stdscr, screen_attr);
+ mvwaddstr (stdscr, 0, 1, (char *)backtitle);
+ wmove (stdscr, 1, 1);
+ for (i = 1; i < COLS - 1; i++)
+ waddch (stdscr, ACS_HLINE);
+ }
+ wnoutrefresh (stdscr);
+}
+
+/*
+ * Do some initialization for dialog
+ */
+void
+init_dialog (void)
+{
+ initscr (); /* Init curses */
+ keypad (stdscr, TRUE);
+ cbreak ();
+ noecho ();
+
+
+ if (use_colors) /* Set up colors */
+ color_setup ();
+
+
+ dialog_clear ();
+}
+
+/*
+ * Setup for color display
+ */
+void
+color_setup (void)
+{
+ int i;
+
+ if (has_colors ()) { /* Terminal supports color? */
+ start_color ();
+
+ /* Initialize color pairs */
+ for (i = 0; i < ATTRIBUTE_COUNT; i++)
+ init_pair (i + 1, color_table[i][0], color_table[i][1]);
+
+ /* Setup color attributes */
+ for (i = 0; i < ATTRIBUTE_COUNT; i++)
+ attributes[i] = C_ATTR (color_table[i][2], i + 1);
+ }
+}
+
+/*
+ * End using dialog functions.
+ */
+void
+end_dialog (void)
+{
+ endwin ();
+}
+
+
+/*
+ * Print a string of text in a window, automatically wrap around to the
+ * next line if the string is too long to fit on one line. Newline
+ * characters '\n' are replaced by spaces. We start on a new line
+ * if there is no room for at least 4 nonblanks following a double-space.
+ */
+void
+print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x)
+{
+ int newl, cur_x, cur_y;
+ int i, prompt_len, room, wlen;
+ char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
+
+ strcpy (tempstr, prompt);
+
+ prompt_len = strlen(tempstr);
+
+ /*
+ * Remove newlines
+ */
+ for(i=0; i<prompt_len; i++) {
+ if(tempstr[i] == '\n') tempstr[i] = ' ';
+ }
+
+ if (prompt_len <= width - x * 2) { /* If prompt is short */
+ wmove (win, y, (width - prompt_len) / 2);
+ waddstr (win, tempstr);
+ } else {
+ cur_x = x;
+ cur_y = y;
+ newl = 1;
+ word = tempstr;
+ while (word && *word) {
+ sp = index(word, ' ');
+ if (sp)
+ *sp++ = 0;
+
+ /* Wrap to next line if either the word does not fit,
+ or it is the first word of a new sentence, and it is
+ short, and the next word does not fit. */
+ room = width - cur_x;
+ wlen = strlen(word);
+ if (wlen > room ||
+ (newl && wlen < 4 && sp && wlen+1+strlen(sp) > room
+ && (!(sp2 = index(sp, ' ')) || wlen+1+(sp2-sp) > room))) {
+ cur_y++;
+ cur_x = x;
+ }
+ wmove (win, cur_y, cur_x);
+ waddstr (win, word);
+ getyx (win, cur_y, cur_x);
+ cur_x++;
+ if (sp && *sp == ' ') {
+ cur_x++; /* double space */
+ while (*++sp == ' ');
+ newl = 1;
+ } else
+ newl = 0;
+ word = sp;
+ }
+ }
+}
+
+/*
+ * Print a button
+ */
+void
+print_button (WINDOW * win, const char *label, int y, int x, int selected)
+{
+ int i, temp;
+
+ wmove (win, y, x);
+ wattrset (win, selected ? button_active_attr : button_inactive_attr);
+ waddstr (win, "<");
+ temp = strspn (label, " ");
+ label += temp;
+ wattrset (win, selected ? button_label_active_attr
+ : button_label_inactive_attr);
+ for (i = 0; i < temp; i++)
+ waddch (win, ' ');
+ wattrset (win, selected ? button_key_active_attr
+ : button_key_inactive_attr);
+ waddch (win, label[0]);
+ wattrset (win, selected ? button_label_active_attr
+ : button_label_inactive_attr);
+ waddstr (win, (char *)label + 1);
+ wattrset (win, selected ? button_active_attr : button_inactive_attr);
+ waddstr (win, ">");
+ wmove (win, y, x + temp + 1);
+}
+
+/*
+ * Draw a rectangular box with line drawing characters
+ */
+void
+draw_box (WINDOW * win, int y, int x, int height, int width,
+ chtype box, chtype border)
+{
+ int i, j;
+
+ wattrset (win, 0);
+ for (i = 0; i < height; i++) {
+ wmove (win, y + i, x);
+ for (j = 0; j < width; j++)
+ if (!i && !j)
+ waddch (win, border | ACS_ULCORNER);
+ else if (i == height - 1 && !j)
+ waddch (win, border | ACS_LLCORNER);
+ else if (!i && j == width - 1)
+ waddch (win, box | ACS_URCORNER);
+ else if (i == height - 1 && j == width - 1)
+ waddch (win, box | ACS_LRCORNER);
+ else if (!i)
+ waddch (win, border | ACS_HLINE);
+ else if (i == height - 1)
+ waddch (win, box | ACS_HLINE);
+ else if (!j)
+ waddch (win, border | ACS_VLINE);
+ else if (j == width - 1)
+ waddch (win, box | ACS_VLINE);
+ else
+ waddch (win, box | ' ');
+ }
+}
+
+/*
+ * Draw shadows along the right and bottom edge to give a more 3D look
+ * to the boxes
+ */
+void
+draw_shadow (WINDOW * win, int y, int x, int height, int width)
+{
+ int i;
+
+ if (has_colors ()) { /* Whether terminal supports color? */
+ wattrset (win, shadow_attr);
+ wmove (win, y + height, x + 2);
+ for (i = 0; i < width; i++)
+ waddch (win, winch (win) & A_CHARTEXT);
+ for (i = y + 1; i < y + height + 1; i++) {
+ wmove (win, i, x + width);
+ waddch (win, winch (win) & A_CHARTEXT);
+ waddch (win, winch (win) & A_CHARTEXT);
+ }
+ wnoutrefresh (win);
+ }
+}
+
+/*
+ * Return the position of the first alphabetic character in a string.
+ */
+int
+first_alpha(const char *string, const char *exempt)
+{
+ int i, in_paren=0, c;
+
+ for (i = 0; i < strlen(string); i++) {
+ c = tolower(string[i]);
+
+ if (strchr("<[(", c)) ++in_paren;
+ if (strchr(">])", c) && in_paren > 0) --in_paren;
+
+ if ((! in_paren) && isalpha(c) &&
+ strchr(exempt, c) == 0)
+ return i;
+ }
+
+ return 0;
+}
+
+/*
+ * Get the first selected item in the dialog_list_item list.
+ */
+struct dialog_list_item *
+first_sel_item(int item_no, struct dialog_list_item ** items)
+{
+ int i;
+
+ for (i = 0; i < item_no; i++) {
+ if (items[i]->selected)
+ return items[i];
+ }
+
+ return NULL;
+}
--- /dev/null
+/*
+ * yesno.c -- implements the yes/no box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+/*
+ * Display termination buttons
+ */
+static void
+print_buttons(WINDOW *dialog, int height, int width, int selected)
+{
+ int x = width / 2 - 10;
+ int y = height - 2;
+
+ print_button (dialog, " Yes ", y, x, selected == 0);
+ print_button (dialog, " No ", y, x + 13, selected == 1);
+
+ wmove(dialog, y, x+1 + 13*selected );
+ wrefresh (dialog);
+}
+
+/*
+ * Display a dialog box with two buttons - Yes and No
+ */
+int
+dialog_yesno (const char *title, const char *prompt, int height, int width)
+{
+ int i, x, y, key = 0, button = 0;
+ WINDOW *dialog;
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - height) / 2;
+
+ draw_shadow (stdscr, y, x, height, width);
+
+ dialog = newwin (height, width, y, x);
+ keypad (dialog, TRUE);
+
+ draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
+ wattrset (dialog, border_attr);
+ mvwaddch (dialog, height-3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch (dialog, ACS_HLINE);
+ wattrset (dialog, dialog_attr);
+ waddch (dialog, ACS_RTEE);
+
+ if (title != NULL && strlen(title) >= width-2 ) {
+ /* truncate long title -- mec */
+ char * title2 = malloc(width-2+1);
+ memcpy( title2, title, width-2 );
+ title2[width-2] = '\0';
+ title = title2;
+ }
+
+ if (title != NULL) {
+ wattrset (dialog, title_attr);
+ mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
+ waddstr (dialog, (char *)title);
+ waddch (dialog, ' ');
+ }
+
+ wattrset (dialog, dialog_attr);
+ print_autowrap (dialog, prompt, width - 2, 1, 3);
+
+ print_buttons(dialog, height, width, 0);
+
+ while (key != ESC) {
+ key = wgetch (dialog);
+ switch (key) {
+ case 'Y':
+ case 'y':
+ delwin (dialog);
+ return 0;
+ case 'N':
+ case 'n':
+ delwin (dialog);
+ return 1;
+
+ case TAB:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ button = ((key == KEY_LEFT ? --button : ++button) < 0)
+ ? 1 : (button > 1 ? 0 : button);
+
+ print_buttons(dialog, height, width, button);
+ wrefresh (dialog);
+ break;
+ case ' ':
+ case '\n':
+ delwin (dialog);
+ return button;
+ case ESC:
+ break;
+ }
+ }
+
+ delwin (dialog);
+ return -1; /* ESC pressed */
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Introduced single menu mode (show all sub-menus in one large tree).
+ * 2002-11-06 Petr Baudis <pasky@ucw.cz>
+ *
+ * Directly use liblxdialog library routines.
+ * 2002-11-14 Petr Baudis <pasky@ucw.cz>
+ */
+
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/termios.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "lxdialog/dialog.h"
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static char menu_backtitle[128];
+static const char mconf_readme[] =
+"Overview\n"
+"--------\n"
+"Some features may be built directly into axTLS. Some features\n"
+"may be completely removed altogether. There are also certain\n"
+"parameters which are not really features, but must be\n"
+"entered in as decimal or hexadecimal numbers or possibly text.\n"
+"\n"
+"Menu items beginning with [*] or [ ] represent features\n"
+"configured to be built in or removed respectively.\n"
+"\n"
+"To change any of these features, highlight it with the cursor\n"
+"keys and press <Y> to build it in or <N> to removed it.\n"
+"You may also press the <Space Bar> to cycle\n"
+"through the available options (ie. Y->N->Y).\n"
+"\n"
+"Some additional keyboard hints:\n"
+"\n"
+"Menus\n"
+"----------\n"
+"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
+" you wish to change or submenu wish to select and press <Enter>.\n"
+" Submenus are designated by \"--->\".\n"
+"\n"
+" Shortcut: Press the option's highlighted letter (hotkey).\n"
+" Pressing a hotkey more than once will sequence\n"
+" through all visible items which use that hotkey.\n"
+"\n"
+" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+" unseen options into view.\n"
+"\n"
+"o To exit a menu use the cursor keys to highlight the <Exit> button\n"
+" and press <ENTER>.\n"
+"\n"
+" Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
+" using those letters. You may press a single <ESC>, but\n"
+" there is a delayed response which you may find annoying.\n"
+"\n"
+" Also, the <TAB> and cursor keys will cycle between <Select>,\n"
+" <Exit> and <Help>\n"
+"\n"
+"o To get help with an item, use the cursor keys to highlight <Help>\n"
+" and Press <ENTER>.\n"
+"\n"
+" Shortcut: Press <H> or <?>.\n"
+"\n"
+"\n"
+"Radiolists (Choice lists)\n"
+"-----------\n"
+"o Use the cursor keys to select the option you wish to set and press\n"
+" <S> or the <SPACE BAR>.\n"
+"\n"
+" Shortcut: Press the first letter of the option you wish to set then\n"
+" press <S> or <SPACE BAR>.\n"
+"\n"
+"o To see available help for the item, use the cursor keys to highlight\n"
+" <Help> and Press <ENTER>.\n"
+"\n"
+" Shortcut: Press <H> or <?>.\n"
+"\n"
+" Also, the <TAB> and cursor keys will cycle between <Select> and\n"
+" <Help>\n"
+"\n"
+"\n"
+"Data Entry\n"
+"-----------\n"
+"o Enter the requested information and press <ENTER>\n"
+" If you are entering hexadecimal values, it is not necessary to\n"
+" add the '0x' prefix to the entry.\n"
+"\n"
+"o For help, use the <TAB> or cursor keys to highlight the help option\n"
+" and press <ENTER>. You can try <TAB><H> as well.\n"
+"\n"
+"\n"
+"Text Box (Help Window)\n"
+"--------\n"
+"o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
+" keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
+" who are familiar with less and lynx.\n"
+"\n"
+"o Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
+"\n"
+"\n"
+"Alternate Configuration Files\n"
+"-----------------------------\n"
+"Menuconfig supports the use of alternate configuration files for\n"
+"those who, for various reasons, find it necessary to switch\n"
+"between different configurations.\n"
+"\n"
+"At the end of the main menu you will find two options. One is\n"
+"for saving the current configuration to a file of your choosing.\n"
+"The other option is for loading a previously saved alternate\n"
+"configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you\n"
+"find during a Menuconfig session that you have completely messed\n"
+"up your settings, you may use the \"Load Alternate...\" option to\n"
+"restore your previously saved settings from \".config\" without\n"
+"restarting Menuconfig.\n"
+"\n"
+"Other information\n"
+"-----------------\n"
+"If you use Menuconfig in an XTERM window make sure you have your\n"
+"$TERM variable set to point to a xterm definition which supports color.\n"
+"Otherwise, Menuconfig will look rather bad. Menuconfig will not\n"
+"display correctly in a RXVT window because rxvt displays only one\n"
+"intensity of color, bright.\n"
+"\n"
+"Menuconfig will display larger menus on screens or xterms which are\n"
+"set to display more than the standard 25 row by 80 column geometry.\n"
+"In order for this to work, the \"stty size\" command must be able to\n"
+"display the screen's current row and column geometry. I STRONGLY\n"
+"RECOMMEND that you make sure you do NOT have the shell variables\n"
+"LINES and COLUMNS exported into your environment. Some distributions\n"
+"export those variables via /etc/profile. Some ncurses programs can\n"
+"become confused when those variables (LINES & COLUMNS) don't reflect\n"
+"the true screen size.\n"
+"\n"
+"Optional personality available\n"
+"------------------------------\n"
+"If you prefer to have all of the options listed in a single\n"
+"menu, rather than the default multimenu hierarchy, run the menuconfig\n"
+"with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
+"\n"
+"make MENUCONFIG_MODE=single_menu menuconfig\n"
+"\n"
+"<Enter> will then unroll the appropriate category, or enfold it if it\n"
+"is already unrolled.\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive\n"
+"(especially with a larger number of unrolled categories) than the\n"
+"default mode.\n",
+menu_instructions[] =
+ "Arrow keys navigate the menu. "
+ "<Enter> selects submenus --->. "
+ "Highlighted letters are hotkeys. "
+ "Pressing <Y> selectes a feature, while <N> will exclude a feature. "
+ "Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
+ "Legend: [*] feature is selected [ ] feature is excluded",
+radiolist_instructions[] =
+ "Use the arrow keys to navigate this window or "
+ "press the hotkey of the item you wish to select "
+ "followed by the <SPACE BAR>. "
+ "Press <?> for additional information about this option.",
+inputbox_instructions_int[] =
+ "Please enter a decimal value. "
+ "Fractions will not be accepted. "
+ "Use the <TAB> key to move from the input field to the buttons below it.",
+inputbox_instructions_hex[] =
+ "Please enter a hexadecimal value. "
+ "Use the <TAB> key to move from the input field to the buttons below it.",
+inputbox_instructions_string[] =
+ "Please enter a string value. "
+ "Use the <TAB> key to move from the input field to the buttons below it.",
+setmod_text[] =
+ "This feature depends on another which has been configured as a module.\n"
+ "As a result, this feature will be built as a module.",
+nohelp_text[] =
+ "There is no help available for this option.\n",
+load_config_text[] =
+ "Enter the name of the configuration file you wish to load. "
+ "Accept the name shown to restore the configuration you "
+ "last retrieved. Leave blank to abort.",
+load_config_help[] =
+ "\n"
+ "For various reasons, one may wish to keep several different axTLS\n"
+ "configurations available on a single machine.\n"
+ "\n"
+ "If you have saved a previous configuration in a file other than the\n"
+ "axTLS's default, entering the name of the file here will allow you\n"
+ "to modify that configuration.\n"
+ "\n"
+ "If you are uncertain, then you have probably never used alternate\n"
+ "configuration files. You should therefor leave this blank to abort.\n",
+save_config_text[] =
+ "Enter a filename to which this configuration should be saved "
+ "as an alternate. Leave blank to abort.",
+save_config_help[] =
+ "\n"
+ "For various reasons, one may wish to keep different axTLS\n"
+ "configurations available on a single machine.\n"
+ "\n"
+ "Entering a file name here will allow you to later retrieve, modify\n"
+ "and use the current configuration as an alternate to whatever\n"
+ "configuration options you have selected at that time.\n"
+ "\n"
+ "If you are uncertain what all this means then you should probably\n"
+ "leave this blank.\n",
+search_help[] =
+ "\n"
+ "Search for CONFIG_ symbols and display their relations.\n"
+ "Example: search for \"^FOO\"\n"
+ "Result:\n"
+ "-----------------------------------------------------------------\n"
+ "Symbol: FOO [=m]\n"
+ "Prompt: Foo bus is used to drive the bar HW\n"
+ "Defined at drivers/pci/Kconfig:47\n"
+ "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+ "Location:\n"
+ " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+ " -> PCI support (PCI [=y])\n"
+ " -> PCI access mode (<choice> [=y])\n"
+ "Selects: LIBCRC32\n"
+ "Selected by: BAR\n"
+ "-----------------------------------------------------------------\n"
+ "o The line 'Prompt:' shows the text used in the menu structure for\n"
+ " this CONFIG_ symbol\n"
+ "o The 'Defined at' line tell at what file / line number the symbol\n"
+ " is defined\n"
+ "o The 'Depends on:' line tell what symbols needs to be defined for\n"
+ " this symbol to be visible in the menu (selectable)\n"
+ "o The 'Location:' lines tell where in the menu structure this symbol\n"
+ " is located\n"
+ " A location followed by a [=y] indicate that this is a selectable\n"
+ " menu item - and current value is displayed inside brackets.\n"
+ "o The 'Selects:' line tell what symbol will be automatically\n"
+ " selected if this symbol is selected (y or m)\n"
+ "o The 'Selected by' line tell what symbol has selected this symbol\n"
+ "\n"
+ "Only relevant lines are shown.\n"
+ "\n\n"
+ "Search examples:\n"
+ "Examples: USB => find all CONFIG_ symbols containing USB\n"
+ " ^USB => find all CONFIG_ symbols starting with USB\n"
+ " USB$ => find all CONFIG_ symbols ending with USB\n"
+ "\n";
+
+static char filename[PATH_MAX+1] = ".config";
+static int indent;
+static struct termios ios_org;
+static int rows = 0, cols = 0;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+
+static struct dialog_list_item *items[16384]; /* FIXME: This ought to be dynamic. */
+static int item_no;
+
+static void conf(struct menu *menu);
+static void conf_choice(struct menu *menu);
+static void conf_string(struct menu *menu);
+static void conf_load(void);
+static void conf_save(void);
+static void show_textbox(const char *title, const char *text, int r, int c);
+static void show_helptext(const char *title, const char *text);
+static void show_help(struct menu *menu);
+static void show_file(const char *filename, const char *title, int r, int c);
+
+static void init_wsize(void)
+{
+ struct winsize ws;
+ char *env;
+
+ if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
+ rows = ws.ws_row;
+ cols = ws.ws_col;
+ }
+
+ if (!rows) {
+ env = getenv("LINES");
+ if (env)
+ rows = atoi(env);
+ if (!rows)
+ rows = 24;
+ }
+ if (!cols) {
+ env = getenv("COLUMNS");
+ if (env)
+ cols = atoi(env);
+ if (!cols)
+ cols = 80;
+ }
+
+ if (rows < 19 || cols < 80) {
+ fprintf(stderr, "Your display is too small to run Menuconfig!\n");
+ fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
+ exit(1);
+ }
+
+ rows -= 4;
+ cols -= 5;
+}
+
+static void cinit(void)
+{
+ item_no = 0;
+}
+
+static void cmake(void)
+{
+ items[item_no] = malloc(sizeof(struct dialog_list_item));
+ memset(items[item_no], 0, sizeof(struct dialog_list_item));
+ items[item_no]->tag = malloc(32); items[item_no]->tag[0] = 0;
+ items[item_no]->name = malloc(512); items[item_no]->name[0] = 0;
+ items[item_no]->namelen = 0;
+ item_no++;
+}
+
+static int cprint_name(const char *fmt, ...)
+{
+ va_list ap;
+ int res;
+
+ if (!item_no)
+ cmake();
+ va_start(ap, fmt);
+ res = vsnprintf(items[item_no - 1]->name + items[item_no - 1]->namelen,
+ 512 - items[item_no - 1]->namelen, fmt, ap);
+ if (res > 0)
+ items[item_no - 1]->namelen += res;
+ va_end(ap);
+
+ return res;
+}
+
+static int cprint_tag(const char *fmt, ...)
+{
+ va_list ap;
+ int res;
+
+ if (!item_no)
+ cmake();
+ va_start(ap, fmt);
+ res = vsnprintf(items[item_no - 1]->tag, 32, fmt, ap);
+ va_end(ap);
+
+ return res;
+}
+
+static void cdone(void)
+{
+ int i;
+
+ for (i = 0; i < item_no; i++) {
+ free(items[i]->tag);
+ free(items[i]->name);
+ free(items[i]);
+ }
+
+ item_no = 0;
+}
+
+static void get_prompt_str(struct gstr *r, struct property *prop)
+{
+ int i, j;
+ struct menu *submenu[8], *menu;
+
+ str_printf(r, "Prompt: %s\n", prop->text);
+ str_printf(r, " Defined at %s:%d\n", prop->menu->file->name,
+ prop->menu->lineno);
+ if (!expr_is_yes(prop->visible.expr)) {
+ str_append(r, " Depends on: ");
+ expr_gstr_print(prop->visible.expr, r);
+ str_append(r, "\n");
+ }
+ menu = prop->menu->parent;
+ for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
+ submenu[i++] = menu;
+ if (i > 0) {
+ str_printf(r, " Location:\n");
+ for (j = 4; --i >= 0; j += 2) {
+ menu = submenu[i];
+ str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
+ if (menu->sym) {
+ str_printf(r, " (%s [=%s])", menu->sym->name ?
+ menu->sym->name : "<choice>",
+ sym_get_string_value(menu->sym));
+ }
+ str_append(r, "\n");
+ }
+ }
+}
+
+static void get_symbol_str(struct gstr *r, struct symbol *sym)
+{
+ bool hit;
+ struct property *prop;
+
+ str_printf(r, "Symbol: %s [=%s]\n", sym->name,
+ sym_get_string_value(sym));
+ for_all_prompts(sym, prop)
+ get_prompt_str(r, prop);
+ hit = false;
+ for_all_properties(sym, prop, P_SELECT) {
+ if (!hit) {
+ str_append(r, " Selects: ");
+ hit = true;
+ } else
+ str_printf(r, " && ");
+ expr_gstr_print(prop->expr, r);
+ }
+ if (hit)
+ str_append(r, "\n");
+ if (sym->rev_dep.expr) {
+ str_append(r, " Selected by: ");
+ expr_gstr_print(sym->rev_dep.expr, r);
+ str_append(r, "\n");
+ }
+ str_append(r, "\n\n");
+}
+
+static struct gstr get_relations_str(struct symbol **sym_arr)
+{
+ struct symbol *sym;
+ struct gstr res = str_new();
+ int i;
+
+ for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
+ get_symbol_str(&res, sym);
+ if (!i)
+ str_append(&res, "No matches found.\n");
+ return res;
+}
+
+static void search_conf(void)
+{
+ struct symbol **sym_arr;
+ struct gstr res;
+
+again:
+ switch (dialog_inputbox("Search Configuration Parameter",
+ "Enter Keyword", 10, 75,
+ NULL)) {
+ case 0:
+ break;
+ case 1:
+ show_helptext("Search Configuration", search_help);
+ goto again;
+ default:
+ return;
+ }
+
+ sym_arr = sym_re_search(dialog_input_result);
+ res = get_relations_str(sym_arr);
+ free(sym_arr);
+ show_textbox("Search Results", str_get(&res), 0, 0);
+ str_free(&res);
+}
+
+static void build_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+ int type, tmp, doint = 2;
+ tristate val;
+ char ch;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (!sym) {
+ if (prop && menu != current_menu) {
+ const char *prompt = menu_get_prompt(menu);
+ switch (prop->type) {
+ case P_MENU:
+ child_count++;
+ cmake();
+ cprint_tag("m%p", menu);
+
+ if (single_menu_mode) {
+ cprint_name("%s%*c%s",
+ menu->data ? "-->" : "++>",
+ indent + 1, ' ', prompt);
+ } else {
+ cprint_name(" %*c%s --->", indent + 1, ' ', prompt);
+ }
+
+ if (single_menu_mode && menu->data)
+ goto conf_childs;
+ return;
+ default:
+ if (prompt) {
+ child_count++;
+ cmake();
+ cprint_tag(":%p", menu);
+ cprint_name("---%*c%s", indent + 1, ' ', prompt);
+ }
+ }
+ } else
+ doint = 0;
+ goto conf_childs;
+ }
+
+ cmake();
+ type = sym_get_type(sym);
+ if (sym_is_choice(sym)) {
+ struct symbol *def_sym = sym_get_choice_value(sym);
+ struct menu *def_menu = NULL;
+
+ child_count++;
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child) && child->sym == def_sym)
+ def_menu = child;
+ }
+
+ val = sym_get_tristate_value(sym);
+ if (sym_is_changable(sym)) {
+ cprint_tag("t%p", menu);
+ switch (type) {
+ case S_BOOLEAN:
+ cprint_name("[%c]", val == no ? ' ' : '*');
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes: ch = '*'; break;
+ case mod: ch = 'M'; break;
+ default: ch = ' '; break;
+ }
+ cprint_name("<%c>", ch);
+ break;
+ }
+ } else {
+ cprint_tag("%c%p", def_menu ? 't' : ':', menu);
+ cprint_name(" ");
+ }
+
+ cprint_name("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+ if (val == yes) {
+ if (def_menu) {
+ cprint_name(" (%s)", menu_get_prompt(def_menu));
+ cprint_name(" --->");
+ if (def_menu->list) {
+ indent += 2;
+ build_conf(def_menu);
+ indent -= 2;
+ }
+ }
+ return;
+ }
+ } else {
+ if (menu == current_menu) {
+ cprint_tag(":%p", menu);
+ cprint_name("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+ goto conf_childs;
+ }
+ child_count++;
+ val = sym_get_tristate_value(sym);
+ if (sym_is_choice_value(sym) && val == yes) {
+ cprint_tag(":%p", menu);
+ cprint_name(" ");
+ } else {
+ switch (type) {
+ case S_BOOLEAN:
+ cprint_tag("t%p", menu);
+ if (sym_is_changable(sym))
+ cprint_name("[%c]", val == no ? ' ' : '*');
+ else
+ cprint_name("---");
+ break;
+ case S_TRISTATE:
+ cprint_tag("t%p", menu);
+ switch (val) {
+ case yes: ch = '*'; break;
+ case mod: ch = 'M'; break;
+ default: ch = ' '; break;
+ }
+ if (sym_is_changable(sym))
+ cprint_name("<%c>", ch);
+ else
+ cprint_name("---");
+ break;
+ default:
+ cprint_tag("s%p", menu);
+ tmp = cprint_name("(%s)", sym_get_string_value(sym));
+ tmp = indent - tmp + 4;
+ if (tmp < 0)
+ tmp = 0;
+ cprint_name("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
+ (sym_has_value(sym) || !sym_is_changable(sym)) ?
+ "" : " (NEW)");
+ goto conf_childs;
+ }
+ }
+ cprint_name("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
+ (sym_has_value(sym) || !sym_is_changable(sym)) ?
+ "" : " (NEW)");
+ if (menu->prompt->type == P_MENU) {
+ cprint_name(" --->");
+ return;
+ }
+ }
+
+conf_childs:
+ indent += doint;
+ for (child = menu->list; child; child = child->next)
+ build_conf(child);
+ indent -= doint;
+}
+
+static void conf(struct menu *menu)
+{
+ struct dialog_list_item *active_item = NULL;
+ struct menu *submenu;
+ const char *prompt = menu_get_prompt(menu);
+ struct symbol *sym;
+ char active_entry[40];
+ int stat, type;
+
+ unlink("lxdialog.scrltmp");
+ active_entry[0] = 0;
+ while (1) {
+ indent = 0;
+ child_count = 0;
+ current_menu = menu;
+ cdone(); cinit();
+ build_conf(menu);
+ if (!child_count)
+ break;
+ if (menu == &rootmenu) {
+ cmake(); cprint_tag(":"); cprint_name("--- ");
+ cmake(); cprint_tag("L"); cprint_name("Load an Alternate Configuration File");
+ cmake(); cprint_tag("S"); cprint_name("Save Configuration to an Alternate File");
+ }
+ dialog_clear();
+ stat = dialog_menu(prompt ? prompt : "Main Menu",
+ menu_instructions, rows, cols, rows - 10,
+ active_entry, item_no, items);
+ if (stat < 0)
+ return;
+
+ if (stat == 1 || stat == 255)
+ break;
+
+ active_item = first_sel_item(item_no, items);
+ if (!active_item)
+ continue;
+ active_item->selected = 0;
+ strncpy(active_entry, active_item->tag, sizeof(active_entry));
+ active_entry[sizeof(active_entry)-1] = 0;
+ type = active_entry[0];
+ if (!type)
+ continue;
+
+ sym = NULL;
+ submenu = NULL;
+ if (sscanf(active_entry + 1, "%p", &submenu) == 1)
+ sym = submenu->sym;
+
+ switch (stat) {
+ case 0:
+ switch (type) {
+ case 'm':
+ if (single_menu_mode)
+ submenu->data = (void *) (long) !submenu->data;
+ else
+ conf(submenu);
+ break;
+ case 't':
+ if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
+ conf_choice(submenu);
+ else if (submenu->prompt->type == P_MENU)
+ conf(submenu);
+ break;
+ case 's':
+ conf_string(submenu);
+ break;
+ case 'L':
+ conf_load();
+ break;
+ case 'S':
+ conf_save();
+ break;
+ }
+ break;
+ case 2:
+ if (sym)
+ show_help(submenu);
+ else
+ show_helptext("README", mconf_readme);
+ break;
+ case 3:
+ if (type == 't') {
+ if (sym_set_tristate_value(sym, yes))
+ break;
+ if (sym_set_tristate_value(sym, mod))
+ show_textbox(NULL, setmod_text, 6, 74);
+ }
+ break;
+ case 4:
+ if (type == 't')
+ sym_set_tristate_value(sym, no);
+ break;
+ case 5:
+ if (type == 't')
+ sym_set_tristate_value(sym, mod);
+ break;
+ case 6:
+ if (type == 't')
+ sym_toggle_tristate_value(sym);
+ else if (type == 'm')
+ conf(submenu);
+ break;
+ case 7:
+ search_conf();
+ break;
+ }
+ }
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+ int fd;
+
+ fd = creat(".help.tmp", 0777);
+ write(fd, text, strlen(text));
+ close(fd);
+ show_file(".help.tmp", title, r, c);
+ unlink(".help.tmp");
+}
+
+static void show_helptext(const char *title, const char *text)
+{
+ show_textbox(title, text, 0, 0);
+}
+
+static void show_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+ struct symbol *sym = menu->sym;
+
+ if (sym->help)
+ {
+ if (sym->name) {
+ str_printf(&help, "%s:\n\n", sym->name);
+ str_append(&help, sym->help);
+ str_append(&help, "\n");
+ }
+ } else {
+ str_append(&help, nohelp_text);
+ }
+ get_symbol_str(&help, sym);
+ show_helptext(menu_get_prompt(menu), str_get(&help));
+ str_free(&help);
+}
+
+static void show_file(const char *filename, const char *title, int r, int c)
+{
+ while (dialog_textbox(title, filename, r ? r : rows, c ? c : cols) < 0)
+ ;
+}
+
+static void conf_choice(struct menu *menu)
+{
+ const char *prompt = menu_get_prompt(menu);
+ struct menu *child;
+ struct symbol *active;
+
+ active = sym_get_choice_value(menu->sym);
+ while (1) {
+ current_menu = menu;
+ cdone(); cinit();
+ for (child = menu->list; child; child = child->next) {
+ if (!menu_is_visible(child))
+ continue;
+ cmake();
+ cprint_tag("%p", child);
+ cprint_name("%s", menu_get_prompt(child));
+ if (child->sym == sym_get_choice_value(menu->sym))
+ items[item_no - 1]->selected = 1; /* ON */
+ else if (child->sym == active)
+ items[item_no - 1]->selected = 2; /* SELECTED */
+ else
+ items[item_no - 1]->selected = 0; /* OFF */
+ }
+
+ switch (dialog_checklist(prompt ? prompt : "Main Menu",
+ radiolist_instructions, 15, 70, 6,
+ item_no, items, FLAG_RADIO)) {
+ case 0:
+ if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) != 1)
+ break;
+ sym_set_tristate_value(child->sym, yes);
+ return;
+ case 1:
+ if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) == 1) {
+ show_help(child);
+ active = child->sym;
+ } else
+ show_help(menu);
+ break;
+ case 255:
+ return;
+ }
+ }
+}
+
+static void conf_string(struct menu *menu)
+{
+ const char *prompt = menu_get_prompt(menu);
+
+ while (1) {
+ char *heading;
+
+ switch (sym_get_type(menu->sym)) {
+ case S_INT:
+ heading = (char *) inputbox_instructions_int;
+ break;
+ case S_HEX:
+ heading = (char *) inputbox_instructions_hex;
+ break;
+ case S_STRING:
+ heading = (char *) inputbox_instructions_string;
+ break;
+ default:
+ heading = "Internal mconf error!";
+ /* panic? */;
+ }
+
+ switch (dialog_inputbox(prompt ? prompt : "Main Menu",
+ heading, 10, 75,
+ sym_get_string_value(menu->sym))) {
+ case 0:
+ if (sym_set_string_value(menu->sym, dialog_input_result))
+ return;
+ show_textbox(NULL, "You have made an invalid entry.", 5, 43);
+ break;
+ case 1:
+ show_help(menu);
+ break;
+ case 255:
+ return;
+ }
+ }
+}
+
+static void conf_load(void)
+{
+ while (1) {
+ switch (dialog_inputbox(NULL, load_config_text, 11, 55,
+ filename)) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ if (!conf_read(dialog_input_result))
+ return;
+ show_textbox(NULL, "File does not exist!", 5, 38);
+ break;
+ case 1:
+ show_helptext("Load Alternate Configuration", load_config_help);
+ break;
+ case 255:
+ return;
+ }
+ }
+}
+
+static void conf_save(void)
+{
+ while (1) {
+ switch (dialog_inputbox(NULL, save_config_text, 11, 55,
+ filename)) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ if (!conf_write(dialog_input_result))
+ return;
+ show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60);
+ break;
+ case 1:
+ show_helptext("Save Alternate Configuration", save_config_help);
+ break;
+ case 255:
+ return;
+ }
+ }
+}
+
+static void conf_cleanup(void)
+{
+ tcsetattr(1, TCSAFLUSH, &ios_org);
+ unlink(".help.tmp");
+}
+
+static void winch_handler(int sig)
+{
+ struct winsize ws;
+
+ if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
+ rows = 24;
+ cols = 80;
+ } else {
+ rows = ws.ws_row;
+ cols = ws.ws_col;
+ }
+
+ if (rows < 19 || cols < 80) {
+ end_dialog();
+ fprintf(stderr, "Your display is too small to run Menuconfig!\n");
+ fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
+ exit(1);
+ }
+
+ rows -= 4;
+ cols -= 5;
+
+}
+
+int main(int ac, char **av)
+{
+ struct symbol *sym;
+ char *mode;
+ int stat;
+
+ conf_parse(av[1]);
+ conf_read(NULL);
+
+ sym = sym_lookup("VERSION", 0);
+ sym_calc_value(sym);
+ snprintf(menu_backtitle, 128, "axTLS v%s Configuration",
+ sym_get_string_value(sym));
+
+ mode = getenv("MENUCONFIG_MODE");
+ if (mode) {
+ if (!strcasecmp(mode, "single_menu"))
+ single_menu_mode = 1;
+ }
+
+ tcgetattr(1, &ios_org);
+ atexit(conf_cleanup);
+ init_wsize();
+ init_dialog();
+ signal(SIGWINCH, winch_handler);
+ conf(&rootmenu);
+ end_dialog();
+
+ /* Restart dialog to act more like when lxdialog was still separate */
+ init_dialog();
+ do {
+ stat = dialog_yesno(NULL,
+ "Do you wish to save your new axTLS configuration?", 5, 60);
+ } while (stat < 0);
+ end_dialog();
+
+ if (stat == 0) {
+ conf_write(NULL);
+ printf("\n\n"
+ "*** End of axTLS configuration.\n"
+ "*** Check the top-level Makefile for additional configuration options.\n\n");
+ } else
+ printf("\n\nYour axTLS configuration changes were NOT saved.\n\n");
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+struct menu rootmenu;
+static struct menu **last_entry_ptr;
+
+struct file *file_list;
+struct file *current_file;
+
+static void menu_warn(struct menu *menu, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+static void prop_warn(struct property *prop, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+void menu_init(void)
+{
+ current_entry = current_menu = &rootmenu;
+ last_entry_ptr = &rootmenu.list;
+}
+
+void menu_add_entry(struct symbol *sym)
+{
+ struct menu *menu;
+
+ menu = malloc(sizeof(*menu));
+ memset(menu, 0, sizeof(*menu));
+ menu->sym = sym;
+ menu->parent = current_menu;
+ menu->file = current_file;
+ menu->lineno = zconf_lineno();
+
+ *last_entry_ptr = menu;
+ last_entry_ptr = &menu->next;
+ current_entry = menu;
+}
+
+void menu_end_entry(void)
+{
+}
+
+void menu_add_menu(void)
+{
+ current_menu = current_entry;
+ last_entry_ptr = ¤t_entry->list;
+}
+
+void menu_end_menu(void)
+{
+ last_entry_ptr = ¤t_menu->next;
+ current_menu = current_menu->parent;
+}
+
+struct expr *menu_check_dep(struct expr *e)
+{
+ if (!e)
+ return e;
+
+ switch (e->type) {
+ case E_NOT:
+ e->left.expr = menu_check_dep(e->left.expr);
+ break;
+ case E_OR:
+ case E_AND:
+ e->left.expr = menu_check_dep(e->left.expr);
+ e->right.expr = menu_check_dep(e->right.expr);
+ break;
+ case E_SYMBOL:
+ /* change 'm' into 'm' && MODULES */
+ if (e->left.sym == &symbol_mod)
+ return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
+ break;
+ default:
+ break;
+ }
+ return e;
+}
+
+void menu_add_dep(struct expr *dep)
+{
+ current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
+}
+
+void menu_set_type(int type)
+{
+ struct symbol *sym = current_entry->sym;
+
+ if (sym->type == type)
+ return;
+ if (sym->type == S_UNKNOWN) {
+ sym->type = type;
+ return;
+ }
+ menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'\n",
+ sym->name ? sym->name : "<choice>",
+ sym_type_name(sym->type), sym_type_name(type));
+}
+
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
+{
+ struct property *prop = prop_alloc(type, current_entry->sym);
+
+ prop->menu = current_entry;
+ prop->text = prompt;
+ prop->expr = expr;
+ prop->visible.expr = menu_check_dep(dep);
+
+ if (prompt) {
+ if (current_entry->prompt)
+ menu_warn(current_entry, "prompt redefined\n");
+ current_entry->prompt = prop;
+ }
+
+ return prop;
+}
+
+void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
+{
+ menu_add_prop(type, prompt, NULL, dep);
+}
+
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
+{
+ menu_add_prop(type, NULL, expr, dep);
+}
+
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
+{
+ menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
+}
+
+void sym_check_prop(struct symbol *sym)
+{
+ struct property *prop;
+ struct symbol *sym2;
+ for (prop = sym->prop; prop; prop = prop->next) {
+ switch (prop->type) {
+ case P_DEFAULT:
+ if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
+ prop->expr->type != E_SYMBOL)
+ prop_warn(prop,
+ "default for config symbol '%'"
+ " must be a single symbol", sym->name);
+ break;
+ case P_SELECT:
+ sym2 = prop_get_symbol(prop);
+ if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
+ prop_warn(prop,
+ "config symbol '%s' uses select, but is "
+ "not boolean or tristate", sym->name);
+ else if (sym2->type == S_UNKNOWN)
+ prop_warn(prop,
+ "'select' used by config symbol '%s' "
+ "refer to undefined symbol '%s'",
+ sym->name, sym2->name);
+ else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
+ prop_warn(prop,
+ "'%s' has wrong type. 'select' only "
+ "accept arguments of boolean and "
+ "tristate type", sym2->name);
+ break;
+ case P_RANGE:
+ if (sym->type != S_INT && sym->type != S_HEX)
+ prop_warn(prop, "range is only allowed "
+ "for int or hex symbols");
+ if (!sym_string_valid(sym, prop->expr->left.sym->name) ||
+ !sym_string_valid(sym, prop->expr->right.sym->name))
+ prop_warn(prop, "range is invalid");
+ break;
+ default:
+ ;
+ }
+ }
+}
+
+void menu_finalize(struct menu *parent)
+{
+ struct menu *menu, *last_menu;
+ struct symbol *sym;
+ struct property *prop;
+ struct expr *parentdep, *basedep, *dep, *dep2, **ep;
+
+ sym = parent->sym;
+ if (parent->list) {
+ if (sym && sym_is_choice(sym)) {
+ /* find the first choice value and find out choice type */
+ for (menu = parent->list; menu; menu = menu->next) {
+ if (menu->sym) {
+ current_entry = parent;
+ menu_set_type(menu->sym->type);
+ current_entry = menu;
+ menu_set_type(sym->type);
+ break;
+ }
+ }
+ parentdep = expr_alloc_symbol(sym);
+ } else if (parent->prompt)
+ parentdep = parent->prompt->visible.expr;
+ else
+ parentdep = parent->dep;
+
+ for (menu = parent->list; menu; menu = menu->next) {
+ basedep = expr_transform(menu->dep);
+ basedep = expr_alloc_and(expr_copy(parentdep), basedep);
+ basedep = expr_eliminate_dups(basedep);
+ menu->dep = basedep;
+ if (menu->sym)
+ prop = menu->sym->prop;
+ else
+ prop = menu->prompt;
+ for (; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ dep = expr_transform(prop->visible.expr);
+ dep = expr_alloc_and(expr_copy(basedep), dep);
+ dep = expr_eliminate_dups(dep);
+ if (menu->sym && menu->sym->type != S_TRISTATE)
+ dep = expr_trans_bool(dep);
+ prop->visible.expr = dep;
+ if (prop->type == P_SELECT) {
+ struct symbol *es = prop_get_symbol(prop);
+ es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
+ expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
+ }
+ }
+ }
+ for (menu = parent->list; menu; menu = menu->next)
+ menu_finalize(menu);
+ } else if (sym) {
+ basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
+ basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
+ basedep = expr_eliminate_dups(expr_transform(basedep));
+ last_menu = NULL;
+ for (menu = parent->next; menu; menu = menu->next) {
+ dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
+ if (!expr_contains_symbol(dep, sym))
+ break;
+ if (expr_depends_symbol(dep, sym))
+ goto next;
+ dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
+ dep = expr_eliminate_dups(expr_transform(dep));
+ dep2 = expr_copy(basedep);
+ expr_eliminate_eq(&dep, &dep2);
+ expr_free(dep);
+ if (!expr_is_yes(dep2)) {
+ expr_free(dep2);
+ break;
+ }
+ expr_free(dep2);
+ next:
+ menu_finalize(menu);
+ menu->parent = parent;
+ last_menu = menu;
+ }
+ if (last_menu) {
+ parent->list = parent->next;
+ parent->next = last_menu->next;
+ last_menu->next = NULL;
+ }
+ }
+ for (menu = parent->list; menu; menu = menu->next) {
+ if (sym && sym_is_choice(sym) && menu->sym) {
+ menu->sym->flags |= SYMBOL_CHOICEVAL;
+ if (!menu->prompt)
+ menu_warn(menu, "choice value must have a prompt");
+ for (prop = menu->sym->prop; prop; prop = prop->next) {
+ if (prop->type == P_PROMPT && prop->menu != menu) {
+ prop_warn(prop, "choice values "
+ "currently only support a "
+ "single prompt");
+ }
+ if (prop->type == P_DEFAULT)
+ prop_warn(prop, "defaults for choice "
+ "values not supported");
+ }
+ current_entry = menu;
+ menu_set_type(sym->type);
+ menu_add_symbol(P_CHOICE, sym, NULL);
+ prop = sym_get_choice_prop(sym);
+ for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
+ ;
+ *ep = expr_alloc_one(E_CHOICE, NULL);
+ (*ep)->right.sym = menu->sym;
+ }
+ if (menu->list && (!menu->prompt || !menu->prompt->text)) {
+ for (last_menu = menu->list; ; last_menu = last_menu->next) {
+ last_menu->parent = parent;
+ if (!last_menu->next)
+ break;
+ }
+ last_menu->next = menu->next;
+ menu->next = menu->list;
+ menu->list = NULL;
+ }
+ }
+
+ if (sym && !(sym->flags & SYMBOL_WARNED)) {
+ if (sym->type == S_UNKNOWN)
+ menu_warn(parent, "config symbol defined "
+ "without type\n");
+
+ if (sym_is_choice(sym) && !parent->prompt)
+ menu_warn(parent, "choice must have a prompt\n");
+
+ /* Check properties connected to this symbol */
+ sym_check_prop(sym);
+ sym->flags |= SYMBOL_WARNED;
+ }
+
+ if (sym && !sym_is_optional(sym) && parent->prompt) {
+ sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
+ expr_alloc_and(parent->prompt->visible.expr,
+ expr_alloc_symbol(&symbol_mod)));
+ }
+}
+
+bool menu_is_visible(struct menu *menu)
+{
+ struct menu *child;
+ struct symbol *sym;
+ tristate visible;
+
+ if (!menu->prompt)
+ return false;
+ sym = menu->sym;
+ if (sym) {
+ sym_calc_value(sym);
+ visible = menu->prompt->visible.tri;
+ } else
+ visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
+
+ if (visible != no)
+ return true;
+ if (!sym || sym_get_tristate_value(menu->sym) == no)
+ return false;
+
+ for (child = menu->list; child; child = child->next)
+ if (menu_is_visible(child))
+ return true;
+ return false;
+}
+
+const char *menu_get_prompt(struct menu *menu)
+{
+ if (menu->prompt)
+ return menu->prompt->text;
+ else if (menu->sym)
+ return menu->sym->name;
+ return NULL;
+}
+
+struct menu *menu_get_root_menu(struct menu *menu)
+{
+ return &rootmenu;
+}
+
+struct menu *menu_get_parent_menu(struct menu *menu)
+{
+ enum prop_type type;
+
+ for (; menu != &rootmenu; menu = menu->parent) {
+ type = menu->prompt ? menu->prompt->type : 0;
+ if (type == P_MENU)
+ break;
+ }
+ return menu;
+}
+
--- /dev/null
+#!/bin/sh
+#
+# Copyright (C) 2002 Khalid Aziz <khalid_aziz at hp.com>
+# Copyright (C) 2002 Randy Dunlap <rddunlap at osdl.org>
+# Copyright (C) 2002 Al Stone <ahs3 at fc.hp.com>
+# Copyright (C) 2002 Hewlett-Packard Company
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# Busybox version by Matteo Croce <3297627799 at wind.it>
+#
+# Rules to generate bbconfig.h from .config:
+# - Retain lines that begin with "CONFIG_"
+# - Retain lines that begin with "# CONFIG_"
+# - lines that use double-quotes must \\-escape-quote them
+
+if [ $# -lt 1 ]
+then
+ config=.config
+else config=$1
+fi
+
+echo "#ifndef _BBCONFIG_H"
+echo "#define _BBCONFIG_H"
+echo \
+"/*
+ * busybox configuration options.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *
+ * This file is generated automatically by scripts/config/mkconfigs.
+ * Do not edit.
+ *
+ */"
+
+echo "static char const bbconfig_config[] ="
+echo "\"CONFIG_BEGIN=n\\n\\"
+echo "`sed 's/\"/\\\\\"/g' $config | grep "^#\? \?CONFIG_" | awk '{ print $0 "\\\\n\\\\" }' `"
+echo "CONFIG_END=n\\n\";"
+echo "#endif /* _BBCONFIG_H */"
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include <sys/utsname.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+struct symbol symbol_yes = {
+ .name = "y",
+ .curr = { "y", yes },
+ .flags = SYMBOL_YES|SYMBOL_VALID,
+}, symbol_mod = {
+ .name = "m",
+ .curr = { "m", mod },
+ .flags = SYMBOL_MOD|SYMBOL_VALID,
+}, symbol_no = {
+ .name = "n",
+ .curr = { "n", no },
+ .flags = SYMBOL_NO|SYMBOL_VALID,
+}, symbol_empty = {
+ .name = "",
+ .curr = { "", no },
+ .flags = SYMBOL_VALID,
+};
+
+int sym_change_count;
+struct symbol *modules_sym;
+tristate modules_val;
+
+void sym_add_default(struct symbol *sym, const char *def)
+{
+ struct property *prop = prop_alloc(P_DEFAULT, sym);
+
+ prop->expr = expr_alloc_symbol(sym_lookup(def, 1));
+}
+
+void sym_init(void)
+{
+ struct symbol *sym;
+ char *p;
+ static bool inited = false;
+
+ if (inited)
+ return;
+ inited = true;
+
+ sym = sym_lookup("VERSION", 0);
+ sym->type = S_STRING;
+ sym->flags |= SYMBOL_AUTO;
+ p = getenv("VERSION");
+ if (p)
+ sym_add_default(sym, p);
+
+ sym = sym_lookup("TARGET_ARCH", 0);
+ sym->type = S_STRING;
+ sym->flags |= SYMBOL_AUTO;
+ p = getenv("TARGET_ARCH");
+ if (p)
+ sym_add_default(sym, p);
+
+}
+
+enum symbol_type sym_get_type(struct symbol *sym)
+{
+ enum symbol_type type = sym->type;
+
+ if (type == S_TRISTATE) {
+ if (sym_is_choice_value(sym) && sym->visible == yes)
+ type = S_BOOLEAN;
+ else if (modules_val == no)
+ type = S_BOOLEAN;
+ }
+ return type;
+}
+
+const char *sym_type_name(enum symbol_type type)
+{
+ switch (type) {
+ case S_BOOLEAN:
+ return "boolean";
+ case S_TRISTATE:
+ return "tristate";
+ case S_INT:
+ return "integer";
+ case S_HEX:
+ return "hex";
+ case S_STRING:
+ return "string";
+ case S_UNKNOWN:
+ return "unknown";
+ case S_OTHER:
+ break;
+ }
+ return "???";
+}
+
+struct property *sym_get_choice_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_choices(sym, prop)
+ return prop;
+ return NULL;
+}
+
+struct property *sym_get_default_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_defaults(sym, prop) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ if (prop->visible.tri != no)
+ return prop;
+ }
+ return NULL;
+}
+
+struct property *sym_get_range_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_properties(sym, prop, P_RANGE) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ if (prop->visible.tri != no)
+ return prop;
+ }
+ return NULL;
+}
+
+static void sym_calc_visibility(struct symbol *sym)
+{
+ struct property *prop;
+ tristate tri;
+
+ /* any prompt visible? */
+ tri = no;
+ for_all_prompts(sym, prop) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ tri = E_OR(tri, prop->visible.tri);
+ }
+ if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
+ tri = yes;
+ if (sym->visible != tri) {
+ sym->visible = tri;
+ sym_set_changed(sym);
+ }
+ if (sym_is_choice_value(sym))
+ return;
+ tri = no;
+ if (sym->rev_dep.expr)
+ tri = expr_calc_value(sym->rev_dep.expr);
+ if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+ tri = yes;
+ if (sym->rev_dep.tri != tri) {
+ sym->rev_dep.tri = tri;
+ sym_set_changed(sym);
+ }
+}
+
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+ struct symbol *def_sym;
+ struct property *prop;
+ struct expr *e;
+
+ /* is the user choice visible? */
+ def_sym = sym->user.val;
+ if (def_sym) {
+ sym_calc_visibility(def_sym);
+ if (def_sym->visible != no)
+ return def_sym;
+ }
+
+ /* any of the defaults visible? */
+ for_all_defaults(sym, prop) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ if (prop->visible.tri == no)
+ continue;
+ def_sym = prop_get_symbol(prop);
+ sym_calc_visibility(def_sym);
+ if (def_sym->visible != no)
+ return def_sym;
+ }
+
+ /* just get the first visible value */
+ prop = sym_get_choice_prop(sym);
+ for (e = prop->expr; e; e = e->left.expr) {
+ def_sym = e->right.sym;
+ sym_calc_visibility(def_sym);
+ if (def_sym->visible != no)
+ return def_sym;
+ }
+
+ /* no choice? reset tristate value */
+ sym->curr.tri = no;
+ return NULL;
+}
+
+void sym_calc_value(struct symbol *sym)
+{
+ struct symbol_value newval, oldval;
+ struct property *prop;
+ struct expr *e;
+
+ if (!sym)
+ return;
+
+ if (sym->flags & SYMBOL_VALID)
+ return;
+ sym->flags |= SYMBOL_VALID;
+
+ oldval = sym->curr;
+
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ newval = symbol_empty.curr;
+ break;
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ newval = symbol_no.curr;
+ break;
+ default:
+ sym->curr.val = sym->name;
+ sym->curr.tri = no;
+ return;
+ }
+ if (!sym_is_choice_value(sym))
+ sym->flags &= ~SYMBOL_WRITE;
+
+ sym_calc_visibility(sym);
+
+ /* set default if recursively called */
+ sym->curr = newval;
+
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_is_choice_value(sym) && sym->visible == yes) {
+ prop = sym_get_choice_prop(sym);
+ newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
+ } else if (E_OR(sym->visible, sym->rev_dep.tri) != no) {
+ sym->flags |= SYMBOL_WRITE;
+ if (sym_has_value(sym))
+ newval.tri = sym->user.tri;
+ else if (!sym_is_choice(sym)) {
+ prop = sym_get_default_prop(sym);
+ if (prop)
+ newval.tri = expr_calc_value(prop->expr);
+ }
+ newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri);
+ } else if (!sym_is_choice(sym)) {
+ prop = sym_get_default_prop(sym);
+ if (prop) {
+ sym->flags |= SYMBOL_WRITE;
+ newval.tri = expr_calc_value(prop->expr);
+ }
+ }
+ if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
+ newval.tri = yes;
+ break;
+ case S_STRING:
+ case S_HEX:
+ case S_INT:
+ if (sym->visible != no) {
+ sym->flags |= SYMBOL_WRITE;
+ if (sym_has_value(sym)) {
+ newval.val = sym->user.val;
+ break;
+ }
+ }
+ prop = sym_get_default_prop(sym);
+ if (prop) {
+ struct symbol *ds = prop_get_symbol(prop);
+ if (ds) {
+ sym->flags |= SYMBOL_WRITE;
+ sym_calc_value(ds);
+ newval.val = ds->curr.val;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+
+ sym->curr = newval;
+ if (sym_is_choice(sym) && newval.tri == yes)
+ sym->curr.val = sym_calc_choice(sym);
+
+ if (memcmp(&oldval, &sym->curr, sizeof(oldval)))
+ sym_set_changed(sym);
+ if (modules_sym == sym)
+ modules_val = modules_sym->curr.tri;
+
+ if (sym_is_choice(sym)) {
+ int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
+ prop = sym_get_choice_prop(sym);
+ for (e = prop->expr; e; e = e->left.expr) {
+ e->right.sym->flags |= flags;
+ if (flags & SYMBOL_CHANGED)
+ sym_set_changed(e->right.sym);
+ }
+ }
+}
+
+void sym_clear_all_valid(void)
+{
+ struct symbol *sym;
+ int i;
+
+ for_all_symbols(i, sym)
+ sym->flags &= ~SYMBOL_VALID;
+ sym_change_count++;
+ if (modules_sym)
+ sym_calc_value(modules_sym);
+}
+
+void sym_set_changed(struct symbol *sym)
+{
+ struct property *prop;
+
+ sym->flags |= SYMBOL_CHANGED;
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu)
+ prop->menu->flags |= MENU_CHANGED;
+ }
+}
+
+void sym_set_all_changed(void)
+{
+ struct symbol *sym;
+ int i;
+
+ for_all_symbols(i, sym)
+ sym_set_changed(sym);
+}
+
+bool sym_tristate_within_range(struct symbol *sym, tristate val)
+{
+ int type = sym_get_type(sym);
+
+ if (sym->visible == no)
+ return false;
+
+ if (type != S_BOOLEAN && type != S_TRISTATE)
+ return false;
+
+ if (type == S_BOOLEAN && val == mod)
+ return false;
+ if (sym->visible <= sym->rev_dep.tri)
+ return false;
+ if (sym_is_choice_value(sym) && sym->visible == yes)
+ return val == yes;
+ return val >= sym->rev_dep.tri && val <= sym->visible;
+}
+
+bool sym_set_tristate_value(struct symbol *sym, tristate val)
+{
+ tristate oldval = sym_get_tristate_value(sym);
+
+ if (oldval != val && !sym_tristate_within_range(sym, val))
+ return false;
+
+ if (sym->flags & SYMBOL_NEW) {
+ sym->flags &= ~SYMBOL_NEW;
+ sym_set_changed(sym);
+ }
+ if (sym_is_choice_value(sym) && val == yes) {
+ struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+
+ cs->user.val = sym;
+ cs->flags &= ~SYMBOL_NEW;
+ }
+
+ sym->user.tri = val;
+ if (oldval != val) {
+ sym_clear_all_valid();
+ if (sym == modules_sym)
+ sym_set_all_changed();
+ }
+
+ return true;
+}
+
+tristate sym_toggle_tristate_value(struct symbol *sym)
+{
+ tristate oldval, newval;
+
+ oldval = newval = sym_get_tristate_value(sym);
+ do {
+ switch (newval) {
+ case no:
+ newval = mod;
+ break;
+ case mod:
+ newval = yes;
+ break;
+ case yes:
+ newval = no;
+ break;
+ }
+ if (sym_set_tristate_value(sym, newval))
+ break;
+ } while (oldval != newval);
+ return newval;
+}
+
+bool sym_string_valid(struct symbol *sym, const char *str)
+{
+ signed char ch;
+
+ switch (sym->type) {
+ case S_STRING:
+ return true;
+ case S_INT:
+ ch = *str++;
+ if (ch == '-')
+ ch = *str++;
+ if (!isdigit(ch))
+ return false;
+ if (ch == '0' && *str != 0)
+ return false;
+ while ((ch = *str++)) {
+ if (!isdigit(ch))
+ return false;
+ }
+ return true;
+ case S_HEX:
+ if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+ str += 2;
+ ch = *str++;
+ do {
+ if (!isxdigit(ch))
+ return false;
+ } while ((ch = *str++));
+ return true;
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (str[0]) {
+ case 'y': case 'Y':
+ case 'm': case 'M':
+ case 'n': case 'N':
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+bool sym_string_within_range(struct symbol *sym, const char *str)
+{
+ struct property *prop;
+ int val;
+
+ switch (sym->type) {
+ case S_STRING:
+ return sym_string_valid(sym, str);
+ case S_INT:
+ if (!sym_string_valid(sym, str))
+ return false;
+ prop = sym_get_range_prop(sym);
+ if (!prop)
+ return true;
+ val = strtol(str, NULL, 10);
+ return val >= strtol(prop->expr->left.sym->name, NULL, 10) &&
+ val <= strtol(prop->expr->right.sym->name, NULL, 10);
+ case S_HEX:
+ if (!sym_string_valid(sym, str))
+ return false;
+ prop = sym_get_range_prop(sym);
+ if (!prop)
+ return true;
+ val = strtol(str, NULL, 16);
+ return val >= strtol(prop->expr->left.sym->name, NULL, 16) &&
+ val <= strtol(prop->expr->right.sym->name, NULL, 16);
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (str[0]) {
+ case 'y': case 'Y':
+ return sym_tristate_within_range(sym, yes);
+ case 'm': case 'M':
+ return sym_tristate_within_range(sym, mod);
+ case 'n': case 'N':
+ return sym_tristate_within_range(sym, no);
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+bool sym_set_string_value(struct symbol *sym, const char *newval)
+{
+ const char *oldval;
+ char *val;
+ int size;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (newval[0]) {
+ case 'y': case 'Y':
+ return sym_set_tristate_value(sym, yes);
+ case 'm': case 'M':
+ return sym_set_tristate_value(sym, mod);
+ case 'n': case 'N':
+ return sym_set_tristate_value(sym, no);
+ }
+ return false;
+ default:
+ ;
+ }
+
+ if (!sym_string_within_range(sym, newval))
+ return false;
+
+ if (sym->flags & SYMBOL_NEW) {
+ sym->flags &= ~SYMBOL_NEW;
+ sym_set_changed(sym);
+ }
+
+ oldval = sym->user.val;
+ size = strlen(newval) + 1;
+ if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
+ size += 2;
+ sym->user.val = val = malloc(size);
+ *val++ = '0';
+ *val++ = 'x';
+ } else if (!oldval || strcmp(oldval, newval))
+ sym->user.val = val = malloc(size);
+ else
+ return true;
+
+ strcpy(val, newval);
+ free((void *)oldval);
+ sym_clear_all_valid();
+
+ return true;
+}
+
+const char *sym_get_string_value(struct symbol *sym)
+{
+ tristate val;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ val = sym_get_tristate_value(sym);
+ switch (val) {
+ case no:
+ return "n";
+ case mod:
+ return "m";
+ case yes:
+ return "y";
+ }
+ break;
+ default:
+ ;
+ }
+ return (const char *)sym->curr.val;
+}
+
+bool sym_is_changable(struct symbol *sym)
+{
+ return sym->visible > sym->rev_dep.tri;
+}
+
+struct symbol *sym_lookup(const char *name, int isconst)
+{
+ struct symbol *symbol;
+ const char *ptr;
+ char *new_name;
+ int hash = 0;
+
+ if (name) {
+ if (name[0] && !name[1]) {
+ switch (name[0]) {
+ case 'y': return &symbol_yes;
+ case 'm': return &symbol_mod;
+ case 'n': return &symbol_no;
+ }
+ }
+ for (ptr = name; *ptr; ptr++)
+ hash += *ptr;
+ hash &= 0xff;
+
+ for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+ if (!strcmp(symbol->name, name)) {
+ if ((isconst && symbol->flags & SYMBOL_CONST) ||
+ (!isconst && !(symbol->flags & SYMBOL_CONST)))
+ return symbol;
+ }
+ }
+ new_name = strdup(name);
+ } else {
+ new_name = NULL;
+ hash = 256;
+ }
+
+ symbol = malloc(sizeof(*symbol));
+ memset(symbol, 0, sizeof(*symbol));
+ symbol->name = new_name;
+ symbol->type = S_UNKNOWN;
+ symbol->flags = SYMBOL_NEW;
+ if (isconst)
+ symbol->flags |= SYMBOL_CONST;
+
+ symbol->next = symbol_hash[hash];
+ symbol_hash[hash] = symbol;
+
+ return symbol;
+}
+
+struct symbol *sym_find(const char *name)
+{
+ struct symbol *symbol = NULL;
+ const char *ptr;
+ int hash = 0;
+
+ if (!name)
+ return NULL;
+
+ if (name[0] && !name[1]) {
+ switch (name[0]) {
+ case 'y': return &symbol_yes;
+ case 'm': return &symbol_mod;
+ case 'n': return &symbol_no;
+ }
+ }
+ for (ptr = name; *ptr; ptr++)
+ hash += *ptr;
+ hash &= 0xff;
+
+ for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+ if (!strcmp(symbol->name, name) &&
+ !(symbol->flags & SYMBOL_CONST))
+ break;
+ }
+
+ return symbol;
+}
+
+struct symbol **sym_re_search(const char *pattern)
+{
+ struct symbol *sym, **sym_arr = NULL;
+ int i, cnt, size;
+ regex_t re;
+
+ cnt = size = 0;
+ /* Skip if empty */
+ if (strlen(pattern) == 0)
+ return NULL;
+ if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
+ return NULL;
+
+ for_all_symbols(i, sym) {
+ if (sym->flags & SYMBOL_CONST || !sym->name)
+ continue;
+ if (regexec(&re, sym->name, 0, NULL, 0))
+ continue;
+ if (cnt + 1 >= size) {
+ void *tmp = sym_arr;
+ size += 16;
+ sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
+ if (!sym_arr) {
+ free(tmp);
+ return NULL;
+ }
+ }
+ sym_arr[cnt++] = sym;
+ }
+ if (sym_arr)
+ sym_arr[cnt] = NULL;
+ regfree(&re);
+
+ return sym_arr;
+}
+
+
+struct symbol *sym_check_deps(struct symbol *sym);
+
+static struct symbol *sym_check_expr_deps(struct expr *e)
+{
+ struct symbol *sym;
+
+ if (!e)
+ return NULL;
+ switch (e->type) {
+ case E_OR:
+ case E_AND:
+ sym = sym_check_expr_deps(e->left.expr);
+ if (sym)
+ return sym;
+ return sym_check_expr_deps(e->right.expr);
+ case E_NOT:
+ return sym_check_expr_deps(e->left.expr);
+ case E_EQUAL:
+ case E_UNEQUAL:
+ sym = sym_check_deps(e->left.sym);
+ if (sym)
+ return sym;
+ return sym_check_deps(e->right.sym);
+ case E_SYMBOL:
+ return sym_check_deps(e->left.sym);
+ default:
+ break;
+ }
+ printf("Oops! How to check %d?\n", e->type);
+ return NULL;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+ struct symbol *sym2;
+ struct property *prop;
+
+ if (sym->flags & SYMBOL_CHECK_DONE)
+ return NULL;
+ if (sym->flags & SYMBOL_CHECK) {
+ printf("Warning! Found recursive dependency: %s", sym->name);
+ return sym;
+ }
+
+ sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+ sym2 = sym_check_expr_deps(sym->rev_dep.expr);
+ if (sym2)
+ goto out;
+
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->type == P_CHOICE || prop->type == P_SELECT)
+ continue;
+ sym2 = sym_check_expr_deps(prop->visible.expr);
+ if (sym2)
+ goto out;
+ if (prop->type != P_DEFAULT || sym_is_choice(sym))
+ continue;
+ sym2 = sym_check_expr_deps(prop->expr);
+ if (sym2)
+ goto out;
+ }
+out:
+ if (sym2)
+ printf(" %s", sym->name);
+ sym->flags &= ~SYMBOL_CHECK;
+ return sym2;
+}
+
+struct property *prop_alloc(enum prop_type type, struct symbol *sym)
+{
+ struct property *prop;
+ struct property **propp;
+
+ prop = malloc(sizeof(*prop));
+ memset(prop, 0, sizeof(*prop));
+ prop->type = type;
+ prop->sym = sym;
+ prop->file = current_file;
+ prop->lineno = zconf_lineno();
+
+ /* append property to the prop list of symbol */
+ if (sym) {
+ for (propp = &sym->prop; *propp; propp = &(*propp)->next)
+ ;
+ *propp = prop;
+ }
+
+ return prop;
+}
+
+struct symbol *prop_get_symbol(struct property *prop)
+{
+ if (prop->expr && (prop->expr->type == E_SYMBOL ||
+ prop->expr->type == E_CHOICE))
+ return prop->expr->left.sym;
+ return NULL;
+}
+
+const char *prop_get_type_name(enum prop_type type)
+{
+ switch (type) {
+ case P_PROMPT:
+ return "prompt";
+ case P_COMMENT:
+ return "comment";
+ case P_MENU:
+ return "menu";
+ case P_DEFAULT:
+ return "default";
+ case P_CHOICE:
+ return "choice";
+ case P_SELECT:
+ return "select";
+ case P_RANGE:
+ return "range";
+ case P_UNKNOWN:
+ break;
+ }
+ return "unknown";
+}
--- /dev/null
+/*
+ * Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org>
+ * Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <string.h>
+#include "lkc.h"
+
+/* file already present in list? If not add it */
+struct file *file_lookup(const char *name)
+{
+ struct file *file;
+
+ for (file = file_list; file; file = file->next) {
+ if (!strcmp(name, file->name))
+ return file;
+ }
+
+ file = malloc(sizeof(*file));
+ memset(file, 0, sizeof(*file));
+ file->name = strdup(name);
+ file->next = file_list;
+ file_list = file;
+ return file;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+int file_write_dep(const char *name)
+{
+ struct file *file;
+ FILE *out;
+
+ if (!name)
+ name = "config/.config.cmd";
+ out = fopen("config/.config.tmp", "w");
+ if (!out)
+ return 1;
+ fprintf(out, "deps_config := \\\n");
+ for (file = file_list; file; file = file->next) {
+ if (file->next)
+ fprintf(out, "\t%s \\\n", file->name);
+ else
+ fprintf(out, "\t%s\n", file->name);
+ }
+ fprintf(out, "\n.config include/config.h: $(deps_config)\n\n$(deps_config):\n");
+ fclose(out);
+ rename(".config.tmp", name);
+ return 0;
+}
+
+
+/* Allocate initial growable sting */
+struct gstr str_new(void)
+{
+ struct gstr gs;
+ gs.s = malloc(sizeof(char) * 64);
+ gs.len = 16;
+ strcpy(gs.s, "\0");
+ return gs;
+}
+
+/* Allocate and assign growable string */
+struct gstr str_assign(const char *s)
+{
+ struct gstr gs;
+ gs.s = strdup(s);
+ gs.len = strlen(s) + 1;
+ return gs;
+}
+
+/* Free storage for growable string */
+void str_free(struct gstr *gs)
+{
+ if (gs->s)
+ free(gs->s);
+ gs->s = NULL;
+ gs->len = 0;
+}
+
+/* Append to growable string */
+void str_append(struct gstr *gs, const char *s)
+{
+ size_t l = strlen(gs->s) + strlen(s) + 1;
+ if (l > gs->len) {
+ gs->s = realloc(gs->s, l);
+ gs->len = l;
+ }
+ strcat(gs->s, s);
+}
+
+/* Append printf formatted string to growable string */
+void str_printf(struct gstr *gs, const char *fmt, ...)
+{
+ va_list ap;
+ char s[10000]; /* big enough... */
+ va_start(ap, fmt);
+ vsnprintf(s, sizeof(s), fmt, ap);
+ str_append(gs, s);
+ va_end(ap);
+}
+
+/* Retreive value of growable string */
+const char *str_get(struct gstr *gs)
+{
+ return gs->s;
+}
+
--- /dev/null
+%option backup nostdinit noyywrap never-interactive full ecs
+%option 8bit backup nodefault perf-report perf-report
+%x COMMAND HELP STRING PARAM
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE 16
+
+char *text;
+static char *text_ptr;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static struct buffer *zconf_endfile(void);
+
+void new_string(void)
+{
+ text = malloc(START_STRSIZE);
+ text_asize = START_STRSIZE;
+ text_ptr = text;
+ text_size = 0;
+ *text_ptr = 0;
+}
+
+void append_string(const char *str, int size)
+{
+ int new_size = text_size + size + 1;
+ if (new_size > text_asize) {
+ text = realloc(text, new_size);
+ text_asize = new_size;
+ text_ptr = text + text_size;
+ }
+ memcpy(text_ptr, str, size);
+ text_ptr += size;
+ text_size += size;
+ *text_ptr = 0;
+}
+
+void alloc_string(const char *str, int size)
+{
+ text = malloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+%}
+
+ws [ \n\t]
+n [A-Za-z0-9_]
+
+%%
+ int str = 0;
+ int ts, i;
+
+[ \t]*#.*\n current_file->lineno++;
+[ \t]*#.*
+
+[ \t]*\n current_file->lineno++; return T_EOL;
+
+[ \t]+ {
+ BEGIN(COMMAND);
+}
+
+. {
+ unput(yytext[0]);
+ BEGIN(COMMAND);
+}
+
+
+<COMMAND>{
+ "mainmenu" BEGIN(PARAM); return T_MAINMENU;
+ "menu" BEGIN(PARAM); return T_MENU;
+ "endmenu" BEGIN(PARAM); return T_ENDMENU;
+ "source" BEGIN(PARAM); return T_SOURCE;
+ "choice" BEGIN(PARAM); return T_CHOICE;
+ "endchoice" BEGIN(PARAM); return T_ENDCHOICE;
+ "comment" BEGIN(PARAM); return T_COMMENT;
+ "config" BEGIN(PARAM); return T_CONFIG;
+ "menuconfig" BEGIN(PARAM); return T_MENUCONFIG;
+ "help" BEGIN(PARAM); return T_HELP;
+ "if" BEGIN(PARAM); return T_IF;
+ "endif" BEGIN(PARAM); return T_ENDIF;
+ "depends" BEGIN(PARAM); return T_DEPENDS;
+ "requires" BEGIN(PARAM); return T_REQUIRES;
+ "optional" BEGIN(PARAM); return T_OPTIONAL;
+ "default" BEGIN(PARAM); return T_DEFAULT;
+ "prompt" BEGIN(PARAM); return T_PROMPT;
+ "tristate" BEGIN(PARAM); return T_TRISTATE;
+ "def_tristate" BEGIN(PARAM); return T_DEF_TRISTATE;
+ "bool" BEGIN(PARAM); return T_BOOLEAN;
+ "boolean" BEGIN(PARAM); return T_BOOLEAN;
+ "def_bool" BEGIN(PARAM); return T_DEF_BOOLEAN;
+ "def_boolean" BEGIN(PARAM); return T_DEF_BOOLEAN;
+ "int" BEGIN(PARAM); return T_INT;
+ "hex" BEGIN(PARAM); return T_HEX;
+ "string" BEGIN(PARAM); return T_STRING;
+ "select" BEGIN(PARAM); return T_SELECT;
+ "enable" BEGIN(PARAM); return T_SELECT;
+ "range" BEGIN(PARAM); return T_RANGE;
+ {n}+ {
+ alloc_string(yytext, yyleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ .
+ \n current_file->lineno++; BEGIN(INITIAL);
+}
+
+<PARAM>{
+ "&&" return T_AND;
+ "||" return T_OR;
+ "(" return T_OPEN_PAREN;
+ ")" return T_CLOSE_PAREN;
+ "!" return T_NOT;
+ "=" return T_EQUAL;
+ "!=" return T_UNEQUAL;
+ "if" return T_IF;
+ "on" return T_ON;
+ \"|\' {
+ str = yytext[0];
+ new_string();
+ BEGIN(STRING);
+ }
+ \n BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+ --- /* ignore */
+ ({n}|[-/.])+ {
+ alloc_string(yytext, yyleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ #.* /* comment */
+ \\\n current_file->lineno++;
+ .
+ <<EOF>> {
+ BEGIN(INITIAL);
+ }
+}
+
+<STRING>{
+ [^'"\\\n]+/\n {
+ append_string(yytext, yyleng);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ [^'"\\\n]+ {
+ append_string(yytext, yyleng);
+ }
+ \\.?/\n {
+ append_string(yytext + 1, yyleng - 1);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ \\.? {
+ append_string(yytext + 1, yyleng - 1);
+ }
+ \'|\" {
+ if (str == yytext[0]) {
+ BEGIN(PARAM);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(yytext, 1);
+ }
+ \n {
+ printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+ current_file->lineno++;
+ BEGIN(INITIAL);
+ return T_EOL;
+ }
+ <<EOF>> {
+ BEGIN(INITIAL);
+ }
+}
+
+<HELP>{
+ [ \t]+ {
+ ts = 0;
+ for (i = 0; i < yyleng; i++) {
+ if (yytext[i] == '\t')
+ ts = (ts & ~7) + 8;
+ else
+ ts++;
+ }
+ last_ts = ts;
+ if (first_ts) {
+ if (ts < first_ts) {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ ts -= first_ts;
+ while (ts > 8) {
+ append_string(" ", 8);
+ ts -= 8;
+ }
+ append_string(" ", ts);
+ }
+ }
+ [ \t]*\n/[^ \t\n] {
+ current_file->lineno++;
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ [ \t]*\n {
+ current_file->lineno++;
+ append_string("\n", 1);
+ }
+ [^ \t\n].* {
+ append_string(yytext, yyleng);
+ if (!first_ts)
+ first_ts = last_ts;
+ }
+ <<EOF>> {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+}
+
+<<EOF>> {
+ if (current_buf) {
+ zconf_endfile();
+ return T_EOF;
+ }
+ fclose(yyin);
+ yyterminate();
+}
+
+%%
+void zconf_starthelp(void)
+{
+ new_string();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ zconflval.string = text;
+ BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+ char *env, fullname[PATH_MAX+1];
+ FILE *f;
+
+ f = fopen(name, "r");
+ if (!f && name[0] != '/') {
+ env = getenv(SRCTREE);
+ if (env) {
+ sprintf(fullname, "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ yyin = zconf_fopen(name);
+ if (!yyin) {
+ printf("can't find file %s\n", name);
+ exit(1);
+ }
+
+ current_buf = malloc(sizeof(*current_buf));
+ memset(current_buf, 0, sizeof(*current_buf));
+
+ current_file = file_lookup(name);
+ current_file->lineno = 1;
+ current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct file *file = file_lookup(name);
+ struct buffer *buf = malloc(sizeof(*buf));
+ memset(buf, 0, sizeof(*buf));
+
+ current_buf->state = YY_CURRENT_BUFFER;
+ yyin = zconf_fopen(name);
+ if (!yyin) {
+ printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
+ exit(1);
+ }
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+ buf->parent = current_buf;
+ current_buf = buf;
+
+ if (file->flags & FILE_BUSY) {
+ printf("recursive scan (%s)?\n", name);
+ exit(1);
+ }
+ if (file->flags & FILE_SCANNED) {
+ printf("file %s already scanned?\n", name);
+ exit(1);
+ }
+ file->flags |= FILE_BUSY;
+ file->lineno = 1;
+ file->parent = current_file;
+ current_file = file;
+}
+
+static struct buffer *zconf_endfile(void)
+{
+ struct buffer *parent;
+
+ current_file->flags |= FILE_SCANNED;
+ current_file->flags &= ~FILE_BUSY;
+ current_file = current_file->parent;
+
+ parent = current_buf->parent;
+ if (parent) {
+ fclose(yyin);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(parent->state);
+ }
+ free(current_buf);
+ current_buf = parent;
+
+ return parent;
+}
+
+int zconf_lineno(void)
+{
+ if (current_buf)
+ return current_file->lineno - 1;
+ else
+ return 0;
+}
+
+char *zconf_curname(void)
+{
+ if (current_buf)
+ return current_file->name;
+ else
+ return "<none>";
+}
--- /dev/null
+/* A Bison parser, made by GNU Bison 1.875a. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+/* If NAME_PREFIX is specified substitute the variables and functions
+ names. */
+#define yyparse zconfparse
+#define yylex zconflex
+#define yyerror zconferror
+#define yylval zconflval
+#define yychar zconfchar
+#define yydebug zconfdebug
+#define yynerrs zconfnerrs
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ T_MAINMENU = 258,
+ T_MENU = 259,
+ T_ENDMENU = 260,
+ T_SOURCE = 261,
+ T_CHOICE = 262,
+ T_ENDCHOICE = 263,
+ T_COMMENT = 264,
+ T_CONFIG = 265,
+ T_MENUCONFIG = 266,
+ T_HELP = 267,
+ T_HELPTEXT = 268,
+ T_IF = 269,
+ T_ENDIF = 270,
+ T_DEPENDS = 271,
+ T_REQUIRES = 272,
+ T_OPTIONAL = 273,
+ T_PROMPT = 274,
+ T_DEFAULT = 275,
+ T_TRISTATE = 276,
+ T_DEF_TRISTATE = 277,
+ T_BOOLEAN = 278,
+ T_DEF_BOOLEAN = 279,
+ T_STRING = 280,
+ T_INT = 281,
+ T_HEX = 282,
+ T_WORD = 283,
+ T_WORD_QUOTE = 284,
+ T_UNEQUAL = 285,
+ T_EOF = 286,
+ T_EOL = 287,
+ T_CLOSE_PAREN = 288,
+ T_OPEN_PAREN = 289,
+ T_ON = 290,
+ T_SELECT = 291,
+ T_RANGE = 292,
+ T_OR = 293,
+ T_AND = 294,
+ T_EQUAL = 295,
+ T_NOT = 296
+ };
+#endif
+#define T_MAINMENU 258
+#define T_MENU 259
+#define T_ENDMENU 260
+#define T_SOURCE 261
+#define T_CHOICE 262
+#define T_ENDCHOICE 263
+#define T_COMMENT 264
+#define T_CONFIG 265
+#define T_MENUCONFIG 266
+#define T_HELP 267
+#define T_HELPTEXT 268
+#define T_IF 269
+#define T_ENDIF 270
+#define T_DEPENDS 271
+#define T_REQUIRES 272
+#define T_OPTIONAL 273
+#define T_PROMPT 274
+#define T_DEFAULT 275
+#define T_TRISTATE 276
+#define T_DEF_TRISTATE 277
+#define T_BOOLEAN 278
+#define T_DEF_BOOLEAN 279
+#define T_STRING 280
+#define T_INT 281
+#define T_HEX 282
+#define T_WORD 283
+#define T_WORD_QUOTE 284
+#define T_UNEQUAL 285
+#define T_EOF 286
+#define T_EOL 287
+#define T_CLOSE_PAREN 288
+#define T_OPEN_PAREN 289
+#define T_ON 290
+#define T_SELECT 291
+#define T_RANGE 292
+#define T_OR 293
+#define T_AND 294
+#define T_EQUAL 295
+#define T_NOT 296
+
+
+
+
+/* Copy the first part of user declarations. */
+
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD 0x0001
+#define DEBUG_PARSE 0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(int token, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[257];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYERROR_VERBOSE
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+
+typedef union YYSTYPE {
+ int token;
+ char *string;
+ struct symbol *symbol;
+ struct expr *expr;
+ struct menu *menu;
+} YYSTYPE;
+/* Line 191 of yacc.c. */
+
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+
+/* Line 214 of yacc.c. */
+
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# else
+# ifndef YYSTACK_USE_ALLOCA
+# if defined (alloca) || (defined (_ALLOCA_H) && defined (__GNUC__))
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC malloc
+# define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 201
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 42
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 41
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 104
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 182
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 296
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned char yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned short yyprhs[] =
+{
+ 0, 0, 3, 4, 7, 9, 11, 13, 17, 19,
+ 21, 23, 26, 28, 30, 32, 34, 36, 38, 42,
+ 45, 49, 52, 53, 56, 59, 62, 65, 69, 74,
+ 78, 83, 87, 91, 95, 100, 105, 110, 116, 119,
+ 122, 124, 128, 131, 132, 135, 138, 141, 144, 149,
+ 153, 157, 160, 165, 166, 169, 173, 175, 179, 182,
+ 183, 186, 189, 192, 196, 199, 201, 205, 208, 209,
+ 212, 215, 218, 222, 226, 228, 232, 235, 238, 241,
+ 242, 245, 248, 253, 257, 261, 262, 265, 267, 269,
+ 272, 275, 278, 280, 282, 283, 286, 288, 292, 296,
+ 300, 303, 307, 311, 313
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 43, 0, -1, -1, 43, 44, -1, 45, -1, 55,
+ -1, 66, -1, 3, 77, 79, -1, 5, -1, 15,
+ -1, 8, -1, 1, 79, -1, 61, -1, 71, -1,
+ 47, -1, 49, -1, 69, -1, 79, -1, 10, 28,
+ 32, -1, 46, 50, -1, 11, 28, 32, -1, 48,
+ 50, -1, -1, 50, 51, -1, 50, 75, -1, 50,
+ 73, -1, 50, 32, -1, 21, 76, 32, -1, 22,
+ 81, 80, 32, -1, 23, 76, 32, -1, 24, 81,
+ 80, 32, -1, 26, 76, 32, -1, 27, 76, 32,
+ -1, 25, 76, 32, -1, 19, 77, 80, 32, -1,
+ 20, 81, 80, 32, -1, 36, 28, 80, 32, -1,
+ 37, 82, 82, 80, 32, -1, 7, 32, -1, 52,
+ 56, -1, 78, -1, 53, 58, 54, -1, 53, 58,
+ -1, -1, 56, 57, -1, 56, 75, -1, 56, 73,
+ -1, 56, 32, -1, 19, 77, 80, 32, -1, 21,
+ 76, 32, -1, 23, 76, 32, -1, 18, 32, -1,
+ 20, 28, 80, 32, -1, -1, 58, 45, -1, 14,
+ 81, 32, -1, 78, -1, 59, 62, 60, -1, 59,
+ 62, -1, -1, 62, 45, -1, 62, 66, -1, 62,
+ 55, -1, 4, 77, 32, -1, 63, 74, -1, 78,
+ -1, 64, 67, 65, -1, 64, 67, -1, -1, 67,
+ 45, -1, 67, 66, -1, 67, 55, -1, 67, 1,
+ 32, -1, 6, 77, 32, -1, 68, -1, 9, 77,
+ 32, -1, 70, 74, -1, 12, 32, -1, 72, 13,
+ -1, -1, 74, 75, -1, 74, 32, -1, 16, 35,
+ 81, 32, -1, 16, 81, 32, -1, 17, 81, 32,
+ -1, -1, 77, 80, -1, 28, -1, 29, -1, 5,
+ 79, -1, 8, 79, -1, 15, 79, -1, 32, -1,
+ 31, -1, -1, 14, 81, -1, 82, -1, 82, 40,
+ 82, -1, 82, 30, 82, -1, 34, 81, 33, -1,
+ 41, 81, -1, 81, 38, 81, -1, 81, 39, 81,
+ -1, 28, -1, 29, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short yyrline[] =
+{
+ 0, 94, 94, 95, 98, 99, 100, 101, 102, 103,
+ 104, 105, 109, 110, 111, 112, 113, 114, 120, 128,
+ 134, 142, 152, 154, 155, 156, 157, 160, 166, 173,
+ 179, 186, 192, 198, 204, 210, 216, 222, 230, 239,
+ 245, 254, 255, 261, 263, 264, 265, 266, 269, 275,
+ 281, 287, 293, 299, 301, 306, 315, 324, 325, 331,
+ 333, 334, 335, 340, 347, 353, 362, 363, 369, 371,
+ 372, 373, 374, 377, 383, 390, 397, 404, 410, 417,
+ 418, 419, 422, 427, 432, 440, 442, 447, 448, 451,
+ 452, 453, 457, 457, 459, 460, 463, 464, 465, 466,
+ 467, 468, 469, 472, 473
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU",
+ "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
+ "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
+ "T_REQUIRES", "T_OPTIONAL", "T_PROMPT", "T_DEFAULT", "T_TRISTATE",
+ "T_DEF_TRISTATE", "T_BOOLEAN", "T_DEF_BOOLEAN", "T_STRING", "T_INT",
+ "T_HEX", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", "T_EOF", "T_EOL",
+ "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_ON", "T_SELECT", "T_RANGE", "T_OR",
+ "T_AND", "T_EQUAL", "T_NOT", "$accept", "input", "block",
+ "common_block", "config_entry_start", "config_stmt",
+ "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
+ "config_option", "choice", "choice_entry", "choice_end", "choice_stmt",
+ "choice_option_list", "choice_option", "choice_block", "if", "if_end",
+ "if_stmt", "if_block", "menu", "menu_entry", "menu_end", "menu_stmt",
+ "menu_block", "source", "source_stmt", "comment", "comment_stmt",
+ "help_start", "help", "depends_list", "depends", "prompt_stmt_opt",
+ "prompt", "end", "nl_or_eof", "if_expr", "expr", "symbol", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 42, 43, 43, 44, 44, 44, 44, 44, 44,
+ 44, 44, 45, 45, 45, 45, 45, 45, 46, 47,
+ 48, 49, 50, 50, 50, 50, 50, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 52, 53,
+ 54, 55, 55, 56, 56, 56, 56, 56, 57, 57,
+ 57, 57, 57, 58, 58, 59, 60, 61, 61, 62,
+ 62, 62, 62, 63, 64, 65, 66, 66, 67, 67,
+ 67, 67, 67, 68, 69, 70, 71, 72, 73, 74,
+ 74, 74, 75, 75, 75, 76, 76, 77, 77, 78,
+ 78, 78, 79, 79, 80, 80, 81, 81, 81, 81,
+ 81, 81, 81, 82, 82
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 0, 2, 1, 1, 1, 3, 1, 1,
+ 1, 2, 1, 1, 1, 1, 1, 1, 3, 2,
+ 3, 2, 0, 2, 2, 2, 2, 3, 4, 3,
+ 4, 3, 3, 3, 4, 4, 4, 5, 2, 2,
+ 1, 3, 2, 0, 2, 2, 2, 2, 4, 3,
+ 3, 2, 4, 0, 2, 3, 1, 3, 2, 0,
+ 2, 2, 2, 3, 2, 1, 3, 2, 0, 2,
+ 2, 2, 3, 3, 1, 3, 2, 2, 2, 0,
+ 2, 2, 4, 3, 3, 0, 2, 1, 1, 2,
+ 2, 2, 1, 1, 0, 2, 1, 3, 3, 3,
+ 2, 3, 3, 1, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 2, 0, 1, 0, 0, 0, 8, 0, 0, 10,
+ 0, 0, 0, 0, 9, 93, 92, 3, 4, 22,
+ 14, 22, 15, 43, 53, 5, 59, 12, 79, 68,
+ 6, 74, 16, 79, 13, 17, 11, 87, 88, 0,
+ 0, 0, 38, 0, 0, 0, 103, 104, 0, 0,
+ 0, 96, 19, 21, 39, 42, 58, 64, 0, 76,
+ 7, 63, 73, 75, 18, 20, 0, 100, 55, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 85, 0,
+ 85, 0, 85, 85, 85, 26, 0, 0, 23, 0,
+ 25, 24, 0, 0, 0, 85, 85, 47, 44, 46,
+ 45, 0, 0, 0, 54, 41, 40, 60, 62, 57,
+ 61, 56, 81, 80, 0, 69, 71, 66, 70, 65,
+ 99, 101, 102, 98, 97, 77, 0, 0, 0, 94,
+ 94, 0, 94, 94, 0, 94, 0, 0, 0, 94,
+ 0, 78, 51, 94, 94, 0, 0, 89, 90, 91,
+ 72, 0, 83, 84, 0, 0, 0, 27, 86, 0,
+ 29, 0, 33, 31, 32, 0, 94, 0, 0, 49,
+ 50, 82, 95, 34, 35, 28, 30, 36, 0, 48,
+ 52, 37
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short yydefgoto[] =
+{
+ -1, 1, 17, 18, 19, 20, 21, 22, 52, 88,
+ 23, 24, 105, 25, 54, 98, 55, 26, 109, 27,
+ 56, 28, 29, 117, 30, 58, 31, 32, 33, 34,
+ 89, 90, 57, 91, 131, 132, 106, 35, 155, 50,
+ 51
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -99
+static const short yypact[] =
+{
+ -99, 48, -99, 38, 46, 46, -99, 46, -29, -99,
+ 46, -17, -3, -11, -99, -99, -99, -99, -99, -99,
+ -99, -99, -99, -99, -99, -99, -99, -99, -99, -99,
+ -99, -99, -99, -99, -99, -99, -99, -99, -99, 38,
+ 12, 15, -99, 18, 51, 62, -99, -99, -11, -11,
+ 4, -24, 138, 138, 160, 121, 110, -4, 81, -4,
+ -99, -99, -99, -99, -99, -99, -19, -99, -99, -11,
+ -11, 70, 70, 73, 32, -11, 46, -11, 46, -11,
+ 46, -11, 46, 46, 46, -99, 36, 70, -99, 95,
+ -99, -99, 96, 46, 106, 46, 46, -99, -99, -99,
+ -99, 38, 38, 38, -99, -99, -99, -99, -99, -99,
+ -99, -99, -99, -99, 112, -99, -99, -99, -99, -99,
+ -99, 117, -99, -99, -99, -99, -11, 33, 65, 131,
+ 1, 119, 131, 1, 136, 1, 153, 154, 155, 131,
+ 70, -99, -99, 131, 131, 156, 157, -99, -99, -99,
+ -99, 101, -99, -99, -11, 158, 159, -99, -99, 161,
+ -99, 162, -99, -99, -99, 163, 131, 164, 165, -99,
+ -99, -99, 99, -99, -99, -99, -99, -99, 166, -99,
+ -99, -99
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const short yypgoto[] =
+{
+ -99, -99, -99, 111, -99, -99, -99, -99, 178, -99,
+ -99, -99, -99, 91, -99, -99, -99, -99, -99, -99,
+ -99, -99, -99, -99, 115, -99, -99, -99, -99, -99,
+ -99, 146, 168, 89, 27, 0, 126, -1, -98, -48,
+ -63
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -68
+static const short yytable[] =
+{
+ 66, 67, 36, 42, 39, 40, 71, 41, 123, 124,
+ 43, 44, 74, 75, 120, 154, 72, 46, 47, 69,
+ 70, 121, 122, 48, 140, 45, 127, 128, 112, 130,
+ 49, 133, 156, 135, 158, 159, 68, 161, 60, 69,
+ 70, 165, 69, 70, 61, 167, 168, 62, 2, 3,
+ 63, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 46, 47, 13, 14, 139, 152, 48, 126, 178, 15,
+ 16, 69, 70, 49, 37, 38, 129, 166, 151, 15,
+ 16, -67, 114, 64, -67, 5, 101, 7, 8, 102,
+ 10, 11, 12, 143, 65, 13, 103, 153, 46, 47,
+ 147, 148, 149, 69, 70, 125, 172, 134, 141, 136,
+ 137, 138, 15, 16, 5, 101, 7, 8, 102, 10,
+ 11, 12, 145, 146, 13, 103, 101, 7, 142, 102,
+ 10, 11, 12, 171, 144, 13, 103, 69, 70, 69,
+ 70, 15, 16, 100, 150, 154, 113, 108, 113, 116,
+ 73, 157, 15, 16, 74, 75, 70, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 104, 107, 160, 115,
+ 85, 110, 73, 118, 86, 87, 74, 75, 92, 93,
+ 94, 95, 111, 96, 119, 162, 163, 164, 169, 170,
+ 173, 174, 97, 175, 176, 177, 179, 180, 181, 53,
+ 99, 59
+};
+
+static const unsigned char yycheck[] =
+{
+ 48, 49, 3, 32, 4, 5, 30, 7, 71, 72,
+ 10, 28, 16, 17, 33, 14, 40, 28, 29, 38,
+ 39, 69, 70, 34, 87, 28, 74, 75, 32, 77,
+ 41, 79, 130, 81, 132, 133, 32, 135, 39, 38,
+ 39, 139, 38, 39, 32, 143, 144, 32, 0, 1,
+ 32, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 28, 29, 14, 15, 28, 32, 34, 35, 166, 31,
+ 32, 38, 39, 41, 28, 29, 76, 140, 126, 31,
+ 32, 0, 1, 32, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 93, 32, 14, 15, 32, 28, 29,
+ 101, 102, 103, 38, 39, 32, 154, 80, 13, 82,
+ 83, 84, 31, 32, 4, 5, 6, 7, 8, 9,
+ 10, 11, 95, 96, 14, 15, 5, 6, 32, 8,
+ 9, 10, 11, 32, 28, 14, 15, 38, 39, 38,
+ 39, 31, 32, 54, 32, 14, 57, 56, 59, 58,
+ 12, 32, 31, 32, 16, 17, 39, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 55, 56, 32, 58,
+ 32, 56, 12, 58, 36, 37, 16, 17, 18, 19,
+ 20, 21, 56, 23, 58, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 21,
+ 54, 33
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 43, 0, 1, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 14, 15, 31, 32, 44, 45, 46,
+ 47, 48, 49, 52, 53, 55, 59, 61, 63, 64,
+ 66, 68, 69, 70, 71, 79, 79, 28, 29, 77,
+ 77, 77, 32, 77, 28, 28, 28, 29, 34, 41,
+ 81, 82, 50, 50, 56, 58, 62, 74, 67, 74,
+ 79, 32, 32, 32, 32, 32, 81, 81, 32, 38,
+ 39, 30, 40, 12, 16, 17, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 32, 36, 37, 51, 72,
+ 73, 75, 18, 19, 20, 21, 23, 32, 57, 73,
+ 75, 5, 8, 15, 45, 54, 78, 45, 55, 60,
+ 66, 78, 32, 75, 1, 45, 55, 65, 66, 78,
+ 33, 81, 81, 82, 82, 32, 35, 81, 81, 77,
+ 81, 76, 77, 81, 76, 81, 76, 76, 76, 28,
+ 82, 13, 32, 77, 28, 76, 76, 79, 79, 79,
+ 32, 81, 32, 32, 14, 80, 80, 32, 80, 80,
+ 32, 80, 32, 32, 32, 80, 82, 80, 80, 32,
+ 32, 32, 81, 32, 32, 32, 32, 32, 80, 32,
+ 32, 32
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrlab1
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ Current.first_line = Rhs[1].first_line; \
+ Current.first_column = Rhs[1].first_column; \
+ Current.last_line = Rhs[N].last_line; \
+ Current.last_column = Rhs[N].last_column;
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (cinluded). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short *bottom;
+ short *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylineno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylineno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+\f
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+\f
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+\f
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ register int yystate;
+ register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ short yyssa[YYINITDEPTH];
+ short *yyss = yyssa;
+ register short *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 8:
+
+ { zconfprint("unexpected 'endmenu' statement"); ;}
+ break;
+
+ case 9:
+
+ { zconfprint("unexpected 'endif' statement"); ;}
+ break;
+
+ case 10:
+
+ { zconfprint("unexpected 'endchoice' statement"); ;}
+ break;
+
+ case 11:
+
+ { zconfprint("syntax error"); yyerrok; ;}
+ break;
+
+ case 18:
+
+ {
+ struct symbol *sym = sym_lookup(yyvsp[-1].string, 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), yyvsp[-1].string);
+;}
+ break;
+
+ case 19:
+
+ {
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 20:
+
+ {
+ struct symbol *sym = sym_lookup(yyvsp[-1].string, 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), yyvsp[-1].string);
+;}
+ break;
+
+ case 21:
+
+ {
+ if (current_entry->prompt)
+ current_entry->prompt->type = P_MENU;
+ else
+ zconfprint("warning: menuconfig statement without prompt");
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 27:
+
+ {
+ menu_set_type(S_TRISTATE);
+ printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 28:
+
+ {
+ menu_add_expr(P_DEFAULT, yyvsp[-2].expr, yyvsp[-1].expr);
+ menu_set_type(S_TRISTATE);
+ printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 29:
+
+ {
+ menu_set_type(S_BOOLEAN);
+ printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 30:
+
+ {
+ menu_add_expr(P_DEFAULT, yyvsp[-2].expr, yyvsp[-1].expr);
+ menu_set_type(S_BOOLEAN);
+ printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 31:
+
+ {
+ menu_set_type(S_INT);
+ printd(DEBUG_PARSE, "%s:%d:int\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 32:
+
+ {
+ menu_set_type(S_HEX);
+ printd(DEBUG_PARSE, "%s:%d:hex\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 33:
+
+ {
+ menu_set_type(S_STRING);
+ printd(DEBUG_PARSE, "%s:%d:string\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 34:
+
+ {
+ menu_add_prompt(P_PROMPT, yyvsp[-2].string, yyvsp[-1].expr);
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 35:
+
+ {
+ menu_add_expr(P_DEFAULT, yyvsp[-2].expr, yyvsp[-1].expr);
+ printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 36:
+
+ {
+ menu_add_symbol(P_SELECT, sym_lookup(yyvsp[-2].string, 0), yyvsp[-1].expr);
+ printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 37:
+
+ {
+ menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,yyvsp[-3].symbol, yyvsp[-2].symbol), yyvsp[-1].expr);
+ printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 38:
+
+ {
+ struct symbol *sym = sym_lookup(NULL, 0);
+ sym->flags |= SYMBOL_CHOICE;
+ menu_add_entry(sym);
+ menu_add_expr(P_CHOICE, NULL, NULL);
+ printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 39:
+
+ {
+ menu_end_entry();
+ menu_add_menu();
+;}
+ break;
+
+ case 40:
+
+ {
+ if (zconf_endtoken(yyvsp[0].token, T_CHOICE, T_ENDCHOICE)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+ }
+;}
+ break;
+
+ case 42:
+
+ {
+ printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno);
+ zconfnerrs++;
+;}
+ break;
+
+ case 48:
+
+ {
+ menu_add_prompt(P_PROMPT, yyvsp[-2].string, yyvsp[-1].expr);
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 49:
+
+ {
+ menu_set_type(S_TRISTATE);
+ printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 50:
+
+ {
+ menu_set_type(S_BOOLEAN);
+ printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 51:
+
+ {
+ current_entry->sym->flags |= SYMBOL_OPTIONAL;
+ printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 52:
+
+ {
+ menu_add_symbol(P_DEFAULT, sym_lookup(yyvsp[-2].string, 0), yyvsp[-1].expr);
+ printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 55:
+
+ {
+ printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+ menu_add_entry(NULL);
+ menu_add_dep(yyvsp[-1].expr);
+ menu_end_entry();
+ menu_add_menu();
+;}
+ break;
+
+ case 56:
+
+ {
+ if (zconf_endtoken(yyvsp[0].token, T_IF, T_ENDIF)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+ }
+;}
+ break;
+
+ case 58:
+
+ {
+ printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno);
+ zconfnerrs++;
+;}
+ break;
+
+ case 63:
+
+ {
+ menu_add_entry(NULL);
+ menu_add_prop(P_MENU, yyvsp[-1].string, NULL, NULL);
+ printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 64:
+
+ {
+ menu_end_entry();
+ menu_add_menu();
+;}
+ break;
+
+ case 65:
+
+ {
+ if (zconf_endtoken(yyvsp[0].token, T_MENU, T_ENDMENU)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+ }
+;}
+ break;
+
+ case 67:
+
+ {
+ printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno);
+ zconfnerrs++;
+;}
+ break;
+
+ case 72:
+
+ { zconfprint("invalid menu option"); yyerrok; ;}
+ break;
+
+ case 73:
+
+ {
+ yyval.string = yyvsp[-1].string;
+ printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), yyvsp[-1].string);
+;}
+ break;
+
+ case 74:
+
+ {
+ zconf_nextfile(yyvsp[0].string);
+;}
+ break;
+
+ case 75:
+
+ {
+ menu_add_entry(NULL);
+ menu_add_prop(P_COMMENT, yyvsp[-1].string, NULL, NULL);
+ printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 76:
+
+ {
+ menu_end_entry();
+;}
+ break;
+
+ case 77:
+
+ {
+ printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+ zconf_starthelp();
+;}
+ break;
+
+ case 78:
+
+ {
+ current_entry->sym->help = yyvsp[0].string;
+;}
+ break;
+
+ case 82:
+
+ {
+ menu_add_dep(yyvsp[-1].expr);
+ printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 83:
+
+ {
+ menu_add_dep(yyvsp[-1].expr);
+ printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 84:
+
+ {
+ menu_add_dep(yyvsp[-1].expr);
+ printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 86:
+
+ {
+ menu_add_prop(P_PROMPT, yyvsp[-1].string, NULL, yyvsp[0].expr);
+;}
+ break;
+
+ case 89:
+
+ { yyval.token = T_ENDMENU; ;}
+ break;
+
+ case 90:
+
+ { yyval.token = T_ENDCHOICE; ;}
+ break;
+
+ case 91:
+
+ { yyval.token = T_ENDIF; ;}
+ break;
+
+ case 94:
+
+ { yyval.expr = NULL; ;}
+ break;
+
+ case 95:
+
+ { yyval.expr = yyvsp[0].expr; ;}
+ break;
+
+ case 96:
+
+ { yyval.expr = expr_alloc_symbol(yyvsp[0].symbol); ;}
+ break;
+
+ case 97:
+
+ { yyval.expr = expr_alloc_comp(E_EQUAL, yyvsp[-2].symbol, yyvsp[0].symbol); ;}
+ break;
+
+ case 98:
+
+ { yyval.expr = expr_alloc_comp(E_UNEQUAL, yyvsp[-2].symbol, yyvsp[0].symbol); ;}
+ break;
+
+ case 99:
+
+ { yyval.expr = yyvsp[-1].expr; ;}
+ break;
+
+ case 100:
+
+ { yyval.expr = expr_alloc_one(E_NOT, yyvsp[0].expr); ;}
+ break;
+
+ case 101:
+
+ { yyval.expr = expr_alloc_two(E_OR, yyvsp[-2].expr, yyvsp[0].expr); ;}
+ break;
+
+ case 102:
+
+ { yyval.expr = expr_alloc_two(E_AND, yyvsp[-2].expr, yyvsp[0].expr); ;}
+ break;
+
+ case 103:
+
+ { yyval.symbol = sym_lookup(yyvsp[0].string, 0); free(yyvsp[0].string); ;}
+ break;
+
+ case 104:
+
+ { yyval.symbol = sym_lookup(yyvsp[0].string, 1); free(yyvsp[0].string); ;}
+ break;
+
+
+ }
+
+/* Line 999 of yacc.c. */
+
+\f
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ char *yymsg;
+ int yyx, yycount;
+
+ yycount = 0;
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+ yysize += yystrlen ("syntax error, unexpected ") + 1;
+ yysize += yystrlen (yytname[yytype]);
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
+ {
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
+
+ if (yycount < 5)
+ {
+ yycount = 0;
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *));
+ yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ const char *yyq = ! yycount ? ", expecting " : " or ";
+ yyp = yystpcpy (yyp, yyq);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yycount++;
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ yyerror ("syntax error; also virtual memory exhausted");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("syntax error");
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ {
+ /* Pop the error token. */
+ YYPOPSTACK;
+ /* Pop the rest of the stack. */
+ while (yyss < yyssp)
+ {
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ YYPOPSTACK;
+ }
+ YYABORT;
+ }
+
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
+ yychar = YYEMPTY;
+
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*----------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action. |
+`----------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ yyvsp--;
+ yystate = *--yyssp;
+
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+
+
+
+void conf_parse(const char *name)
+{
+ struct symbol *sym;
+ int i;
+
+ zconf_initscan(name);
+
+ sym_init();
+ menu_init();
+ modules_sym = sym_lookup("MODULES", 0);
+ rootmenu.prompt = menu_add_prop(P_MENU, "axTLS Configuration", NULL, NULL);
+
+ //zconfdebug = 1;
+ zconfparse();
+ if (zconfnerrs)
+ exit(1);
+ menu_finalize(&rootmenu);
+ for_all_symbols(i, sym) {
+ if (!(sym->flags & SYMBOL_CHECKED) && sym_check_deps(sym))
+ printf("\n");
+ else
+ sym->flags |= SYMBOL_CHECK_DONE;
+ }
+
+ sym_change_count = 1;
+}
+
+const char *zconf_tokenname(int token)
+{
+ switch (token) {
+ case T_MENU: return "menu";
+ case T_ENDMENU: return "endmenu";
+ case T_CHOICE: return "choice";
+ case T_ENDCHOICE: return "endchoice";
+ case T_IF: return "if";
+ case T_ENDIF: return "endif";
+ }
+ return "<token>";
+}
+
+static bool zconf_endtoken(int token, int starttoken, int endtoken)
+{
+ if (token != endtoken) {
+ zconfprint("unexpected '%s' within %s block", zconf_tokenname(token), zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ if (current_menu->file != current_file) {
+ zconfprint("'%s' in different file than '%s'", zconf_tokenname(token), zconf_tokenname(starttoken));
+ zconfprint("location of the '%s'", zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno() + 1);
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+ fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+}
+
+void print_quoted_string(FILE *out, const char *str)
+{
+ const char *p;
+ int len;
+
+ putc('"', out);
+ while ((p = strchr(str, '"'))) {
+ len = p - str;
+ if (len)
+ fprintf(out, "%.*s", len, str);
+ fputs("\\\"", out);
+ str = p + 1;
+ }
+ fputs(str, out);
+ putc('"', out);
+}
+
+void print_symbol(FILE *out, struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ struct property *prop;
+
+ if (sym_is_choice(sym))
+ fprintf(out, "choice\n");
+ else
+ fprintf(out, "config %s\n", sym->name);
+ switch (sym->type) {
+ case S_BOOLEAN:
+ fputs(" boolean\n", out);
+ break;
+ case S_TRISTATE:
+ fputs(" tristate\n", out);
+ break;
+ case S_STRING:
+ fputs(" string\n", out);
+ break;
+ case S_INT:
+ fputs(" integer\n", out);
+ break;
+ case S_HEX:
+ fputs(" hex\n", out);
+ break;
+ default:
+ fputs(" ???\n", out);
+ break;
+ }
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ switch (prop->type) {
+ case P_PROMPT:
+ fputs(" prompt ", out);
+ print_quoted_string(out, prop->text);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_DEFAULT:
+ fputs( " default ", out);
+ expr_fprint(prop->expr, out);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_CHOICE:
+ fputs(" #choice value\n", out);
+ break;
+ default:
+ fprintf(out, " unknown prop %d!\n", prop->type);
+ break;
+ }
+ }
+ if (sym->help) {
+ int len = strlen(sym->help);
+ while (sym->help[--len] == '\n')
+ sym->help[len] = 0;
+ fprintf(out, " help\n%s\n", sym->help);
+ }
+ fputc('\n', out);
+}
+
+void zconfdump(FILE *out)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct menu *menu;
+
+ menu = rootmenu.list;
+ while (menu) {
+ if ((sym = menu->sym))
+ print_symbol(out, menu);
+ else if ((prop = menu->prompt)) {
+ switch (prop->type) {
+ case P_COMMENT:
+ fputs("\ncomment ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ case P_MENU:
+ fputs("\nmenu ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ default:
+ ;
+ }
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" depends ", out);
+ expr_fprint(prop->visible.expr, out);
+ fputc('\n', out);
+ }
+ fputs("\n", out);
+ }
+
+ if (menu->list)
+ menu = menu->list;
+ else if (menu->next)
+ menu = menu->next;
+ else while ((menu = menu->parent)) {
+ if (menu->prompt && menu->prompt->type == P_MENU)
+ fputs("\nendmenu\n", out);
+ if (menu->next) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
+
+
--- /dev/null
+/* A Bison parser, made from zconf.y, by GNU bison 1.75. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+#ifndef BISON_ZCONF_TAB_H
+# define BISON_ZCONF_TAB_H
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ T_MAINMENU = 258,
+ T_MENU = 259,
+ T_ENDMENU = 260,
+ T_SOURCE = 261,
+ T_CHOICE = 262,
+ T_ENDCHOICE = 263,
+ T_COMMENT = 264,
+ T_CONFIG = 265,
+ T_HELP = 266,
+ T_HELPTEXT = 267,
+ T_IF = 268,
+ T_ENDIF = 269,
+ T_DEPENDS = 270,
+ T_REQUIRES = 271,
+ T_OPTIONAL = 272,
+ T_PROMPT = 273,
+ T_DEFAULT = 274,
+ T_TRISTATE = 275,
+ T_BOOLEAN = 276,
+ T_INT = 277,
+ T_HEX = 278,
+ T_WORD = 279,
+ T_STRING = 280,
+ T_UNEQUAL = 281,
+ T_EOF = 282,
+ T_EOL = 283,
+ T_CLOSE_PAREN = 284,
+ T_OPEN_PAREN = 285,
+ T_ON = 286,
+ T_OR = 287,
+ T_AND = 288,
+ T_EQUAL = 289,
+ T_NOT = 290
+ };
+#endif
+#define T_MAINMENU 258
+#define T_MENU 259
+#define T_ENDMENU 260
+#define T_SOURCE 261
+#define T_CHOICE 262
+#define T_ENDCHOICE 263
+#define T_COMMENT 264
+#define T_CONFIG 265
+#define T_HELP 266
+#define T_HELPTEXT 267
+#define T_IF 268
+#define T_ENDIF 269
+#define T_DEPENDS 270
+#define T_REQUIRES 271
+#define T_OPTIONAL 272
+#define T_PROMPT 273
+#define T_DEFAULT 274
+#define T_TRISTATE 275
+#define T_BOOLEAN 276
+#define T_INT 277
+#define T_HEX 278
+#define T_WORD 279
+#define T_STRING 280
+#define T_UNEQUAL 281
+#define T_EOF 282
+#define T_EOL 283
+#define T_CLOSE_PAREN 284
+#define T_OPEN_PAREN 285
+#define T_ON 286
+#define T_OR 287
+#define T_AND 288
+#define T_EQUAL 289
+#define T_NOT 290
+
+
+
+
+#ifndef YYSTYPE
+#line 33 "zconf.y"
+typedef union {
+ int token;
+ char *string;
+ struct symbol *symbol;
+ struct expr *expr;
+ struct menu *menu;
+} yystype;
+/* Line 1281 of /usr/share/bison/yacc.c. */
+#line 118 "zconf.tab.h"
+# define YYSTYPE yystype
+#endif
+
+extern YYSTYPE zconflval;
+
+
+#endif /* not BISON_ZCONF_TAB_H */
+
--- /dev/null
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD 0x0001
+#define DEBUG_PARSE 0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(int token, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[257];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYERROR_VERBOSE
+%}
+%expect 40
+
+%union
+{
+ int token;
+ char *string;
+ struct symbol *symbol;
+ struct expr *expr;
+ struct menu *menu;
+}
+
+%token T_MAINMENU
+%token T_MENU
+%token T_ENDMENU
+%token T_SOURCE
+%token T_CHOICE
+%token T_ENDCHOICE
+%token T_COMMENT
+%token T_CONFIG
+%token T_MENUCONFIG
+%token T_HELP
+%token <string> T_HELPTEXT
+%token T_IF
+%token T_ENDIF
+%token T_DEPENDS
+%token T_REQUIRES
+%token T_OPTIONAL
+%token T_PROMPT
+%token T_DEFAULT
+%token T_TRISTATE
+%token T_DEF_TRISTATE
+%token T_BOOLEAN
+%token T_DEF_BOOLEAN
+%token T_STRING
+%token T_INT
+%token T_HEX
+%token <string> T_WORD
+%token <string> T_WORD_QUOTE
+%token T_UNEQUAL
+%token T_EOF
+%token T_EOL
+%token T_CLOSE_PAREN
+%token T_OPEN_PAREN
+%token T_ON
+%token T_SELECT
+%token T_RANGE
+
+%left T_OR
+%left T_AND
+%left T_EQUAL T_UNEQUAL
+%nonassoc T_NOT
+
+%type <string> prompt
+%type <string> source
+%type <symbol> symbol
+%type <expr> expr
+%type <expr> if_expr
+%type <token> end
+
+%{
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+%}
+%%
+input: /* empty */
+ | input block
+;
+
+block: common_block
+ | choice_stmt
+ | menu_stmt
+ | T_MAINMENU prompt nl_or_eof
+ | T_ENDMENU { zconfprint("unexpected 'endmenu' statement"); }
+ | T_ENDIF { zconfprint("unexpected 'endif' statement"); }
+ | T_ENDCHOICE { zconfprint("unexpected 'endchoice' statement"); }
+ | error nl_or_eof { zconfprint("syntax error"); yyerrok; }
+;
+
+common_block:
+ if_stmt
+ | comment_stmt
+ | config_stmt
+ | menuconfig_stmt
+ | source_stmt
+ | nl_or_eof
+;
+
+
+/* config/menuconfig entry */
+
+config_entry_start: T_CONFIG T_WORD T_EOL
+{
+ struct symbol *sym = sym_lookup($2, 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+config_stmt: config_entry_start config_option_list
+{
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
+{
+ struct symbol *sym = sym_lookup($2, 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+menuconfig_stmt: menuconfig_entry_start config_option_list
+{
+ if (current_entry->prompt)
+ current_entry->prompt->type = P_MENU;
+ else
+ zconfprint("warning: menuconfig statement without prompt");
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+config_option_list:
+ /* empty */
+ | config_option_list config_option
+ | config_option_list depends
+ | config_option_list help
+ | config_option_list T_EOL
+;
+
+config_option: T_TRISTATE prompt_stmt_opt T_EOL
+{
+ menu_set_type(S_TRISTATE);
+ printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_DEF_TRISTATE expr if_expr T_EOL
+{
+ menu_add_expr(P_DEFAULT, $2, $3);
+ menu_set_type(S_TRISTATE);
+ printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_BOOLEAN prompt_stmt_opt T_EOL
+{
+ menu_set_type(S_BOOLEAN);
+ printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_DEF_BOOLEAN expr if_expr T_EOL
+{
+ menu_add_expr(P_DEFAULT, $2, $3);
+ menu_set_type(S_BOOLEAN);
+ printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_INT prompt_stmt_opt T_EOL
+{
+ menu_set_type(S_INT);
+ printd(DEBUG_PARSE, "%s:%d:int\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_HEX prompt_stmt_opt T_EOL
+{
+ menu_set_type(S_HEX);
+ printd(DEBUG_PARSE, "%s:%d:hex\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_STRING prompt_stmt_opt T_EOL
+{
+ menu_set_type(S_STRING);
+ printd(DEBUG_PARSE, "%s:%d:string\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_PROMPT prompt if_expr T_EOL
+{
+ menu_add_prompt(P_PROMPT, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_DEFAULT expr if_expr T_EOL
+{
+ menu_add_expr(P_DEFAULT, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_SELECT T_WORD if_expr T_EOL
+{
+ menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
+ printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_RANGE symbol symbol if_expr T_EOL
+{
+ menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
+ printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+};
+
+/* choice entry */
+
+choice: T_CHOICE T_EOL
+{
+ struct symbol *sym = sym_lookup(NULL, 0);
+ sym->flags |= SYMBOL_CHOICE;
+ menu_add_entry(sym);
+ menu_add_expr(P_CHOICE, NULL, NULL);
+ printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+};
+
+choice_entry: choice choice_option_list
+{
+ menu_end_entry();
+ menu_add_menu();
+};
+
+choice_end: end
+{
+ if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+ }
+};
+
+choice_stmt:
+ choice_entry choice_block choice_end
+ | choice_entry choice_block
+{
+ printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno);
+ zconfnerrs++;
+};
+
+choice_option_list:
+ /* empty */
+ | choice_option_list choice_option
+ | choice_option_list depends
+ | choice_option_list help
+ | choice_option_list T_EOL
+;
+
+choice_option: T_PROMPT prompt if_expr T_EOL
+{
+ menu_add_prompt(P_PROMPT, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_TRISTATE prompt_stmt_opt T_EOL
+{
+ menu_set_type(S_TRISTATE);
+ printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_BOOLEAN prompt_stmt_opt T_EOL
+{
+ menu_set_type(S_BOOLEAN);
+ printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_OPTIONAL T_EOL
+{
+ current_entry->sym->flags |= SYMBOL_OPTIONAL;
+ printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_DEFAULT T_WORD if_expr T_EOL
+{
+ menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
+ printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
+};
+
+choice_block:
+ /* empty */
+ | choice_block common_block
+;
+
+/* if entry */
+
+if: T_IF expr T_EOL
+{
+ printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+ menu_add_entry(NULL);
+ menu_add_dep($2);
+ menu_end_entry();
+ menu_add_menu();
+};
+
+if_end: end
+{
+ if (zconf_endtoken($1, T_IF, T_ENDIF)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+ }
+};
+
+if_stmt:
+ if if_block if_end
+ | if if_block
+{
+ printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno);
+ zconfnerrs++;
+};
+
+if_block:
+ /* empty */
+ | if_block common_block
+ | if_block menu_stmt
+ | if_block choice_stmt
+;
+
+/* menu entry */
+
+menu: T_MENU prompt T_EOL
+{
+ menu_add_entry(NULL);
+ menu_add_prop(P_MENU, $2, NULL, NULL);
+ printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+};
+
+menu_entry: menu depends_list
+{
+ menu_end_entry();
+ menu_add_menu();
+};
+
+menu_end: end
+{
+ if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+ }
+};
+
+menu_stmt:
+ menu_entry menu_block menu_end
+ | menu_entry menu_block
+{
+ printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno);
+ zconfnerrs++;
+};
+
+menu_block:
+ /* empty */
+ | menu_block common_block
+ | menu_block menu_stmt
+ | menu_block choice_stmt
+ | menu_block error T_EOL { zconfprint("invalid menu option"); yyerrok; }
+;
+
+source: T_SOURCE prompt T_EOL
+{
+ $$ = $2;
+ printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+source_stmt: source
+{
+ zconf_nextfile($1);
+};
+
+/* comment entry */
+
+comment: T_COMMENT prompt T_EOL
+{
+ menu_add_entry(NULL);
+ menu_add_prop(P_COMMENT, $2, NULL, NULL);
+ printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+};
+
+comment_stmt: comment depends_list
+{
+ menu_end_entry();
+};
+
+/* help option */
+
+help_start: T_HELP T_EOL
+{
+ printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+ zconf_starthelp();
+};
+
+help: help_start T_HELPTEXT
+{
+ current_entry->sym->help = $2;
+};
+
+/* depends option */
+
+depends_list: /* empty */
+ | depends_list depends
+ | depends_list T_EOL
+;
+
+depends: T_DEPENDS T_ON expr T_EOL
+{
+ menu_add_dep($3);
+ printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+}
+ | T_DEPENDS expr T_EOL
+{
+ menu_add_dep($2);
+ printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno());
+}
+ | T_REQUIRES expr T_EOL
+{
+ menu_add_dep($2);
+ printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno());
+};
+
+/* prompt statement */
+
+prompt_stmt_opt:
+ /* empty */
+ | prompt if_expr
+{
+ menu_add_prop(P_PROMPT, $1, NULL, $2);
+};
+
+prompt: T_WORD
+ | T_WORD_QUOTE
+;
+
+end: T_ENDMENU nl_or_eof { $$ = T_ENDMENU; }
+ | T_ENDCHOICE nl_or_eof { $$ = T_ENDCHOICE; }
+ | T_ENDIF nl_or_eof { $$ = T_ENDIF; }
+;
+
+nl_or_eof:
+ T_EOL | T_EOF;
+
+if_expr: /* empty */ { $$ = NULL; }
+ | T_IF expr { $$ = $2; }
+;
+
+expr: symbol { $$ = expr_alloc_symbol($1); }
+ | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
+ | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
+ | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; }
+ | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); }
+ | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); }
+ | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); }
+;
+
+symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); }
+ | T_WORD_QUOTE { $$ = sym_lookup($1, 1); free($1); }
+;
+
+%%
+
+void conf_parse(const char *name)
+{
+ struct symbol *sym;
+ int i;
+
+ zconf_initscan(name);
+
+ sym_init();
+ menu_init();
+ modules_sym = sym_lookup("MODULES", 0);
+ rootmenu.prompt = menu_add_prop(P_MENU, "axTLS Configuration", NULL, NULL);
+
+ //zconfdebug = 1;
+ zconfparse();
+ if (zconfnerrs)
+ exit(1);
+ menu_finalize(&rootmenu);
+ for_all_symbols(i, sym) {
+ if (!(sym->flags & SYMBOL_CHECKED) && sym_check_deps(sym))
+ printf("\n");
+ else
+ sym->flags |= SYMBOL_CHECK_DONE;
+ }
+
+ sym_change_count = 1;
+}
+
+const char *zconf_tokenname(int token)
+{
+ switch (token) {
+ case T_MENU: return "menu";
+ case T_ENDMENU: return "endmenu";
+ case T_CHOICE: return "choice";
+ case T_ENDCHOICE: return "endchoice";
+ case T_IF: return "if";
+ case T_ENDIF: return "endif";
+ }
+ return "<token>";
+}
+
+static bool zconf_endtoken(int token, int starttoken, int endtoken)
+{
+ if (token != endtoken) {
+ zconfprint("unexpected '%s' within %s block", zconf_tokenname(token), zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ if (current_menu->file != current_file) {
+ zconfprint("'%s' in different file than '%s'", zconf_tokenname(token), zconf_tokenname(starttoken));
+ zconfprint("location of the '%s'", zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno() + 1);
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+ fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+}
+
+void print_quoted_string(FILE *out, const char *str)
+{
+ const char *p;
+ int len;
+
+ putc('"', out);
+ while ((p = strchr(str, '"'))) {
+ len = p - str;
+ if (len)
+ fprintf(out, "%.*s", len, str);
+ fputs("\\\"", out);
+ str = p + 1;
+ }
+ fputs(str, out);
+ putc('"', out);
+}
+
+void print_symbol(FILE *out, struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ struct property *prop;
+
+ if (sym_is_choice(sym))
+ fprintf(out, "choice\n");
+ else
+ fprintf(out, "config %s\n", sym->name);
+ switch (sym->type) {
+ case S_BOOLEAN:
+ fputs(" boolean\n", out);
+ break;
+ case S_TRISTATE:
+ fputs(" tristate\n", out);
+ break;
+ case S_STRING:
+ fputs(" string\n", out);
+ break;
+ case S_INT:
+ fputs(" integer\n", out);
+ break;
+ case S_HEX:
+ fputs(" hex\n", out);
+ break;
+ default:
+ fputs(" ???\n", out);
+ break;
+ }
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ switch (prop->type) {
+ case P_PROMPT:
+ fputs(" prompt ", out);
+ print_quoted_string(out, prop->text);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_DEFAULT:
+ fputs( " default ", out);
+ expr_fprint(prop->expr, out);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_CHOICE:
+ fputs(" #choice value\n", out);
+ break;
+ default:
+ fprintf(out, " unknown prop %d!\n", prop->type);
+ break;
+ }
+ }
+ if (sym->help) {
+ int len = strlen(sym->help);
+ while (sym->help[--len] == '\n')
+ sym->help[len] = 0;
+ fprintf(out, " help\n%s\n", sym->help);
+ }
+ fputc('\n', out);
+}
+
+void zconfdump(FILE *out)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct menu *menu;
+
+ menu = rootmenu.list;
+ while (menu) {
+ if ((sym = menu->sym))
+ print_symbol(out, menu);
+ else if ((prop = menu->prompt)) {
+ switch (prop->type) {
+ case P_COMMENT:
+ fputs("\ncomment ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ case P_MENU:
+ fputs("\nmenu ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ default:
+ ;
+ }
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" depends ", out);
+ expr_fprint(prop->visible.expr, out);
+ fputc('\n', out);
+ }
+ fputs("\n", out);
+ }
+
+ if (menu->list)
+ menu = menu->list;
+ else if (menu->next)
+ menu = menu->next;
+ else while ((menu = menu->parent)) {
+ if (menu->prompt && menu->prompt->type == P_MENU)
+ fputs("\nendmenu\n", out);
+ if (menu->next) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
--- /dev/null
+#
+# Automatically generated make config: don't edit
+#
+HAVE_DOT_CONFIG=y
+# CONFIG_PLATFORM_LINUX is not set
+# CONFIG_PLATFORM_CYGWIN is not set
+# CONFIG_PLATFORM_SOLARIS is not set
+CONFIG_PLATFORM_WIN32=y
+
+#
+# General Configuration
+#
+PREFIX=""
+# CONFIG_DEBUG is not set
+# CONFIG_STRIP_UNWANTED_SECTIONS is not set
+
+#
+# Microsoft Compiler Options
+#
+# CONFIG_VISUAL_STUDIO_7_0 is not set
+CONFIG_VISUAL_STUDIO_8_0=y
+CONFIG_VISUAL_STUDIO_7_0_BASE=""
+CONFIG_VISUAL_STUDIO_8_0_BASE="c:\\Program Files\\Microsoft Visual Studio 8"
+CONFIG_EXTRA_CFLAGS_OPTIONS=""
+CONFIG_EXTRA_LDFLAGS_OPTIONS=""
+
+#
+# SSL Library
+#
+# CONFIG_SSL_SERVER_ONLY is not set
+# CONFIG_SSL_CERT_VERIFICATION is not set
+# CONFIG_SSL_ENABLE_CLIENT is not set
+CONFIG_SSL_FULL_MODE=y
+# CONFIG_SSL_SKELETON_MODE is not set
+# CONFIG_SSL_PROT_LOW is not set
+CONFIG_SSL_PROT_MEDIUM=y
+# CONFIG_SSL_PROT_HIGH is not set
+CONFIG_SSL_USE_DEFAULT_KEY=y
+CONFIG_SSL_PRIVATE_KEY_LOCATION=""
+CONFIG_SSL_PRIVATE_KEY_PASSWORD=""
+CONFIG_SSL_X509_CERT_LOCATION=""
+CONFIG_SSL_GENERATE_X509_CERT=y
+CONFIG_SSL_X509_COMMON_NAME=""
+CONFIG_SSL_X509_ORGANIZATION_NAME=""
+CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME=""
+CONFIG_SSL_ENABLE_V23_HANDSHAKE=y
+CONFIG_SSL_HAS_PEM=y
+CONFIG_SSL_USE_PKCS12=y
+CONFIG_SSL_EXPIRY_TIME=24
+CONFIG_X509_MAX_CA_CERTS=4
+CONFIG_SSL_MAX_CERTS=2
+# CONFIG_SSL_CTX_MUTEXING is not set
+# CONFIG_USE_DEV_URANDOM is not set
+CONFIG_WIN32_USE_CRYPTO_LIB=y
+# CONFIG_OPENSSL_COMPATIBLE is not set
+# CONFIG_PERFORMANCE_TESTING is not set
+# CONFIG_SSL_TEST is not set
+CONFIG_AXHTTPD=y
+
+#
+# Axhttpd Configuration
+#
+# CONFIG_HTTP_STATIC_BUILD is not set
+CONFIG_HTTP_PORT=80
+CONFIG_HTTP_HTTPS_PORT=443
+CONFIG_HTTP_SESSION_CACHE_SIZE=5
+CONFIG_HTTP_WEBROOT="www"
+CONFIG_HTTP_TIMEOUT=300
+# CONFIG_HTTP_HAS_CGI is not set
+CONFIG_HTTP_CGI_EXTENSIONS=""
+# CONFIG_HTTP_ENABLE_LUA is not set
+CONFIG_HTTP_LUA_PREFIX=""
+CONFIG_HTTP_LUA_CGI_LAUNCHER=""
+# CONFIG_HTTP_BUILD_LUA is not set
+CONFIG_HTTP_DIRECTORIES=y
+CONFIG_HTTP_HAS_AUTHORIZATION=y
+# CONFIG_HTTP_HAS_IPV6 is not set
+CONFIG_HTTP_VERBOSE=y
+# CONFIG_HTTP_IS_DAEMON is not set
+
+#
+# Language Bindings
+#
+# CONFIG_BINDINGS is not set
+# CONFIG_CSHARP_BINDINGS is not set
+# CONFIG_VBNET_BINDINGS is not set
+CONFIG_DOT_NET_FRAMEWORK_BASE=""
+# CONFIG_JAVA_BINDINGS is not set
+CONFIG_JAVA_HOME=""
+# CONFIG_PERL_BINDINGS is not set
+CONFIG_PERL_CORE=""
+CONFIG_PERL_LIB=""
+# CONFIG_LUA_BINDINGS is not set
+CONFIG_LUA_CORE=""
+
+#
+# Samples
+#
+CONFIG_SAMPLES=y
+CONFIG_C_SAMPLES=y
+# CONFIG_CSHARP_SAMPLES is not set
+# CONFIG_VBNET_SAMPLES is not set
+# CONFIG_JAVA_SAMPLES is not set
+# CONFIG_PERL_SAMPLES is not set
+# CONFIG_LUA_SAMPLES is not set
+
+#
+# BigInt Options
+#
+# CONFIG_BIGINT_CLASSICAL is not set
+# CONFIG_BIGINT_MONTGOMERY is not set
+CONFIG_BIGINT_BARRETT=y
+CONFIG_BIGINT_CRT=y
+# CONFIG_BIGINT_KARATSUBA is not set
+MUL_KARATSUBA_THRESH=0
+SQU_KARATSUBA_THRESH=0
+CONFIG_BIGINT_SLIDING_WINDOW=y
+CONFIG_BIGINT_SQUARE=y
+# CONFIG_BIGINT_CHECK_ON is not set
--- /dev/null
+aes.o: aes.c crypto.h ../config/config.h ../ssl/os_port.h bigint_impl.h \
+ bigint.h
+bigint.o: bigint.c bigint.h crypto.h ../config/config.h ../ssl/os_port.h \
+ bigint_impl.h
+crypto_misc.o: crypto_misc.c ../ssl/crypto_misc.h ../crypto/crypto.h \
+ ../config/config.h ../ssl/os_port.h ../crypto/bigint_impl.h \
+ ../crypto/bigint.h ../crypto/crypto.h ../crypto/bigint.h
+hmac.o: hmac.c crypto.h ../config/config.h ../ssl/os_port.h bigint_impl.h \
+ bigint.h
+md2.o: md2.c crypto.h ../config/config.h ../ssl/os_port.h bigint_impl.h \
+ bigint.h
+md5.o: md5.c crypto.h ../config/config.h ../ssl/os_port.h bigint_impl.h \
+ bigint.h
+rc4.o: rc4.c crypto.h ../config/config.h ../ssl/os_port.h bigint_impl.h \
+ bigint.h
+rsa.o: rsa.c crypto.h ../config/config.h ../ssl/os_port.h bigint_impl.h \
+ bigint.h
+sha1.o: sha1.c crypto.h ../config/config.h ../ssl/os_port.h bigint_impl.h \
+ bigint.h
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+include ../config/.config
+include ../config/makefile.conf
+
+AXTLS_HOME=..
+
+OBJ=\
+ aes.o \
+ bigint.o \
+ crypto_misc.o \
+ hmac.o \
+ md2.o \
+ md5.o \
+ rc4.o \
+ rsa.o \
+ sha1.o
+
+include ../config/makefile.post
+
+all: $(OBJ)
+
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * AES implementation - this is a small code version. There are much faster
+ * versions around but they are much larger in size (i.e. they use large
+ * submix tables).
+ */
+
+#include <string.h>
+#include "crypto.h"
+
+/* all commented out in skeleton mode */
+#ifndef CONFIG_SSL_SKELETON_MODE
+
+#define rot1(x) (((x) << 24) | ((x) >> 8))
+#define rot2(x) (((x) << 16) | ((x) >> 16))
+#define rot3(x) (((x) << 8) | ((x) >> 24))
+
+/*
+ * This cute trick does 4 'mul by two' at once. Stolen from
+ * Dr B. R. Gladman <brg@gladman.uk.net> but I'm sure the u-(u>>7) is
+ * a standard graphics trick
+ * The key to this is that we need to xor with 0x1b if the top bit is set.
+ * a 1xxx xxxx 0xxx 0xxx First we mask the 7bit,
+ * b 1000 0000 0000 0000 then we shift right by 7 putting the 7bit in 0bit,
+ * c 0000 0001 0000 0000 we then subtract (c) from (b)
+ * d 0111 1111 0000 0000 and now we and with our mask
+ * e 0001 1011 0000 0000
+ */
+#define mt 0x80808080
+#define ml 0x7f7f7f7f
+#define mh 0xfefefefe
+#define mm 0x1b1b1b1b
+#define mul2(x,t) ((t)=((x)&mt), \
+ ((((x)+(x))&mh)^(((t)-((t)>>7))&mm)))
+
+#define inv_mix_col(x,f2,f4,f8,f9) (\
+ (f2)=mul2(x,f2), \
+ (f4)=mul2(f2,f4), \
+ (f8)=mul2(f4,f8), \
+ (f9)=(x)^(f8), \
+ (f8)=((f2)^(f4)^(f8)), \
+ (f2)^=(f9), \
+ (f4)^=(f9), \
+ (f8)^=rot3(f2), \
+ (f8)^=rot2(f4), \
+ (f8)^rot1(f9))
+
+/*
+ * AES S-box
+ */
+static const uint8_t aes_sbox[256] =
+{
+ 0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,
+ 0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76,
+ 0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,
+ 0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0,
+ 0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,
+ 0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15,
+ 0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,
+ 0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75,
+ 0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,
+ 0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84,
+ 0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,
+ 0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF,
+ 0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,
+ 0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8,
+ 0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,
+ 0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2,
+ 0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,
+ 0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73,
+ 0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,
+ 0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB,
+ 0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,
+ 0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79,
+ 0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,
+ 0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08,
+ 0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,
+ 0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A,
+ 0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,
+ 0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E,
+ 0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,
+ 0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF,
+ 0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,
+ 0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16,
+};
+
+/*
+ * AES is-box
+ */
+static const uint8_t aes_isbox[256] =
+{
+ 0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,
+ 0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
+ 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,
+ 0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
+ 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,
+ 0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
+ 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,
+ 0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
+ 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,
+ 0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
+ 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,
+ 0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
+ 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,
+ 0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
+ 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,
+ 0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
+ 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,
+ 0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
+ 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,
+ 0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
+ 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,
+ 0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
+ 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,
+ 0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
+ 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,
+ 0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
+ 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,
+ 0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
+ 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,
+ 0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
+ 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,
+ 0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d
+};
+
+static const unsigned char Rcon[30]=
+{
+ 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
+ 0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,
+ 0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,
+ 0xb3,0x7d,0xfa,0xef,0xc5,0x91,
+};
+
+/* ----- static functions ----- */
+static void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
+static void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
+
+/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial
+ x^8+x^4+x^3+x+1 */
+static unsigned char AES_xtime(uint32_t x)
+{
+ return x = (x&0x80) ? (x<<1)^0x1b : x<<1;
+}
+
+/**
+ * Set up AES with the key/iv and cipher size.
+ */
+void AES_set_key(AES_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, AES_MODE mode)
+{
+ int i, ii;
+ uint32_t *W, tmp, tmp2;
+ const unsigned char *ip;
+ int words;
+
+ switch (mode)
+ {
+ case AES_MODE_128:
+ i = 10;
+ words = 4;
+ break;
+
+ case AES_MODE_256:
+ i = 14;
+ words = 8;
+ break;
+
+ default: /* fail silently */
+ return;
+ }
+
+ ctx->rounds = i;
+ ctx->key_size = words;
+ W = ctx->ks;
+ for (i = 0; i < words; i+=2)
+ {
+ W[i+0]= ((uint32_t)key[ 0]<<24)|
+ ((uint32_t)key[ 1]<<16)|
+ ((uint32_t)key[ 2]<< 8)|
+ ((uint32_t)key[ 3] );
+ W[i+1]= ((uint32_t)key[ 4]<<24)|
+ ((uint32_t)key[ 5]<<16)|
+ ((uint32_t)key[ 6]<< 8)|
+ ((uint32_t)key[ 7] );
+ key += 8;
+ }
+
+ ip = Rcon;
+ ii = 4 * (ctx->rounds+1);
+ for (i = words; i<ii; i++)
+ {
+ tmp = W[i-1];
+
+ if ((i % words) == 0)
+ {
+ tmp2 =(uint32_t)aes_sbox[(tmp )&0xff]<< 8;
+ tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<<16;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<24;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>24) ];
+ tmp=tmp2^(((unsigned int)*ip)<<24);
+ ip++;
+ }
+
+ if ((words == 8) && ((i % words) == 4))
+ {
+ tmp2 =(uint32_t)aes_sbox[(tmp )&0xff] ;
+ tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<< 8;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<16;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>24) ]<<24;
+ tmp=tmp2;
+ }
+
+ W[i]=W[i-words]^tmp;
+ }
+
+ /* copy the iv across */
+ memcpy(ctx->iv, iv, 16);
+}
+
+/**
+ * Change a key for decryption.
+ */
+void AES_convert_key(AES_CTX *ctx)
+{
+ int i;
+ uint32_t *k,w,t1,t2,t3,t4;
+
+ k = ctx->ks;
+ k += 4;
+
+ for (i= ctx->rounds*4; i > 4; i--)
+ {
+ w= *k;
+ w = inv_mix_col(w,t1,t2,t3,t4);
+ *k++ =w;
+ }
+}
+
+/**
+ * Encrypt a byte sequence (with a block size 16) using the AES cipher.
+ */
+void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+ int i;
+ uint32_t tin[4], tout[4], iv[4];
+
+ memcpy(iv, ctx->iv, AES_IV_SIZE);
+ for (i = 0; i < 4; i++)
+ tout[i] = ntohl(iv[i]);
+
+ for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE)
+ {
+ uint32_t msg_32[4];
+ uint32_t out_32[4];
+ memcpy(msg_32, msg, AES_BLOCKSIZE);
+ msg += AES_BLOCKSIZE;
+
+ for (i = 0; i < 4; i++)
+ tin[i] = ntohl(msg_32[i])^tout[i];
+
+ AES_encrypt(ctx, tin);
+
+ for (i = 0; i < 4; i++)
+ {
+ tout[i] = tin[i];
+ out_32[i] = htonl(tout[i]);
+ }
+
+ memcpy(out, out_32, AES_BLOCKSIZE);
+ out += AES_BLOCKSIZE;
+ }
+
+ for (i = 0; i < 4; i++)
+ iv[i] = htonl(tout[i]);
+ memcpy(ctx->iv, iv, AES_IV_SIZE);
+}
+
+/**
+ * Decrypt a byte sequence (with a block size 16) using the AES cipher.
+ */
+void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+ int i;
+ uint32_t tin[4], xor[4], tout[4], data[4], iv[4];
+
+ memcpy(iv, ctx->iv, AES_IV_SIZE);
+ for (i = 0; i < 4; i++)
+ xor[i] = ntohl(iv[i]);
+
+ for (length -= 16; length >= 0; length -= 16)
+ {
+ uint32_t msg_32[4];
+ uint32_t out_32[4];
+ memcpy(msg_32, msg, AES_BLOCKSIZE);
+ msg += AES_BLOCKSIZE;
+
+ for (i = 0; i < 4; i++)
+ {
+ tin[i] = ntohl(msg_32[i]);
+ data[i] = tin[i];
+ }
+
+ AES_decrypt(ctx, data);
+
+ for (i = 0; i < 4; i++)
+ {
+ tout[i] = data[i]^xor[i];
+ xor[i] = tin[i];
+ out_32[i] = htonl(tout[i]);
+ }
+
+ memcpy(out, out_32, AES_BLOCKSIZE);
+ out += AES_BLOCKSIZE;
+ }
+
+ for (i = 0; i < 4; i++)
+ iv[i] = htonl(xor[i]);
+ memcpy(ctx->iv, iv, AES_IV_SIZE);
+}
+
+/**
+ * Encrypt a single block (16 bytes) of data
+ */
+static void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
+{
+ /* To make this code smaller, generate the sbox entries on the fly.
+ * This will have a really heavy effect upon performance.
+ */
+ uint32_t tmp[4];
+ uint32_t tmp1, old_a0, a0, a1, a2, a3, row;
+ int curr_rnd;
+ int rounds = ctx->rounds;
+ const uint32_t *k = ctx->ks;
+
+ /* Pre-round key addition */
+ for (row = 0; row < 4; row++)
+ data[row] ^= *(k++);
+
+ /* Encrypt one block. */
+ for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
+ {
+ /* Perform ByteSub and ShiftRow operations together */
+ for (row = 0; row < 4; row++)
+ {
+ a0 = (uint32_t)aes_sbox[(data[row%4]>>24)&0xFF];
+ a1 = (uint32_t)aes_sbox[(data[(row+1)%4]>>16)&0xFF];
+ a2 = (uint32_t)aes_sbox[(data[(row+2)%4]>>8)&0xFF];
+ a3 = (uint32_t)aes_sbox[(data[(row+3)%4])&0xFF];
+
+ /* Perform MixColumn iff not last round */
+ if (curr_rnd < (rounds - 1))
+ {
+ tmp1 = a0 ^ a1 ^ a2 ^ a3;
+ old_a0 = a0;
+ a0 ^= tmp1 ^ AES_xtime(a0 ^ a1);
+ a1 ^= tmp1 ^ AES_xtime(a1 ^ a2);
+ a2 ^= tmp1 ^ AES_xtime(a2 ^ a3);
+ a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0);
+ }
+
+ tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3);
+ }
+
+ /* KeyAddition - note that it is vital that this loop is separate from
+ the MixColumn operation, which must be atomic...*/
+ for (row = 0; row < 4; row++)
+ data[row] = tmp[row] ^ *(k++);
+ }
+}
+
+/**
+ * Decrypt a single block (16 bytes) of data
+ */
+static void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
+{
+ uint32_t tmp[4];
+ uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6;
+ uint32_t a0, a1, a2, a3, row;
+ int curr_rnd;
+ int rounds = ctx->rounds;
+ const uint32_t *k = ctx->ks + ((rounds+1)*4);
+
+ /* pre-round key addition */
+ for (row=4; row > 0;row--)
+ data[row-1] ^= *(--k);
+
+ /* Decrypt one block */
+ for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
+ {
+ /* Perform ByteSub and ShiftRow operations together */
+ for (row = 4; row > 0; row--)
+ {
+ a0 = aes_isbox[(data[(row+3)%4]>>24)&0xFF];
+ a1 = aes_isbox[(data[(row+2)%4]>>16)&0xFF];
+ a2 = aes_isbox[(data[(row+1)%4]>>8)&0xFF];
+ a3 = aes_isbox[(data[row%4])&0xFF];
+
+ /* Perform MixColumn iff not last round */
+ if (curr_rnd<(rounds-1))
+ {
+ /* The MDS cofefficients (0x09, 0x0B, 0x0D, 0x0E)
+ are quite large compared to encryption; this
+ operation slows decryption down noticeably. */
+ xt0 = AES_xtime(a0^a1);
+ xt1 = AES_xtime(a1^a2);
+ xt2 = AES_xtime(a2^a3);
+ xt3 = AES_xtime(a3^a0);
+ xt4 = AES_xtime(xt0^xt1);
+ xt5 = AES_xtime(xt1^xt2);
+ xt6 = AES_xtime(xt4^xt5);
+
+ xt0 ^= a1^a2^a3^xt4^xt6;
+ xt1 ^= a0^a2^a3^xt5^xt6;
+ xt2 ^= a0^a1^a3^xt4^xt6;
+ xt3 ^= a0^a1^a2^xt5^xt6;
+ tmp[row-1] = ((xt0<<24)|(xt1<<16)|(xt2<<8)|xt3);
+ }
+ else
+ tmp[row-1] = ((a0<<24)|(a1<<16)|(a2<<8)|a3);
+ }
+
+ for (row = 4; row > 0; row--)
+ data[row-1] = tmp[row-1] ^ *(--k);
+ }
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @defgroup bigint_api Big Integer API
+ * @brief The bigint implementation as used by the axTLS project.
+ *
+ * The bigint library is for RSA encryption/decryption as well as signing.
+ * This code tries to minimise use of malloc/free by maintaining a small
+ * cache. A bigint context may maintain state by being made "permanent".
+ * It be be later released with a bi_depermanent() and bi_free() call.
+ *
+ * It supports the following reduction techniques:
+ * - Classical
+ * - Barrett
+ * - Montgomery
+ *
+ * It also implements the following:
+ * - Karatsuba multiplication
+ * - Squaring
+ * - Sliding window exponentiation
+ * - Chinese Remainder Theorem (implemented in rsa.c).
+ *
+ * All the algorithms used are pretty standard, and designed for different
+ * data bus sizes. Negative numbers are not dealt with at all, so a subtraction
+ * may need to be tested for negativity.
+ *
+ * This library steals some ideas from Jef Poskanzer
+ * <http://cs.marlboro.edu/term/cs-fall02/algorithms/crypto/RSA/bigint>
+ * and GMP <http://www.swox.com/gmp>. It gets most of its implementation
+ * detail from "The Handbook of Applied Cryptography"
+ * <http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf>
+ * @{
+ */
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include "bigint.h"
+
+#define V1 v->comps[v->size-1] /**< v1 for division */
+#define V2 v->comps[v->size-2] /**< v2 for division */
+#define U(j) tmp_u->comps[tmp_u->size-j-1] /**< uj for division */
+#define Q(j) quotient->comps[quotient->size-j-1] /**< qj for division */
+
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i);
+static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom);
+static bigint *alloc(BI_CTX *ctx, int size);
+static bigint *trim(bigint *bi);
+static void more_comps(bigint *bi, int n);
+#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
+ defined(CONFIG_BIGINT_MONTGOMERY)
+static bigint *comp_right_shift(bigint *biR, int num_shifts);
+static bigint *comp_left_shift(bigint *biR, int num_shifts);
+#endif
+
+#ifdef CONFIG_BIGINT_CHECK_ON
+static void check(const bigint *bi);
+#else
+#define check(A) /**< disappears in normal production mode */
+#endif
+
+
+/**
+ * @brief Start a new bigint context.
+ * @return A bigint context.
+ */
+BI_CTX *bi_initialize(void)
+{
+ /* calloc() sets everything to zero */
+ BI_CTX *ctx = (BI_CTX *)calloc(1, sizeof(BI_CTX));
+
+ /* the radix */
+ ctx->bi_radix = alloc(ctx, 2);
+ ctx->bi_radix->comps[0] = 0;
+ ctx->bi_radix->comps[1] = 1;
+ bi_permanent(ctx->bi_radix);
+ return ctx;
+}
+
+/**
+ * @brief Close the bigint context and free any resources.
+ *
+ * Free up any used memory - a check is done if all objects were not
+ * properly freed.
+ * @param ctx [in] The bigint session context.
+ */
+void bi_terminate(BI_CTX *ctx)
+{
+ bi_depermanent(ctx->bi_radix);
+ bi_free(ctx, ctx->bi_radix);
+
+ if (ctx->active_count != 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("bi_terminate: there were %d un-freed bigints\n",
+ ctx->active_count);
+#endif
+ abort();
+ }
+
+ bi_clear_cache(ctx);
+ free(ctx);
+}
+
+/**
+ *@brief Clear the memory cache.
+ */
+void bi_clear_cache(BI_CTX *ctx)
+{
+ bigint *p, *pn;
+
+ if (ctx->free_list == NULL)
+ return;
+
+ for (p = ctx->free_list; p != NULL; p = pn)
+ {
+ pn = p->next;
+ free(p->comps);
+ free(p);
+ }
+
+ ctx->free_count = 0;
+ ctx->free_list = NULL;
+}
+
+/**
+ * @brief Increment the number of references to this object.
+ * It does not do a full copy.
+ * @param bi [in] The bigint to copy.
+ * @return A reference to the same bigint.
+ */
+bigint *bi_copy(bigint *bi)
+{
+ check(bi);
+ if (bi->refs != PERMANENT)
+ bi->refs++;
+ return bi;
+}
+
+/**
+ * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it.
+ *
+ * For this object to be freed, bi_depermanent() must be called.
+ * @param bi [in] The bigint to be made permanent.
+ */
+void bi_permanent(bigint *bi)
+{
+ check(bi);
+ if (bi->refs != 1)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("bi_permanent: refs was not 1\n");
+#endif
+ abort();
+ }
+
+ bi->refs = PERMANENT;
+}
+
+/**
+ * @brief Take a permanent object and make it eligible for freedom.
+ * @param bi [in] The bigint to be made back to temporary.
+ */
+void bi_depermanent(bigint *bi)
+{
+ check(bi);
+ if (bi->refs != PERMANENT)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("bi_depermanent: bigint was not permanent\n");
+#endif
+ abort();
+ }
+
+ bi->refs = 1;
+}
+
+/**
+ * @brief Free a bigint object so it can be used again.
+ *
+ * The memory itself it not actually freed, just tagged as being available
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint to be freed.
+ */
+void bi_free(BI_CTX *ctx, bigint *bi)
+{
+ check(bi);
+ if (bi->refs == PERMANENT)
+ {
+ return;
+ }
+
+ if (--bi->refs > 0)
+ {
+ return;
+ }
+
+ bi->next = ctx->free_list;
+ ctx->free_list = bi;
+ ctx->free_count++;
+
+ if (--ctx->active_count < 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("bi_free: active_count went negative "
+ "- double-freed bigint?\n");
+#endif
+ abort();
+ }
+}
+
+/**
+ * @brief Convert an (unsigned) integer into a bigint.
+ * @param ctx [in] The bigint session context.
+ * @param i [in] The (unsigned) integer to be converted.
+ *
+ */
+bigint *int_to_bi(BI_CTX *ctx, comp i)
+{
+ bigint *biR = alloc(ctx, 1);
+ biR->comps[0] = i;
+ return biR;
+}
+
+/**
+ * @brief Do a full copy of the bigint object.
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint object to be copied.
+ */
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi)
+{
+ bigint *biR = alloc(ctx, bi->size);
+ check(bi);
+ memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE);
+ return biR;
+}
+
+/**
+ * @brief Perform an addition operation between two bigints.
+ * @param ctx [in] The bigint session context.
+ * @param bia [in] A bigint.
+ * @param bib [in] Another bigint.
+ * @return The result of the addition.
+ */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+ int n;
+ comp carry = 0;
+ comp *pa, *pb;
+
+ check(bia);
+ check(bib);
+
+ n = max(bia->size, bib->size);
+ more_comps(bia, n+1);
+ more_comps(bib, n);
+ pa = bia->comps;
+ pb = bib->comps;
+
+ do
+ {
+ comp sl, rl, cy1;
+ sl = *pa + *pb++;
+ rl = sl + carry;
+ cy1 = sl < *pa;
+ carry = cy1 | (rl < sl);
+ *pa++ = rl;
+ } while (--n != 0);
+
+ *pa = carry; /* do overflow */
+ bi_free(ctx, bib);
+ return trim(bia);
+}
+
+/**
+ * @brief Perform a subtraction operation between two bigints.
+ * @param ctx [in] The bigint session context.
+ * @param bia [in] A bigint.
+ * @param bib [in] Another bigint.
+ * @param is_negative [out] If defined, indicates that the result was negative.
+ * is_negative may be null.
+ * @return The result of the subtraction. The result is always positive.
+ */
+bigint *bi_subtract(BI_CTX *ctx,
+ bigint *bia, bigint *bib, int *is_negative)
+{
+ int n = bia->size;
+ comp *pa, *pb, carry = 0;
+
+ check(bia);
+ check(bib);
+
+ more_comps(bib, n);
+ pa = bia->comps;
+ pb = bib->comps;
+
+ do
+ {
+ comp sl, rl, cy1;
+ sl = *pa - *pb++;
+ rl = sl - carry;
+ cy1 = sl > *pa;
+ carry = cy1 | (rl > sl);
+ *pa++ = rl;
+ } while (--n != 0);
+
+ if (is_negative) /* indicate a negative result */
+ {
+ *is_negative = carry;
+ }
+
+ bi_free(ctx, trim(bib)); /* put bib back to the way it was */
+ return trim(bia);
+}
+
+/**
+ * Perform a multiply between a bigint an an (unsigned) integer
+ */
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b)
+{
+ int j = 0, n = bia->size;
+ bigint *biR = alloc(ctx, n + 1);
+ comp carry = 0;
+ comp *r = biR->comps;
+ comp *a = bia->comps;
+
+ check(bia);
+
+ /* clear things to start with */
+ memset(r, 0, ((n+1)*COMP_BYTE_SIZE));
+
+ do
+ {
+ long_comp tmp = *r + (long_comp)a[j]*b + carry;
+ *r++ = (comp)tmp; /* downsize */
+ carry = (comp)(tmp >> COMP_BIT_SIZE);
+ } while (++j < n);
+
+ *r = carry;
+ bi_free(ctx, bia);
+ return trim(biR);
+}
+
+/**
+ * @brief Does both division and modulo calculations.
+ *
+ * Used extensively when doing classical reduction.
+ * @param ctx [in] The bigint session context.
+ * @param u [in] A bigint which is the numerator.
+ * @param v [in] Either the denominator or the modulus depending on the mode.
+ * @param is_mod [n] Determines if this is a normal division (0) or a reduction
+ * (1).
+ * @return The result of the division/reduction.
+ */
+bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod)
+{
+ int n = v->size, m = u->size-n;
+ int j = 0, orig_u_size = u->size;
+ uint8_t mod_offset = ctx->mod_offset;
+ comp d;
+ bigint *quotient, *tmp_u;
+ comp q_dash;
+
+ check(u);
+ check(v);
+
+ /* if doing reduction and we are < mod, then return mod */
+ if (is_mod && bi_compare(v, u) > 0)
+ {
+ bi_free(ctx, v);
+ return u;
+ }
+
+ quotient = alloc(ctx, m+1);
+ tmp_u = alloc(ctx, n+1);
+ v = trim(v); /* make sure we have no leading 0's */
+ d = (comp)((long_comp)COMP_RADIX/(V1+1));
+
+ /* clear things to start with */
+ memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE));
+
+ /* normalise */
+ if (d > 1)
+ {
+ u = bi_int_multiply(ctx, u, d);
+
+ if (is_mod)
+ {
+ v = ctx->bi_normalised_mod[mod_offset];
+ }
+ else
+ {
+ v = bi_int_multiply(ctx, v, d);
+ }
+ }
+
+ if (orig_u_size == u->size) /* new digit position u0 */
+ {
+ more_comps(u, orig_u_size + 1);
+ }
+
+ do
+ {
+ /* get a temporary short version of u */
+ memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE);
+
+ /* calculate q' */
+ if (U(0) == V1)
+ {
+ q_dash = COMP_RADIX-1;
+ }
+ else
+ {
+ q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1);
+ }
+
+ if (v->size > 1 && V2)
+ {
+ /* we are implementing the following:
+ if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) -
+ q_dash*V1)*COMP_RADIX) + U(2))) ... */
+ comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) -
+ (long_comp)q_dash*V1);
+ if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2))
+ {
+ q_dash--;
+ }
+ }
+
+ /* multiply and subtract */
+ if (q_dash)
+ {
+ int is_negative;
+ tmp_u = bi_subtract(ctx, tmp_u,
+ bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative);
+ more_comps(tmp_u, n+1);
+
+ Q(j) = q_dash;
+
+ /* add back */
+ if (is_negative)
+ {
+ Q(j)--;
+ tmp_u = bi_add(ctx, tmp_u, bi_copy(v));
+
+ /* lop off the carry */
+ tmp_u->size--;
+ v->size--;
+ }
+ }
+ else
+ {
+ Q(j) = 0;
+ }
+
+ /* copy back to u */
+ memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE);
+ } while (++j <= m);
+
+ bi_free(ctx, tmp_u);
+ bi_free(ctx, v);
+
+ if (is_mod) /* get the remainder */
+ {
+ bi_free(ctx, quotient);
+ return bi_int_divide(ctx, trim(u), d);
+ }
+ else /* get the quotient */
+ {
+ bi_free(ctx, u);
+ return trim(quotient);
+ }
+}
+
+/*
+ * Perform an integer divide on a bigint.
+ */
+static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom)
+{
+ int i = biR->size - 1;
+ long_comp r = 0;
+
+ check(biR);
+
+ do
+ {
+ r = (r<<COMP_BIT_SIZE) + biR->comps[i];
+ biR->comps[i] = (comp)(r / denom);
+ r %= denom;
+ } while (--i >= 0);
+
+ return trim(biR);
+}
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+/**
+ * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1,
+ * where B^-1(B-1) mod N=1. Actually, only the least significant part of
+ * N' is needed, hence the definition N0'=N' mod b. We reproduce below the
+ * simple algorithm from an article by Dusse and Kaliski to efficiently
+ * find N0' from N0 and b */
+static comp modular_inverse(bigint *bim)
+{
+ int i;
+ comp t = 1;
+ comp two_2_i_minus_1 = 2; /* 2^(i-1) */
+ long_comp two_2_i = 4; /* 2^i */
+ comp N = bim->comps[0];
+
+ for (i = 2; i <= COMP_BIT_SIZE; i++)
+ {
+ if ((long_comp)N*t%two_2_i >= two_2_i_minus_1)
+ {
+ t += two_2_i_minus_1;
+ }
+
+ two_2_i_minus_1 <<= 1;
+ two_2_i <<= 1;
+ }
+
+ return (comp)(COMP_RADIX-t);
+}
+#endif
+
+#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
+ defined(CONFIG_BIGINT_MONTGOMERY)
+/**
+ * Take each component and shift down (in terms of components)
+ */
+static bigint *comp_right_shift(bigint *biR, int num_shifts)
+{
+ int i = biR->size-num_shifts;
+ comp *x = biR->comps;
+ comp *y = &biR->comps[num_shifts];
+
+ check(biR);
+
+ if (i <= 0) /* have we completely right shifted? */
+ {
+ biR->comps[0] = 0; /* return 0 */
+ biR->size = 1;
+ return biR;
+ }
+
+ do
+ {
+ *x++ = *y++;
+ } while (--i > 0);
+
+ biR->size -= num_shifts;
+ return biR;
+}
+
+/**
+ * Take each component and shift it up (in terms of components)
+ */
+static bigint *comp_left_shift(bigint *biR, int num_shifts)
+{
+ int i = biR->size-1;
+ comp *x, *y;
+
+ check(biR);
+
+ if (num_shifts <= 0)
+ {
+ return biR;
+ }
+
+ more_comps(biR, biR->size + num_shifts);
+
+ x = &biR->comps[i+num_shifts];
+ y = &biR->comps[i];
+
+ do
+ {
+ *x-- = *y--;
+ } while (i--);
+
+ memset(biR->comps, 0, num_shifts*COMP_BYTE_SIZE); /* zero LS comps */
+ return biR;
+}
+#endif
+
+/**
+ * @brief Allow a binary sequence to be imported as a bigint.
+ * @param ctx [in] The bigint session context.
+ * @param data [in] The data to be converted.
+ * @param size [in] The number of bytes of data.
+ * @return A bigint representing this data.
+ */
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size)
+{
+ bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE);
+ int i, j = 0, offset = 0;
+
+ memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
+
+ for (i = size-1; i >= 0; i--)
+ {
+ biR->comps[offset] += data[i] << (j*8);
+
+ if (++j == COMP_BYTE_SIZE)
+ {
+ j = 0;
+ offset ++;
+ }
+ }
+
+ return trim(biR);
+}
+
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * @brief The testharness uses this code to import text hex-streams and
+ * convert them into bigints.
+ * @param ctx [in] The bigint session context.
+ * @param data [in] A string consisting of hex characters. The characters must
+ * be in upper case.
+ * @return A bigint representing this data.
+ */
+bigint *bi_str_import(BI_CTX *ctx, const char *data)
+{
+ int size = strlen(data);
+ bigint *biR = alloc(ctx, (size+COMP_NUM_NIBBLES-1)/COMP_NUM_NIBBLES);
+ int i, j = 0, offset = 0;
+ memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
+
+ for (i = size-1; i >= 0; i--)
+ {
+ int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10);
+ biR->comps[offset] += num << (j*4);
+
+ if (++j == COMP_NUM_NIBBLES)
+ {
+ j = 0;
+ offset ++;
+ }
+ }
+
+ return biR;
+}
+
+void bi_print(const char *label, bigint *x)
+{
+ int i, j;
+
+ if (x == NULL)
+ {
+ printf("%s: (null)\n", label);
+ return;
+ }
+
+ printf("%s: (size %d)\n", label, x->size);
+ for (i = x->size-1; i >= 0; i--)
+ {
+ for (j = COMP_NUM_NIBBLES-1; j >= 0; j--)
+ {
+ comp mask = 0x0f << (j*4);
+ comp num = (x->comps[i] & mask) >> (j*4);
+ putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout);
+ }
+ }
+
+ printf("\n");
+}
+#endif
+
+/**
+ * @brief Take a bigint and convert it into a byte sequence.
+ *
+ * This is useful after a decrypt operation.
+ * @param ctx [in] The bigint session context.
+ * @param x [in] The bigint to be converted.
+ * @param data [out] The converted data as a byte stream.
+ * @param size [in] The maximum size of the byte stream. Unused bytes will be
+ * zeroed.
+ */
+void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size)
+{
+ int i, j, k = size-1;
+
+ check(x);
+ memset(data, 0, size); /* ensure all leading 0's are cleared */
+
+ for (i = 0; i < x->size; i++)
+ {
+ for (j = 0; j < COMP_BYTE_SIZE; j++)
+ {
+ comp mask = 0xff << (j*8);
+ int num = (x->comps[i] & mask) >> (j*8);
+ data[k--] = num;
+
+ if (k < 0)
+ {
+ break;
+ }
+ }
+ }
+
+ bi_free(ctx, x);
+}
+
+/**
+ * @brief Pre-calculate some of the expensive steps in reduction.
+ *
+ * This function should only be called once (normally when a session starts).
+ * When the session is over, bi_free_mod() should be called. bi_mod_power()
+ * relies on this function being called.
+ * @param ctx [in] The bigint session context.
+ * @param bim [in] The bigint modulus that will be used.
+ * @param mod_offset [in] There are three moduluii that can be stored - the
+ * standard modulus, and its two primes p and q. This offset refers to which
+ * modulus we are referring to.
+ * @see bi_free_mod(), bi_mod_power().
+ */
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset)
+{
+ int k = bim->size;
+ comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1));
+#ifdef CONFIG_BIGINT_MONTGOMERY
+ bigint *R, *R2;
+#endif
+
+ ctx->bi_mod[mod_offset] = bim;
+ bi_permanent(ctx->bi_mod[mod_offset]);
+ ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d);
+ bi_permanent(ctx->bi_normalised_mod[mod_offset]);
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ /* set montgomery variables */
+ R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k-1); /* R */
+ R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k*2-1); /* R^2 */
+ ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2); /* R^2 mod m */
+ ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R); /* R mod m */
+
+ bi_permanent(ctx->bi_RR_mod_m[mod_offset]);
+ bi_permanent(ctx->bi_R_mod_m[mod_offset]);
+
+ ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]);
+
+#elif defined (CONFIG_BIGINT_BARRETT)
+ ctx->bi_mu[mod_offset] =
+ bi_divide(ctx, comp_left_shift(
+ bi_clone(ctx, ctx->bi_radix), k*2-1), ctx->bi_mod[mod_offset], 0);
+ bi_permanent(ctx->bi_mu[mod_offset]);
+#endif
+}
+
+/**
+ * @brief Used when cleaning various bigints at the end of a session.
+ * @param ctx [in] The bigint session context.
+ * @param mod_offset [in] The offset to use.
+ * @see bi_set_mod().
+ */
+void bi_free_mod(BI_CTX *ctx, int mod_offset)
+{
+ bi_depermanent(ctx->bi_mod[mod_offset]);
+ bi_free(ctx, ctx->bi_mod[mod_offset]);
+#if defined (CONFIG_BIGINT_MONTGOMERY)
+ bi_depermanent(ctx->bi_RR_mod_m[mod_offset]);
+ bi_depermanent(ctx->bi_R_mod_m[mod_offset]);
+ bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]);
+ bi_free(ctx, ctx->bi_R_mod_m[mod_offset]);
+#elif defined(CONFIG_BIGINT_BARRETT)
+ bi_depermanent(ctx->bi_mu[mod_offset]);
+ bi_free(ctx, ctx->bi_mu[mod_offset]);
+#endif
+ bi_depermanent(ctx->bi_normalised_mod[mod_offset]);
+ bi_free(ctx, ctx->bi_normalised_mod[mod_offset]);
+}
+
+/**
+ * Perform a standard multiplication between two bigints.
+ */
+static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+ int i, j, i_plus_j;
+ int n = bia->size;
+ int t = bib->size;
+ bigint *biR = alloc(ctx, n + t);
+ comp *sr = biR->comps;
+ comp *sa = bia->comps;
+ comp *sb = bib->comps;
+
+ check(bia);
+ check(bib);
+
+ /* clear things to start with */
+ memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE));
+ i = 0;
+
+ do
+ {
+ comp carry = 0;
+ comp b = *sb++;
+ i_plus_j = i;
+ j = 0;
+
+ do
+ {
+ long_comp tmp = sr[i_plus_j] + (long_comp)sa[j]*b + carry;
+ sr[i_plus_j++] = (comp)tmp; /* downsize */
+ carry = (comp)(tmp >> COMP_BIT_SIZE);
+ } while (++j < n);
+
+ sr[i_plus_j] = carry;
+ } while (++i < t);
+
+ bi_free(ctx, bia);
+ bi_free(ctx, bib);
+ return trim(biR);
+}
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+/*
+ * Karatsuba improves on regular multiplication due to only 3 multiplications
+ * being done instead of 4. The additional additions/subtractions are O(N)
+ * rather than O(N^2) and so for big numbers it saves on a few operations
+ */
+static bigint *karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square)
+{
+ bigint *x0, *x1;
+ bigint *p0, *p1, *p2;
+ int m;
+
+ if (is_square)
+ {
+ m = (bia->size + 1)/2;
+ }
+ else
+ {
+ m = (max(bia->size, bib->size) + 1)/2;
+ }
+
+ x0 = bi_clone(ctx, bia);
+ x0->size = m;
+ x1 = bi_clone(ctx, bia);
+ comp_right_shift(x1, m);
+ bi_free(ctx, bia);
+
+ /* work out the 3 partial products */
+ if (is_square)
+ {
+ p0 = bi_square(ctx, bi_copy(x0));
+ p2 = bi_square(ctx, bi_copy(x1));
+ p1 = bi_square(ctx, bi_add(ctx, x0, x1));
+ }
+ else /* normal multiply */
+ {
+ bigint *y0, *y1;
+ y0 = bi_clone(ctx, bib);
+ y0->size = m;
+ y1 = bi_clone(ctx, bib);
+ comp_right_shift(y1, m);
+ bi_free(ctx, bib);
+
+ p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0));
+ p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1));
+ p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1));
+ }
+
+ p1 = bi_subtract(ctx,
+ bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), NULL);
+
+ comp_left_shift(p1, m);
+ comp_left_shift(p2, 2*m);
+ return bi_add(ctx, p1, bi_add(ctx, p0, p2));
+}
+#endif
+
+/**
+ * @brief Perform a multiplication operation between two bigints.
+ * @param ctx [in] The bigint session context.
+ * @param bia [in] A bigint.
+ * @param bib [in] Another bigint.
+ * @return The result of the multiplication.
+ */
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+ check(bia);
+ check(bib);
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+ if (min(bia->size, bib->size) < MUL_KARATSUBA_THRESH)
+ {
+ return regular_multiply(ctx, bia, bib);
+ }
+
+ return karatsuba(ctx, bia, bib, 0);
+#else
+ return regular_multiply(ctx, bia, bib);
+#endif
+}
+
+#ifdef CONFIG_BIGINT_SQUARE
+/*
+ * Perform the actual square operion. It takes into account overflow.
+ */
+static bigint *regular_square(BI_CTX *ctx, bigint *bi)
+{
+ int t = bi->size;
+ int i = 0, j;
+ bigint *biR = alloc(ctx, t*2);
+ comp *w = biR->comps;
+ comp *x = bi->comps;
+ comp carry;
+
+ memset(w, 0, biR->size*COMP_BYTE_SIZE);
+
+ do
+ {
+ long_comp tmp = w[2*i] + (long_comp)x[i]*x[i];
+ comp u = 0;
+ w[2*i] = (comp)tmp;
+ carry = (comp)(tmp >> COMP_BIT_SIZE);
+
+ for (j = i+1; j < t; j++)
+ {
+ long_comp xx = (long_comp)x[i]*x[j];
+ long_comp xx2 = 2*xx;
+ long_comp blob = (long_comp)w[i+j]+carry;
+
+ if (u) /* previous overflow */
+ {
+ blob += COMP_RADIX;
+ }
+
+
+ u = 0;
+ tmp = xx2 + blob;
+
+ /* check for overflow */
+ if ((COMP_MAX-xx) < xx || (COMP_MAX-xx2) < blob)
+ {
+ u = 1;
+ }
+
+ w[i+j] = (comp)tmp;
+ carry = (comp)(tmp >> COMP_BIT_SIZE);
+ }
+
+ w[i+t] += carry;
+
+ if (u)
+ {
+ w[i+t+1] = 1; /* add carry */
+ }
+ } while (++i < t);
+
+ bi_free(ctx, bi);
+ return trim(biR);
+}
+
+/**
+ * @brief Perform a square operation on a bigint.
+ * @param ctx [in] The bigint session context.
+ * @param bia [in] A bigint.
+ * @return The result of the multiplication.
+ */
+bigint *bi_square(BI_CTX *ctx, bigint *bia)
+{
+ check(bia);
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+ if (bia->size < SQU_KARATSUBA_THRESH)
+ {
+ return regular_square(ctx, bia);
+ }
+
+ return karatsuba(ctx, bia, NULL, 1);
+#else
+ return regular_square(ctx, bia);
+#endif
+}
+#endif
+
+/**
+ * @brief Compare two bigints.
+ * @param bia [in] A bigint.
+ * @param bib [in] Another bigint.
+ * @return -1 if smaller, 1 if larger and 0 if equal.
+ */
+int bi_compare(bigint *bia, bigint *bib)
+{
+ int r, i;
+
+ check(bia);
+ check(bib);
+
+ if (bia->size > bib->size)
+ r = 1;
+ else if (bia->size < bib->size)
+ r = -1;
+ else
+ {
+ comp *a = bia->comps;
+ comp *b = bib->comps;
+
+ /* Same number of components. Compare starting from the high end
+ * and working down. */
+ r = 0;
+ i = bia->size - 1;
+
+ do
+ {
+ if (a[i] > b[i])
+ {
+ r = 1;
+ break;
+ }
+ else if (a[i] < b[i])
+ {
+ r = -1;
+ break;
+ }
+ } while (--i >= 0);
+ }
+
+ return r;
+}
+
+/*
+ * Allocate and zero more components. Does not consume bi.
+ */
+static void more_comps(bigint *bi, int n)
+{
+ if (n > bi->max_comps)
+ {
+ bi->max_comps = max(bi->max_comps * 2, n);
+ bi->comps = (comp*)realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE);
+ }
+
+ if (n > bi->size)
+ {
+ memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE);
+ }
+
+ bi->size = n;
+}
+
+/*
+ * Make a new empty bigint. It may just use an old one if one is available.
+ * Otherwise get one off the heap.
+ */
+static bigint *alloc(BI_CTX *ctx, int size)
+{
+ bigint *biR;
+
+ /* Can we recycle an old bigint? */
+ if (ctx->free_list != NULL)
+ {
+ biR = ctx->free_list;
+ ctx->free_list = biR->next;
+ ctx->free_count--;
+
+ if (biR->refs != 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("alloc: refs was not 0\n");
+#endif
+ abort(); /* create a stack trace from a core dump */
+ }
+
+ more_comps(biR, size);
+ }
+ else
+ {
+ /* No free bigints available - create a new one. */
+ biR = (bigint *)malloc(sizeof(bigint));
+ biR->comps = (comp*)malloc(size * COMP_BYTE_SIZE);
+ biR->max_comps = size; /* give some space to spare */
+ }
+
+ biR->size = size;
+ biR->refs = 1;
+ biR->next = NULL;
+ ctx->active_count++;
+ return biR;
+}
+
+/*
+ * Work out the highest '1' bit in an exponent. Used when doing sliding-window
+ * exponentiation.
+ */
+static int find_max_exp_index(bigint *biexp)
+{
+ int i = COMP_BIT_SIZE-1;
+ comp shift = COMP_RADIX/2;
+ comp test = biexp->comps[biexp->size-1]; /* assume no leading zeroes */
+
+ check(biexp);
+
+ do
+ {
+ if (test & shift)
+ {
+ return i+(biexp->size-1)*COMP_BIT_SIZE;
+ }
+
+ shift >>= 1;
+ } while (--i != 0);
+
+ return -1; /* error - must have been a leading 0 */
+}
+
+/*
+ * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window
+ * exponentiation.
+ */
+static int exp_bit_is_one(bigint *biexp, int offset)
+{
+ comp test = biexp->comps[offset / COMP_BIT_SIZE];
+ int num_shifts = offset % COMP_BIT_SIZE;
+ comp shift = 1;
+ int i;
+
+ check(biexp);
+
+ for (i = 0; i < num_shifts; i++)
+ {
+ shift <<= 1;
+ }
+
+ return test & shift;
+}
+
+#ifdef CONFIG_BIGINT_CHECK_ON
+/*
+ * Perform a sanity check on bi.
+ */
+static void check(const bigint *bi)
+{
+ if (bi->refs <= 0)
+ {
+ printf("check: zero or negative refs in bigint\n");
+ abort();
+ }
+
+ if (bi->next != NULL)
+ {
+ printf("check: attempt to use a bigint from "
+ "the free list\n");
+ abort();
+ }
+}
+#endif
+
+/*
+ * Delete any leading 0's (and allow for 0).
+ */
+static bigint *trim(bigint *bi)
+{
+ check(bi);
+
+ while (bi->comps[bi->size-1] == 0 && bi->size > 1)
+ {
+ bi->size--;
+ }
+
+ return bi;
+}
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+/**
+ * @brief Perform a single montgomery reduction.
+ * @param ctx [in] The bigint session context.
+ * @param bixy [in] A bigint.
+ * @return The result of the montgomery reduction.
+ */
+bigint *bi_mont(BI_CTX *ctx, bigint *bixy)
+{
+ int i = 0, n;
+ uint8_t mod_offset = ctx->mod_offset;
+ bigint *bim = ctx->bi_mod[mod_offset];
+ comp mod_inv = ctx->N0_dash[mod_offset];
+
+ check(bixy);
+
+ if (ctx->use_classical) /* just use classical instead */
+ {
+ return bi_mod(ctx, bixy);
+ }
+
+ n = bim->size;
+
+ do
+ {
+ bixy = bi_add(ctx, bixy, comp_left_shift(
+ bi_int_multiply(ctx, bim, bixy->comps[i]*mod_inv), i));
+ } while (++i < n);
+
+ comp_right_shift(bixy, n);
+
+ if (bi_compare(bixy, bim) >= 0)
+ {
+ bixy = bi_subtract(ctx, bixy, bim, NULL);
+ }
+
+ return bixy;
+}
+
+#elif defined(CONFIG_BIGINT_BARRETT)
+/*
+ * Stomp on the most significant components to give the illusion of a "mod base
+ * radix" operation
+ */
+static bigint *comp_mod(bigint *bi, int mod)
+{
+ check(bi);
+
+ if (bi->size > mod)
+ {
+ bi->size = mod;
+ }
+
+ return bi;
+}
+
+/*
+ * Barrett reduction has no need for some parts of the product, so ignore bits
+ * of the multiply. This routine gives Barrett its big performance
+ * improvements over Classical/Montgomery reduction methods.
+ */
+static bigint *partial_multiply(BI_CTX *ctx, bigint *bia, bigint *bib,
+ int inner_partial, int outer_partial)
+{
+ int i = 0, j, n = bia->size, t = bib->size;
+ bigint *biR;
+ comp carry;
+ comp *sr, *sa, *sb;
+
+ check(bia);
+ check(bib);
+
+ biR = alloc(ctx, n + t);
+ sa = bia->comps;
+ sb = bib->comps;
+ sr = biR->comps;
+
+ if (inner_partial)
+ {
+ memset(sr, 0, inner_partial*COMP_BYTE_SIZE);
+ }
+ else /* outer partial */
+ {
+ if (n < outer_partial || t < outer_partial) /* should we bother? */
+ {
+ bi_free(ctx, bia);
+ bi_free(ctx, bib);
+ biR->comps[0] = 0; /* return 0 */
+ biR->size = 1;
+ return biR;
+ }
+
+ memset(&sr[outer_partial], 0, (n+t-outer_partial)*COMP_BYTE_SIZE);
+ }
+
+ do
+ {
+ comp *a = sa;
+ comp b = *sb++;
+ long_comp tmp;
+ int i_plus_j = i;
+ carry = 0;
+ j = n;
+
+ if (outer_partial && i_plus_j < outer_partial)
+ {
+ i_plus_j = outer_partial;
+ a = &sa[outer_partial-i];
+ j = n-(outer_partial-i);
+ }
+
+ do
+ {
+ if (inner_partial && i_plus_j >= inner_partial)
+ {
+ break;
+ }
+
+ tmp = sr[i_plus_j] + ((long_comp)*a++)*b + carry;
+ sr[i_plus_j++] = (comp)tmp; /* downsize */
+ carry = (comp)(tmp >> COMP_BIT_SIZE);
+ } while (--j != 0);
+
+ sr[i_plus_j] = carry;
+ } while (++i < t);
+
+ bi_free(ctx, bia);
+ bi_free(ctx, bib);
+ return trim(biR);
+}
+
+/**
+ * @brief Perform a single Barrett reduction.
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] A bigint.
+ * @return The result of the Barrett reduction.
+ */
+bigint *bi_barrett(BI_CTX *ctx, bigint *bi)
+{
+ bigint *q1, *q2, *q3, *r1, *r2, *r;
+ uint8_t mod_offset = ctx->mod_offset;
+ bigint *bim = ctx->bi_mod[mod_offset];
+ int k = bim->size;
+
+ check(bi);
+ check(bim);
+
+ /* use Classical method instead - Barrett cannot help here */
+ if (bi->size > k*2)
+ {
+ return bi_mod(ctx, bi);
+ }
+
+ q1 = comp_right_shift(bi_clone(ctx, bi), k-1);
+
+ /* do outer partial multiply */
+ q2 = partial_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1);
+ q3 = comp_right_shift(q2, k+1);
+ r1 = comp_mod(bi, k+1);
+
+ /* do inner partial multiply */
+ r2 = comp_mod(partial_multiply(ctx, q3, bim, k+1, 0), k+1);
+ r = bi_subtract(ctx, r1, r2, NULL);
+
+ /* if (r >= m) r = r - m; */
+ if (bi_compare(r, bim) >= 0)
+ {
+ r = bi_subtract(ctx, r, bim, NULL);
+ }
+
+ return r;
+}
+#endif /* CONFIG_BIGINT_BARRETT */
+
+#ifdef CONFIG_BIGINT_SLIDING_WINDOW
+/*
+ * Work out g1, g3, g5, g7... etc for the sliding-window algorithm
+ */
+static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1)
+{
+ int k = 1, i;
+ bigint *g2;
+
+ for (i = 0; i < window-1; i++) /* compute 2^(window-1) */
+ {
+ k <<= 1;
+ }
+
+ ctx->g = (bigint **)malloc(k*sizeof(bigint *));
+ ctx->g[0] = bi_clone(ctx, g1);
+ bi_permanent(ctx->g[0]);
+ g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0])); /* g^2 */
+
+ for (i = 1; i < k; i++)
+ {
+ ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i-1], bi_copy(g2)));
+ bi_permanent(ctx->g[i]);
+ }
+
+ bi_free(ctx, g2);
+ ctx->window = k;
+}
+#endif
+
+/**
+ * @brief Perform a modular exponentiation.
+ *
+ * This function requires bi_set_mod() to have been called previously. This is
+ * one of the optimisations used for performance.
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint on which to perform the mod power operation.
+ * @param biexp [in] The bigint exponent.
+ * @return The result of the mod exponentiation operation
+ * @see bi_set_mod().
+ */
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp)
+{
+ int i = find_max_exp_index(biexp), j, window_size = 1;
+ bigint *biR = int_to_bi(ctx, 1);
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ uint8_t mod_offset = ctx->mod_offset;
+ if (!ctx->use_classical)
+ {
+ /* preconvert */
+ bi = bi_mont(ctx,
+ bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset])); /* x' */
+ bi_free(ctx, biR);
+ biR = ctx->bi_R_mod_m[mod_offset]; /* A */
+ }
+#endif
+
+ check(bi);
+ check(biexp);
+
+#ifdef CONFIG_BIGINT_SLIDING_WINDOW
+ for (j = i; j > 32; j /= 5) /* work out an optimum size */
+ window_size++;
+
+ /* work out the slide constants */
+ precompute_slide_window(ctx, window_size, bi);
+#else /* just one constant */
+ ctx->g = (bigint **)malloc(sizeof(bigint *));
+ ctx->g[0] = bi_clone(ctx, bi);
+ ctx->window = 1;
+ bi_permanent(ctx->g[0]);
+#endif
+
+ /* if sliding-window is off, then only one bit will be done at a time and
+ * will reduce to standard left-to-right exponentiation */
+ do
+ {
+ if (exp_bit_is_one(biexp, i))
+ {
+ int l = i-window_size+1;
+ int part_exp = 0;
+
+ if (l < 0) /* LSB of exponent will always be 1 */
+ l = 0;
+ else
+ {
+ while (exp_bit_is_one(biexp, l) == 0)
+ l++; /* go back up */
+ }
+
+ /* build up the section of the exponent */
+ for (j = i; j >= l; j--)
+ {
+ biR = bi_residue(ctx, bi_square(ctx, biR));
+ if (exp_bit_is_one(biexp, j))
+ part_exp++;
+
+ if (j != l)
+ part_exp <<= 1;
+ }
+
+ part_exp = (part_exp-1)/2; /* adjust for array */
+ biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp]));
+ i = l-1;
+ }
+ else /* square it */
+ {
+ biR = bi_residue(ctx, bi_square(ctx, biR));
+ i--;
+ }
+ } while (i >= 0);
+
+ /* cleanup */
+ for (i = 0; i < ctx->window; i++)
+ {
+ bi_depermanent(ctx->g[i]);
+ bi_free(ctx, ctx->g[i]);
+ }
+
+ free(ctx->g);
+ bi_free(ctx, bi);
+ bi_free(ctx, biexp);
+#if defined CONFIG_BIGINT_MONTGOMERY
+ return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */
+#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */
+ return biR;
+#endif
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * @brief Perform a modular exponentiation using a temporary modulus.
+ *
+ * We need this function to check the signatures of certificates. The modulus
+ * of this function is temporary as it's just used for authentication.
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint to perform the exp/mod.
+ * @param bim [in] The temporary modulus.
+ * @param biexp [in] The bigint exponent.
+ * @return The result of the mod exponentiation operation
+ * @see bi_set_mod().
+ */
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp)
+{
+ bigint *biR, *tmp_biR;
+
+ /* Set up a temporary bigint context and transfer what we need between
+ * them. We need to do this since we want to keep the original modulus
+ * which is already in this context. This operation is only called when
+ * doing peer verification, and so is not expensive :-) */
+ BI_CTX *tmp_ctx = bi_initialize();
+ bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET);
+ tmp_biR = bi_mod_power(tmp_ctx,
+ bi_clone(tmp_ctx, bi),
+ bi_clone(tmp_ctx, biexp));
+ biR = bi_clone(ctx, tmp_biR);
+ bi_free(tmp_ctx, tmp_biR);
+ bi_free_mod(tmp_ctx, BIGINT_M_OFFSET);
+ bi_terminate(tmp_ctx);
+
+ bi_free(ctx, bi);
+ bi_free(ctx, bim);
+ bi_free(ctx, biexp);
+ return biR;
+}
+#endif
+
+#ifdef CONFIG_BIGINT_CRT
+/**
+ * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
+ *
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint to perform the exp/mod.
+ * @param dP [in] CRT's dP bigint
+ * @param dQ [in] CRT's dQ bigint
+ * @param p [in] CRT's p bigint
+ * @param q [in] CRT's q bigint
+ * @param qInv [in] CRT's qInv bigint
+ * @return The result of the CRT operation
+ */
+bigint *bi_crt(BI_CTX *ctx, bigint *bi,
+ bigint *dP, bigint *dQ,
+ bigint *p, bigint *q, bigint *qInv)
+{
+ bigint *m1, *m2, *h;
+
+ /* Montgomery has a condition the 0 < x, y < m and these products violate
+ * that condition. So disable Montgomery when using CRT */
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ ctx->use_classical = 1;
+#endif
+ ctx->mod_offset = BIGINT_P_OFFSET;
+ m1 = bi_mod_power(ctx, bi_copy(bi), dP);
+
+ ctx->mod_offset = BIGINT_Q_OFFSET;
+ m2 = bi_mod_power(ctx, bi, dQ);
+
+ h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL);
+ h = bi_multiply(ctx, h, qInv);
+ ctx->mod_offset = BIGINT_P_OFFSET;
+ h = bi_residue(ctx, h);
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ ctx->use_classical = 0; /* reset for any further operation */
+#endif
+ return bi_add(ctx, m2, bi_multiply(ctx, q, h));
+}
+#endif
+/** @} */
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BIGINT_HEADER
+#define BIGINT_HEADER
+
+#include "crypto.h"
+
+BI_CTX *bi_initialize(void);
+void bi_terminate(BI_CTX *ctx);
+void bi_permanent(bigint *bi);
+void bi_depermanent(bigint *bi);
+void bi_clear_cache(BI_CTX *ctx);
+void bi_free(BI_CTX *ctx, bigint *bi);
+bigint *bi_copy(bigint *bi);
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
+void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size);
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len);
+bigint *int_to_bi(BI_CTX *ctx, comp i);
+
+/* the functions that actually do something interesting */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_subtract(BI_CTX *ctx, bigint *bia,
+ bigint *bib, int *is_negative);
+bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod);
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp);
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp);
+int bi_compare(bigint *bia, bigint *bib);
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset);
+void bi_free_mod(BI_CTX *ctx, int mod_offset);
+
+#ifdef CONFIG_SSL_FULL_MODE
+void bi_print(const char *label, bigint *bi);
+bigint *bi_str_import(BI_CTX *ctx, const char *data);
+#endif
+
+/**
+ * @def bi_mod
+ * Find the residue of B. bi_set_mod() must be called before hand.
+ */
+#define bi_mod(A, B) bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1)
+
+/**
+ * bi_residue() is technically the same as bi_mod(), but it uses the
+ * appropriate reduction technique (which is bi_mod() when doing classical
+ * reduction).
+ */
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+#define bi_residue(A, B) bi_mont(A, B)
+bigint *bi_mont(BI_CTX *ctx, bigint *bixy);
+#elif defined(CONFIG_BIGINT_BARRETT)
+#define bi_residue(A, B) bi_barrett(A, B)
+bigint *bi_barrett(BI_CTX *ctx, bigint *bi);
+#else /* if defined(CONFIG_BIGINT_CLASSICAL) */
+#define bi_residue(A, B) bi_mod(A, B)
+#endif
+
+#ifdef CONFIG_BIGINT_SQUARE
+bigint *bi_square(BI_CTX *ctx, bigint *bi);
+#else
+#define bi_square(A, B) bi_multiply(A, bi_copy(B), B)
+#endif
+
+#ifdef CONFIG_BIGINT_CRT
+bigint *bi_crt(BI_CTX *ctx, bigint *bi,
+ bigint *dP, bigint *dQ,
+ bigint *p, bigint *q,
+ bigint *qInv);
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BIGINT_IMPL_HEADER
+#define BIGINT_IMPL_HEADER
+
+/* Maintain a number of precomputed variables when doing reduction */
+#define BIGINT_M_OFFSET 0 /**< Normal modulo offset. */
+#ifdef CONFIG_BIGINT_CRT
+#define BIGINT_P_OFFSET 1 /**< p modulo offset. */
+#define BIGINT_Q_OFFSET 2 /**< q module offset. */
+#define BIGINT_NUM_MODS 3 /**< The number of modulus constants used. */
+#else
+#define BIGINT_NUM_MODS 1
+#endif
+
+/* Architecture specific functions for big ints */
+#ifdef WIN32
+#define COMP_RADIX 4294967296i64
+#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64
+#else
+#define COMP_RADIX 4294967296ULL /**< Max component + 1 */
+#define COMP_MAX 0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */
+#endif
+#define COMP_BIT_SIZE 32 /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */
+
+typedef uint32_t comp; /**< A single precision component. */
+typedef uint64_t long_comp; /**< A double precision component. */
+typedef int64_t slong_comp; /**< A signed double precision component. */
+
+/**
+ * @struct _bigint
+ * @brief A big integer basic object
+ */
+struct _bigint
+{
+ struct _bigint* next; /**< The next bigint in the cache. */
+ short size; /**< The number of components in this bigint. */
+ short max_comps; /**< The heapsize allocated for this bigint */
+ int refs; /**< An internal reference count. */
+ comp* comps; /**< A ptr to the actual component data */
+};
+
+typedef struct _bigint bigint; /**< An alias for _bigint */
+
+/**
+ * Maintains the state of the cache, and a number of variables used in
+ * reduction.
+ */
+typedef struct /**< A big integer "session" context. */
+{
+ bigint *active_list; /**< Bigints currently used. */
+ bigint *free_list; /**< Bigints not used. */
+ bigint *bi_radix; /**< The radix used. */
+ bigint *bi_mod[BIGINT_NUM_MODS]; /**< modulus */
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ bigint *bi_RR_mod_m[BIGINT_NUM_MODS]; /**< R^2 mod m */
+ bigint *bi_R_mod_m[BIGINT_NUM_MODS]; /**< R mod m */
+ comp N0_dash[BIGINT_NUM_MODS];
+#elif defined(CONFIG_BIGINT_BARRETT)
+ bigint *bi_mu[BIGINT_NUM_MODS]; /**< Storage for mu */
+#endif
+ bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */
+ bigint **g; /**< Used by sliding-window. */
+ int window; /**< The size of the sliding window */
+ int active_count; /**< Number of active bigints. */
+ int free_count; /**< Number of free bigints. */
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+ uint8_t use_classical; /**< Use classical reduction. */
+#endif
+ uint8_t mod_offset; /**< The mod offset we are using */
+} BI_CTX;
+
+#ifndef WIN32
+#define max(a,b) ((a)>(b)?(a):(b)) /**< Find the maximum of 2 numbers. */
+#define min(a,b) ((a)<(b)?(a):(b)) /**< Find the minimum of 2 numbers. */
+#endif
+
+#define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file crypto.h
+ */
+
+#ifndef HEADER_CRYPTO_H
+#define HEADER_CRYPTO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "config.h"
+#include "os_port.h"
+#include "bigint_impl.h"
+#include "bigint.h"
+
+/* enable features based on a 'super-set' capbaility. */
+#if defined(CONFIG_SSL_FULL_MODE)
+#define CONFIG_SSL_ENABLE_CLIENT
+#define CONFIG_SSL_CERT_VERIFICATION
+#elif defined(CONFIG_SSL_ENABLE_CLIENT)
+#define CONFIG_SSL_CERT_VERIFICATION
+#endif
+
+/**************************************************************************
+ * AES declarations
+ **************************************************************************/
+
+#define AES_MAXROUNDS 14
+#define AES_BLOCKSIZE 16
+#define AES_IV_SIZE 16
+
+typedef struct aes_key_st
+{
+ uint16_t rounds;
+ uint16_t key_size;
+ uint32_t ks[(AES_MAXROUNDS+1)*8];
+ uint8_t iv[AES_IV_SIZE];
+} AES_CTX;
+
+typedef enum
+{
+ AES_MODE_128,
+ AES_MODE_256
+} AES_MODE;
+
+void AES_set_key(AES_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, AES_MODE mode);
+void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg,
+ uint8_t *out, int length);
+void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length);
+void AES_convert_key(AES_CTX *ctx);
+
+/**************************************************************************
+ * RC4 declarations
+ **************************************************************************/
+
+typedef struct
+{
+ uint8_t x, y, m[256];
+} RC4_CTX;
+
+void RC4_setup(RC4_CTX *s, const uint8_t *key, int length);
+void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length);
+
+/**************************************************************************
+ * SHA1 declarations
+ **************************************************************************/
+
+#define SHA1_SIZE 20
+
+/*
+ * This structure will hold context information for the SHA-1
+ * hashing operation
+ */
+typedef struct
+{
+ uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */
+ uint32_t Length_Low; /* Message length in bits */
+ uint32_t Length_High; /* Message length in bits */
+ uint16_t Message_Block_Index; /* Index into message block array */
+ uint8_t Message_Block[64]; /* 512-bit message blocks */
+} SHA1_CTX;
+
+void SHA1_Init(SHA1_CTX *);
+void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len);
+void SHA1_Final(uint8_t *digest, SHA1_CTX *);
+
+/**************************************************************************
+ * MD2 declarations
+ **************************************************************************/
+
+#define MD2_SIZE 16
+
+typedef struct
+{
+ unsigned char cksum[16]; /* checksum of the data block */
+ unsigned char state[48]; /* intermediate digest state */
+ unsigned char buffer[16]; /* data block being processed */
+ int left; /* amount of data in buffer */
+} MD2_CTX;
+
+EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx);
+EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen);
+EXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx);
+
+/**************************************************************************
+ * MD5 declarations
+ **************************************************************************/
+
+#define MD5_SIZE 16
+
+typedef struct
+{
+ uint32_t state[4]; /* state (ABCD) */
+ uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ uint8_t buffer[64]; /* input buffer */
+} MD5_CTX;
+
+EXP_FUNC void STDCALL MD5_Init(MD5_CTX *);
+EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len);
+EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *);
+
+/**************************************************************************
+ * HMAC declarations
+ **************************************************************************/
+void hmac_md5(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest);
+void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest);
+
+/**************************************************************************
+ * RSA declarations
+ **************************************************************************/
+
+typedef struct
+{
+ bigint *m; /* modulus */
+ bigint *e; /* public exponent */
+ bigint *d; /* private exponent */
+#ifdef CONFIG_BIGINT_CRT
+ bigint *p; /* p as in m = pq */
+ bigint *q; /* q as in m = pq */
+ bigint *dP; /* d mod (p-1) */
+ bigint *dQ; /* d mod (q-1) */
+ bigint *qInv; /* q^-1 mod p */
+#endif
+ int num_octets;
+ BI_CTX *bi_ctx;
+} RSA_CTX;
+
+void RSA_priv_key_new(RSA_CTX **rsa_ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len,
+ const uint8_t *priv_exp, int priv_len
+#ifdef CONFIG_BIGINT_CRT
+ , const uint8_t *p, int p_len,
+ const uint8_t *q, int q_len,
+ const uint8_t *dP, int dP_len,
+ const uint8_t *dQ, int dQ_len,
+ const uint8_t *qInv, int qInv_len
+#endif
+ );
+void RSA_pub_key_new(RSA_CTX **rsa_ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len);
+void RSA_free(RSA_CTX *ctx);
+int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
+ int is_decryption);
+bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);
+#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
+bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
+ bigint *modulus, bigint *pub_exp);
+bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg);
+int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
+ uint8_t *out_data, int is_signing);
+void RSA_print(const RSA_CTX *ctx);
+#endif
+
+/**************************************************************************
+ * RNG declarations
+ **************************************************************************/
+EXP_FUNC void STDCALL RNG_initialize(const uint8_t *seed_buf, int size);
+EXP_FUNC void STDCALL RNG_terminate(void);
+EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data);
+void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Some misc. routines to help things out
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include "crypto_misc.h"
+#ifdef CONFIG_WIN32_USE_CRYPTO_LIB
+#include "wincrypt.h"
+#endif
+
+#ifndef WIN32
+static int rng_fd = -1;
+#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+static HCRYPTPROV gCryptProv;
+#endif
+
+#if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB))
+static uint64_t rng_num;
+#endif
+
+static int rng_ref_count;
+const char * const unsupported_str = "Error: Feature not supported\n";
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+/**
+ * Retrieve a file and put it into memory
+ * @return The size of the file, or -1 on failure.
+ */
+int get_file(const char *filename, uint8_t **buf)
+{
+ int total_bytes = 0;
+ int bytes_read = 0;
+ int filesize;
+ FILE *stream = fopen(filename, "rb");
+
+ if (stream == NULL)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("file '%s' does not exist\n", filename); TTY_FLUSH();
+#endif
+ return -1;
+ }
+
+ /* Win CE doesn't support stat() */
+ fseek(stream, 0, SEEK_END);
+ filesize = ftell(stream);
+ *buf = (uint8_t *)malloc(filesize);
+ fseek(stream, 0, SEEK_SET);
+
+ do
+ {
+ bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream);
+ total_bytes += bytes_read;
+ } while (total_bytes < filesize && bytes_read > 0);
+
+ fclose(stream);
+ return filesize;
+}
+#endif
+
+/**
+ * Initialise the Random Number Generator engine.
+ * - On Win32 use the platform SDK's crypto engine.
+ * - On Linux use /dev/urandom
+ * - If none of these work then use a custom RNG.
+ */
+EXP_FUNC void STDCALL RNG_initialize(const uint8_t *seed_buf, int size)
+{
+ if (rng_ref_count == 0)
+ {
+#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
+ rng_fd = ax_open("/dev/urandom", O_RDONLY);
+#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+ if (!CryptAcquireContext(&gCryptProv,
+ NULL, NULL, PROV_RSA_FULL, 0))
+ {
+ if (GetLastError() == NTE_BAD_KEYSET &&
+ !CryptAcquireContext(&gCryptProv,
+ NULL,
+ NULL,
+ PROV_RSA_FULL,
+ CRYPT_NEWKEYSET))
+ {
+ printf("CryptoLib: %x\n", unsupported_str, GetLastError());
+ exit(1);
+ }
+ }
+#else
+ /* help seed with the user's private key - this is a number that
+ should be hard to find, due to the fact that it relies on knowing
+ the private key */
+ int i;
+
+ for (i = 0; i < size/(int)sizeof(uint64_t); i++)
+ rng_num ^= *((uint64_t *)&seed_buf[i*sizeof(uint64_t)]);
+
+ srand((long)&seed_buf); /* use the stack ptr as another rnd seed */
+#endif
+ }
+
+ rng_ref_count++;
+}
+
+/**
+ * Terminate the RNG engine.
+ */
+EXP_FUNC void STDCALL RNG_terminate(void)
+{
+ if (--rng_ref_count == 0)
+ {
+#ifndef WIN32
+ close(rng_fd);
+#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+ CryptReleaseContext(gCryptProv, 0);
+#endif
+ }
+}
+
+/**
+ * Set a series of bytes with a random number. Individual bytes can be 0
+ */
+EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data)
+{
+#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
+ /* use the Linux default */
+ read(rng_fd, rand_data, num_rand_bytes); /* read from /dev/urandom */
+#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
+ /* use Microsoft Crypto Libraries */
+ CryptGenRandom(gCryptProv, num_rand_bytes, rand_data);
+#else /* nothing else to use, so use a custom RNG */
+ /* The method we use when we've got nothing better. Use RC4, time
+ and a couple of random seeds to generate a random sequence */
+ RC4_CTX rng_ctx;
+ struct timeval tv;
+ uint64_t big_num1, big_num2;
+
+ gettimeofday(&tv, NULL); /* yes I know we shouldn't do this */
+
+ /* all numbers by themselves are pretty simple, but combined should
+ * be a challenge */
+ big_num1 = (uint64_t)tv.tv_sec*(tv.tv_usec+1);
+ big_num2 = (uint64_t)rand()*big_num1;
+ big_num1 ^= rng_num;
+
+ memcpy(rand_data, &big_num1, sizeof(uint64_t));
+ if (num_rand_bytes > sizeof(uint64_t))
+ memcpy(&rand_data[8], &big_num2, sizeof(uint64_t));
+
+ if (num_rand_bytes > 16)
+ {
+ /* clear rest of data */
+ memset(&rand_data[16], 0, num_rand_bytes-16);
+ }
+
+ RC4_setup(&rng_ctx, rand_data, 16); /* use as a key */
+ RC4_crypt(&rng_ctx, rand_data, rand_data, num_rand_bytes);
+
+ /* use last 8 bytes for next time */
+ memcpy(&rng_num, &rand_data[num_rand_bytes-8], sizeof(uint64_t));
+#endif
+}
+
+/**
+ * Set a series of bytes with a random number. Individual bytes are not zero.
+ */
+void get_random_NZ(int num_rand_bytes, uint8_t *rand_data)
+{
+ int i;
+ get_random(num_rand_bytes, rand_data);
+
+ for (i = 0; i < num_rand_bytes; i++)
+ {
+ while (rand_data[i] == 0) /* can't be 0 */
+ rand_data[i] = (uint8_t)(rand());
+ }
+}
+
+/**
+ * Some useful diagnostic routines
+ */
+#if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG)
+int hex_finish;
+int hex_index;
+
+static void print_hex_init(int finish)
+{
+ hex_finish = finish;
+ hex_index = 0;
+}
+
+static void print_hex(uint8_t hex)
+{
+ static int column;
+
+ if (hex_index == 0)
+ {
+ column = 0;
+ }
+
+ printf("%02x ", hex);
+ if (++column == 8)
+ {
+ printf(": ");
+ }
+ else if (column >= 16)
+ {
+ printf("\n");
+ column = 0;
+ }
+
+ if (++hex_index >= hex_finish && column > 0)
+ {
+ printf("\n");
+ }
+}
+
+/**
+ * Spit out a blob of data for diagnostics. The data is is a nice column format
+ * for easy reading.
+ *
+ * @param format [in] The string (with possible embedded format characters)
+ * @param size [in] The number of numbers to print
+ * @param data [in] The start of data to use
+ * @param ... [in] Any additional arguments
+ */
+EXP_FUNC void STDCALL print_blob(const char *format,
+ const uint8_t *data, int size, ...)
+{
+ int i;
+ char tmp[80];
+ va_list(ap);
+
+ va_start(ap, size);
+ sprintf(tmp, "%s\n", format);
+ vprintf(tmp, ap);
+ print_hex_init(size);
+ for (i = 0; i < size; i++)
+ {
+ print_hex(data[i]);
+ }
+
+ va_end(ap);
+ TTY_FLUSH();
+}
+#elif defined(WIN32)
+/* VC6.0 doesn't handle variadic macros */
+EXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data,
+ int size, ...) {}
+#endif
+
+#if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION)
+/* base64 to binary lookup table */
+static const uint8_t map[128] =
+{
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
+ 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
+ 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 255, 255, 255, 255, 255
+};
+
+EXP_FUNC int STDCALL base64_decode(const char *in, int len,
+ uint8_t *out, int *outlen)
+{
+ int g, t, x, y, z;
+ uint8_t c;
+ int ret = -1;
+
+ g = 3;
+ for (x = y = z = t = 0; x < len; x++)
+ {
+ if ((c = map[in[x]&0x7F]) == 0xff)
+ continue;
+
+ if (c == 254) /* this is the end... */
+ {
+ c = 0;
+
+ if (--g < 0)
+ goto error;
+ }
+ else if (g != 3) /* only allow = at end */
+ goto error;
+
+ t = (t<<6) | c;
+
+ if (++y == 4)
+ {
+ out[z++] = (uint8_t)((t>>16)&255);
+
+ if (g > 1)
+ out[z++] = (uint8_t)((t>>8)&255);
+
+ if (g > 2)
+ out[z++] = (uint8_t)(t&255);
+
+ y = t = 0;
+ }
+ }
+
+ if (y != 0)
+ goto error;
+
+ if (outlen)
+ *outlen = z;
+ ret = 0;
+
+error:
+#ifdef CONFIG_SSL_FULL_MODE
+ if (ret < 0)
+ printf("Error: Invalid base64\n"); TTY_FLUSH();
+#endif
+ TTY_FLUSH();
+ return ret;
+
+}
+#endif
+
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * HMAC implementation - This code was originally taken from RFC2104
+ */
+
+#include <string.h>
+#include "crypto.h"
+
+/**
+ * Perform HMAC-MD5
+ */
+void hmac_md5(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest)
+{
+ MD5_CTX context;
+ uint8_t k_ipad[64];
+ uint8_t k_opad[64];
+ int i;
+
+ memset(k_ipad, 0, sizeof k_ipad);
+ memset(k_opad, 0, sizeof k_opad);
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+
+ for (i = 0; i < 64; i++)
+ {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ MD5_Init(&context);
+ MD5_Update(&context, k_ipad, 64);
+ MD5_Update(&context, msg, length);
+ MD5_Final(digest, &context);
+ MD5_Init(&context);
+ MD5_Update(&context, k_opad, 64);
+ MD5_Update(&context, digest, MD5_SIZE);
+ MD5_Final(digest, &context);
+}
+
+/**
+ * Perform HMAC-SHA1
+ */
+void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest)
+{
+ SHA1_CTX context;
+ uint8_t k_ipad[64];
+ uint8_t k_opad[64];
+ int i;
+
+ memset(k_ipad, 0, sizeof k_ipad);
+ memset(k_opad, 0, sizeof k_opad);
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+
+ for (i = 0; i < 64; i++)
+ {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ SHA1_Init(&context);
+ SHA1_Update(&context, k_ipad, 64);
+ SHA1_Update(&context, msg, length);
+ SHA1_Final(digest, &context);
+ SHA1_Init(&context);
+ SHA1_Update(&context, k_opad, 64);
+ SHA1_Update(&context, digest, SHA1_SIZE);
+ SHA1_Final(digest, &context);
+}
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * RFC 1115/1319 compliant MD2 implementation
+ * The MD2 algorithm was designed by Ron Rivest in 1989.
+ *
+ * http://www.ietf.org/rfc/rfc1115.txt
+ * http://www.ietf.org/rfc/rfc1319.txt
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "crypto.h"
+
+/**
+ * This code is only here to enable the verification of Verisign root
+ * certificates. So only enable it for verification mode.
+ */
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+
+static const uint8_t PI_SUBST[256] =
+{
+ 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36,
+ 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3,
+ 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C,
+ 0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16,
+ 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 0xBE, 0x4E,
+ 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E,
+ 0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2,
+ 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
+ 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E,
+ 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 0xFF, 0x19, 0x30, 0xB3,
+ 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56,
+ 0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6,
+ 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D,
+ 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65,
+ 0xE6, 0x2D, 0xA8, 0x02, 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0,
+ 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
+ 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C,
+ 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E,
+ 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81,
+ 0x4D, 0x52, 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA,
+ 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88,
+ 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE,
+ 0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58,
+ 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
+ 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99,
+ 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
+};
+
+/*
+ * MD2 context setup
+ */
+EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+}
+
+static void md2_process(MD2_CTX *ctx)
+{
+ int i, j;
+ uint8_t t = 0;
+
+ for (i = 0; i < 16; i++)
+ {
+ ctx->state[i + 16] = ctx->buffer[i];
+ ctx->state[i + 32] = ctx->buffer[i] ^ ctx->state[i];
+ }
+
+ for (i = 0; i < 18; i++)
+ {
+ for (j = 0; j < 48; j++)
+ t = (ctx->state[j] ^= PI_SUBST[t]);
+
+ t = (t + i) & 0xFF;
+ }
+
+ t = ctx->cksum[15];
+
+ for (i = 0; i < 16; i++)
+ t = (ctx->cksum[i] ^= PI_SUBST[ctx->buffer[i] ^ t]);
+}
+
+/*
+ * MD2 process buffer
+ */
+EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen)
+{
+ int fill;
+
+ while (ilen > 0)
+ {
+ if (ctx->left + ilen > 16)
+ fill = 16 - ctx->left;
+ else
+ fill = ilen;
+
+ memcpy(ctx->buffer + ctx->left, input, fill);
+
+ ctx->left += fill;
+ input += fill;
+ ilen -= fill;
+
+ if (ctx->left == 16)
+ {
+ ctx->left = 0;
+ md2_process(ctx);
+ }
+ }
+}
+
+/*
+ * MD2 final digest
+ */
+EXP_FUNC void STDCALL MD2_Final(uint8_t *output, MD2_CTX *ctx)
+{
+ int i;
+ uint8_t x;
+
+ x = (uint8_t)(16 - ctx->left);
+
+ for (i = ctx->left; i < 16; i++)
+ ctx->buffer[i] = x;
+
+ md2_process(ctx);
+
+ memcpy(ctx->buffer, ctx->cksum, 16);
+ md2_process(ctx);
+
+ memcpy(output, ctx->state, 16);
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * This file implements the MD5 algorithm as defined in RFC1321
+ */
+
+#include <string.h>
+#include "crypto.h"
+
+/* Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+/* ----- static functions ----- */
+static void MD5Transform(uint32_t state[4], const uint8_t block[64]);
+static void Encode(uint8_t *output, uint32_t *input, uint32_t len);
+static void Decode(uint32_t *output, const uint8_t *input, uint32_t len);
+
+static const uint8_t PADDING[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits. */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+ Rotation is separate from addition to prevent recomputation. */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/**
+ * MD5 initialization - begins an MD5 operation, writing a new ctx.
+ */
+EXP_FUNC void STDCALL MD5_Init(MD5_CTX *ctx)
+{
+ ctx->count[0] = ctx->count[1] = 0;
+
+ /* Load magic initialization constants.
+ */
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xefcdab89;
+ ctx->state[2] = 0x98badcfe;
+ ctx->state[3] = 0x10325476;
+}
+
+/**
+ * Accepts an array of octets as the next portion of the message.
+ */
+EXP_FUNC void STDCALL MD5_Update(MD5_CTX *ctx, const uint8_t * msg, int len)
+{
+ uint32_t x;
+ int i, partLen;
+
+ /* Compute number of bytes mod 64 */
+ x = (uint32_t)((ctx->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((ctx->count[0] += ((uint32_t)len << 3)) < ((uint32_t)len << 3))
+ ctx->count[1]++;
+ ctx->count[1] += ((uint32_t)len >> 29);
+
+ partLen = 64 - x;
+
+ /* Transform as many times as possible. */
+ if (len >= partLen)
+ {
+ memcpy(&ctx->buffer[x], msg, partLen);
+ MD5Transform(ctx->state, ctx->buffer);
+
+ for (i = partLen; i + 63 < len; i += 64)
+ MD5Transform(ctx->state, &msg[i]);
+
+ x = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy(&ctx->buffer[x], &msg[i], len-i);
+}
+
+/**
+ * Return the 128-bit message digest into the user's array
+ */
+EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *ctx)
+{
+ uint8_t bits[8];
+ uint32_t x, padLen;
+
+ /* Save number of bits */
+ Encode(bits, ctx->count, 8);
+
+ /* Pad out to 56 mod 64.
+ */
+ x = (uint32_t)((ctx->count[0] >> 3) & 0x3f);
+ padLen = (x < 56) ? (56 - x) : (120 - x);
+ MD5_Update(ctx, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5_Update(ctx, bits, 8);
+
+ /* Store state in digest */
+ Encode(digest, ctx->state, MD5_SIZE);
+}
+
+/**
+ * MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform(uint32_t state[4], const uint8_t block[64])
+{
+ uint32_t a = state[0], b = state[1], c = state[2],
+ d = state[3], x[MD5_SIZE];
+
+ Decode(x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+}
+
+/**
+ * Encodes input (uint32_t) into output (uint8_t). Assumes len is
+ * a multiple of 4.
+ */
+static void Encode(uint8_t *output, uint32_t *input, uint32_t len)
+{
+ uint32_t i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ {
+ output[j] = (uint8_t)(input[i] & 0xff);
+ output[j+1] = (uint8_t)((input[i] >> 8) & 0xff);
+ output[j+2] = (uint8_t)((input[i] >> 16) & 0xff);
+ output[j+3] = (uint8_t)((input[i] >> 24) & 0xff);
+ }
+}
+
+/**
+ * Decodes input (uint8_t) into output (uint32_t). Assumes len is
+ * a multiple of 4.
+ */
+static void Decode(uint32_t *output, const uint8_t *input, uint32_t len)
+{
+ uint32_t i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
+ (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
+}
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * An implementation of the RC4/ARC4 algorithm.
+ * Originally written by Christophe Devine.
+ */
+
+#include <string.h>
+#include "crypto.h"
+
+/**
+ * Get ready for an encrypt/decrypt operation
+ */
+void RC4_setup(RC4_CTX *ctx, const uint8_t *key, int length)
+{
+ int i, j = 0, k = 0, a;
+ uint8_t *m;
+
+ ctx->x = 0;
+ ctx->y = 0;
+ m = ctx->m;
+
+ for (i = 0; i < 256; i++)
+ m[i] = i;
+
+ for (i = 0; i < 256; i++)
+ {
+ a = m[i];
+ j = (uint8_t)(j + a + key[k]);
+ m[i] = m[j];
+ m[j] = a;
+
+ if (++k >= length)
+ k = 0;
+ }
+}
+
+/**
+ * Perform the encrypt/decrypt operation (can use it for either since
+ * this is a stream cipher).
+ */
+void RC4_crypt(RC4_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+ int i;
+ uint8_t *m, x, y, a, b;
+ out = (uint8_t *)msg;
+
+ x = ctx->x;
+ y = ctx->y;
+ m = ctx->m;
+
+ for (i = 0; i < length; i++)
+ {
+ a = m[++x];
+ y += a;
+ m[x] = b = m[y];
+ m[y] = a;
+ out[i] ^= m[(uint8_t)(a + b)];
+ }
+
+ ctx->x = x;
+ ctx->y = y;
+}
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Implements the RSA public encryption algorithm. Uses the bigint library to
+ * perform its calculations.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include "crypto.h"
+
+void RSA_priv_key_new(RSA_CTX **ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len,
+ const uint8_t *priv_exp, int priv_len
+#if CONFIG_BIGINT_CRT
+ , const uint8_t *p, int p_len,
+ const uint8_t *q, int q_len,
+ const uint8_t *dP, int dP_len,
+ const uint8_t *dQ, int dQ_len,
+ const uint8_t *qInv, int qInv_len
+#endif
+ )
+{
+ RSA_CTX *rsa_ctx;
+ BI_CTX *bi_ctx;
+ RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len);
+ rsa_ctx = *ctx;
+ bi_ctx = rsa_ctx->bi_ctx;
+ rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len);
+ bi_permanent(rsa_ctx->d);
+
+#ifdef CONFIG_BIGINT_CRT
+ rsa_ctx->p = bi_import(bi_ctx, p, p_len);
+ rsa_ctx->q = bi_import(bi_ctx, q, q_len);
+ rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len);
+ rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len);
+ rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len);
+ bi_permanent(rsa_ctx->dP);
+ bi_permanent(rsa_ctx->dQ);
+ bi_permanent(rsa_ctx->qInv);
+ bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET);
+ bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET);
+#endif
+}
+
+void RSA_pub_key_new(RSA_CTX **ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len)
+{
+ RSA_CTX *rsa_ctx;
+ BI_CTX *bi_ctx;
+
+ if (*ctx) /* if we load multiple certs, dump the old one */
+ RSA_free(*ctx);
+
+ bi_ctx = bi_initialize();
+ *ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX));
+ rsa_ctx = *ctx;
+ rsa_ctx->bi_ctx = bi_ctx;
+ rsa_ctx->num_octets = (mod_len & 0xFFF0);
+ rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len);
+ bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET);
+ rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len);
+ bi_permanent(rsa_ctx->e);
+}
+
+/**
+ * Free up any RSA context resources.
+ */
+void RSA_free(RSA_CTX *rsa_ctx)
+{
+ BI_CTX *bi_ctx;
+ if (rsa_ctx == NULL) /* deal with ptrs that are null */
+ return;
+
+ bi_ctx = rsa_ctx->bi_ctx;
+
+ bi_depermanent(rsa_ctx->e);
+ bi_free(bi_ctx, rsa_ctx->e);
+ bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET);
+
+ if (rsa_ctx->d)
+ {
+ bi_depermanent(rsa_ctx->d);
+ bi_free(bi_ctx, rsa_ctx->d);
+#ifdef CONFIG_BIGINT_CRT
+ bi_depermanent(rsa_ctx->dP);
+ bi_depermanent(rsa_ctx->dQ);
+ bi_depermanent(rsa_ctx->qInv);
+ bi_free(bi_ctx, rsa_ctx->dP);
+ bi_free(bi_ctx, rsa_ctx->dQ);
+ bi_free(bi_ctx, rsa_ctx->qInv);
+ bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET);
+ bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET);
+#endif
+ }
+
+ bi_terminate(bi_ctx);
+ free(rsa_ctx);
+}
+
+/**
+ * @brief Use PKCS1.5 for decryption/verification.
+ * @param ctx [in] The context
+ * @param in_data [in] The data to encrypt (must be < modulus size-11)
+ * @param out_data [out] The encrypted data.
+ * @param is_decryption [in] Decryption or verify operation.
+ * @return The number of bytes that were originally encrypted. -1 on error.
+ * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
+ */
+int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data,
+ uint8_t *out_data, int is_decryption)
+{
+ const int byte_size = ctx->num_octets;
+ int i, size;
+ bigint *decrypted_bi, *dat_bi;
+ uint8_t *block = (uint8_t *)alloca(byte_size);
+
+ memset(out_data, 0, byte_size); /* initialise */
+
+ /* decrypt */
+ dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ decrypted_bi = is_decryption ? /* decrypt or verify? */
+ RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi);
+#else /* always a decryption */
+ decrypted_bi = RSA_private(ctx, dat_bi);
+#endif
+
+ /* convert to a normal block */
+ bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size);
+
+ i = 10; /* start at the first possible non-padded byte */
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */
+ {
+ while (block[i++] == 0xff && i < byte_size);
+
+ if (block[i-2] != 0xff)
+ i = byte_size; /*ensure size is 0 */
+ }
+ else /* PKCS1.5 encryption padding is random */
+#endif
+ {
+ while (block[i++] && i < byte_size);
+ }
+ size = byte_size - i;
+
+ /* get only the bit we want */
+ if (size > 0)
+ memcpy(out_data, &block[i], size);
+
+ return size ? size : -1;
+}
+
+/**
+ * Performs m = c^d mod n
+ */
+bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg)
+{
+#ifdef CONFIG_BIGINT_CRT
+ return bi_crt(c->bi_ctx, bi_msg, c->dP, c->dQ, c->p, c->q, c->qInv);
+#else
+ BI_CTX *ctx = c->bi_ctx;
+ ctx->mod_offset = BIGINT_M_OFFSET;
+ return bi_mod_power(ctx, bi_msg, c->d);
+#endif
+}
+
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * Used for diagnostics.
+ */
+void RSA_print(const RSA_CTX *rsa_ctx)
+{
+ if (rsa_ctx == NULL)
+ return;
+
+ printf("----------------- RSA DEBUG ----------------\n");
+ printf("Size:\t%d\n", rsa_ctx->num_octets);
+ bi_print("Modulus", rsa_ctx->m);
+ bi_print("Public Key", rsa_ctx->e);
+ bi_print("Private Key", rsa_ctx->d);
+}
+#endif
+
+#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
+/**
+ * Performs c = m^e mod n
+ */
+bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg)
+{
+ c->bi_ctx->mod_offset = BIGINT_M_OFFSET;
+ return bi_mod_power(c->bi_ctx, bi_msg, c->e);
+}
+
+/**
+ * Use PKCS1.5 for encryption/signing.
+ * see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
+ */
+int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
+ uint8_t *out_data, int is_signing)
+{
+ int byte_size = ctx->num_octets;
+ int num_pads_needed = byte_size-in_len-3;
+ bigint *dat_bi, *encrypt_bi;
+
+ /* note: in_len+11 must be > byte_size */
+ out_data[0] = 0; /* ensure encryption block is < modulus */
+
+ if (is_signing)
+ {
+ out_data[1] = 1; /* PKCS1.5 signing pads with "0xff"'s */
+ memset(&out_data[2], 0xff, num_pads_needed);
+ }
+ else /* randomize the encryption padding with non-zero bytes */
+ {
+ out_data[1] = 2;
+ get_random_NZ(num_pads_needed, &out_data[2]);
+ }
+
+ out_data[2+num_pads_needed] = 0;
+ memcpy(&out_data[3+num_pads_needed], in_data, in_len);
+
+ /* now encrypt it */
+ dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size);
+ encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) :
+ RSA_public(ctx, dat_bi);
+ bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size);
+
+ /* save a few bytes of memory */
+ bi_clear_cache(ctx->bi_ctx);
+ return byte_size;
+}
+
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995.
+ * This code was originally taken from RFC3174
+ */
+
+#include <string.h>
+#include "crypto.h"
+
+/*
+ * Define the SHA1 circular left shift macro
+ */
+#define SHA1CircularShift(bits,word) \
+ (((word) << (bits)) | ((word) >> (32-(bits))))
+
+/* ----- static functions ----- */
+static void SHA1PadMessage(SHA1_CTX *ctx);
+static void SHA1ProcessMessageBlock(SHA1_CTX *ctx);
+
+/**
+ * Initialize the SHA1 context
+ */
+void SHA1_Init(SHA1_CTX *ctx)
+{
+ ctx->Length_Low = 0;
+ ctx->Length_High = 0;
+ ctx->Message_Block_Index = 0;
+ ctx->Intermediate_Hash[0] = 0x67452301;
+ ctx->Intermediate_Hash[1] = 0xEFCDAB89;
+ ctx->Intermediate_Hash[2] = 0x98BADCFE;
+ ctx->Intermediate_Hash[3] = 0x10325476;
+ ctx->Intermediate_Hash[4] = 0xC3D2E1F0;
+}
+
+/**
+ * Accepts an array of octets as the next portion of the message.
+ */
+void SHA1_Update(SHA1_CTX *ctx, const uint8_t *msg, int len)
+{
+ while (len--)
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF);
+ ctx->Length_Low += 8;
+
+ if (ctx->Length_Low == 0)
+ ctx->Length_High++;
+
+ if (ctx->Message_Block_Index == 64)
+ SHA1ProcessMessageBlock(ctx);
+
+ msg++;
+ }
+}
+
+/**
+ * Return the 160-bit message digest into the user's array
+ */
+void SHA1_Final(uint8_t *digest, SHA1_CTX *ctx)
+{
+ int i;
+
+ SHA1PadMessage(ctx);
+ memset(ctx->Message_Block, 0, 64);
+ ctx->Length_Low = 0; /* and clear length */
+ ctx->Length_High = 0;
+
+ for (i = 0; i < SHA1_SIZE; i++)
+ {
+ digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) );
+ }
+}
+
+/**
+ * Process the next 512 bits of the message stored in the array.
+ */
+static void SHA1ProcessMessageBlock(SHA1_CTX *ctx)
+{
+ const uint32_t K[] = { /* Constants defined in SHA-1 */
+ 0x5A827999,
+ 0x6ED9EBA1,
+ 0x8F1BBCDC,
+ 0xCA62C1D6
+ };
+ int t; /* Loop counter */
+ uint32_t temp; /* Temporary word value */
+ uint32_t W[80]; /* Word sequence */
+ uint32_t A, B, C, D, E; /* Word buffers */
+
+ /*
+ * Initialize the first 16 words in the array W
+ */
+ for (t = 0; t < 16; t++)
+ {
+ W[t] = ctx->Message_Block[t * 4] << 24;
+ W[t] |= ctx->Message_Block[t * 4 + 1] << 16;
+ W[t] |= ctx->Message_Block[t * 4 + 2] << 8;
+ W[t] |= ctx->Message_Block[t * 4 + 3];
+ }
+
+ for (t = 16; t < 80; t++)
+ {
+ W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+ }
+
+ A = ctx->Intermediate_Hash[0];
+ B = ctx->Intermediate_Hash[1];
+ C = ctx->Intermediate_Hash[2];
+ D = ctx->Intermediate_Hash[3];
+ E = ctx->Intermediate_Hash[4];
+
+ for (t = 0; t < 20; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+
+ B = A;
+ A = temp;
+ }
+
+ for (t = 20; t < 40; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 40; t < 60; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 60; t < 80; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ ctx->Intermediate_Hash[0] += A;
+ ctx->Intermediate_Hash[1] += B;
+ ctx->Intermediate_Hash[2] += C;
+ ctx->Intermediate_Hash[3] += D;
+ ctx->Intermediate_Hash[4] += E;
+ ctx->Message_Block_Index = 0;
+}
+
+/*
+ * According to the standard, the message must be padded to an even
+ * 512 bits. The first padding bit must be a '1'. The last 64
+ * bits represent the length of the original message. All bits in
+ * between should be 0. This function will pad the message
+ * according to those rules by filling the Message_Block array
+ * accordingly. It will also call the ProcessMessageBlock function
+ * provided appropriately. When it returns, it can be assumed that
+ * the message digest has been computed.
+ *
+ * @param ctx [in, out] The SHA1 context
+ */
+static void SHA1PadMessage(SHA1_CTX *ctx)
+{
+ /*
+ * Check to see if the current message block is too small to hold
+ * the initial padding bits and length. If so, we will pad the
+ * block, process it, and then continue padding into a second
+ * block.
+ */
+ if (ctx->Message_Block_Index > 55)
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
+ while(ctx->Message_Block_Index < 64)
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+ }
+
+ SHA1ProcessMessageBlock(ctx);
+
+ while (ctx->Message_Block_Index < 56)
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+ }
+ }
+ else
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
+ while(ctx->Message_Block_Index < 56)
+ {
+
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+ }
+ }
+
+ /*
+ * Store the message length as the last 8 octets
+ */
+ ctx->Message_Block[56] = ctx->Length_High >> 24;
+ ctx->Message_Block[57] = ctx->Length_High >> 16;
+ ctx->Message_Block[58] = ctx->Length_High >> 8;
+ ctx->Message_Block[59] = ctx->Length_High;
+ ctx->Message_Block[60] = ctx->Length_Low >> 24;
+ ctx->Message_Block[61] = ctx->Length_Low >> 16;
+ ctx->Message_Block[62] = ctx->Length_Low >> 8;
+ ctx->Message_Block[63] = ctx->Length_Low;
+ SHA1ProcessMessageBlock(ctx);
+}
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+include ../config/makefile.conf
+
+all:
+
+doco:
+ doxygen ./axTLS.dox
+
+clean::
+ @-rm -fr html *~
--- /dev/null
+# Doxyfile 1.4.5\r
+\r
+# This file describes the settings to be used by the documentation system\r
+# doxygen (www.doxygen.org) for a project\r
+#\r
+# All text after a hash (#) is considered a comment and will be ignored\r
+# The format is:\r
+# TAG = value [value, ...]\r
+# For lists items can also be appended using:\r
+# TAG += value [value, ...]\r
+# Values that contain spaces should be placed between quotes (" ")\r
+\r
+#---------------------------------------------------------------------------\r
+# Project related configuration options\r
+#---------------------------------------------------------------------------\r
+\r
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded \r
+# by quotes) that should identify the project.\r
+\r
+PROJECT_NAME = axTLS\r
+\r
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. \r
+# This could be handy for archiving the generated documentation or \r
+# if some version control system is used.\r
+\r
+PROJECT_NUMBER = \r
+\r
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) \r
+# base path where the generated documentation will be put. \r
+# If a relative path is entered, it will be relative to the location \r
+# where doxygen was started. If left blank the current directory will be used.\r
+\r
+OUTPUT_DIRECTORY = \r
+\r
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create \r
+# 4096 sub-directories (in 2 levels) under the output directory of each output \r
+# format and will distribute the generated files over these directories. \r
+# Enabling this option can be useful when feeding doxygen a huge amount of \r
+# source files, where putting all generated files in the same directory would \r
+# otherwise cause performance problems for the file system.\r
+\r
+CREATE_SUBDIRS = NO\r
+\r
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all \r
+# documentation generated by doxygen is written. Doxygen will use this \r
+# information to generate all constant output in the proper language. \r
+# The default language is English, other supported languages are: \r
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, \r
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, \r
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, \r
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, \r
+# Swedish, and Ukrainian.\r
+\r
+OUTPUT_LANGUAGE = English\r
+\r
+# This tag can be used to specify the encoding used in the generated output. \r
+# The encoding is not always determined by the language that is chosen, \r
+# but also whether or not the output is meant for Windows or non-Windows users. \r
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES \r
+# forces the Windows encoding (this is the default for the Windows binary), \r
+# whereas setting the tag to NO uses a Unix-style encoding (the default for \r
+# all platforms other than Windows).\r
+\r
+USE_WINDOWS_ENCODING = NO\r
+\r
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will \r
+# include brief member descriptions after the members that are listed in \r
+# the file and class documentation (similar to JavaDoc). \r
+# Set to NO to disable this.\r
+\r
+BRIEF_MEMBER_DESC = YES\r
+\r
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend \r
+# the brief description of a member or function before the detailed description. \r
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the \r
+# brief descriptions will be completely suppressed.\r
+\r
+REPEAT_BRIEF = YES\r
+\r
+# This tag implements a quasi-intelligent brief description abbreviator \r
+# that is used to form the text in various listings. Each string \r
+# in this list, if found as the leading text of the brief description, will be \r
+# stripped from the text and the result after processing the whole list, is \r
+# used as the annotated text. Otherwise, the brief description is used as-is. \r
+# If left blank, the following values are used ("$name" is automatically \r
+# replaced with the name of the entity): "The $name class" "The $name widget" \r
+# "The $name file" "is" "provides" "specifies" "contains" \r
+# "represents" "a" "an" "the"\r
+\r
+ABBREVIATE_BRIEF = \r
+\r
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then \r
+# Doxygen will generate a detailed section even if there is only a brief \r
+# description.\r
+\r
+ALWAYS_DETAILED_SEC = NO\r
+\r
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all \r
+# inherited members of a class in the documentation of that class as if those \r
+# members were ordinary class members. Constructors, destructors and assignment \r
+# operators of the base classes will not be shown.\r
+\r
+INLINE_INHERITED_MEMB = NO\r
+\r
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full \r
+# path before files name in the file list and in the header files. If set \r
+# to NO the shortest path that makes the file name unique will be used.\r
+\r
+FULL_PATH_NAMES = NO\r
+\r
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag \r
+# can be used to strip a user-defined part of the path. Stripping is \r
+# only done if one of the specified strings matches the left-hand part of \r
+# the path. The tag can be used to show relative paths in the file list. \r
+# If left blank the directory from which doxygen is run is used as the \r
+# path to strip.\r
+\r
+STRIP_FROM_PATH = \r
+\r
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of \r
+# the path mentioned in the documentation of a class, which tells \r
+# the reader which header file to include in order to use a class. \r
+# If left blank only the name of the header file containing the class \r
+# definition is used. Otherwise one should specify the include paths that \r
+# are normally passed to the compiler using the -I flag.\r
+\r
+STRIP_FROM_INC_PATH = \r
+\r
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter \r
+# (but less readable) file names. This can be useful is your file systems \r
+# doesn't support long names like on DOS, Mac, or CD-ROM.\r
+\r
+SHORT_NAMES = NO\r
+\r
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen \r
+# will interpret the first line (until the first dot) of a JavaDoc-style \r
+# comment as the brief description. If set to NO, the JavaDoc \r
+# comments will behave just like the Qt-style comments (thus requiring an \r
+# explicit @brief command for a brief description.\r
+\r
+JAVADOC_AUTOBRIEF = NO\r
+\r
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen \r
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// \r
+# comments) as a brief description. This used to be the default behaviour. \r
+# The new default is to treat a multi-line C++ comment block as a detailed \r
+# description. Set this tag to YES if you prefer the old behaviour instead.\r
+\r
+MULTILINE_CPP_IS_BRIEF = NO\r
+\r
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen \r
+# will output the detailed description near the top, like JavaDoc.\r
+# If set to NO, the detailed description appears after the member \r
+# documentation.\r
+\r
+DETAILS_AT_TOP = NO\r
+\r
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented \r
+# member inherits the documentation from any documented member that it \r
+# re-implements.\r
+\r
+INHERIT_DOCS = YES\r
+\r
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce \r
+# a new page for each member. If set to NO, the documentation of a member will \r
+# be part of the file/class/namespace that contains it.\r
+\r
+SEPARATE_MEMBER_PAGES = NO\r
+\r
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. \r
+# Doxygen uses this value to replace tabs by spaces in code fragments.\r
+\r
+TAB_SIZE = 4\r
+\r
+# This tag can be used to specify a number of aliases that acts \r
+# as commands in the documentation. An alias has the form "name=value". \r
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to \r
+# put the command \sideeffect (or @sideeffect) in the documentation, which \r
+# will result in a user-defined paragraph with heading "Side Effects:". \r
+# You can put \n's in the value part of an alias to insert newlines.\r
+\r
+ALIASES = \r
+\r
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C \r
+# sources only. Doxygen will then generate output that is more tailored for C. \r
+# For instance, some of the names that are used will be different. The list \r
+# of all members will be omitted, etc.\r
+\r
+OPTIMIZE_OUTPUT_FOR_C = YES\r
+\r
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java \r
+# sources only. Doxygen will then generate output that is more tailored for Java. \r
+# For instance, namespaces will be presented as packages, qualified scopes \r
+# will look different, etc.\r
+\r
+OPTIMIZE_OUTPUT_JAVA = NO\r
+\r
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to \r
+# include (a tag file for) the STL sources as input, then you should \r
+# set this tag to YES in order to let doxygen match functions declarations and \r
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. \r
+# func(std::string) {}). This also make the inheritance and collaboration \r
+# diagrams that involve STL classes more complete and accurate.\r
+\r
+BUILTIN_STL_SUPPORT = NO\r
+\r
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC \r
+# tag is set to YES, then doxygen will reuse the documentation of the first \r
+# member in the group (if any) for the other members of the group. By default \r
+# all members of a group must be documented explicitly.\r
+\r
+DISTRIBUTE_GROUP_DOC = NO\r
+\r
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of \r
+# the same type (for instance a group of public functions) to be put as a \r
+# subgroup of that type (e.g. under the Public Functions section). Set it to \r
+# NO to prevent subgrouping. Alternatively, this can be done per class using \r
+# the \nosubgrouping command.\r
+\r
+SUBGROUPING = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# Build related configuration options\r
+#---------------------------------------------------------------------------\r
+\r
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in \r
+# documentation are documented, even if no documentation was available. \r
+# Private class members and static file members will be hidden unless \r
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES\r
+\r
+EXTRACT_ALL = NO\r
+\r
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class \r
+# will be included in the documentation.\r
+\r
+EXTRACT_PRIVATE = NO\r
+\r
+# If the EXTRACT_STATIC tag is set to YES all static members of a file \r
+# will be included in the documentation.\r
+\r
+EXTRACT_STATIC = NO\r
+\r
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) \r
+# defined locally in source files will be included in the documentation. \r
+# If set to NO only classes defined in header files are included.\r
+\r
+EXTRACT_LOCAL_CLASSES = YES\r
+\r
+# This flag is only useful for Objective-C code. When set to YES local \r
+# methods, which are defined in the implementation section but not in \r
+# the interface are included in the documentation. \r
+# If set to NO (the default) only methods in the interface are included.\r
+\r
+EXTRACT_LOCAL_METHODS = NO\r
+\r
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all \r
+# undocumented members of documented classes, files or namespaces. \r
+# If set to NO (the default) these members will be included in the \r
+# various overviews, but no documentation section is generated. \r
+# This option has no effect if EXTRACT_ALL is enabled.\r
+\r
+HIDE_UNDOC_MEMBERS = NO\r
+\r
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all \r
+# undocumented classes that are normally visible in the class hierarchy. \r
+# If set to NO (the default) these classes will be included in the various \r
+# overviews. This option has no effect if EXTRACT_ALL is enabled.\r
+\r
+HIDE_UNDOC_CLASSES = NO\r
+\r
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all \r
+# friend (class|struct|union) declarations. \r
+# If set to NO (the default) these declarations will be included in the \r
+# documentation.\r
+\r
+HIDE_FRIEND_COMPOUNDS = NO\r
+\r
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any \r
+# documentation blocks found inside the body of a function. \r
+# If set to NO (the default) these blocks will be appended to the \r
+# function's detailed documentation block.\r
+\r
+HIDE_IN_BODY_DOCS = NO\r
+\r
+# The INTERNAL_DOCS tag determines if documentation \r
+# that is typed after a \internal command is included. If the tag is set \r
+# to NO (the default) then the documentation will be excluded. \r
+# Set it to YES to include the internal documentation.\r
+\r
+INTERNAL_DOCS = NO\r
+\r
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate \r
+# file names in lower-case letters. If set to YES upper-case letters are also \r
+# allowed. This is useful if you have classes or files whose names only differ \r
+# in case and if your file system supports case sensitive file names. Windows \r
+# and Mac users are advised to set this option to NO.\r
+\r
+CASE_SENSE_NAMES = YES\r
+\r
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen \r
+# will show members with their full class and namespace scopes in the \r
+# documentation. If set to YES the scope will be hidden.\r
+\r
+HIDE_SCOPE_NAMES = NO\r
+\r
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen \r
+# will put a list of the files that are included by a file in the documentation \r
+# of that file.\r
+\r
+SHOW_INCLUDE_FILES = NO\r
+\r
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] \r
+# is inserted in the documentation for inline members.\r
+\r
+INLINE_INFO = YES\r
+\r
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen \r
+# will sort the (detailed) documentation of file and class members \r
+# alphabetically by member name. If set to NO the members will appear in \r
+# declaration order.\r
+\r
+SORT_MEMBER_DOCS = NO\r
+\r
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the \r
+# brief documentation of file, namespace and class members alphabetically \r
+# by member name. If set to NO (the default) the members will appear in \r
+# declaration order.\r
+\r
+SORT_BRIEF_DOCS = NO\r
+\r
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be \r
+# sorted by fully-qualified names, including namespaces. If set to \r
+# NO (the default), the class list will be sorted only by class name, \r
+# not including the namespace part. \r
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\r
+# Note: This option applies only to the class list, not to the \r
+# alphabetical list.\r
+\r
+SORT_BY_SCOPE_NAME = NO\r
+\r
+# The GENERATE_TODOLIST tag can be used to enable (YES) or \r
+# disable (NO) the todo list. This list is created by putting \todo \r
+# commands in the documentation.\r
+\r
+GENERATE_TODOLIST = YES\r
+\r
+# The GENERATE_TESTLIST tag can be used to enable (YES) or \r
+# disable (NO) the test list. This list is created by putting \test \r
+# commands in the documentation.\r
+\r
+GENERATE_TESTLIST = YES\r
+\r
+# The GENERATE_BUGLIST tag can be used to enable (YES) or \r
+# disable (NO) the bug list. This list is created by putting \bug \r
+# commands in the documentation.\r
+\r
+GENERATE_BUGLIST = YES\r
+\r
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or \r
+# disable (NO) the deprecated list. This list is created by putting \r
+# \deprecated commands in the documentation.\r
+\r
+GENERATE_DEPRECATEDLIST= YES\r
+\r
+# The ENABLED_SECTIONS tag can be used to enable conditional \r
+# documentation sections, marked by \if sectionname ... \endif.\r
+\r
+ENABLED_SECTIONS = \r
+\r
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines \r
+# the initial value of a variable or define consists of for it to appear in \r
+# the documentation. If the initializer consists of more lines than specified \r
+# here it will be hidden. Use a value of 0 to hide initializers completely. \r
+# The appearance of the initializer of individual variables and defines in the \r
+# documentation can be controlled using \showinitializer or \hideinitializer \r
+# command in the documentation regardless of this setting.\r
+\r
+MAX_INITIALIZER_LINES = 30\r
+\r
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated \r
+# at the bottom of the documentation of classes and structs. If set to YES the \r
+# list will mention the files that were used to generate the documentation.\r
+\r
+SHOW_USED_FILES = NO\r
+\r
+# If the sources in your project are distributed over multiple directories \r
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy \r
+# in the documentation. The default is YES.\r
+\r
+SHOW_DIRECTORIES = NO\r
+\r
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that \r
+# doxygen should invoke to get the current version for each file (typically from the \r
+# version control system). Doxygen will invoke the program by executing (via \r
+# popen()) the command <command> <input-file>, where <command> is the value of \r
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file \r
+# provided by doxygen. Whatever the program writes to standard output \r
+# is used as the file version. See the manual for examples.\r
+\r
+FILE_VERSION_FILTER = \r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to warning and progress messages\r
+#---------------------------------------------------------------------------\r
+\r
+# The QUIET tag can be used to turn on/off the messages that are generated \r
+# by doxygen. Possible values are YES and NO. If left blank NO is used.\r
+\r
+QUIET = NO\r
+\r
+# The WARNINGS tag can be used to turn on/off the warning messages that are \r
+# generated by doxygen. Possible values are YES and NO. If left blank \r
+# NO is used.\r
+\r
+WARNINGS = YES\r
+\r
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings \r
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will \r
+# automatically be disabled.\r
+\r
+WARN_IF_UNDOCUMENTED = YES\r
+\r
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for \r
+# potential errors in the documentation, such as not documenting some \r
+# parameters in a documented function, or documenting parameters that \r
+# don't exist or using markup commands wrongly.\r
+\r
+WARN_IF_DOC_ERROR = YES\r
+\r
+# This WARN_NO_PARAMDOC option can be abled to get warnings for \r
+# functions that are documented, but have no documentation for their parameters \r
+# or return value. If set to NO (the default) doxygen will only warn about \r
+# wrong or incomplete parameter documentation, but not about the absence of \r
+# documentation.\r
+\r
+WARN_NO_PARAMDOC = NO\r
+\r
+# The WARN_FORMAT tag determines the format of the warning messages that \r
+# doxygen can produce. The string should contain the $file, $line, and $text \r
+# tags, which will be replaced by the file and line number from which the \r
+# warning originated and the warning text. Optionally the format may contain \r
+# $version, which will be replaced by the version of the file (if it could \r
+# be obtained via FILE_VERSION_FILTER)\r
+\r
+WARN_FORMAT = "$file:$line: $text"\r
+\r
+# The WARN_LOGFILE tag can be used to specify a file to which warning \r
+# and error messages should be written. If left blank the output is written \r
+# to stderr.\r
+\r
+WARN_LOGFILE = \r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the input files\r
+#---------------------------------------------------------------------------\r
+\r
+# The INPUT tag can be used to specify the files and/or directories that contain \r
+# documented source files. You may enter file names like "myfile.cpp" or \r
+# directories like "/usr/src/myproject". Separate the files or directories \r
+# with spaces.\r
+\r
+INPUT = ../bindings/csharp/axTLS.cs ../bindings/java/SSL.java ../bindings/java/SSLUtil.java ../bindings/java/SSLCTX.java ../bindings/java/SSLServer.java ../bindings/java/SSLClient.java ../bindings/java/SSLReadHolder.java ../ssl/ssl.h ../crypto/bigint.c ../crypto/bigint.h \r
+\r
+# If the value of the INPUT tag contains directories, you can use the \r
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \r
+# and *.h) to filter out the source-files in the directories. If left \r
+# blank the following patterns are tested: \r
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx \r
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py\r
+\r
+FILE_PATTERNS = \r
+\r
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories \r
+# should be searched for input files as well. Possible values are YES and NO. \r
+# If left blank NO is used.\r
+\r
+RECURSIVE = NO\r
+\r
+# The EXCLUDE tag can be used to specify files and/or directories that should \r
+# excluded from the INPUT source files. This way you can easily exclude a \r
+# subdirectory from a directory tree whose root is specified with the INPUT tag.\r
+\r
+EXCLUDE = \r
+\r
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or \r
+# directories that are symbolic links (a Unix filesystem feature) are excluded \r
+# from the input.\r
+\r
+EXCLUDE_SYMLINKS = NO\r
+\r
+# If the value of the INPUT tag contains directories, you can use the \r
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude \r
+# certain files from those directories. Note that the wildcards are matched \r
+# against the file with absolute path, so to exclude all test directories \r
+# for example use the pattern */test/*\r
+\r
+EXCLUDE_PATTERNS = \r
+\r
+# The EXAMPLE_PATH tag can be used to specify one or more files or \r
+# directories that contain example code fragments that are included (see \r
+# the \include command).\r
+\r
+EXAMPLE_PATH = \r
+\r
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the \r
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \r
+# and *.h) to filter out the source-files in the directories. If left \r
+# blank all files are included.\r
+\r
+EXAMPLE_PATTERNS = \r
+\r
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be \r
+# searched for input files to be used with the \include or \dontinclude \r
+# commands irrespective of the value of the RECURSIVE tag. \r
+# Possible values are YES and NO. If left blank NO is used.\r
+\r
+EXAMPLE_RECURSIVE = NO\r
+\r
+# The IMAGE_PATH tag can be used to specify one or more files or \r
+# directories that contain image that are included in the documentation (see \r
+# the \image command).\r
+\r
+IMAGE_PATH = images\r
+\r
+# The INPUT_FILTER tag can be used to specify a program that doxygen should \r
+# invoke to filter for each input file. Doxygen will invoke the filter program \r
+# by executing (via popen()) the command <filter> <input-file>, where <filter> \r
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an \r
+# input file. Doxygen will then use the output that the filter program writes \r
+# to standard output. If FILTER_PATTERNS is specified, this tag will be \r
+# ignored.\r
+\r
+INPUT_FILTER = \r
+\r
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern \r
+# basis. Doxygen will compare the file name with each pattern and apply the \r
+# filter if there is a match. The filters are a list of the form: \r
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further \r
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER \r
+# is applied to all files.\r
+\r
+FILTER_PATTERNS = \r
+\r
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using \r
+# INPUT_FILTER) will be used to filter the input files when producing source \r
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).\r
+\r
+FILTER_SOURCE_FILES = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to source browsing\r
+#---------------------------------------------------------------------------\r
+\r
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will \r
+# be generated. Documented entities will be cross-referenced with these sources. \r
+# Note: To get rid of all source code in the generated output, make sure also \r
+# VERBATIM_HEADERS is set to NO.\r
+\r
+SOURCE_BROWSER = NO\r
+\r
+# Setting the INLINE_SOURCES tag to YES will include the body \r
+# of functions and classes directly in the documentation.\r
+\r
+INLINE_SOURCES = NO\r
+\r
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct \r
+# doxygen to hide any special comment blocks from generated source code \r
+# fragments. Normal C and C++ comments will always remain visible.\r
+\r
+STRIP_CODE_COMMENTS = YES\r
+\r
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) \r
+# then for each documented function all documented \r
+# functions referencing it will be listed.\r
+\r
+REFERENCED_BY_RELATION = YES\r
+\r
+# If the REFERENCES_RELATION tag is set to YES (the default) \r
+# then for each documented function all documented entities \r
+# called/used by that function will be listed.\r
+\r
+REFERENCES_RELATION = YES\r
+\r
+# If the USE_HTAGS tag is set to YES then the references to source code \r
+# will point to the HTML generated by the htags(1) tool instead of doxygen \r
+# built-in source browser. The htags tool is part of GNU's global source \r
+# tagging system (see http://www.gnu.org/software/global/global.html). You \r
+# will need version 4.8.6 or higher.\r
+\r
+USE_HTAGS = NO\r
+\r
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen \r
+# will generate a verbatim copy of the header file for each class for \r
+# which an include is specified. Set to NO to disable this.\r
+\r
+VERBATIM_HEADERS = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the alphabetical class index\r
+#---------------------------------------------------------------------------\r
+\r
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index \r
+# of all compounds will be generated. Enable this if the project \r
+# contains a lot of classes, structs, unions or interfaces.\r
+\r
+ALPHABETICAL_INDEX = NO\r
+\r
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then \r
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns \r
+# in which this list will be split (can be a number in the range [1..20])\r
+\r
+COLS_IN_ALPHA_INDEX = 5\r
+\r
+# In case all classes in a project start with a common prefix, all \r
+# classes will be put under the same header in the alphabetical index. \r
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that \r
+# should be ignored while generating the index headers.\r
+\r
+IGNORE_PREFIX = \r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the HTML output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will \r
+# generate HTML output.\r
+\r
+GENERATE_HTML = YES\r
+\r
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `html' will be used as the default path.\r
+\r
+HTML_OUTPUT = html\r
+\r
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for \r
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank \r
+# doxygen will generate files with .html extension.\r
+\r
+HTML_FILE_EXTENSION = .html\r
+\r
+# The HTML_HEADER tag can be used to specify a personal HTML header for \r
+# each generated HTML page. If it is left blank doxygen will generate a \r
+# standard header.\r
+\r
+HTML_HEADER = \r
+\r
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for \r
+# each generated HTML page. If it is left blank doxygen will generate a \r
+# standard footer.\r
+\r
+HTML_FOOTER = doco_footer.html \r
+\r
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading \r
+# style sheet that is used by each HTML page. It can be used to \r
+# fine-tune the look of the HTML output. If the tag is left blank doxygen \r
+# will generate a default style sheet. Note that doxygen will try to copy \r
+# the style sheet file to the HTML output directory, so don't put your own \r
+# stylesheet in the HTML output directory as well, or it will be erased!\r
+\r
+HTML_STYLESHEET = \r
+\r
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, \r
+# files or namespaces will be aligned in HTML using tables. If set to \r
+# NO a bullet list will be used.\r
+\r
+HTML_ALIGN_MEMBERS = YES\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files \r
+# will be generated that can be used as input for tools like the \r
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) \r
+# of the generated HTML documentation.\r
+\r
+GENERATE_HTMLHELP = NO\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can \r
+# be used to specify the file name of the resulting .chm file. You \r
+# can add a path in front of the file if the result should not be \r
+# written to the html output directory.\r
+\r
+CHM_FILE = \r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can \r
+# be used to specify the location (absolute path including file name) of \r
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run \r
+# the HTML help compiler on the generated index.hhp.\r
+\r
+HHC_LOCATION = \r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag \r
+# controls if a separate .chi index file is generated (YES) or that \r
+# it should be included in the master .chm file (NO).\r
+\r
+GENERATE_CHI = NO\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag \r
+# controls whether a binary table of contents is generated (YES) or a \r
+# normal table of contents (NO) in the .chm file.\r
+\r
+BINARY_TOC = NO\r
+\r
+# The TOC_EXPAND flag can be set to YES to add extra items for group members \r
+# to the contents of the HTML help documentation and to the tree view.\r
+\r
+TOC_EXPAND = YES\r
+\r
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at \r
+# top of each HTML page. The value NO (the default) enables the index and \r
+# the value YES disables it.\r
+\r
+DISABLE_INDEX = YES\r
+\r
+# This tag can be used to set the number of enum values (range [1..20]) \r
+# that doxygen will group on one line in the generated HTML documentation.\r
+\r
+ENUM_VALUES_PER_LINE = 4\r
+\r
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be\r
+# generated containing a tree-like index structure (just like the one that \r
+# is generated for HTML Help). For this to work a browser that supports \r
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, \r
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are \r
+# probably better off using the HTML help feature.\r
+\r
+GENERATE_TREEVIEW = YES\r
+\r
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be \r
+# used to set the initial width (in pixels) of the frame in which the tree \r
+# is shown.\r
+\r
+TREEVIEW_WIDTH = 250\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the LaTeX output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will \r
+# generate Latex output.\r
+\r
+GENERATE_LATEX = NO\r
+\r
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `latex' will be used as the default path.\r
+\r
+LATEX_OUTPUT = latex\r
+\r
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be \r
+# invoked. If left blank `latex' will be used as the default command name.\r
+\r
+LATEX_CMD_NAME = latex\r
+\r
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to \r
+# generate index for LaTeX. If left blank `makeindex' will be used as the \r
+# default command name.\r
+\r
+MAKEINDEX_CMD_NAME = makeindex\r
+\r
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact \r
+# LaTeX documents. This may be useful for small projects and may help to \r
+# save some trees in general.\r
+\r
+COMPACT_LATEX = NO\r
+\r
+# The PAPER_TYPE tag can be used to set the paper type that is used \r
+# by the printer. Possible values are: a4, a4wide, letter, legal and \r
+# executive. If left blank a4wide will be used.\r
+\r
+PAPER_TYPE = a4wide\r
+\r
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX \r
+# packages that should be included in the LaTeX output.\r
+\r
+EXTRA_PACKAGES = \r
+\r
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for \r
+# the generated latex document. The header should contain everything until \r
+# the first chapter. If it is left blank doxygen will generate a \r
+# standard header. Notice: only use this tag if you know what you are doing!\r
+\r
+LATEX_HEADER = \r
+\r
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated \r
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will \r
+# contain links (just like the HTML output) instead of page references \r
+# This makes the output suitable for online browsing using a pdf viewer.\r
+\r
+PDF_HYPERLINKS = NO\r
+\r
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of \r
+# plain latex in the generated Makefile. Set this option to YES to get a \r
+# higher quality PDF documentation.\r
+\r
+USE_PDFLATEX = NO\r
+\r
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. \r
+# command to the generated LaTeX files. This will instruct LaTeX to keep \r
+# running if errors occur, instead of asking the user for help. \r
+# This option is also used when generating formulas in HTML.\r
+\r
+LATEX_BATCHMODE = NO\r
+\r
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not \r
+# include the index chapters (such as File Index, Compound Index, etc.) \r
+# in the output.\r
+\r
+LATEX_HIDE_INDICES = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the RTF output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output \r
+# The RTF output is optimized for Word 97 and may not look very pretty with \r
+# other RTF readers or editors.\r
+\r
+GENERATE_RTF = NO\r
+\r
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `rtf' will be used as the default path.\r
+\r
+RTF_OUTPUT = rtf\r
+\r
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact \r
+# RTF documents. This may be useful for small projects and may help to \r
+# save some trees in general.\r
+\r
+COMPACT_RTF = NO\r
+\r
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated \r
+# will contain hyperlink fields. The RTF file will \r
+# contain links (just like the HTML output) instead of page references. \r
+# This makes the output suitable for online browsing using WORD or other \r
+# programs which support those fields. \r
+# Note: wordpad (write) and others do not support links.\r
+\r
+RTF_HYPERLINKS = NO\r
+\r
+# Load stylesheet definitions from file. Syntax is similar to doxygen's \r
+# config file, i.e. a series of assignments. You only have to provide \r
+# replacements, missing definitions are set to their default value.\r
+\r
+RTF_STYLESHEET_FILE = \r
+\r
+# Set optional variables used in the generation of an rtf document. \r
+# Syntax is similar to doxygen's config file.\r
+\r
+RTF_EXTENSIONS_FILE = \r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the man page output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will \r
+# generate man pages\r
+\r
+GENERATE_MAN = NO\r
+\r
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `man' will be used as the default path.\r
+\r
+MAN_OUTPUT = man\r
+\r
+# The MAN_EXTENSION tag determines the extension that is added to \r
+# the generated man pages (default is the subroutine's section .3)\r
+\r
+MAN_EXTENSION = .3\r
+\r
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, \r
+# then it will generate one additional man file for each entity \r
+# documented in the real man page(s). These additional files \r
+# only source the real man page, but without them the man command \r
+# would be unable to find the correct page. The default is NO.\r
+\r
+MAN_LINKS = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the XML output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_XML tag is set to YES Doxygen will \r
+# generate an XML file that captures the structure of \r
+# the code including all documentation.\r
+\r
+GENERATE_XML = NO\r
+\r
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. \r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r
+# put in front of it. If left blank `xml' will be used as the default path.\r
+\r
+XML_OUTPUT = xml\r
+\r
+# The XML_SCHEMA tag can be used to specify an XML schema, \r
+# which can be used by a validating XML parser to check the \r
+# syntax of the XML files.\r
+\r
+XML_SCHEMA = \r
+\r
+# The XML_DTD tag can be used to specify an XML DTD, \r
+# which can be used by a validating XML parser to check the \r
+# syntax of the XML files.\r
+\r
+XML_DTD = \r
+\r
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will \r
+# dump the program listings (including syntax highlighting \r
+# and cross-referencing information) to the XML output. Note that \r
+# enabling this will significantly increase the size of the XML output.\r
+\r
+XML_PROGRAMLISTING = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options for the AutoGen Definitions output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will \r
+# generate an AutoGen Definitions (see autogen.sf.net) file \r
+# that captures the structure of the code including all \r
+# documentation. Note that this feature is still experimental \r
+# and incomplete at the moment.\r
+\r
+GENERATE_AUTOGEN_DEF = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the Perl module output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will \r
+# generate a Perl module file that captures the structure of \r
+# the code including all documentation. Note that this \r
+# feature is still experimental and incomplete at the \r
+# moment.\r
+\r
+GENERATE_PERLMOD = NO\r
+\r
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate \r
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able \r
+# to generate PDF and DVI output from the Perl module output.\r
+\r
+PERLMOD_LATEX = NO\r
+\r
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be \r
+# nicely formatted so it can be parsed by a human reader. This is useful \r
+# if you want to understand what is going on. On the other hand, if this \r
+# tag is set to NO the size of the Perl module output will be much smaller \r
+# and Perl will parse it just the same.\r
+\r
+PERLMOD_PRETTY = YES\r
+\r
+# The names of the make variables in the generated doxyrules.make file \r
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. \r
+# This is useful so different doxyrules.make files included by the same \r
+# Makefile don't overwrite each other's variables.\r
+\r
+PERLMOD_MAKEVAR_PREFIX = \r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration options related to the preprocessor \r
+#---------------------------------------------------------------------------\r
+\r
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will \r
+# evaluate all C-preprocessor directives found in the sources and include \r
+# files.\r
+\r
+ENABLE_PREPROCESSING = YES\r
+\r
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro \r
+# names in the source code. If set to NO (the default) only conditional \r
+# compilation will be performed. Macro expansion can be done in a controlled \r
+# way by setting EXPAND_ONLY_PREDEF to YES.\r
+\r
+MACRO_EXPANSION = YES\r
+\r
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES \r
+# then the macro expansion is limited to the macros specified with the \r
+# PREDEFINED and EXPAND_AS_DEFINED tags.\r
+\r
+EXPAND_ONLY_PREDEF = YES\r
+\r
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files \r
+# in the INCLUDE_PATH (see below) will be search if a #include is found.\r
+\r
+SEARCH_INCLUDES = YES\r
+\r
+# The INCLUDE_PATH tag can be used to specify one or more directories that \r
+# contain include files that are not input files but should be processed by \r
+# the preprocessor.\r
+\r
+INCLUDE_PATH = \r
+\r
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard \r
+# patterns (like *.h and *.hpp) to filter out the header-files in the \r
+# directories. If left blank, the patterns specified with FILE_PATTERNS will \r
+# be used.\r
+\r
+INCLUDE_FILE_PATTERNS = \r
+\r
+# The PREDEFINED tag can be used to specify one or more macro names that \r
+# are defined before the preprocessor is started (similar to the -D option of \r
+# gcc). The argument of the tag is a list of macros of the form: name \r
+# or name=definition (no spaces). If the definition and the = are \r
+# omitted =1 is assumed. To prevent a macro definition from being \r
+# undefined via #undef or recursively expanded use the := operator \r
+# instead of the = operator.\r
+\r
+PREDEFINED = CONFIG_SSL_CERT_VERIFICATION CONFIG_SSL_ENABLE_CLIENT CONFIG_SSL_GENERATE_X509_CERT CONFIG_BIGINT_MONTGOMERY CONFIG_BIGINT_BARRETT CONFIG_BIGINT_CRT EXP_FUNC="" STDCALL=""\r
+\r
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then \r
+# this tag can be used to specify a list of macro names that should be expanded. \r
+# The macro definition that is found in the sources will be used. \r
+# Use the PREDEFINED tag if you want to use a different macro definition.\r
+\r
+EXPAND_AS_DEFINED = \r
+\r
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then \r
+# doxygen's preprocessor will remove all function-like macros that are alone \r
+# on a line, have an all uppercase name, and do not end with a semicolon. Such \r
+# function macros are typically used for boiler-plate code, and will confuse \r
+# the parser if not removed.\r
+\r
+SKIP_FUNCTION_MACROS = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration::additions related to external references \r
+#---------------------------------------------------------------------------\r
+\r
+# The TAGFILES option can be used to specify one or more tagfiles. \r
+# Optionally an initial location of the external documentation \r
+# can be added for each tagfile. The format of a tag file without \r
+# this location is as follows: \r
+# TAGFILES = file1 file2 ... \r
+# Adding location for the tag files is done as follows: \r
+# TAGFILES = file1=loc1 "file2 = loc2" ... \r
+# where "loc1" and "loc2" can be relative or absolute paths or \r
+# URLs. If a location is present for each tag, the installdox tool \r
+# does not have to be run to correct the links.\r
+# Note that each tag file must have a unique name\r
+# (where the name does NOT include the path)\r
+# If a tag file is not located in the directory in which doxygen \r
+# is run, you must also specify the path to the tagfile here.\r
+\r
+TAGFILES = \r
+\r
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create \r
+# a tag file that is based on the input files it reads.\r
+\r
+GENERATE_TAGFILE = \r
+\r
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed \r
+# in the class index. If set to NO only the inherited external classes \r
+# will be listed.\r
+\r
+ALLEXTERNALS = NO\r
+\r
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed \r
+# in the modules index. If set to NO, only the current project's groups will \r
+# be listed.\r
+\r
+EXTERNAL_GROUPS = NO\r
+\r
+# The PERL_PATH should be the absolute path and name of the perl script \r
+# interpreter (i.e. the result of `which perl').\r
+\r
+PERL_PATH = /usr/bin/perl\r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration options related to the dot tool \r
+#---------------------------------------------------------------------------\r
+\r
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will \r
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base \r
+# or super classes. Setting the tag to NO turns the diagrams off. Note that \r
+# this option is superseded by the HAVE_DOT option below. This is only a \r
+# fallback. It is recommended to install and use dot, since it yields more \r
+# powerful graphs.\r
+\r
+CLASS_DIAGRAMS = YES\r
+\r
+# If set to YES, the inheritance and collaboration graphs will hide \r
+# inheritance and usage relations if the target is undocumented \r
+# or is not a class.\r
+\r
+HIDE_UNDOC_RELATIONS = YES\r
+\r
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is \r
+# available from the path. This tool is part of Graphviz, a graph visualization \r
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section \r
+# have no effect if this option is set to NO (the default)\r
+\r
+HAVE_DOT = NO\r
+\r
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen \r
+# will generate a graph for each documented class showing the direct and \r
+# indirect inheritance relations. Setting this tag to YES will force the \r
+# the CLASS_DIAGRAMS tag to NO.\r
+\r
+CLASS_GRAPH = NO\r
+\r
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen \r
+# will generate a graph for each documented class showing the direct and \r
+# indirect implementation dependencies (inheritance, containment, and \r
+# class references variables) of the class with other documented classes.\r
+\r
+COLLABORATION_GRAPH = NO\r
+\r
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen \r
+# will generate a graph for groups, showing the direct groups dependencies\r
+\r
+GROUP_GRAPHS = NO\r
+\r
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and \r
+# collaboration diagrams in a style similar to the OMG's Unified Modeling \r
+# Language.\r
+\r
+UML_LOOK = NO\r
+\r
+# If set to YES, the inheritance and collaboration graphs will show the \r
+# relations between templates and their instances.\r
+\r
+TEMPLATE_RELATIONS = NO\r
+\r
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT \r
+# tags are set to YES then doxygen will generate a graph for each documented \r
+# file showing the direct and indirect include dependencies of the file with \r
+# other documented files.\r
+\r
+INCLUDE_GRAPH = NO\r
+\r
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and \r
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each \r
+# documented header file showing the documented files that directly or \r
+# indirectly include this file.\r
+\r
+INCLUDED_BY_GRAPH = NO\r
+\r
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will \r
+# generate a call dependency graph for every global function or class method. \r
+# Note that enabling this option will significantly increase the time of a run. \r
+# So in most cases it will be better to enable call graphs for selected \r
+# functions only using the \callgraph command.\r
+\r
+CALL_GRAPH = NO\r
+\r
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen \r
+# will graphical hierarchy of all classes instead of a textual one.\r
+\r
+GRAPHICAL_HIERARCHY = NO\r
+\r
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES \r
+# then doxygen will show the dependencies a directory has on other directories \r
+# in a graphical way. The dependency relations are determined by the #include\r
+# relations between the files in the directories.\r
+\r
+DIRECTORY_GRAPH = NO\r
+\r
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images \r
+# generated by dot. Possible values are png, jpg, or gif\r
+# If left blank png will be used.\r
+\r
+DOT_IMAGE_FORMAT = png\r
+\r
+# The tag DOT_PATH can be used to specify the path where the dot tool can be \r
+# found. If left blank, it is assumed the dot tool can be found in the path.\r
+\r
+DOT_PATH = \r
+\r
+# The DOTFILE_DIRS tag can be used to specify one or more directories that \r
+# contain dot files that are included in the documentation (see the \r
+# \dotfile command).\r
+\r
+DOTFILE_DIRS = \r
+\r
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width \r
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than \r
+# this value, doxygen will try to truncate the graph, so that it fits within \r
+# the specified constraint. Beware that most browsers cannot cope with very \r
+# large images.\r
+\r
+MAX_DOT_GRAPH_WIDTH = 1024\r
+\r
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height \r
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than \r
+# this value, doxygen will try to truncate the graph, so that it fits within \r
+# the specified constraint. Beware that most browsers cannot cope with very \r
+# large images.\r
+\r
+MAX_DOT_GRAPH_HEIGHT = 1024\r
+\r
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the \r
+# graphs generated by dot. A depth value of 3 means that only nodes reachable \r
+# from the root by following a path via at most 3 edges will be shown. Nodes \r
+# that lay further from the root node will be omitted. Note that setting this \r
+# option to 1 or 2 may greatly reduce the computation time needed for large \r
+# code bases. Also note that a graph may be further truncated if the graph's \r
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH \r
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), \r
+# the graph is not depth-constrained.\r
+\r
+MAX_DOT_GRAPH_DEPTH = 0\r
+\r
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent \r
+# background. This is disabled by default, which results in a white background. \r
+# Warning: Depending on the platform used, enabling this option may lead to \r
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to \r
+# read).\r
+\r
+DOT_TRANSPARENT = NO\r
+\r
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output \r
+# files in one run (i.e. multiple -o and -T options on the command line). This \r
+# makes dot run faster, but since only newer versions of dot (>1.8.10) \r
+# support this, this feature is disabled by default.\r
+\r
+DOT_MULTI_TARGETS = NO\r
+\r
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will \r
+# generate a legend page explaining the meaning of the various boxes and \r
+# arrows in the dot generated graphs.\r
+\r
+GENERATE_LEGEND = YES\r
+\r
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will \r
+# remove the intermediate dot files that are used to generate \r
+# the various graphs.\r
+\r
+DOT_CLEANUP = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration::additions related to the search engine \r
+#---------------------------------------------------------------------------\r
+\r
+# The SEARCHENGINE tag specifies whether or not a search engine should be \r
+# used. If set to NO the values of all tags below this one will be ignored.\r
+\r
+SEARCHENGINE = NO\r
--- /dev/null
+<p></p>
+<p align="center"><img src="../images/tsbasbw.gif" width="1000" height="7"></p>
+<CITE>Copyright <sup>©</sup> 2007 Cameron Rich</CITE>
--- /dev/null
+#
+# For a description of the syntax of this configuration file,
+# see scripts/config/Kconfig-language.txt
+#
+
+menu "Axhttpd Configuration"
+depends on CONFIG_AXHTTPD
+
+config CONFIG_HTTP_STATIC_BUILD
+ bool "Static Build"
+ default n
+ help
+ Select y if you want axhttpd to be a static build (i.e. don't use the
+ axtls shared library or dll).
+
+config CONFIG_HTTP_PORT
+ int "HTTP port"
+ default 80
+ help
+ The port number of the normal HTTP server.
+
+ You must be a root user in order to use the default port.
+
+config CONFIG_HTTP_HTTPS_PORT
+ int "HTTPS port"
+ default 443
+ help
+ The port number of the HTTPS server.
+
+ You must be a root user in order to use the default port.
+
+config CONFIG_HTTP_SESSION_CACHE_SIZE
+ int "SSL session cache size"
+ default 5
+ help
+ The size of the SSL session cache.
+
+ This is not actually related to the number of concurrent users, but
+ for optimum performance they should be the same (with a penalty
+ in memory usage).
+
+config CONFIG_HTTP_WEBROOT
+ string "Web root location"
+ default "../www" if !CONFIG_PLATFORM_WIN32
+ default "..\\www" if CONFIG_PLATFORM_WIN32
+ help
+ The location of the web root in relation to axhttpd. This is
+ the directory where index.html lives.
+
+config CONFIG_HTTP_TIMEOUT
+ int "Timeout"
+ default 300
+ help
+ Set the timeout of a connection in seconds.
+
+menu "CGI"
+depends on !CONFIG_PLATFORM_WIN32
+
+config CONFIG_HTTP_HAS_CGI
+ bool "Enable CGI"
+ default y
+ depends on !CONFIG_PLATFORM_WIN32
+ help
+ Enable the CGI capability. Not available on Win32 platforms.
+
+config CONFIG_HTTP_CGI_EXTENSIONS
+ string "CGI File Extension(s)"
+ default ".lua,.lp"
+ depends on CONFIG_HTTP_HAS_CGI
+ help
+ Tell axhhtpd what file extension(s) are used for CGI.
+
+ This is a comma separated list - e.g. ".php,.pl" etc
+
+config CONFIG_HTTP_ENABLE_LUA
+ bool "Enable Lua"
+ default y
+ depends on CONFIG_HTTP_HAS_CGI
+ help
+ Lua is a powerful, fast, light-weight, embeddable scripting language.
+
+ See http://www.lua.org for details.
+
+config CONFIG_HTTP_LUA_PREFIX
+ string "Lua's Installation Prefix"
+ default "/usr/local"
+ depends on CONFIG_HTTP_ENABLE_LUA
+
+ help
+ The location of Lua's installation prefix. This is also necessary for
+ Lua's cgi launcher application.
+
+config CONFIG_HTTP_LUA_CGI_LAUNCHER
+ string "CGI launcher location"
+ default "/bin/cgi.exe" if CONFIG_PLATFORM_CYGWIN
+ default "/bin/cgi" if !CONFIG_PLATFORM_CYGWIN
+ depends on CONFIG_HTTP_ENABLE_LUA
+ help
+ The location of LUA's CGI launcher application (after
+ the CONFIG_HTTP_LUA_PREFIX)
+
+config CONFIG_HTTP_BUILD_LUA
+ bool "Build Lua"
+ default n
+ depends on CONFIG_HTTP_ENABLE_LUA
+ help
+ Build Lua and install in /usr/local/bin
+
+endmenu
+
+config CONFIG_HTTP_DIRECTORIES
+ bool "Enable Directory Listing"
+ default y
+ help
+ Enable directory listing.
+
+config CONFIG_HTTP_HAS_AUTHORIZATION
+ bool "Enable authorization"
+ default y
+ help
+ Pages/directories can have passwords associated with them.
+
+config CONFIG_HTTP_HAS_IPV6
+ bool "Enable IPv6"
+ default n
+ depends on !CONFIG_PLATFORM_WIN32
+ help
+ Use IPv6 instead of IPv4.
+
+ Does not work under Win32
+
+config CONFIG_HTTP_ENABLE_DIFFERENT_USER
+ bool "Enable different user"
+ default n
+ depends on !CONFIG_PLATFORM_WIN32
+ help
+ Allow the web server to be run as a different user
+
+config CONFIG_HTTP_USER
+ string "As User"
+ default "nobody"
+ depends on CONFIG_HTTP_ENABLE_DIFFERENT_USER
+ help
+ The user name that will be used to run axhttpd.
+
+config CONFIG_HTTP_VERBOSE
+ bool "Verbose Mode"
+ default y if CONFIG_SSL_FULL_MODE
+ default n if !CONFIG_SSL_FULL_MODE
+ help
+ Enable extra statements used when using axhttpd.
+
+config CONFIG_HTTP_IS_DAEMON
+ bool "Run as a daemon"
+ default n
+ depends on !CONFIG_PLATFORM_WIN32
+ help
+ Run axhttpd as a background process.
+
+ Does not work under Win32
+
+endmenu
+
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+all : web_server lua
+
+AXTLS_HOME=..
+
+include $(AXTLS_HOME)/config/.config
+include $(AXTLS_HOME)/config/makefile.conf
+
+ifndef CONFIG_PLATFORM_WIN32
+
+ifdef CONFIG_PLATFORM_CYGWIN
+TARGET=$(AXTLS_HOME)/$(STAGE)/axhttpd.exe
+TARGET2=$(AXTLS_HOME)/$(STAGE)/htpasswd.exe
+else
+TARGET=$(AXTLS_HOME)/$(STAGE)/axhttpd
+TARGET2=$(AXTLS_HOME)/$(STAGE)/htpasswd
+endif
+
+ifdef CONFIG_HTTP_STATIC_BUILD
+LIBS=$(AXTLS_HOME)/$(STAGE)/libaxtls.a
+else
+LIBS=-L$(AXTLS_HOME)/$(STAGE) -laxtls
+endif
+
+ifdef CONFIG_HTTP_BUILD_LUA
+lua: kepler-1.1
+
+kepler-1.1:
+ @tar xvfz kepler-1.1-snapshot-20070521-1825.tar.gz
+ @cat kepler.patch | patch -p0
+ cd kepler-1.1; ./configure --prefix=$(CONFIG_HTTP_LUA_PREFIX) --launcher=cgi --lua-suffix= ; make install
+else
+lua:
+endif
+
+else # win32 build
+lua:
+
+TARGET=$(AXTLS_HOME)/$(STAGE)/axhttpd.exe
+TARGET2=$(AXTLS_HOME)/$(STAGE)/htpasswd.exe
+
+ifdef CONFIG_HTTP_STATIC_BUILD
+LIBS=$(AXTLS_HOME)/$(STAGE)/axtls.static.lib $(AXTLS_HOME)\\config\\axtls.res
+else
+LIBS=$(AXTLS_HOME)/$(STAGE)/axtls.lib $(AXTLS_HOME)\\config\\axtls.res
+endif
+endif
+
+ifndef CONFIG_AXHTTPD
+web_server:
+else
+
+web_server :: $(TARGET)
+
+ifdef CONFIG_HTTP_HAS_AUTHORIZATION
+web_server :: $(TARGET2)
+endif
+
+OBJ= \
+ axhttpd.o \
+ proc.o \
+ tdate_parse.o
+
+include $(AXTLS_HOME)/config/makefile.post
+
+ifndef CONFIG_PLATFORM_WIN32
+
+$(TARGET): $(OBJ) $(AXTLS_HOME)/$(STAGE)/libaxtls.a
+ $(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
+ifdef CONFIG_STRIP_UNWANTED_SECTIONS
+ $(STRIP) --remove-section=.comment $(TARGET)
+endif
+
+$(TARGET2): htpasswd.o $(AXTLS_HOME)/$(STAGE)/libaxtls.a
+ $(LD) $(LDFLAGS) -o $@ htpasswd.o $(LIBS)
+
+else # Win32
+
+OBJ:=$(OBJ:.o=.obj)
+%.obj : %.c
+ $(CC) $(CFLAGS) $<
+
+htpasswd.obj : htpasswd.c
+ $(CC) $(CFLAGS) $?
+
+$(TARGET): $(OBJ)
+ $(LD) $(LDFLAGS) /out:$@ $(LIBS) $?
+
+$(TARGET2): htpasswd.obj
+ $(LD) $(LDFLAGS) /out:$@ $(LIBS) $?
+endif
+
+endif # CONFIG_AXHTTPD
+
+clean::
+ -@rm -f $(TARGET)*
+ -@rm -fr kepler-1.1
+
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ssl.h"
+
+#define BACKLOG 15
+#define VERSION "1.0.0"
+#ifdef CONFIG_HTTP_HAS_IPV6
+#define HAVE_IPV6
+#endif
+
+#define MAXPOSTDATASIZE 30000
+#define MAXREQUESTLENGTH 256
+#define BLOCKSIZE 4096
+
+#define INITIAL_CONNECTION_SLOTS 10
+#define CONFIG_HTTP_DEFAULT_SSL_OPTIONS SSL_DISPLAY_CERTS
+
+#define STATE_WANT_TO_READ_HEAD 1
+#define STATE_WANT_TO_SEND_HEAD 2
+#define STATE_WANT_TO_READ_FILE 3
+#define STATE_WANT_TO_SEND_FILE 4
+#define STATE_DOING_DIR 5
+
+enum
+{
+ TYPE_GET,
+ TYPE_HEAD,
+ TYPE_POST
+};
+
+struct connstruct
+{
+ struct connstruct *next;
+ int state;
+ int reqtype;
+ int networkdesc;
+ int filedesc;
+ SSL *ssl;
+
+#if defined(CONFIG_HTTP_DIRECTORIES)
+#ifdef WIN32
+ HANDLE dirp;
+ WIN32_FIND_DATA file_data;
+#else
+ DIR *dirp;
+#endif
+#endif
+
+ time_t timeout;
+ char actualfile[MAXREQUESTLENGTH];
+ char filereq[MAXREQUESTLENGTH];
+ char dirname[MAXREQUESTLENGTH];
+ char server_name[MAXREQUESTLENGTH];
+ int numbytes;
+ char databuf[BLOCKSIZE];
+ uint8_t is_ssl;
+ uint8_t close_when_done;
+ time_t if_modified_since;
+
+#if defined(CONFIG_HTTP_HAS_CGI)
+ uint8_t is_cgi;
+#ifdef CONFIG_HTTP_ENABLE_LUA
+ uint8_t is_lua;
+#endif
+ int content_length;
+ char remote_addr[MAXREQUESTLENGTH];
+ char uri_request[MAXREQUESTLENGTH];
+ char uri_path_info[MAXREQUESTLENGTH];
+ char uri_query[MAXREQUESTLENGTH];
+ char cookie[MAXREQUESTLENGTH];
+#endif
+#if defined(CONFIG_HTTP_HAS_AUTHORIZATION)
+ char authorization[MAXREQUESTLENGTH];
+#endif
+ int post_read;
+ int post_state;
+ char *post_data;
+};
+
+struct serverstruct
+{
+ struct serverstruct *next;
+ int sd;
+ int is_ssl;
+ SSL_CTX *ssl_ctx;
+};
+
+#if defined(CONFIG_HTTP_HAS_CGI)
+struct cgiextstruct
+{
+ struct cgiextstruct *next;
+ char *ext;
+};
+#endif
+
+/* global prototypes */
+extern struct serverstruct *servers;
+extern struct connstruct *usedconns;
+extern struct connstruct *freeconns;
+extern const char * const server_version;
+
+#if defined(CONFIG_HTTP_HAS_CGI)
+extern struct cgiextstruct *cgiexts;
+#endif
+
+/* conn.c prototypes */
+void removeconnection(struct connstruct *cn);
+
+/* proc.c prototypes */
+void procdodir(struct connstruct *cn);
+void procreadhead(struct connstruct *cn);
+void procsendhead(struct connstruct *cn);
+void procreadfile(struct connstruct *cn);
+void procsendfile(struct connstruct *cn);
+#if defined(CONFIG_HTTP_HAS_CGI)
+void read_post_data(struct connstruct *cn);
+#endif
+
+/* misc.c prototypes */
+char *my_strncpy(char *dest, const char *src, size_t n);
+int isdir(const char *name);
+
+/* tdate prototypes */
+void tdate_init(void);
+time_t tdate_parse(const char* str);
+
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include "axhttp.h"
+
+struct serverstruct *servers;
+struct connstruct *usedconns;
+struct connstruct *freeconns;
+const char * const server_version = "axhttpd/"AXTLS_VERSION;
+
+static void addtoservers(int sd);
+static int openlistener(int port);
+static void handlenewconnection(int listenfd, int is_ssl);
+static void addconnection(int sd, char *ip, int is_ssl);
+static void ax_chdir(void);
+
+#if defined(CONFIG_HTTP_HAS_CGI)
+struct cgiextstruct *cgiexts;
+static void addcgiext(const char *tp);
+
+#if !defined(WIN32)
+static void reaper(int sigtype)
+{
+ wait3(NULL, WNOHANG, NULL);
+}
+#endif
+#endif
+
+#ifdef CONFIG_HTTP_VERBOSE /* should really be in debug mode or something */
+/* clean up memory for valgrind */
+static void sigint_cleanup(int sig)
+{
+ struct serverstruct *sp;
+ struct connstruct *tp;
+
+ while (servers != NULL)
+ {
+ if (servers->is_ssl)
+ ssl_ctx_free(servers->ssl_ctx);
+
+ sp = servers->next;
+ free(servers);
+ servers = sp;
+ }
+
+ while (freeconns != NULL)
+ {
+ tp = freeconns->next;
+ free(freeconns);
+ freeconns = tp;
+ }
+
+ while (usedconns != NULL)
+ {
+ tp = usedconns->next;
+ free(usedconns);
+ usedconns = tp;
+ }
+
+#if defined(CONFIG_HTTP_HAS_CGI)
+ while (cgiexts)
+ {
+ struct cgiextstruct *cp = cgiexts->next;
+ if (cp == NULL) /* last entry */
+ free(cgiexts->ext);
+ free(cgiexts);
+ cgiexts = cp;
+ }
+#endif
+
+ exit(0);
+}
+
+static void die(int sigtype)
+{
+ exit(0);
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+ fd_set rfds, wfds;
+ struct connstruct *tp, *to;
+ struct serverstruct *sp;
+ int rnum, wnum, active;
+ int i;
+ time_t currtime;
+
+#ifdef WIN32
+ WORD wVersionRequested = MAKEWORD(2, 2);
+ WSADATA wsaData;
+ WSAStartup(wVersionRequested,&wsaData);
+#else
+ signal(SIGPIPE, SIG_IGN);
+#if defined(CONFIG_HTTP_HAS_CGI)
+ signal(SIGCHLD, reaper);
+#endif
+#ifdef CONFIG_HTTP_VERBOSE
+ signal(SIGQUIT, die);
+#endif
+#endif
+
+#ifdef CONFIG_HTTP_VERBOSE
+ signal(SIGTERM, die);
+ signal(SIGINT, sigint_cleanup);
+#endif
+ tdate_init();
+
+ for (i = 0; i < INITIAL_CONNECTION_SLOTS; i++)
+ {
+ tp = freeconns;
+ freeconns = (struct connstruct *)calloc(1, sizeof(struct connstruct));
+ freeconns->next = tp;
+ }
+
+ if ((active = openlistener(CONFIG_HTTP_PORT)) == -1)
+ {
+#ifdef CONFIG_HTTP_VERBOSE
+ fprintf(stderr, "ERR: Couldn't bind to port %d\n",
+ CONFIG_HTTP_PORT);
+#endif
+ exit(1);
+ }
+
+ addtoservers(active);
+
+ if ((active = openlistener(CONFIG_HTTP_HTTPS_PORT)) == -1)
+ {
+#ifdef CONFIG_HTTP_VERBOSE
+ fprintf(stderr, "ERR: Couldn't bind to port %d\n",
+ CONFIG_HTTP_HTTPS_PORT);
+#endif
+ exit(1);
+ }
+
+ addtoservers(active);
+ servers->ssl_ctx = ssl_ctx_new(CONFIG_HTTP_DEFAULT_SSL_OPTIONS,
+ CONFIG_HTTP_SESSION_CACHE_SIZE);
+ servers->is_ssl = 1;
+
+#if defined(CONFIG_HTTP_HAS_CGI)
+ addcgiext(CONFIG_HTTP_CGI_EXTENSIONS);
+#endif
+
+#if defined(CONFIG_HTTP_VERBOSE)
+#if defined(CONFIG_HTTP_HAS_CGI)
+ printf("addcgiext %s\n", CONFIG_HTTP_CGI_EXTENSIONS);
+#endif
+ printf("%s: listening on ports %d (http) and %d (https)\n",
+ server_version, CONFIG_HTTP_PORT, CONFIG_HTTP_HTTPS_PORT);
+ TTY_FLUSH();
+#endif
+
+ ax_chdir();
+
+#ifdef CONFIG_HTTP_ENABLE_DIFFERENT_USER
+ {
+ struct passwd *pd = getpwnam(CONFIG_HTTP_USER);
+
+ if (pd != NULL)
+ {
+ int res = setuid(pd->pw_uid);
+ res |= setgid(pd->pw_gid);
+
+#if defined(CONFIG_HTTP_VERBOSE)
+ if (res == 0)
+ {
+ printf("change to '%s' successful\n", CONFIG_HTTP_USER);
+ TTY_FLUSH();
+ }
+#endif
+ }
+
+ }
+#endif
+
+
+#ifndef WIN32
+#ifdef CONFIG_HTTP_IS_DAEMON
+ if (fork() > 0) /* parent will die */
+ exit(0);
+
+ setsid();
+#endif
+#endif
+
+ /* main loop */
+ while (1)
+ {
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ rnum = wnum = -1;
+ sp = servers;
+
+ while (sp != NULL) /* read each server port */
+ {
+ FD_SET(sp->sd, &rfds);
+
+ if (sp->sd > rnum)
+ rnum = sp->sd;
+ sp = sp->next;
+ }
+
+ /* Add the established sockets */
+ tp = usedconns;
+ currtime = time(NULL);
+
+ while (tp != NULL)
+ {
+ if (currtime > tp->timeout) /* timed out? Kill it. */
+ {
+ to = tp;
+ tp = tp->next;
+ removeconnection(to);
+ continue;
+ }
+
+ if (tp->state == STATE_WANT_TO_READ_HEAD)
+ {
+ FD_SET(tp->networkdesc, &rfds);
+ if (tp->networkdesc > rnum)
+ rnum = tp->networkdesc;
+ }
+
+ if (tp->state == STATE_WANT_TO_SEND_HEAD)
+ {
+ FD_SET(tp->networkdesc, &wfds);
+ if (tp->networkdesc > wnum)
+ wnum = tp->networkdesc;
+ }
+
+ if (tp->state == STATE_WANT_TO_READ_FILE)
+ {
+ FD_SET(tp->filedesc, &rfds);
+ if (tp->filedesc > rnum)
+ rnum = tp->filedesc;
+ }
+
+ if (tp->state == STATE_WANT_TO_SEND_FILE)
+ {
+ FD_SET(tp->networkdesc, &wfds);
+ if (tp->networkdesc > wnum)
+ wnum = tp->networkdesc;
+ }
+
+#if defined(CONFIG_HTTP_DIRECTORIES)
+ if (tp->state == STATE_DOING_DIR)
+ {
+ FD_SET(tp->networkdesc, &wfds);
+ if (tp->networkdesc > wnum)
+ wnum = tp->networkdesc;
+ }
+#endif
+ tp = tp->next;
+ }
+
+ active = select(wnum > rnum ? wnum+1 : rnum+1,
+ rnum != -1 ? &rfds : NULL,
+ wnum != -1 ? &wfds : NULL,
+ NULL, NULL);
+
+ /* New connection? */
+ sp = servers;
+ while (active > 0 && sp != NULL)
+ {
+ if (FD_ISSET(sp->sd, &rfds))
+ {
+ handlenewconnection(sp->sd, sp->is_ssl);
+ active--;
+ }
+
+ sp = sp->next;
+ }
+
+ /* Handle the established sockets */
+ tp = usedconns;
+
+ while (active > 0 && tp != NULL)
+ {
+ to = tp;
+ tp = tp->next;
+
+ if (to->state == STATE_WANT_TO_READ_HEAD &&
+ FD_ISSET(to->networkdesc, &rfds))
+ {
+ active--;
+#if defined(CONFIG_HTTP_HAS_CGI)
+ if (to->post_state)
+ read_post_data(to);
+ else
+#endif
+ procreadhead(to);
+ }
+
+ if (to->state == STATE_WANT_TO_SEND_HEAD &&
+ FD_ISSET(to->networkdesc, &wfds))
+ {
+ active--;
+ procsendhead(to);
+ }
+
+ if (to->state == STATE_WANT_TO_READ_FILE &&
+ FD_ISSET(to->filedesc, &rfds))
+ {
+ active--;
+ procreadfile(to);
+ }
+
+ if (to->state == STATE_WANT_TO_SEND_FILE &&
+ FD_ISSET(to->networkdesc, &wfds))
+ {
+ active--;
+ procsendfile(to);
+ }
+
+#if defined(CONFIG_HTTP_DIRECTORIES)
+ if (to->state == STATE_DOING_DIR &&
+ FD_ISSET(to->networkdesc, &wfds))
+ {
+ active--;
+ procdodir(to);
+ }
+#endif
+ }
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_HTTP_HAS_CGI)
+static void addcgiext(const char *cgi_exts)
+{
+ char *cp = strdup(cgi_exts);
+
+ /* extenstions are comma separated */
+ do
+ {
+ struct cgiextstruct *ex = (struct cgiextstruct *)
+ malloc(sizeof(struct cgiextstruct));
+ ex->ext = cp;
+ ex->next = cgiexts;
+ cgiexts = ex;
+ if ((cp = strchr(cp, ',')) != NULL)
+ *cp++ = 0;
+ } while (cp != NULL);
+}
+#endif
+
+static void addtoservers(int sd)
+{
+ struct serverstruct *tp = (struct serverstruct *)
+ calloc(1, sizeof(struct serverstruct));
+ tp->next = servers;
+ tp->sd = sd;
+ servers = tp;
+}
+
+#ifdef HAVE_IPV6
+static void handlenewconnection(int listenfd, int is_ssl)
+{
+ struct sockaddr_in6 their_addr;
+ int tp = sizeof(their_addr);
+ char ipbuf[100];
+ int connfd = accept(listenfd, (struct sockaddr *)&their_addr, &tp);
+
+ if (tp == sizeof(struct sockaddr_in6))
+ inet_ntop(AF_INET6, &their_addr.sin6_addr, ipbuf, sizeof(ipbuf));
+ else if (tp == sizeof(struct sockaddr_in))
+ inet_ntop(AF_INET, &(((struct sockaddr_in *)&their_addr)->sin_addr),
+ ipbuf, sizeof(ipbuf));
+ else
+ *ipbuf = '\0';
+
+ addconnection(connfd, ipbuf, is_ssl);
+}
+
+#else
+static void handlenewconnection(int listenfd, int is_ssl)
+{
+ struct sockaddr_in their_addr;
+ socklen_t tp = sizeof(struct sockaddr_in);
+ int connfd = accept(listenfd, (struct sockaddr *)&their_addr, &tp);
+ addconnection(connfd, inet_ntoa(their_addr.sin_addr), is_ssl);
+}
+#endif
+
+static int openlistener(int port)
+{
+ int sd;
+#ifdef WIN32
+ char tp = 1;
+#else
+ int tp = 1;
+#endif
+#ifndef HAVE_IPV6
+ struct sockaddr_in my_addr;
+
+ if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ return -1;
+
+ memset(&my_addr, 0, sizeof(my_addr));
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_port = htons((short)port);
+ my_addr.sin_addr.s_addr = INADDR_ANY;
+#else
+ struct sockaddr_in6 my_addr;
+
+ if ((sd = socket(AF_INET6, SOCK_STREAM, 0)) == -1)
+ return -1;
+
+ memset(&my_addr, 0, sizeof(my_addr));
+ my_addr.sin6_family = AF_INET6;
+ my_addr.sin6_port = htons(port);
+ my_addr.sin6_addr.s_addr = INADDR_ANY;
+#endif
+
+ setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &tp, sizeof(tp));
+ if (bind(sd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
+ {
+ close(sd);
+ return -1;
+ }
+
+ listen(sd, BACKLOG);
+ return sd;
+}
+
+/* Wrapper function for strncpy() that guarantees
+ a null-terminated string. This is to avoid any possible
+ issues due to strncpy()'s behaviour.
+ */
+char *my_strncpy(char *dest, const char *src, size_t n)
+{
+ strncpy(dest, src, n);
+ dest[n-1] = '\0';
+ return dest;
+}
+
+int isdir(const char *tpbuf)
+{
+ struct stat st;
+ char path[MAXREQUESTLENGTH];
+ strcpy(path, tpbuf);
+
+#ifdef WIN32 /* win32 stat() can't handle trailing '\' */
+ if (path[strlen(path)-1] == '\\')
+ path[strlen(path)-1] = 0;
+#endif
+
+ if (stat(path, &st) == -1)
+ return 0;
+
+ if ((st.st_mode & S_IFMT) == S_IFDIR)
+ return 1;
+
+ return 0;
+}
+
+static void addconnection(int sd, char *ip, int is_ssl)
+{
+ struct connstruct *tp;
+
+ /* Get ourselves a connstruct */
+ if (freeconns == NULL)
+ tp = (struct connstruct *)calloc(1, sizeof(struct connstruct));
+ else
+ {
+ tp = freeconns;
+ freeconns = tp->next;
+ }
+
+ /* Attach it to the used list */
+ tp->next = usedconns;
+ usedconns = tp;
+ tp->networkdesc = sd;
+
+ if (is_ssl)
+ tp->ssl = ssl_server_new(servers->ssl_ctx, sd);
+
+ tp->is_ssl = is_ssl;
+ tp->filedesc = -1;
+#if defined(CONFIG_HTTP_HAS_DIRECTORIES)
+ tp->dirp = NULL;
+#endif
+ *tp->actualfile = '\0';
+ *tp->filereq = '\0';
+ tp->state = STATE_WANT_TO_READ_HEAD;
+ tp->reqtype = TYPE_GET;
+ tp->close_when_done = 0;
+ tp->timeout = time(NULL) + CONFIG_HTTP_TIMEOUT;
+#if defined(CONFIG_HTTP_HAS_CGI)
+ strcpy(tp->remote_addr, ip);
+#endif
+}
+
+void removeconnection(struct connstruct *cn)
+{
+ struct connstruct *tp;
+ int shouldret = 0;
+
+ tp = usedconns;
+
+ if (tp == NULL || cn == NULL)
+ shouldret = 1;
+ else if (tp == cn)
+ usedconns = tp->next;
+ else
+ {
+ while (tp != NULL)
+ {
+ if (tp->next == cn)
+ {
+ tp->next = (tp->next)->next;
+ shouldret = 0;
+ break;
+ }
+
+ tp = tp->next;
+ shouldret = 1;
+ }
+ }
+
+ if (shouldret)
+ return;
+
+ /* If we did, add it to the free list */
+ cn->next = freeconns;
+ freeconns = cn;
+
+ /* Close it all down */
+ if (cn->networkdesc != -1)
+ {
+ if (cn->is_ssl)
+ {
+ ssl_free(cn->ssl);
+ cn->ssl = NULL;
+ }
+
+ SOCKET_CLOSE(cn->networkdesc);
+ }
+
+ if (cn->filedesc != -1)
+ close(cn->filedesc);
+
+#if defined(CONFIG_HTTP_HAS_DIRECTORIES)
+ if (cn->dirp != NULL)
+#ifdef WIN32
+ FindClose(cn->dirp);
+#else
+ closedir(cn->dirp);
+#endif
+#endif
+}
+
+/*
+ * Change directories one way or the other.
+ */
+static void ax_chdir(void)
+{
+ static char *webroot = CONFIG_HTTP_WEBROOT;
+
+ if (chdir(webroot))
+ {
+#ifdef CONFIG_HTTP_VERBOSE
+ fprintf(stderr, "'%s' is not a directory\n", webroot);
+#endif
+ exit(1);
+ }
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "ssl.h"
+
+int tfd;
+
+void base64_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen)
+{
+ static const char b64str[64] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ while (inlen && outlen)
+ {
+ *out++ = b64str[(in[0] >> 2) & 0x3f];
+ if (!--outlen)
+ break;
+
+ *out++ = b64str[((in[0] << 4)
+ + (--inlen ? in[1] >> 4 : 0)) & 0x3f];
+ if (!--outlen)
+ break;
+ *out++ = (inlen
+ ? b64str[((in[1] << 2)
+ + (--inlen ? in[2] >> 6 : 0))
+ & 0x3f]
+ : '=');
+ if (!--outlen)
+ break;
+ *out++ = inlen ? b64str[in[2] & 0x3f] : '=';
+ if (!--outlen)
+ break;
+ if (inlen)
+ inlen--;
+ if (inlen)
+ in += 3;
+ }
+
+ if (outlen)
+ *out = '\0';
+}
+
+static void usage(void)
+{
+ fprintf(stderr,"Usage: htpasswd username\n");
+ exit(1);
+}
+
+#ifdef WIN32
+static char * getpass(const char *prompt)
+{
+ static char buf[127];
+ FILE *fp = stdin;
+
+ printf(prompt); TTY_FLUSH();
+#if 0
+ fp = fopen("/dev/tty", "w");
+ if (fp == NULL)
+ {
+ printf("null\n"); TTY_FLUSH();
+ fp = stdin;
+ }
+#endif
+
+ fgets(buf, sizeof(buf), fp);
+ while (buf[strlen(buf)-1] < ' ')
+ buf[strlen(buf)-1] = '\0';
+
+ //if (fp != stdin)
+ // fclose(fp);
+ return buf;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+ char* pw;
+ uint8_t md5_salt[MD5_SIZE], md5_pass[MD5_SIZE];
+ char b64_salt[MD5_SIZE+10], b64_pass[MD5_SIZE+10];
+ MD5_CTX ctx;
+
+ if (argc != 2)
+ usage();
+
+ pw = strdup(getpass("New password:"));
+ if (strcmp(pw, getpass("Re-type new password:")) != 0)
+ {
+ fprintf(stderr, "They don't match, sorry.\n" );
+ exit(1);
+ }
+
+ RNG_initialize((uint8_t *)pw, sizeof(pw));
+ get_random(MD5_SIZE, md5_salt);
+ RNG_terminate();
+ base64_encode(md5_salt, MD5_SIZE, b64_salt, sizeof(b64_salt));
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, md5_salt, MD5_SIZE);
+ MD5_Update(&ctx, (uint8_t *)pw, strlen(pw));
+ MD5_Final(md5_pass, &ctx);
+ base64_encode(md5_pass, MD5_SIZE, b64_pass, sizeof(b64_pass));
+
+ printf("Add the following to your '.htpasswd' file\n");
+ printf("%s:%s$%s\n", argv[1], b64_salt, b64_pass);
+ return 0;
+}
--- /dev/null
+diff -Naur kepler-1.1/launcher/cgi/Makefile kepler-1.1.new/launcher/cgi/Makefile
+--- kepler-1.1/launcher/cgi/Makefile 2007-04-21 06:41:49.000000000 +1000
++++ kepler-1.1.new/launcher/cgi/Makefile 2007-05-16 22:13:38.750000000 +1000
+@@ -16,7 +16,7 @@
+
+
+ $T: $(CH) $(OBJS)
+- $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
++ $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) -L../../lua-5.1.2/src -llua
+
+ build: $T
+
+diff -Naur kepler-1.1/luafilesystem/Makefile kepler-1.1.new/luafilesystem/Makefile
+--- kepler-1.1/luafilesystem/Makefile 2007-04-21 06:41:49.000000000 +1000
++++ kepler-1.1.new/luafilesystem/Makefile 2007-05-16 22:06:25.546875000 +1000
+@@ -12,7 +12,7 @@
+ lib: src/$(LIBNAME)
+
+ src/$(LIBNAME): $(OBJS)
+- export MACOSX_DEPLOYMENT_TARGET="10.3"; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/$(LIBNAME) $(OBJS)
++ export MACOSX_DEPLOYMENT_TARGET="10.3"; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/$(LIBNAME) $(OBJS) -L../lua-5.1.2/src -llua
+
+ install: src/$(LIBNAME)
+ mkdir -p $(LUA_LIBDIR)
+diff -Naur kepler-1.1/luasocket-2.0.1/src/makefile kepler-1.1.new/luasocket-2.0.1/src/makefile
+--- kepler-1.1/luasocket-2.0.1/src/makefile 2007-04-21 06:41:49.000000000 +1000
++++ kepler-1.1.new/luasocket-2.0.1/src/makefile 2007-05-16 22:36:37.125000000 +1000
+@@ -47,10 +47,10 @@
+ all: $(SOCKET_SO) $(MIME_SO)
+
+ $(SOCKET_SO): $(SOCKET_OBJS)
+- $(LD) $(LDFLAGS) -o $@ $(SOCKET_OBJS)
++ $(LD) $(LDFLAGS) -o $@ $(SOCKET_OBJS) -L../../lua-5.1.2/src -llua
+
+ $(MIME_SO): $(MIME_OBJS)
+- $(LD) $(LDFLAGS) -o $@ $(MIME_OBJS)
++ $(LD) $(LDFLAGS) -o $@ $(MIME_OBJS) -L../../lua-5.1.2/src -llua
+
+ $(UNIX_SO): $(UNIX_OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(UNIX_OBJS)
+diff -Naur kepler-1.1/md5/Makefile kepler-1.1.new/md5/Makefile
+--- kepler-1.1/md5/Makefile 2007-04-21 06:41:49.000000000 +1000
++++ kepler-1.1.new/md5/Makefile 2007-05-16 22:06:44.593750000 +1000
+@@ -15,7 +15,7 @@
+
+
+ src/$(LIBNAME) : $(OBJS)
+- export MACOSX_DEPLOYMENT_TARGET="10.3"; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/$(LIBNAME) $(OBJS)
++ export MACOSX_DEPLOYMENT_TARGET="10.3"; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/$(LIBNAME) $(OBJS) -L../lua-5.1.2/src -llua
+
+ $(COMPAT_DIR)/compat-5.1.o: $(COMPAT_DIR)/compat-5.1.c
+ $(CC) -c $(CFLAGS) -o $@ $(COMPAT_DIR)/compat-5.1.c
+diff -Naur kepler-1.1/rings/Makefile kepler-1.1.new/rings/Makefile
+--- kepler-1.1/rings/Makefile 2007-04-21 06:41:49.000000000 +1000
++++ kepler-1.1.new/rings/Makefile 2007-05-16 22:05:28.765625000 +1000
+@@ -10,7 +10,7 @@
+ OBJS= src/rings.o
+
+ src/$(LIBNAME) : $(OBJS)
+- export MACOSX_DEPLOYMENT_TARGET="10.3"; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/$(LIBNAME) $(OBJS)
++ export MACOSX_DEPLOYMENT_TARGET="10.3"; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/$(LIBNAME) $(OBJS) -L../lua-5.1.2/src -llua
+
+ install:
+ mkdir -p $(LUA_LIBDIR)
--- /dev/null
+/*
+ * Copyright (c) 2007-2008, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#include "axhttp.h"
+
+#define HTTP_VERSION "HTTP/1.1"
+
+static const char * index_file = "index.html";
+
+static int special_read(struct connstruct *cn, void *buf, size_t count);
+static int special_write(struct connstruct *cn,
+ const char *buf, size_t count);
+static void send_error(struct connstruct *cn, int err);
+static int hexit(char c);
+static void urldecode(char *buf);
+static void buildactualfile(struct connstruct *cn);
+static int sanitizefile(const char *buf);
+static int sanitizehost(char *buf);
+static int htaccess_check(struct connstruct *cn);
+static const char *getmimetype(const char *name);
+
+#if defined(CONFIG_HTTP_DIRECTORIES)
+static void urlencode(const uint8_t *s, char *t);
+static void procdirlisting(struct connstruct *cn);
+#endif
+#if defined(CONFIG_HTTP_HAS_CGI)
+static void proccgi(struct connstruct *cn);
+static void decode_path_info(struct connstruct *cn, char *path_info);
+static int init_read_post_data(char *buf, char *data, struct connstruct *cn, int old_rv);
+#endif
+#ifdef CONFIG_HTTP_HAS_AUTHORIZATION
+static int auth_check(struct connstruct *cn);
+#endif
+
+#if AXDEBUG
+#define AXDEBUGSTART \
+ { \
+ FILE *axdout; \
+ axdout = fopen("/var/log/axdebug", "a"); \
+
+#define AXDEBUGEND \
+ fclose(axdout); \
+ }
+#else /* AXDEBUG */
+#define AXDEBUGSTART
+#define AXDEBUGEND
+#endif /* AXDEBUG */
+
+/* Returns 1 if elems should continue being read, 0 otherwise */
+static int procheadelem(struct connstruct *cn, char *buf)
+{
+ char *delim, *value;
+
+ if ((delim = strchr(buf, ' ')) == NULL)
+ return 0;
+
+ *delim = 0;
+ value = delim+1;
+
+ if (strcmp(buf, "GET") == 0 || strcmp(buf, "HEAD") == 0 ||
+ strcmp(buf, "POST") == 0)
+ {
+ if (buf[0] == 'H')
+ cn->reqtype = TYPE_HEAD;
+ else if (buf[0] == 'P')
+ cn->reqtype = TYPE_POST;
+
+ if ((delim = strchr(value, ' ')) == NULL) /* expect HTTP type */
+ return 0;
+
+ *delim = 0;
+ urldecode(value);
+
+ if (sanitizefile(value) == 0)
+ {
+ send_error(cn, 403);
+ return 0;
+ }
+
+#if defined(CONFIG_HTTP_HAS_CGI)
+ decode_path_info(cn, value);
+#else
+ my_strncpy(cn->filereq, value, MAXREQUESTLENGTH);
+#endif
+ cn->if_modified_since = -1;
+ }
+ else if (strcmp(buf, "Host:") == 0)
+ {
+ if (sanitizehost(value) == 0)
+ {
+ removeconnection(cn);
+ return 0;
+ }
+
+ my_strncpy(cn->server_name, value, MAXREQUESTLENGTH);
+ }
+ else if (strcmp(buf, "Connection:") == 0 && strcmp(value, "close") == 0)
+ {
+ cn->close_when_done = 1;
+ }
+ else if (strcmp(buf, "If-Modified-Since:") == 0)
+ {
+ cn->if_modified_since = tdate_parse(value);
+ }
+ else if (strcmp(buf, "Expect:") == 0)
+ {
+ send_error(cn, 417); /* expectation failed */
+ return 0;
+ }
+#ifdef CONFIG_HTTP_HAS_AUTHORIZATION
+ else if (strcmp(buf, "Authorization:") == 0 &&
+ strncmp(value, "Basic ", 6) == 0)
+ {
+ int size;
+ if (base64_decode(&value[6], strlen(&value[6]),
+ (uint8_t *)cn->authorization, &size))
+ cn->authorization[0] = 0; /* error */
+ else
+ cn->authorization[size] = 0;
+ }
+#endif
+#if defined(CONFIG_HTTP_HAS_CGI)
+ else if (strcmp(buf, "Content-Length:") == 0)
+ {
+ sscanf(value, "%d", &cn->content_length);
+ }
+ else if (strcmp(buf, "Cookie:") == 0)
+ {
+ my_strncpy(cn->cookie, value, MAXREQUESTLENGTH);
+ }
+#endif
+
+ return 1;
+}
+
+#if defined(CONFIG_HTTP_DIRECTORIES)
+static void procdirlisting(struct connstruct *cn)
+{
+ char buf[MAXREQUESTLENGTH];
+ char actualfile[1024];
+
+ if (cn->reqtype == TYPE_HEAD)
+ {
+ snprintf(buf, sizeof(buf), HTTP_VERSION
+ " 200 OK\nContent-Type: text/html\n\n");
+ write(cn->networkdesc, buf, strlen(buf));
+ removeconnection(cn);
+ return;
+ }
+
+ strcpy(actualfile, cn->actualfile);
+
+#ifdef WIN32
+ strcat(actualfile, "*");
+ cn->dirp = FindFirstFile(actualfile, &cn->file_data);
+
+ if (cn->dirp == INVALID_HANDLE_VALUE)
+ {
+ send_error(cn, 404);
+ return;
+ }
+#else
+ if ((cn->dirp = opendir(actualfile)) == NULL)
+ {
+ send_error(cn, 404);
+ return;
+ }
+#endif
+
+ snprintf(buf, sizeof(buf), HTTP_VERSION
+ " 200 OK\nContent-Type: text/html\n\n"
+ "<html><body>\n<title>Directory Listing</title>\n"
+ "<h3>Directory listing of %s://%s%s</h3><br />\n",
+ cn->is_ssl ? "https" : "http", cn->server_name, cn->filereq);
+ special_write(cn, buf, strlen(buf));
+ cn->state = STATE_DOING_DIR;
+}
+
+void procdodir(struct connstruct *cn)
+{
+#ifndef WIN32
+ struct dirent *dp;
+#endif
+ char buf[MAXREQUESTLENGTH];
+ char encbuf[1024];
+ char *file;
+
+ do
+ {
+ buf[0] = 0;
+
+#ifdef WIN32
+ if (!FindNextFile(cn->dirp, &cn->file_data))
+#else
+ if ((dp = readdir(cn->dirp)) == NULL)
+#endif
+ {
+ snprintf(buf, sizeof(buf), "</body></html>\n");
+ special_write(cn, buf, strlen(buf));
+ removeconnection(cn);
+#ifndef WIN32
+ closedir(cn->dirp);
+#endif
+ return;
+ }
+
+#ifdef WIN32
+ file = cn->file_data.cFileName;
+#else
+ file = dp->d_name;
+#endif
+
+ /* if no index file, don't display the ".." directory */
+ if (cn->filereq[0] == '/' && cn->filereq[1] == '\0' &&
+ strcmp(file, "..") == 0)
+ continue;
+
+ /* don't display files beginning with "." */
+ if (file[0] == '.' && file[1] != '.')
+ continue;
+
+ /* make sure a '/' is at the end of a directory */
+ if (cn->filereq[strlen(cn->filereq)-1] != '/')
+ strcat(cn->filereq, "/");
+
+ /* see if the dir + file is another directory */
+ snprintf(buf, sizeof(buf), "%s%s", cn->actualfile, file);
+ if (isdir(buf))
+ strcat(file, "/");
+
+ urlencode((uint8_t *)file, encbuf);
+ snprintf(buf, sizeof(buf), "<a href=\"%s%s\">%s</a><br />\n",
+ cn->filereq, encbuf, file);
+ } while (special_write(cn, buf, strlen(buf)));
+}
+
+/* Encode funny chars -> %xx in newly allocated storage */
+/* (preserves '/' !) */
+static void urlencode(const uint8_t *s, char *t)
+{
+ const uint8_t *p = s;
+ char *tp = t;
+
+ for (; *p; p++)
+ {
+ if ((*p > 0x00 && *p < ',') ||
+ (*p > '9' && *p < 'A') ||
+ (*p > 'Z' && *p < '_') ||
+ (*p > '_' && *p < 'a') ||
+ (*p > 'z' && *p < 0xA1))
+ {
+ sprintf((char *)tp, "%%%02X", *p);
+ tp += 3;
+ }
+ else
+ {
+ *tp = *p;
+ tp++;
+ }
+ }
+
+ *tp='\0';
+}
+
+#endif
+
+void procreadhead(struct connstruct *cn)
+{
+ char buf[MAXREQUESTLENGTH*4], *tp, *next;
+ int rv;
+
+ memset(buf, 0, MAXREQUESTLENGTH*4);
+ rv = special_read(cn, buf, sizeof(buf)-1);
+ if (rv <= 0)
+ {
+ if (rv < 0) /* really dead? */
+ removeconnection(cn);
+ return;
+ }
+
+ buf[rv] = '\0';
+ next = tp = buf;
+
+#ifdef CONFIG_HTTP_HAS_AUTHORIZATION
+ cn->authorization[0] = 0;
+#endif
+
+ /* Split up lines and send to procheadelem() */
+ while (*next != '\0')
+ {
+ /* If we have a blank line, advance to next stage */
+ if (*next == '\r' || *next == '\n')
+ {
+#if defined(CONFIG_HTTP_HAS_CGI)
+ if (cn->reqtype == TYPE_POST && cn->content_length > 0)
+ {
+ if (init_read_post_data(buf,next,cn,rv) == 0)
+ return;
+ }
+#endif
+
+ buildactualfile(cn);
+ cn->state = STATE_WANT_TO_SEND_HEAD;
+ return;
+ }
+
+ while (*next != '\r' && *next != '\n' && *next != '\0')
+ next++;
+
+ if (*next == '\r')
+ {
+ *next = '\0';
+ next += 2;
+ }
+ else if (*next == '\n')
+ *next++ = '\0';
+
+ if (procheadelem(cn, tp) == 0)
+ return;
+
+ tp = next;
+ }
+}
+
+/* In this function we assume that the file has been checked for
+ * maliciousness (".."s, etc) and has been decoded
+ */
+void procsendhead(struct connstruct *cn)
+{
+ char buf[MAXREQUESTLENGTH];
+ struct stat stbuf;
+ time_t now = cn->timeout - CONFIG_HTTP_TIMEOUT;
+ char date[32];
+ int file_exists;
+
+ /* are we trying to access a file over the HTTP connection instead of a
+ * HTTPS connection? Or is this directory disabled? */
+ if (htaccess_check(cn))
+ {
+ send_error(cn, 403);
+ return;
+ }
+
+#ifdef CONFIG_HTTP_HAS_AUTHORIZATION
+ if (auth_check(cn)) /* see if there is a '.htpasswd' file */
+ {
+#ifdef CONFIG_HTTP_VERBOSE
+ printf("axhttpd: access to %s denied\n", cn->filereq); TTY_FLUSH();
+#endif
+ removeconnection(cn);
+ return;
+ }
+#endif
+
+ file_exists = stat(cn->actualfile, &stbuf);
+
+#if defined(CONFIG_HTTP_HAS_CGI)
+
+ if (file_exists != -1 && cn->is_cgi)
+ {
+ if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile))
+ {
+ /* A non-executable file, or directory? */
+ send_error(cn, 403);
+ }
+ else
+ proccgi(cn);
+
+ return;
+ }
+#endif
+
+ /* look for "index.html"? */
+ if (isdir(cn->actualfile))
+ {
+ char tbuf[MAXREQUESTLENGTH];
+ snprintf(tbuf, MAXREQUESTLENGTH, "%s%s", cn->actualfile, index_file);
+
+ if ((file_exists = stat(tbuf, &stbuf)) != -1)
+ my_strncpy(cn->actualfile, tbuf, MAXREQUESTLENGTH);
+ else
+ {
+#if defined(CONFIG_HTTP_DIRECTORIES)
+ /* If not, we do a directory listing of it */
+ procdirlisting(cn);
+#else
+ send_error(cn, 404);
+#endif
+ return;
+ }
+ }
+
+ if (file_exists == -1)
+ {
+ send_error(cn, 404);
+ return;
+ }
+
+ strcpy(date, ctime(&now));
+
+ /* has the file been read before? */
+ if (cn->if_modified_since != -1 && (cn->if_modified_since == 0 ||
+ cn->if_modified_since >= stbuf.st_mtime))
+ {
+ snprintf(buf, sizeof(buf), HTTP_VERSION" 304 Not Modified\nServer: "
+ "%s\nDate: %s\n", server_version, date);
+ special_write(cn, buf, strlen(buf));
+ cn->state = STATE_WANT_TO_READ_HEAD;
+ return;
+ }
+
+ if (cn->reqtype == TYPE_HEAD)
+ {
+ removeconnection(cn);
+ return;
+ }
+ else
+ {
+ int flags = O_RDONLY;
+#if defined(WIN32) || defined(CONFIG_PLATFORM_CYGWIN)
+ flags |= O_BINARY;
+#endif
+ cn->filedesc = open(cn->actualfile, flags);
+
+ if (cn->filedesc < 0)
+ {
+ send_error(cn, 404);
+ return;
+ }
+
+ snprintf(buf, sizeof(buf), HTTP_VERSION" 200 OK\nServer: %s\n"
+ "Content-Type: %s\nContent-Length: %ld\n"
+ "Date: %sLast-Modified: %s\n", server_version,
+ getmimetype(cn->actualfile), (long) stbuf.st_size,
+ date, ctime(&stbuf.st_mtime)); /* ctime() has a \n on the end */
+
+ special_write(cn, buf, strlen(buf));
+
+#ifdef CONFIG_HTTP_VERBOSE
+ printf("axhttpd: %s:/%s\n", cn->is_ssl ? "https" : "http", cn->filereq);
+ TTY_FLUSH();
+#endif
+
+#ifdef WIN32
+ for (;;)
+ {
+ procreadfile(cn);
+ if (cn->filedesc == -1)
+ break;
+
+ do
+ {
+ procsendfile(cn);
+ } while (cn->state != STATE_WANT_TO_READ_FILE);
+ }
+#else
+ cn->state = STATE_WANT_TO_READ_FILE;
+#endif
+ }
+}
+
+void procreadfile(struct connstruct *cn)
+{
+ int rv = read(cn->filedesc, cn->databuf, BLOCKSIZE);
+
+ if (rv <= 0)
+ {
+ close(cn->filedesc);
+ cn->filedesc = -1;
+
+ if (cn->close_when_done) /* close immediately */
+ removeconnection(cn);
+ else
+ { /* keep socket open - HTTP 1.1 */
+ cn->state = STATE_WANT_TO_READ_HEAD;
+ cn->numbytes = 0;
+ }
+
+ return;
+ }
+
+ cn->numbytes = rv;
+ cn->state = STATE_WANT_TO_SEND_FILE;
+}
+
+void procsendfile(struct connstruct *cn)
+{
+ int rv = special_write(cn, cn->databuf, cn->numbytes);
+
+ if (rv < 0)
+ removeconnection(cn);
+ else if (rv == cn->numbytes)
+ {
+ cn->state = STATE_WANT_TO_READ_FILE;
+ }
+ else if (rv == 0)
+ {
+ /* Do nothing */
+ }
+ else
+ {
+ memmove(cn->databuf, cn->databuf + rv, cn->numbytes - rv);
+ cn->numbytes -= rv;
+ }
+}
+
+#if defined(CONFIG_HTTP_HAS_CGI)
+/* Should this be a bit more dynamic? It would mean more calls to malloc etc */
+#define CGI_ARG_SIZE 17
+
+static void proccgi(struct connstruct *cn)
+{
+ int tpipe[2], spipe[2];
+ char *myargs[2];
+ char cgienv[CGI_ARG_SIZE][MAXREQUESTLENGTH];
+ char * cgiptr[CGI_ARG_SIZE+4];
+ const char *type = "HEAD";
+ int cgi_index = 0, i;
+ pid_t pid;
+#ifdef WIN32
+ int tmp_stdout;
+#endif
+
+ snprintf(cgienv[0], MAXREQUESTLENGTH,
+ HTTP_VERSION" 200 OK\nServer: %s\n%s",
+ server_version, (cn->reqtype == TYPE_HEAD) ? "\n" : "");
+ special_write(cn, cgienv[0], strlen(cgienv[0]));
+
+ if (cn->reqtype == TYPE_HEAD)
+ {
+ removeconnection(cn);
+ return;
+ }
+
+#ifdef CONFIG_HTTP_VERBOSE
+ printf("[CGI]: %s:/%s\n", cn->is_ssl ? "https" : "http", cn->filereq);
+ TTY_FLUSH();
+#endif
+
+ /* win32 cgi is a bit too painful */
+#ifndef WIN32
+ /* set up pipe that is used for sending POST query data to CGI script*/
+ if (cn->reqtype == TYPE_POST)
+ {
+ if (pipe(spipe) == -1)
+ {
+ printf("[CGI]: could not create pipe");
+ TTY_FLUSH();
+ return;
+ }
+ }
+
+ if (pipe(tpipe) == -1)
+ {
+ printf("[CGI]: could not create pipe");
+ TTY_FLUSH();
+ return;
+ }
+
+ /*
+ * use vfork() instead of fork() for performance
+ */
+ if ((pid = vfork()) > 0) /* parent */
+ {
+ /* Send POST query data to CGI script */
+ if ((cn->reqtype == TYPE_POST) && (cn->content_length > 0))
+ {
+ write(spipe[1], cn->post_data, cn->content_length);
+ close(spipe[0]);
+ close(spipe[1]);
+
+ /* free the memory that is allocated in read_post_data() */
+ free(cn->post_data);
+ cn->post_data = NULL;
+ }
+
+ /* Close the write descriptor */
+ close(tpipe[1]);
+ cn->filedesc = tpipe[0];
+ cn->state = STATE_WANT_TO_READ_FILE;
+ cn->close_when_done = 1;
+ return;
+ }
+
+ if (pid < 0) /* vfork failed */
+ exit(1);
+
+ /* The problem child... */
+
+ /* Our stdout/stderr goes to the socket */
+ dup2(tpipe[1], 1);
+ dup2(tpipe[1], 2);
+
+ /* If it was a POST request, send the socket data to our stdin */
+ if (cn->reqtype == TYPE_POST)
+ dup2(spipe[0], 0);
+ else /* Otherwise we can shutdown the read side of the sock */
+ shutdown(cn->networkdesc, 0);
+
+ myargs[0] = cn->actualfile;
+ myargs[1] = NULL;
+
+ /*
+ * set the cgi args. A url is defined by:
+ * http://$SERVER_NAME:$SERVER_PORT$SCRIPT_NAME$PATH_INFO?$QUERY_STRING
+ * TODO: other CGI parameters?
+ */
+ sprintf(cgienv[cgi_index++], "SERVER_SOFTWARE=%s", server_version);
+ strcpy(cgienv[cgi_index++], "DOCUMENT_ROOT=" CONFIG_HTTP_WEBROOT);
+ snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
+ "SERVER_NAME=%s", cn->server_name);
+ sprintf(cgienv[cgi_index++], "SERVER_PORT=%d",
+ cn->is_ssl ? CONFIG_HTTP_HTTPS_PORT : CONFIG_HTTP_PORT);
+ snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
+ "REQUEST_URI=%s", cn->uri_request);
+ snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
+ "SCRIPT_NAME=%s", cn->filereq);
+ snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
+ "PATH_INFO=%s", cn->uri_path_info);
+ snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
+ "QUERY_STRING=%s", cn->uri_query);
+ snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
+ "REMOTE_ADDR=%s", cn->remote_addr);
+ snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
+ "HTTP_COOKIE=%s", cn->cookie); /* note: small size */
+#if defined(CONFIG_HTTP_HAS_AUTHORIZATION)
+ snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
+ "REMOTE_USER=%s", cn->authorization);
+#endif
+
+ switch (cn->reqtype)
+ {
+ case TYPE_GET:
+ type = "GET";
+ break;
+
+ case TYPE_POST:
+ type = "POST";
+ sprintf(cgienv[cgi_index++],
+ "CONTENT_LENGTH=%d", cn->content_length);
+ strcpy(cgienv[cgi_index++], /* hard-code? */
+ "CONTENT_TYPE=application/x-www-form-urlencoded");
+ break;
+ }
+
+ sprintf(cgienv[cgi_index++], "REQUEST_METHOD=%s", type);
+
+ if (cn->is_ssl)
+ strcpy(cgienv[cgi_index++], "HTTPS=on");
+
+#ifdef CONFIG_PLATFORM_CYGWIN
+ /* TODO: find out why Lua needs this */
+ strcpy(cgienv[cgi_index++], "PATH=/usr/bin");
+#endif
+
+ if (cgi_index >= CGI_ARG_SIZE)
+ {
+ printf("Content-type: text/plain\n\nToo many CGI args (%d, %d)\n",
+ cgi_index, CGI_ARG_SIZE);
+ _exit(1);
+ }
+
+ /* copy across the pointer indexes */
+ for (i = 0; i < cgi_index; i++)
+ cgiptr[i] = cgienv[i];
+
+ cgiptr[i++] = "AUTH_TYPE=Basic";
+ cgiptr[i++] = "GATEWAY_INTERFACE=CGI/1.1";
+ cgiptr[i++] = "SERVER_PROTOCOL="HTTP_VERSION;
+ cgiptr[i] = NULL;
+
+ execve(myargs[0], myargs, cgiptr);
+ printf("Content-type: text/plain\n\nshouldn't get here\n");
+ _exit(1);
+#endif
+}
+
+static char * cgi_filetype_match(struct connstruct *cn, const char *fn)
+{
+ struct cgiextstruct *tp = cgiexts;
+
+ while (tp != NULL)
+ {
+ char *t;
+
+ if ((t = strstr(fn, tp->ext)) != NULL)
+ {
+ t += strlen(tp->ext);
+
+ if (*t == '/' || *t == '\0')
+ {
+#ifdef CONFIG_HTTP_ENABLE_LUA
+ if (strcmp(tp->ext, ".lua") == 0 || strcmp(tp->ext, ".lp") == 0)
+ cn->is_lua = 1;
+#endif
+
+ return t;
+ }
+ else
+ return NULL;
+
+ }
+
+ tp = tp->next;
+ }
+
+ return NULL;
+}
+
+static void decode_path_info(struct connstruct *cn, char *path_info)
+{
+ char *cgi_delim;
+
+ cn->is_cgi = 0;
+#ifdef CONFIG_HTTP_ENABLE_LUA
+ cn->is_lua = 0;
+#endif
+ *cn->uri_request = '\0';
+ *cn->uri_path_info = '\0';
+ *cn->uri_query = '\0';
+
+ my_strncpy(cn->uri_request, path_info, MAXREQUESTLENGTH);
+
+ /* query info? */
+ if ((cgi_delim = strchr(path_info, '?')))
+ {
+ *cgi_delim = '\0';
+ my_strncpy(cn->uri_query, cgi_delim+1, MAXREQUESTLENGTH);
+ }
+
+ if ((cgi_delim = cgi_filetype_match(cn, path_info)) != NULL)
+ {
+ cn->is_cgi = 1; /* definitely a CGI script */
+
+ /* path info? */
+ if (*cgi_delim != '\0')
+ {
+ my_strncpy(cn->uri_path_info, cgi_delim, MAXREQUESTLENGTH);
+ *cgi_delim = '\0';
+ }
+ }
+
+ /* the bit at the start must be the script name */
+ my_strncpy(cn->filereq, path_info, MAXREQUESTLENGTH);
+}
+
+static int init_read_post_data(char *buf, char *data,
+ struct connstruct *cn, int old_rv)
+{
+ char *next = data;
+ int rv = old_rv;
+ char *post_data;
+
+ /* Too much Post data to send. MAXPOSTDATASIZE should be
+ configured (now it can be chaged in the header file) */
+ if (cn->content_length > MAXPOSTDATASIZE)
+ {
+ send_error(cn, 418);
+ return 0;
+ }
+
+ /* remove CRLF */
+ while ((*next == '\r' || *next == '\n') && (next < &buf[rv]))
+ next++;
+
+ if (cn->post_data == NULL)
+ {
+ cn->post_data = (char *) calloc(1, (cn->content_length + 1));
+ /* Allocate buffer for the POST data that will be used by proccgi
+ to send POST data to the CGI script */
+
+ if (cn->post_data == NULL)
+ {
+ printf("axhttpd: could not allocate memory for POST data\n");
+ TTY_FLUSH();
+ send_error(cn, 599);
+ return 0;
+ }
+ }
+
+ cn->post_state = 0;
+ cn->post_read = 0;
+ post_data = cn->post_data;
+
+ while (next < &buf[rv])
+ {
+ /*copy POST data to buffer*/
+ *post_data = *next;
+ post_data++;
+ next++;
+ cn->post_read++;
+ if (cn->post_read == cn->content_length)
+ {
+ /* No more POST data to be copied */
+ *post_data = '\0';
+ return 1;
+ }
+ }
+
+ /* More POST data has to be read. read_post_data will continue with that */
+ cn->post_state = 1;
+ return 0;
+}
+
+void read_post_data(struct connstruct *cn)
+{
+ char buf[MAXREQUESTLENGTH*4], *next;
+ char *post_data;
+ int rv;
+
+ bzero(buf,MAXREQUESTLENGTH*4);
+ rv = special_read(cn, buf, sizeof(buf)-1);
+ if (rv <= 0)
+ {
+ if (rv < 0) /* really dead? */
+ removeconnection(cn);
+ return;
+ }
+
+ buf[rv] = '\0';
+ next = buf;
+
+ post_data = &cn->post_data[cn->post_read];
+
+ while (next < &buf[rv])
+ {
+ *post_data = *next;
+ post_data++;
+ next++;
+ cn->post_read++;
+ if (cn->post_read == cn->content_length)
+ {
+ /* No more POST data to be copied */
+ *post_data='\0';
+ cn->post_state = 0;
+ buildactualfile(cn);
+ cn->state = STATE_WANT_TO_SEND_HEAD;
+ return;
+ }
+ }
+
+ /* More POST data to read */
+}
+
+#endif /* CONFIG_HTTP_HAS_CGI */
+
+/* Decode string %xx -> char (in place) */
+static void urldecode(char *buf)
+{
+ int v;
+ char *p, *s, *w;
+
+ w = p = buf;
+
+ while (*p)
+ {
+ v = 0;
+
+ if (*p == '%')
+ {
+ s = p;
+ s++;
+
+ if (isxdigit((int) s[0]) && isxdigit((int) s[1]))
+ {
+ v = hexit(s[0])*16 + hexit(s[1]);
+
+ if (v)
+ {
+ /* do not decode %00 to null char */
+ *w = (char)v;
+ p = &s[1];
+ }
+ }
+
+ }
+
+ if (!v) *w=*p;
+ p++;
+ w++;
+ }
+
+ *w='\0';
+}
+
+static int hexit(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ else
+ return 0;
+}
+
+static void buildactualfile(struct connstruct *cn)
+{
+ char *cp;
+ snprintf(cn->actualfile, MAXREQUESTLENGTH, ".%s", cn->filereq);
+
+#ifndef WIN32
+ /* Add directory slash if not there */
+ if (isdir(cn->actualfile) &&
+ cn->actualfile[strlen(cn->actualfile)-1] != '/')
+ strcat(cn->actualfile, "/");
+
+ /* work out the directory name */
+ strncpy(cn->dirname, cn->actualfile, MAXREQUESTLENGTH);
+ if ((cp = strrchr(cn->dirname, '/')) == NULL)
+ cn->dirname[0] = 0;
+ else
+ *cp = 0;
+#else
+ {
+ char curr_dir[MAXREQUESTLENGTH];
+ char path[MAXREQUESTLENGTH];
+ char *t = cn->actualfile;
+
+ GetCurrentDirectory(MAXREQUESTLENGTH, curr_dir);
+
+ /* convert all the forward slashes to back slashes */
+ while ((t = strchr(t, '/')))
+ *t++ = '\\';
+
+ snprintf(path, MAXREQUESTLENGTH, "%s%s", curr_dir, cn->actualfile);
+ memcpy(cn->actualfile, path, MAXREQUESTLENGTH);
+
+ /* Add directory slash if not there */
+ if (isdir(cn->actualfile) &&
+ cn->actualfile[strlen(cn->actualfile)-1] != '\\')
+ strcat(cn->actualfile, "\\");
+
+ /* work out the directory name */
+ strncpy(cn->dirname, cn->actualfile, MAXREQUESTLENGTH);
+ if ((cp = strrchr(cn->dirname, '\\')) == NULL)
+ cn->dirname[0] = 0;
+ else
+ *cp = 0;
+ }
+#endif
+
+#if defined(CONFIG_HTTP_ENABLE_LUA)
+ /*
+ * Use the lua launcher if this file has a lua extension. Put this at the
+ * end as we need the directory name.
+ */
+ if (cn->is_lua)
+ sprintf(cn->actualfile, "%s%s", CONFIG_HTTP_LUA_PREFIX,
+ CONFIG_HTTP_LUA_CGI_LAUNCHER);
+#endif
+}
+
+static int sanitizefile(const char *buf)
+{
+ int len, i;
+
+ /* Don't accept anything not starting with a / */
+ if (*buf != '/')
+ return 0;
+
+ len = strlen(buf);
+ for (i = 0; i < len; i++)
+ {
+ /* Check for "/." i.e. don't send files starting with a . */
+ if (buf[i] == '/' && buf[i+1] == '.')
+ return 0;
+ }
+
+ return 1;
+}
+
+static int sanitizehost(char *buf)
+{
+ while (*buf != '\0')
+ {
+ /* Handle the port */
+ if (*buf == ':')
+ {
+ *buf = '\0';
+ return 1;
+ }
+
+ /* Enforce some basic URL rules... */
+ if ((isalnum(*buf) == 0 && *buf != '-' && *buf != '.') ||
+ (*buf == '.' && *(buf+1) == '.') ||
+ (*buf == '.' && *(buf+1) == '-') ||
+ (*buf == '-' && *(buf+1) == '.'))
+ return 0;
+
+ buf++;
+ }
+
+ return 1;
+}
+
+static FILE * exist_check(struct connstruct *cn, const char *check_file)
+{
+ char pathname[MAXREQUESTLENGTH];
+ snprintf(pathname, MAXREQUESTLENGTH, "%s/%s", cn->dirname, check_file);
+ return fopen(pathname, "r");
+}
+
+#ifdef CONFIG_HTTP_HAS_AUTHORIZATION
+static void send_authenticate(struct connstruct *cn, const char *realm)
+{
+ char buf[1024];
+
+ snprintf(buf, sizeof(buf), HTTP_VERSION" 401 Unauthorized\n"
+ "WWW-Authenticate: Basic\n"
+ "realm=\"%s\"\n", realm);
+ special_write(cn, buf, strlen(buf));
+}
+
+static int check_digest(char *salt, const char *msg_passwd)
+{
+ uint8_t b256_salt[MAXREQUESTLENGTH];
+ uint8_t real_passwd[MD5_SIZE];
+ int salt_size;
+ char *b64_passwd;
+ uint8_t md5_result[MD5_SIZE];
+ MD5_CTX ctx;
+
+ /* retrieve the salt */
+ if ((b64_passwd = strchr(salt, '$')) == NULL)
+ return -1;
+
+ *b64_passwd++ = 0;
+ if (base64_decode(salt, strlen(salt), b256_salt, &salt_size))
+ return -1;
+
+ if (base64_decode(b64_passwd, strlen(b64_passwd), real_passwd, NULL))
+ return -1;
+
+ /* very simple MD5 crypt algorithm, but then the salt we use is large */
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, b256_salt, salt_size); /* process the salt */
+ MD5_Update(&ctx, (uint8_t *)msg_passwd, strlen(msg_passwd));
+ MD5_Final(md5_result, &ctx);
+ return memcmp(md5_result, real_passwd, MD5_SIZE);/* 0 = ok */
+}
+
+static int auth_check(struct connstruct *cn)
+{
+ char line[MAXREQUESTLENGTH];
+ FILE *fp;
+ char *cp;
+
+ if ((fp = exist_check(cn, ".htpasswd")) == NULL)
+ return 0; /* no .htpasswd file, so let though */
+
+ if (cn->authorization[0] == 0)
+ goto error;
+
+ /* cn->authorization is in form "username:password" */
+ if ((cp = strchr(cn->authorization, ':')) == NULL)
+ goto error;
+ else
+ *cp++ = 0; /* cp becomes the password */
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ char *b64_file_passwd;
+ int l = strlen(line);
+
+ /* nuke newline */
+ if (line[l-1] == '\n')
+ line[l-1] = 0;
+
+ /* line is form "username:salt(b64)$password(b64)" */
+ if ((b64_file_passwd = strchr(line, ':')) == NULL)
+ continue;
+
+ *b64_file_passwd++ = 0;
+
+ if (strcmp(line, cn->authorization)) /* our user? */
+ continue;
+
+ if (check_digest(b64_file_passwd, cp) == 0)
+ {
+ fclose(fp);
+ return 0;
+ }
+ }
+
+error:
+ fclose(fp);
+ send_authenticate(cn, cn->server_name);
+ return -1;
+}
+#endif
+
+static int htaccess_check(struct connstruct *cn)
+{
+ char line[MAXREQUESTLENGTH];
+ FILE *fp;
+ int ret = 0;
+
+ if ((fp = exist_check(cn, ".htaccess")) == NULL)
+ return 0; /* no .htaccess file, so let though */
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ if (strstr(line, "Deny all") || /* access to this dir denied */
+ /* Access will be denied unless SSL is active */
+ (!cn->is_ssl && strstr(line, "SSLRequireSSL")) ||
+ /* Access will be denied if SSL is active */
+ (cn->is_ssl && strstr(line, "SSLDenySSL")))
+ {
+ ret = -1;
+ break;
+ }
+ }
+
+ fclose(fp);
+ return ret;
+}
+
+static void send_error(struct connstruct *cn, int err)
+{
+ char buf[MAXREQUESTLENGTH];
+ char *title;
+ char *text;
+
+ switch (err)
+ {
+ case 403:
+ title = "Forbidden";
+ text = "File is protected";
+#ifdef CONFIG_HTTP_VERBOSE
+ printf("axhttpd: access to %s denied\n", cn->filereq); TTY_FLUSH();
+#endif
+ break;
+
+ case 404:
+ title = "Not Found";
+ text = title;
+ break;
+
+ case 418:
+ title = "POST data size is to large";
+ text = title;
+ break;
+
+ default:
+ title = "Unknown";
+ text = "Unknown";
+ break;
+ }
+
+ snprintf(buf, MAXREQUESTLENGTH, "HTTP/1.1 %d %s\n"
+ "Content-Type: text/html\n"
+ "Cache-Control: no-cache,no-store\n"
+ "Connection: close\n\n"
+ "<html>\n<head>\n<title>%d %s</title></head>\n"
+ "<body><h1>%d %s</h1>\n</body></html>\n",
+ err, title, err, title, err, text);
+ special_write(cn, buf, strlen(buf));
+ removeconnection(cn);
+}
+
+static const char *getmimetype(const char *name)
+{
+ /* only bother with a few mime types - let the browser figure the rest out */
+ if (strstr(name, ".htm"))
+ return "text/html";
+ else if (strstr(name, ".css"))
+ return "text/css";
+ else
+ return "application/octet-stream";
+}
+
+static int special_write(struct connstruct *cn,
+ const char *buf, size_t count)
+{
+ if (cn->is_ssl)
+ {
+ SSL *ssl = cn->ssl;
+ return ssl ? ssl_write(ssl, (uint8_t *)buf, count) : -1;
+ }
+ else
+ return SOCKET_WRITE(cn->networkdesc, buf, count);
+}
+
+static int special_read(struct connstruct *cn, void *buf, size_t count)
+{
+ int res;
+
+ if (cn->is_ssl)
+ {
+ uint8_t *read_buf;
+ if ((res = ssl_read(cn->ssl, &read_buf)) > SSL_OK)
+ {
+ memcpy(buf, read_buf, res > (int)count ? count : res);
+ }
+ }
+ else
+ res = SOCKET_READ(cn->networkdesc, buf, count);
+
+ return res;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "axhttp.h"
+
+struct day_mon_map
+{
+ const char* s;
+ uint8_t l;
+};
+
+static struct day_mon_map wday_tab[] =
+{
+ { "Sun", 0 }, { "Mon", 1 }, { "Tue", 2 }, { "Wed", 3 },
+ { "Thu", 4 }, { "Fri", 5 }, { "Sat", 6 },
+};
+
+static struct day_mon_map mon_tab[] =
+{
+ { "Jan", 0 }, { "Feb", 1 }, { "Mar", 2 }, { "Apr", 3 },
+ { "May", 4 }, { "Jun", 5 }, { "Jul", 6 }, { "Aug", 7 },
+ { "Sep", 8 }, { "Oct", 9 }, { "Nov", 10 }, { "Dec", 11 },
+};
+
+static int day_mon_map_compare(const char *v1, const char *v2)
+{
+ return strcmp(((struct day_mon_map*)v1)->s, ((struct day_mon_map*)v2)->s);
+}
+
+void tdate_init(void)
+{
+ qsort(wday_tab, sizeof(wday_tab)/sizeof(struct day_mon_map),
+ sizeof(struct day_mon_map),
+ (int (*)(const void *, const void *))day_mon_map_compare);
+ qsort(mon_tab, sizeof(mon_tab)/sizeof(struct day_mon_map),
+ sizeof(struct day_mon_map),
+ (int (*)(const void *, const void *))day_mon_map_compare);
+}
+
+static int8_t day_mon_map_search(const char* str,
+ const struct day_mon_map* tab, int n)
+{
+ struct day_mon_map *search = bsearch(&str, tab, n,
+ sizeof(struct day_mon_map),
+ (int (*)(const void *, const void *))day_mon_map_compare);
+ return search ? search->l : -1;
+}
+
+time_t tdate_parse(const char* str)
+{
+ struct tm tm;
+ char str_mon[4], str_wday[4];
+ int tm_sec, tm_min, tm_hour, tm_mday, tm_year;
+
+ /* Initialize. */
+ memset(&tm, 0, sizeof(struct tm));
+
+ /* wdy, DD mth YY HH:MM:SS GMT */
+ if ((sscanf(str, "%3[a-zA-Z], %d %3[a-zA-Z] %d %d:%d:%d GMT",
+ str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
+ &tm_sec) == 7) ||
+ /* wdy mth DD HH:MM:SS YY */
+ (sscanf(str, "%3[a-zA-Z] %3[a-zA-Z] %d %d:%d:%d %d",
+ str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec,
+ &tm_year) == 7))
+ {
+ int8_t tm_wday = day_mon_map_search(str_wday, wday_tab,
+ sizeof(wday_tab)/sizeof(struct day_mon_map));
+ int8_t tm_mon = day_mon_map_search(str_mon, mon_tab,
+ sizeof(mon_tab)/sizeof(struct day_mon_map));
+
+ if (tm_wday < 0 || tm_mon < 0)
+ return -1;
+
+ tm.tm_wday = tm_wday;
+ tm.tm_mon = tm_mon;
+ tm.tm_mday = tm_mday;
+ tm.tm_hour = tm_hour;
+ tm.tm_min = tm_min;
+ tm.tm_sec = tm_sec;
+ tm.tm_year = tm_year - 1900;
+ return mktime(&tm);
+ }
+
+ return -1; /* error */
+}
--- /dev/null
+#
+# For a description of the syntax of this configuration file,
+# see scripts/config/Kconfig-language.txt
+#
+menu "Samples"
+
+config CONFIG_SAMPLES
+ bool "Create Samples"
+ default y
+ help
+ axTLS contains various sample code.
+
+ Select Y here if you want to build the various samples.
+
+config CONFIG_C_SAMPLES
+ bool "axssl - C version"
+ default y
+ depends on CONFIG_SAMPLES
+ help
+ Build the "C" version of axssl. The features enabled are very
+ dependent on the build mode ('full' mode will give all features).
+
+config CONFIG_CSHARP_SAMPLES
+ bool "axssl - C# version"
+ default y
+ depends on CONFIG_SAMPLES && CONFIG_CSHARP_BINDINGS
+ help
+ Build the "C#" version of axssl. The features enabled are very
+ dependent on the build mode ('full' mode will give all features).
+
+config CONFIG_VBNET_SAMPLES
+ bool "axssl - VB.NET version"
+ default y
+ depends on CONFIG_SAMPLES && CONFIG_VBNET_BINDINGS
+ help
+ Build the "VB.NET" version of axssl. The features enabled are very
+ dependent on the build mode ('full' mode will give all features).
+
+config CONFIG_JAVA_SAMPLES
+ bool "axssl - Java version"
+ default y
+ depends on CONFIG_SAMPLES && CONFIG_JAVA_BINDINGS
+ help
+ Build the "Java" version of axssl. The features enabled are very
+ dependent on the build mode ('full' mode will give all features).
+
+config CONFIG_PERL_SAMPLES
+ bool "axssl - Perl version"
+ default y
+ depends on CONFIG_SAMPLES && CONFIG_PERL_BINDINGS
+ help
+ Build the "Perl" version of axssl. The features enabled are very
+ dependent on the build mode ('full' mode will give all features).
+
+config CONFIG_LUA_SAMPLES
+ bool "axssl - Lua version"
+ default y
+ depends on CONFIG_SAMPLES && CONFIG_LUA_BINDINGS
+ help
+ Build the "Lua" version of axssl. The features enabled are very
+ dependent on the build mode ('full' mode will give all features).
+endmenu
+
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+all:
+
+include ../config/.config
+include ../config/makefile.conf
+
+all:
+ifdef CONFIG_C_SAMPLES
+ $(MAKE) -C c
+endif
+ifdef CONFIG_CSHARP_SAMPLES
+ $(MAKE) -C csharp
+endif
+ifdef CONFIG_VBNET_SAMPLES
+ $(MAKE) -C vbnet
+endif
+ifdef CONFIG_JAVA_SAMPLES
+ $(MAKE) -C java
+endif
+ifdef CONFIG_PERL_SAMPLES
+ $(MAKE) -C perl
+endif
+ifdef CONFIG_LUA_SAMPLES
+ $(MAKE) -C lua
+endif
+
+clean::
+ $(MAKE) -C c clean
+ $(MAKE) -C csharp clean
+ $(MAKE) -C vbnet clean
+ $(MAKE) -C java clean
+ $(MAKE) -C perl clean
+ $(MAKE) -C lua clean
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+all : sample
+
+AXTLS_HOME=../..
+
+include $(AXTLS_HOME)/config/.config
+include $(AXTLS_HOME)/config/makefile.conf
+
+ifndef CONFIG_PLATFORM_WIN32
+
+ifdef CONFIG_PLATFORM_CYGWIN
+TARGET=$(AXTLS_HOME)/$(STAGE)/axssl.exe
+else
+TARGET=$(AXTLS_HOME)/$(STAGE)/axssl
+endif # cygwin
+
+LIBS=$(AXTLS_HOME)/$(STAGE)
+else
+TARGET=$(AXTLS_HOME)/$(STAGE)/axssl.exe
+endif
+
+ifndef CONFIG_C_SAMPLES
+sample:
+
+else
+sample : $(TARGET)
+OBJ= axssl.o
+include $(AXTLS_HOME)/config/makefile.post
+
+ifndef CONFIG_PLATFORM_WIN32
+
+$(TARGET): $(OBJ) $(LIBS)/libaxtls.a
+ $(LD) $(LDFLAGS) -o $@ $(OBJ) -L$(LIBS) -laxtls
+ifdef CONFIG_STRIP_UNWANTED_SECTIONS
+ $(STRIP) --remove-section=.comment $(TARGET)
+endif # use strip
+else # Win32
+
+$(TARGET): $(OBJ)
+ $(LD) $(LDFLAGS) $(AXTLS_HOME)/config/axtls.res /out:$@ $^ /libpath:"$(AXTLS_HOME)/$(STAGE)" axtls.lib
+endif
+
+endif # CONFIG_C_SAMPLES
+
+clean::
+ -@rm -f $(AXTLS_HOME)/$(STAGE)/axssl*
+
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Demonstrate the use of the axTLS library in C with a set of
+ * command-line parameters similar to openssl. In fact, openssl clients
+ * should be able to communicate with axTLS servers and visa-versa.
+ *
+ * This code has various bits enabled depending on the configuration. To enable
+ * the most interesting version, compile with the 'full mode' enabled.
+ *
+ * To see what options you have, run the following:
+ * > axssl s_server -?
+ * > axssl s_client -?
+ *
+ * The axtls shared library must be in the same directory or be found
+ * by the OS.
+ */
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "ssl.h"
+
+/* define standard input */
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+
+static void do_server(int argc, char *argv[]);
+static void print_options(char *option);
+static void print_server_options(char *option);
+static void do_client(int argc, char *argv[]);
+static void print_client_options(char *option);
+static void display_cipher(SSL *ssl);
+static void display_session_id(SSL *ssl);
+
+/**
+ * Main entry point. Doesn't do much except works out whether we are a client
+ * or a server.
+ */
+int main(int argc, char *argv[])
+{
+#ifdef WIN32
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(2, 2);
+ WSAStartup(wVersionRequested, &wsaData);
+#elif !defined(CONFIG_PLATFORM_SOLARIS)
+ signal(SIGPIPE, SIG_IGN); /* ignore pipe errors */
+#endif
+
+ if (argc == 2 && strcmp(argv[1], "version") == 0)
+ {
+ printf("axssl %s %s\n", ssl_version(), __DATE__);
+ exit(0);
+ }
+
+ if (argc < 2 || (
+ strcmp(argv[1], "s_server") && strcmp(argv[1], "s_client")))
+ print_options(argc > 1 ? argv[1] : "");
+
+ strcmp(argv[1], "s_server") ?
+ do_client(argc, argv) : do_server(argc, argv);
+ return 0;
+}
+
+/**
+ * Implement the SSL server logic.
+ */
+static void do_server(int argc, char *argv[])
+{
+ int i = 2;
+ uint16_t port = 4433;
+ uint32_t options = SSL_DISPLAY_CERTS;
+ int client_fd;
+ SSL_CTX *ssl_ctx;
+ int server_fd, res = 0;
+ socklen_t client_len;
+#ifndef CONFIG_SSL_SKELETON_MODE
+ char *private_key_file = NULL;
+ const char *password = NULL;
+ char **cert;
+ int cert_index = 0;
+ int cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET);
+#endif
+#ifdef WIN32
+ char yes = 1;
+#else
+ int yes = 1;
+#endif
+ struct sockaddr_in serv_addr;
+ struct sockaddr_in client_addr;
+ int quiet = 0;
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ int ca_cert_index = 0;
+ int ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET);
+ char **ca_cert = (char **)calloc(1, sizeof(char *)*ca_cert_size);
+#endif
+ fd_set read_set;
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ cert = (char **)calloc(1, sizeof(char *)*cert_size);
+#endif
+
+ while (i < argc)
+ {
+ if (strcmp(argv[i], "-accept") == 0)
+ {
+ if (i >= argc-1)
+ {
+ print_server_options(argv[i]);
+ }
+
+ port = atoi(argv[++i]);
+ }
+#ifndef CONFIG_SSL_SKELETON_MODE
+ else if (strcmp(argv[i], "-cert") == 0)
+ {
+ if (i >= argc-1 || cert_index >= cert_size)
+ {
+ print_server_options(argv[i]);
+ }
+
+ cert[cert_index++] = argv[++i];
+ }
+ else if (strcmp(argv[i], "-key") == 0)
+ {
+ if (i >= argc-1)
+ {
+ print_server_options(argv[i]);
+ }
+
+ private_key_file = argv[++i];
+ options |= SSL_NO_DEFAULT_KEY;
+ }
+ else if (strcmp(argv[i], "-pass") == 0)
+ {
+ if (i >= argc-1)
+ {
+ print_server_options(argv[i]);
+ }
+
+ password = argv[++i];
+ }
+#endif
+ else if (strcmp(argv[i], "-quiet") == 0)
+ {
+ quiet = 1;
+ options &= ~SSL_DISPLAY_CERTS;
+ }
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ else if (strcmp(argv[i], "-verify") == 0)
+ {
+ options |= SSL_CLIENT_AUTHENTICATION;
+ }
+ else if (strcmp(argv[i], "-CAfile") == 0)
+ {
+ if (i >= argc-1 || ca_cert_index >= ca_cert_size)
+ {
+ print_server_options(argv[i]);
+ }
+
+ ca_cert[ca_cert_index++] = argv[++i];
+ }
+#endif
+#ifdef CONFIG_SSL_FULL_MODE
+ else if (strcmp(argv[i], "-debug") == 0)
+ {
+ options |= SSL_DISPLAY_BYTES;
+ }
+ else if (strcmp(argv[i], "-state") == 0)
+ {
+ options |= SSL_DISPLAY_STATES;
+ }
+ else if (strcmp(argv[i], "-show-rsa") == 0)
+ {
+ options |= SSL_DISPLAY_RSA;
+ }
+#endif
+ else /* don't know what this is */
+ {
+ print_server_options(argv[i]);
+ }
+
+ i++;
+ }
+
+ if ((ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_SVR_SESS)) == NULL)
+ {
+ fprintf(stderr, "Error: Server context is invalid\n");
+ exit(1);
+ }
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ if (private_key_file)
+ {
+ int obj_type = SSL_OBJ_RSA_KEY;
+
+ /* auto-detect the key type from the file extension */
+ if (strstr(private_key_file, ".p8"))
+ obj_type = SSL_OBJ_PKCS8;
+ else if (strstr(private_key_file, ".p12"))
+ obj_type = SSL_OBJ_PKCS12;
+
+ if (ssl_obj_load(ssl_ctx, obj_type, private_key_file, password))
+ {
+ fprintf(stderr, "Error: Private key '%s' is undefined.\n",
+ private_key_file);
+ exit(1);
+ }
+ }
+
+ for (i = 0; i < cert_index; i++)
+ {
+ if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, cert[i], NULL))
+ {
+ printf("Certificate '%s' is undefined.\n", cert[i]);
+ exit(1);
+ }
+ }
+#endif
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ for (i = 0; i < ca_cert_index; i++)
+ {
+ if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, ca_cert[i], NULL))
+ {
+ printf("Certificate '%s' is undefined.\n", ca_cert[i]);
+ exit(1);
+ }
+ }
+
+ free(ca_cert);
+#endif
+#ifndef CONFIG_SSL_SKELETON_MODE
+ free(cert);
+#endif
+
+ /* Create socket for incoming connections */
+ if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ perror("socket");
+ return;
+ }
+
+ setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
+
+ /* Construct local address structure */
+ memset(&serv_addr, 0, sizeof(serv_addr)); /* Zero out structure */
+ serv_addr.sin_family = AF_INET; /* Internet address family */
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
+ serv_addr.sin_port = htons(port); /* Local port */
+
+ /* Bind to the local address */
+ if (bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
+ {
+ perror("bind");
+ exit(1);
+ }
+
+ if (listen(server_fd, 5) < 0)
+ {
+ perror("listen");
+ exit(1);
+ }
+
+ client_len = sizeof(client_addr);
+
+ /*************************************************************************
+ * This is where the interesting stuff happens. Up until now we've
+ * just been setting up sockets etc. Now we do the SSL handshake.
+ *************************************************************************/
+ for (;;)
+ {
+ SSL *ssl;
+ int reconnected = 0;
+
+ if (!quiet)
+ {
+ printf("ACCEPT\n");
+ TTY_FLUSH();
+ }
+
+ if ((client_fd = accept(server_fd,
+ (struct sockaddr *)&client_addr, &client_len)) < 0)
+ {
+ res = 1;
+ break;
+ }
+
+ ssl = ssl_server_new(ssl_ctx, client_fd);
+
+ /* now read (and display) whatever the client sends us */
+ for (;;)
+ {
+ /* allow parallel reading of client and standard input */
+ FD_ZERO(&read_set);
+ FD_SET(client_fd, &read_set);
+
+#ifndef WIN32
+ /* win32 doesn't like mixing up stdin and sockets */
+ if (isatty(STDIN_FILENO))/* but only if we are in an active shell */
+ {
+ FD_SET(STDIN_FILENO, &read_set);
+ }
+
+ if ((res = select(client_fd+1, &read_set, NULL, NULL, NULL)) > 0)
+ {
+ uint8_t buf[1024];
+
+ /* read standard input? */
+ if (FD_ISSET(STDIN_FILENO, &read_set))
+ {
+ if (fgets((char *)buf, sizeof(buf), stdin) == NULL)
+ {
+ res = SSL_ERROR_CONN_LOST;
+ }
+ else
+ {
+ /* small hack to check renegotiation */
+ if (buf[0] == 'r' && (buf[1] == '\n' || buf[1] == '\r'))
+ {
+ res = ssl_renegotiate(ssl);
+ }
+ else /* write our ramblings to the client */
+ {
+ res = ssl_write(ssl, buf, strlen((char *)buf)+1);
+ }
+ }
+ }
+ else /* a socket read */
+#endif
+ {
+ /* keep reading until we get something interesting */
+ uint8_t *read_buf;
+
+ if ((res = ssl_read(ssl, &read_buf)) == SSL_OK)
+ {
+ /* are we in the middle of doing a handshake? */
+ if (ssl_handshake_status(ssl) != SSL_OK)
+ {
+ reconnected = 0;
+ }
+ else if (!reconnected)
+ {
+ /* we are connected/reconnected */
+ if (!quiet)
+ {
+ display_session_id(ssl);
+ display_cipher(ssl);
+ }
+
+ reconnected = 1;
+ }
+ }
+
+ if (res > SSL_OK) /* display our interesting output */
+ {
+ printf("%s", read_buf);
+ TTY_FLUSH();
+ }
+ else if (res < SSL_OK && !quiet)
+ {
+ ssl_display_error(res);
+ }
+ }
+#ifndef WIN32
+ }
+#endif
+
+ if (res < SSL_OK)
+ {
+ if (!quiet)
+ {
+ printf("CONNECTION CLOSED\n");
+ TTY_FLUSH();
+ }
+
+ break;
+ }
+ }
+
+ /* client was disconnected or the handshake failed. */
+ ssl_free(ssl);
+ SOCKET_CLOSE(client_fd);
+ }
+
+ ssl_ctx_free(ssl_ctx);
+}
+
+/**
+ * Implement the SSL client logic.
+ */
+static void do_client(int argc, char *argv[])
+{
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+ int res, i = 2;
+ uint16_t port = 4433;
+ uint32_t options = SSL_SERVER_VERIFY_LATER|SSL_DISPLAY_CERTS;
+ int client_fd;
+ char *private_key_file = NULL;
+ struct sockaddr_in client_addr;
+ struct hostent *hostent;
+ int reconnect = 0;
+ uint32_t sin_addr;
+ SSL_CTX *ssl_ctx;
+ SSL *ssl = NULL;
+ int quiet = 0;
+ int cert_index = 0, ca_cert_index = 0;
+ int cert_size, ca_cert_size;
+ char **ca_cert, **cert;
+ uint8_t session_id[SSL_SESSION_ID_SIZE];
+ fd_set read_set;
+ const char *password = NULL;
+
+ FD_ZERO(&read_set);
+ sin_addr = inet_addr("127.0.0.1");
+ cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET);
+ ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET);
+ ca_cert = (char **)calloc(1, sizeof(char *)*ca_cert_size);
+ cert = (char **)calloc(1, sizeof(char *)*cert_size);
+
+ while (i < argc)
+ {
+ if (strcmp(argv[i], "-connect") == 0)
+ {
+ char *host, *ptr;
+
+ if (i >= argc-1)
+ {
+ print_client_options(argv[i]);
+ }
+
+ host = argv[++i];
+ if ((ptr = strchr(host, ':')) == NULL)
+ {
+ print_client_options(argv[i]);
+ }
+
+ *ptr++ = 0;
+ port = atoi(ptr);
+ hostent = gethostbyname(host);
+
+ if (hostent == NULL)
+ {
+ print_client_options(argv[i]);
+ }
+
+ sin_addr = *((uint32_t **)hostent->h_addr_list)[0];
+ }
+ else if (strcmp(argv[i], "-cert") == 0)
+ {
+ if (i >= argc-1 || cert_index >= cert_size)
+ {
+ print_client_options(argv[i]);
+ }
+
+ cert[cert_index++] = argv[++i];
+ }
+ else if (strcmp(argv[i], "-key") == 0)
+ {
+ if (i >= argc-1)
+ {
+ print_client_options(argv[i]);
+ }
+
+ private_key_file = argv[++i];
+ options |= SSL_NO_DEFAULT_KEY;
+ }
+ else if (strcmp(argv[i], "-CAfile") == 0)
+ {
+ if (i >= argc-1 || ca_cert_index >= ca_cert_size)
+ {
+ print_client_options(argv[i]);
+ }
+
+ ca_cert[ca_cert_index++] = argv[++i];
+ }
+ else if (strcmp(argv[i], "-verify") == 0)
+ {
+ options &= ~SSL_SERVER_VERIFY_LATER;
+ }
+ else if (strcmp(argv[i], "-reconnect") == 0)
+ {
+ reconnect = 4;
+ }
+ else if (strcmp(argv[i], "-quiet") == 0)
+ {
+ quiet = 1;
+ options &= ~SSL_DISPLAY_CERTS;
+ }
+ else if (strcmp(argv[i], "-pass") == 0)
+ {
+ if (i >= argc-1)
+ {
+ print_client_options(argv[i]);
+ }
+
+ password = argv[++i];
+ }
+#ifdef CONFIG_SSL_FULL_MODE
+ else if (strcmp(argv[i], "-debug") == 0)
+ {
+ options |= SSL_DISPLAY_BYTES;
+ }
+ else if (strcmp(argv[i], "-state") == 0)
+ {
+ options |= SSL_DISPLAY_STATES;
+ }
+ else if (strcmp(argv[i], "-show-rsa") == 0)
+ {
+ options |= SSL_DISPLAY_RSA;
+ }
+#endif
+ else /* don't know what this is */
+ {
+ print_client_options(argv[i]);
+ }
+
+ i++;
+ }
+
+ if ((ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL)
+ {
+ fprintf(stderr, "Error: Client context is invalid\n");
+ exit(1);
+ }
+
+ if (private_key_file)
+ {
+ int obj_type = SSL_OBJ_RSA_KEY;
+
+ /* auto-detect the key type from the file extension */
+ if (strstr(private_key_file, ".p8"))
+ obj_type = SSL_OBJ_PKCS8;
+ else if (strstr(private_key_file, ".p12"))
+ obj_type = SSL_OBJ_PKCS12;
+
+ if (ssl_obj_load(ssl_ctx, obj_type, private_key_file, password))
+ {
+ fprintf(stderr, "Error: Private key '%s' is undefined.\n",
+ private_key_file);
+ exit(1);
+ }
+ }
+
+ for (i = 0; i < cert_index; i++)
+ {
+ if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, cert[i], NULL))
+ {
+ printf("Certificate '%s' is undefined.\n", cert[i]);
+ exit(1);
+ }
+ }
+
+ for (i = 0; i < ca_cert_index; i++)
+ {
+ if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, ca_cert[i], NULL))
+ {
+ printf("Certificate '%s' is undefined.\n", ca_cert[i]);
+ exit(1);
+ }
+ }
+
+ free(cert);
+ free(ca_cert);
+
+ /*************************************************************************
+ * This is where the interesting stuff happens. Up until now we've
+ * just been setting up sockets etc. Now we do the SSL handshake.
+ *************************************************************************/
+ client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ memset(&client_addr, 0, sizeof(client_addr));
+ client_addr.sin_family = AF_INET;
+ client_addr.sin_port = htons(port);
+ client_addr.sin_addr.s_addr = sin_addr;
+
+ if (connect(client_fd, (struct sockaddr *)&client_addr,
+ sizeof(client_addr)) < 0)
+ {
+ perror("connect");
+ exit(1);
+ }
+
+ if (!quiet)
+ {
+ printf("CONNECTED\n");
+ TTY_FLUSH();
+ }
+
+ /* Try session resumption? */
+ if (reconnect)
+ {
+ while (reconnect--)
+ {
+ ssl = ssl_client_new(ssl_ctx, client_fd, session_id,
+ sizeof(session_id));
+ if ((res = ssl_handshake_status(ssl)) != SSL_OK)
+ {
+ if (!quiet)
+ {
+ ssl_display_error(res);
+ }
+
+ ssl_free(ssl);
+ exit(1);
+ }
+
+ display_session_id(ssl);
+ memcpy(session_id, ssl_get_session_id(ssl), SSL_SESSION_ID_SIZE);
+
+ if (reconnect)
+ {
+ ssl_free(ssl);
+ SOCKET_CLOSE(client_fd);
+
+ client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ connect(client_fd, (struct sockaddr *)&client_addr,
+ sizeof(client_addr));
+ }
+ }
+ }
+ else
+ {
+ ssl = ssl_client_new(ssl_ctx, client_fd, NULL, 0);
+ }
+
+ /* check the return status */
+ if ((res = ssl_handshake_status(ssl)) != SSL_OK)
+ {
+ if (!quiet)
+ {
+ ssl_display_error(res);
+ }
+
+ exit(1);
+ }
+
+ if (!quiet)
+ {
+ const char *common_name = ssl_get_cert_dn(ssl,
+ SSL_X509_CERT_COMMON_NAME);
+ if (common_name)
+ {
+ printf("Common Name:\t\t\t%s\n", common_name);
+ }
+
+ display_session_id(ssl);
+ display_cipher(ssl);
+ }
+
+ for (;;)
+ {
+ uint8_t buf[1024];
+ res = SSL_OK;
+
+ /* allow parallel reading of server and standard input */
+ FD_SET(client_fd, &read_set);
+#ifndef WIN32
+ /* win32 doesn't like mixing up stdin and sockets */
+ FD_SET(STDIN_FILENO, &read_set);
+
+ if ((res = select(client_fd+1, &read_set, NULL, NULL, NULL)) > 0)
+ {
+ /* read standard input? */
+ if (FD_ISSET(STDIN_FILENO, &read_set))
+#endif
+ {
+ if (fgets((char *)buf, sizeof(buf), stdin) == NULL)
+ {
+ /* bomb out of here */
+ ssl_free(ssl);
+ break;
+ }
+ else
+ {
+ /* small hack to check renegotiation */
+ if (buf[0] == 'R' && (buf[1] == '\n' || buf[1] == '\r'))
+ {
+ res = ssl_renegotiate(ssl);
+ }
+ else
+ {
+ res = ssl_write(ssl, buf, strlen((char *)buf)+1);
+ }
+ }
+ }
+#ifndef WIN32
+ else /* a socket read */
+ {
+ uint8_t *read_buf;
+
+ res = ssl_read(ssl, &read_buf);
+
+ if (res > 0) /* display our interesting output */
+ {
+ printf("%s", read_buf);
+ TTY_FLUSH();
+ }
+ }
+ }
+#endif
+
+ if (res < 0)
+ {
+ if (!quiet)
+ {
+ ssl_display_error(res);
+ }
+
+ break; /* get outta here */
+ }
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ SOCKET_CLOSE(client_fd);
+#else
+ print_client_options(argv[1]);
+#endif
+}
+
+/**
+ * We've had some sort of command-line error. Print out the basic options.
+ */
+static void print_options(char *option)
+{
+ printf("axssl: Error: '%s' is an invalid command.\n", option);
+ printf("usage: axssl [s_server|s_client|version] [args ...]\n");
+ exit(1);
+}
+
+/**
+ * We've had some sort of command-line error. Print out the server options.
+ */
+static void print_server_options(char *option)
+{
+#ifndef CONFIG_SSL_SKELETON_MODE
+ int cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET);
+#endif
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ int ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET);
+#endif
+
+ printf("unknown option %s\n", option);
+ printf("usage: s_server [args ...]\n");
+ printf(" -accept arg\t- port to accept on (default is 4433)\n");
+#ifndef CONFIG_SSL_SKELETON_MODE
+ printf(" -cert arg\t- certificate file to add (in addition to default)"
+ " to chain -\n"
+ "\t\t Can repeat up to %d times\n", cert_size);
+ printf(" -key arg\t- Private key file to use\n");
+ printf(" -pass\t\t- private key file pass phrase source\n");
+#endif
+ printf(" -quiet\t\t- No server output\n");
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ printf(" -verify\t- turn on peer certificate verification\n");
+ printf(" -CAfile arg\t- Certificate authority\n");
+ printf("\t\t Can repeat up to %d times\n", ca_cert_size);
+#endif
+#ifdef CONFIG_SSL_FULL_MODE
+ printf(" -debug\t\t- Print more output\n");
+ printf(" -state\t\t- Show state messages\n");
+ printf(" -show-rsa\t- Show RSA state\n");
+#endif
+ exit(1);
+}
+
+/**
+ * We've had some sort of command-line error. Print out the client options.
+ */
+static void print_client_options(char *option)
+{
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+ int cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET);
+ int ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET);
+#endif
+
+ printf("unknown option %s\n", option);
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+ printf("usage: s_client [args ...]\n");
+ printf(" -connect host:port - who to connect to (default "
+ "is localhost:4433)\n");
+ printf(" -verify\t- turn on peer certificate verification\n");
+ printf(" -cert arg\t- certificate file to use\n");
+ printf("\t\t Can repeat up to %d times\n", cert_size);
+ printf(" -key arg\t- Private key file to use\n");
+ printf(" -CAfile arg\t- Certificate authority\n");
+ printf("\t\t Can repeat up to %d times\n", ca_cert_size);
+ printf(" -quiet\t\t- No client output\n");
+ printf(" -reconnect\t- Drop and re-make the connection "
+ "with the same Session-ID\n");
+ printf(" -pass\t\t- private key file pass phrase source\n");
+#ifdef CONFIG_SSL_FULL_MODE
+ printf(" -debug\t\t- Print more output\n");
+ printf(" -state\t\t- Show state messages\n");
+ printf(" -show-rsa\t- Show RSA state\n");
+#endif
+#else
+ printf("Change configuration to allow this feature\n");
+#endif
+ exit(1);
+}
+
+/**
+ * Display what cipher we are using
+ */
+static void display_cipher(SSL *ssl)
+{
+ printf("CIPHER is ");
+ switch (ssl_get_cipher_id(ssl))
+ {
+ case SSL_AES128_SHA:
+ printf("AES128-SHA");
+ break;
+
+ case SSL_AES256_SHA:
+ printf("AES256-SHA");
+ break;
+
+ case SSL_RC4_128_SHA:
+ printf("RC4-SHA");
+ break;
+
+ case SSL_RC4_128_MD5:
+ printf("RC4-MD5");
+ break;
+
+ default:
+ printf("Unknown - %d", ssl_get_cipher_id(ssl));
+ break;
+ }
+
+ printf("\n");
+ TTY_FLUSH();
+}
+
+/**
+ * Display what session id we have.
+ */
+static void display_session_id(SSL *ssl)
+{
+ int i;
+ const uint8_t *session_id = ssl_get_session_id(ssl);
+ int sess_id_size = ssl_get_session_id_size(ssl);
+
+ if (sess_id_size > 0)
+ {
+ printf("-----BEGIN SSL SESSION PARAMETERS-----\n");
+ for (i = 0; i < sess_id_size; i++)
+ {
+ printf("%02x", session_id[i]);
+ }
+
+ printf("\n-----END SSL SESSION PARAMETERS-----\n");
+ TTY_FLUSH();
+ }
+}
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+include ../../config/.config
+include ../../config/makefile.conf
+include ../../config/makefile.dotnet.conf
+
+all : sample
+TARGET=../../$(STAGE)/axssl.csharp.exe
+sample : $(TARGET)
+
+$(TARGET): ../../bindings/csharp/axTLS.cs ../../bindings/csharp/axInterface.cs axssl.cs
+ifdef GO_DOT_NET
+ csc.exe /nologo /t:exe /out:"`cygpath -w $@`" $(foreach file, $^, "`cygpath -w $(file)`")
+else # use mono to build
+ mcs -out:$@ $^
+
+endif # ARCH
+
+clean::
+ -@rm -f $(TARGET)
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Demonstrate the use of the axTLS library in C# with a set of
+ * command-line parameters similar to openssl. In fact, openssl clients
+ * should be able to communicate with axTLS servers and visa-versa.
+ *
+ * This code has various bits enabled depending on the configuration. To enable
+ * the most interesting version, compile with the 'full mode' enabled.
+ *
+ * To see what options you have, run the following:
+ * > axssl.csharp.exe s_server -?
+ * > axssl.csharp.exe s_client -?
+ *
+ * The axtls shared library must be in the same directory or be found
+ * by the OS.
+ */
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using axTLS;
+
+public class axssl
+{
+ /*
+ * Main()
+ */
+ public static void Main(string[] args)
+ {
+ if (args.Length == 1 && args[0] == "version")
+ {
+ Console.WriteLine("axssl.csharp " + SSLUtil.Version());
+ Environment.Exit(0);
+ }
+
+ axssl runner = new axssl();
+
+ if (args.Length < 1 || (args[0] != "s_server" && args[0] != "s_client"))
+ runner.print_options(args.Length > 0 ? args[0] : "");
+
+ int build_mode = SSLUtil.BuildMode();
+
+ if (args[0] == "s_server")
+ runner.do_server(build_mode, args);
+ else
+ runner.do_client(build_mode, args);
+ }
+
+ /*
+ * do_server()
+ */
+ private void do_server(int build_mode, string[] args)
+ {
+ int i = 1;
+ int port = 4433;
+ uint options = axtls.SSL_DISPLAY_CERTS;
+ bool quiet = false;
+ string password = null;
+ string private_key_file = null;
+
+ /* organise the cert/ca_cert lists */
+ int cert_size = SSLUtil.MaxCerts();
+ int ca_cert_size = SSLUtil.MaxCACerts();
+ string[] cert = new string[cert_size];
+ string[] ca_cert = new string[ca_cert_size];
+ int cert_index = 0;
+ int ca_cert_index = 0;
+
+ while (i < args.Length)
+ {
+ if (args[i] == "-accept")
+ {
+ if (i >= args.Length-1)
+ {
+ print_server_options(build_mode, args[i]);
+ }
+
+ port = Int32.Parse(args[++i]);
+ }
+ else if (args[i] == "-quiet")
+ {
+ quiet = true;
+ options &= ~(uint)axtls.SSL_DISPLAY_CERTS;
+ }
+ else if (build_mode >= axtls.SSL_BUILD_SERVER_ONLY)
+ {
+ if (args[i] == "-cert")
+ {
+ if (i >= args.Length-1 || cert_index >= cert_size)
+ {
+ print_server_options(build_mode, args[i]);
+ }
+
+ cert[cert_index++] = args[++i];
+ }
+ else if (args[i] == "-key")
+ {
+ if (i >= args.Length-1)
+ {
+ print_server_options(build_mode, args[i]);
+ }
+
+ private_key_file = args[++i];
+ options |= axtls.SSL_NO_DEFAULT_KEY;
+ }
+ else if (args[i] == "-pass")
+ {
+ if (i >= args.Length-1)
+ {
+ print_server_options(build_mode, args[i]);
+ }
+
+ password = args[++i];
+ }
+ else if (build_mode >= axtls.SSL_BUILD_ENABLE_VERIFICATION)
+ {
+ if (args[i] == "-verify")
+ {
+ options |= axtls.SSL_CLIENT_AUTHENTICATION;
+ }
+ else if (args[i] == "-CAfile")
+ {
+ if (i >= args.Length-1 || ca_cert_index >= ca_cert_size)
+ {
+ print_server_options(build_mode, args[i]);
+ }
+
+ ca_cert[ca_cert_index++] = args[++i];
+ }
+ else if (build_mode == axtls.SSL_BUILD_FULL_MODE)
+ {
+ if (args[i] == "-debug")
+ {
+ options |= axtls.SSL_DISPLAY_BYTES;
+ }
+ else if (args[i] == "-state")
+ {
+ options |= axtls.SSL_DISPLAY_STATES;
+ }
+ else if (args[i] == "-show-rsa")
+ {
+ options |= axtls.SSL_DISPLAY_RSA;
+ }
+ else
+ print_server_options(build_mode, args[i]);
+ }
+ else
+ print_server_options(build_mode, args[i]);
+ }
+ else
+ print_server_options(build_mode, args[i]);
+ }
+ else
+ print_server_options(build_mode, args[i]);
+
+ i++;
+ }
+
+ /* Create socket for incoming connections */
+ IPEndPoint ep = new IPEndPoint(IPAddress.Any, port);
+ TcpListener server_sock = new TcpListener(ep);
+ server_sock.Start();
+
+ /**********************************************************************
+ * This is where the interesting stuff happens. Up until now we've
+ * just been setting up sockets etc. Now we do the SSL handshake.
+ **********************************************************************/
+ SSLServer ssl_ctx = new SSLServer(
+ options, axtls.SSL_DEFAULT_SVR_SESS);
+
+ if (ssl_ctx == null)
+ {
+ Console.Error.WriteLine("Error: Server context is invalid");
+ Environment.Exit(1);
+ }
+
+ if (private_key_file != null)
+ {
+ int obj_type = axtls.SSL_OBJ_RSA_KEY;
+
+ if (private_key_file.EndsWith(".p8"))
+ obj_type = axtls.SSL_OBJ_PKCS8;
+ else if (private_key_file.EndsWith(".p12"))
+ obj_type = axtls.SSL_OBJ_PKCS12;
+
+ if (ssl_ctx.ObjLoad(obj_type,
+ private_key_file, password) != axtls.SSL_OK)
+ {
+ Console.Error.WriteLine("Private key '" + private_key_file +
+ "' is undefined.");
+ Environment.Exit(1);
+ }
+ }
+
+ for (i = 0; i < cert_index; i++)
+ {
+ if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CERT,
+ cert[i], null) != axtls.SSL_OK)
+ {
+ Console.WriteLine("Certificate '" + cert[i] +
+ "' is undefined.");
+ Environment.Exit(1);
+ }
+ }
+
+ for (i = 0; i < ca_cert_index; i++)
+ {
+ if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CACERT,
+ ca_cert[i], null) != axtls.SSL_OK)
+ {
+ Console.WriteLine("Certificate '" + cert[i] +
+ "' is undefined.");
+ Environment.Exit(1);
+ }
+ }
+
+ byte[] buf = null;
+ int res;
+
+ for (;;)
+ {
+ if (!quiet)
+ {
+ Console.WriteLine("ACCEPT");
+ }
+
+ Socket client_sock = server_sock.AcceptSocket();
+
+ SSL ssl = ssl_ctx.Connect(client_sock);
+
+ /* do the actual SSL handshake */
+ while ((res = ssl_ctx.Read(ssl, out buf)) == axtls.SSL_OK)
+ {
+ /* check when the connection has been established */
+ if (ssl.HandshakeStatus() == axtls.SSL_OK)
+ break;
+
+ /* could do something else here */
+ }
+
+ if (res == axtls.SSL_OK) /* connection established and ok */
+ {
+ if (!quiet)
+ {
+ display_session_id(ssl);
+ display_cipher(ssl);
+ }
+
+ /* now read (and display) whatever the client sends us */
+ for (;;)
+ {
+ /* keep reading until we get something interesting */
+ while ((res = ssl_ctx.Read(ssl, out buf)) == axtls.SSL_OK)
+ {
+ /* could do something else here */
+ }
+
+ if (res < axtls.SSL_OK)
+ {
+ if (!quiet)
+ {
+ Console.WriteLine("CONNECTION CLOSED");
+ }
+
+ break;
+ }
+
+ /* convert to string */
+ char[] str = new char[res];
+ for (i = 0; i < res; i++)
+ {
+ str[i] = (char)buf[i];
+ }
+
+ Console.Write(str);
+ }
+ }
+ else if (!quiet)
+ {
+ SSLUtil.DisplayError(res);
+ }
+
+ /* client was disconnected or the handshake failed. */
+ ssl.Dispose();
+ client_sock.Close();
+ }
+
+ /* ssl_ctx.Dispose(); */
+ }
+
+ /*
+ * do_client()
+ */
+ private void do_client(int build_mode, string[] args)
+ {
+ if (build_mode < axtls.SSL_BUILD_ENABLE_CLIENT)
+ {
+ print_client_options(build_mode, args[1]);
+ }
+
+ int i = 1, res;
+ int port = 4433;
+ bool quiet = false;
+ string password = null;
+ int reconnect = 0;
+ string private_key_file = null;
+ string hostname = "127.0.0.1";
+
+ /* organise the cert/ca_cert lists */
+ int cert_index = 0;
+ int ca_cert_index = 0;
+ int cert_size = SSLUtil.MaxCerts();
+ int ca_cert_size = SSLUtil.MaxCACerts();
+ string[] cert = new string[cert_size];
+ string[] ca_cert = new string[ca_cert_size];
+
+ uint options = axtls.SSL_SERVER_VERIFY_LATER|axtls.SSL_DISPLAY_CERTS;
+ byte[] session_id = null;
+
+ while (i < args.Length)
+ {
+ if (args[i] == "-connect")
+ {
+ string host_port;
+
+ if (i >= args.Length-1)
+ {
+ print_client_options(build_mode, args[i]);
+ }
+
+ host_port = args[++i];
+ int index_colon;
+
+ if ((index_colon = host_port.IndexOf(':')) < 0)
+ print_client_options(build_mode, args[i]);
+
+ hostname = new string(host_port.ToCharArray(),
+ 0, index_colon);
+ port = Int32.Parse(new String(host_port.ToCharArray(),
+ index_colon+1, host_port.Length-index_colon-1));
+ }
+ else if (args[i] == "-cert")
+ {
+ if (i >= args.Length-1 || cert_index >= cert_size)
+ {
+ print_client_options(build_mode, args[i]);
+ }
+
+ cert[cert_index++] = args[++i];
+ }
+ else if (args[i] == "-key")
+ {
+ if (i >= args.Length-1)
+ {
+ print_client_options(build_mode, args[i]);
+ }
+
+ private_key_file = args[++i];
+ options |= axtls.SSL_NO_DEFAULT_KEY;
+ }
+ else if (args[i] == "-CAfile")
+ {
+ if (i >= args.Length-1 || ca_cert_index >= ca_cert_size)
+ {
+ print_client_options(build_mode, args[i]);
+ }
+
+ ca_cert[ca_cert_index++] = args[++i];
+ }
+ else if (args[i] == "-verify")
+ {
+ options &= ~(uint)axtls.SSL_SERVER_VERIFY_LATER;
+ }
+ else if (args[i] == "-reconnect")
+ {
+ reconnect = 4;
+ }
+ else if (args[i] == "-quiet")
+ {
+ quiet = true;
+ options &= ~(uint)axtls.SSL_DISPLAY_CERTS;
+ }
+ else if (args[i] == "-pass")
+ {
+ if (i >= args.Length-1)
+ {
+ print_client_options(build_mode, args[i]);
+ }
+
+ password = args[++i];
+ }
+ else if (build_mode == axtls.SSL_BUILD_FULL_MODE)
+ {
+ if (args[i] == "-debug")
+ {
+ options |= axtls.SSL_DISPLAY_BYTES;
+ }
+ else if (args[i] == "-state")
+ {
+ options |= axtls.SSL_DISPLAY_STATES;
+ }
+ else if (args[i] == "-show-rsa")
+ {
+ options |= axtls.SSL_DISPLAY_RSA;
+ }
+ else
+ print_client_options(build_mode, args[i]);
+ }
+ else /* don't know what this is */
+ print_client_options(build_mode, args[i]);
+
+ i++;
+ }
+
+ // IPHostEntry hostInfo = Dns.Resolve(hostname);
+ IPHostEntry hostInfo = Dns.GetHostEntry(hostname);
+ IPAddress[] addresses = hostInfo.AddressList;
+ IPEndPoint ep = new IPEndPoint(addresses[0], port);
+ Socket client_sock = new Socket(AddressFamily.InterNetwork,
+ SocketType.Stream, ProtocolType.Tcp);
+ client_sock.Connect(ep);
+
+ if (!client_sock.Connected)
+ {
+ Console.WriteLine("could not connect");
+ Environment.Exit(1);
+ }
+
+ if (!quiet)
+ {
+ Console.WriteLine("CONNECTED");
+ }
+
+ /**********************************************************************
+ * This is where the interesting stuff happens. Up until now we've
+ * just been setting up sockets etc. Now we do the SSL handshake.
+ **********************************************************************/
+ SSLClient ssl_ctx = new SSLClient(options,
+ axtls.SSL_DEFAULT_CLNT_SESS);
+
+ if (ssl_ctx == null)
+ {
+ Console.Error.WriteLine("Error: Client context is invalid");
+ Environment.Exit(1);
+ }
+
+ if (private_key_file != null)
+ {
+ int obj_type = axtls.SSL_OBJ_RSA_KEY;
+
+ if (private_key_file.EndsWith(".p8"))
+ obj_type = axtls.SSL_OBJ_PKCS8;
+ else if (private_key_file.EndsWith(".p12"))
+ obj_type = axtls.SSL_OBJ_PKCS12;
+
+ if (ssl_ctx.ObjLoad(obj_type,
+ private_key_file, password) != axtls.SSL_OK)
+ {
+ Console.Error.WriteLine("Private key '" + private_key_file +
+ "' is undefined.");
+ Environment.Exit(1);
+ }
+ }
+
+ for (i = 0; i < cert_index; i++)
+ {
+ if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CERT,
+ cert[i], null) != axtls.SSL_OK)
+ {
+ Console.WriteLine("Certificate '" + cert[i] +
+ "' is undefined.");
+ Environment.Exit(1);
+ }
+ }
+
+ for (i = 0; i < ca_cert_index; i++)
+ {
+ if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CACERT,
+ ca_cert[i], null) != axtls.SSL_OK)
+ {
+ Console.WriteLine("Certificate '" + cert[i] +
+ "' is undefined.");
+ Environment.Exit(1);
+ }
+ }
+
+ SSL ssl = new SSL(new IntPtr(0)); /* keep compiler happy */
+
+ /* Try session resumption? */
+ if (reconnect > 0)
+ {
+ while (reconnect-- > 0)
+ {
+ ssl = ssl_ctx.Connect(client_sock, session_id);
+
+ if ((res = ssl.HandshakeStatus()) != axtls.SSL_OK)
+ {
+ if (!quiet)
+ {
+ SSLUtil.DisplayError(res);
+ }
+
+ ssl.Dispose();
+ Environment.Exit(1);
+ }
+
+ display_session_id(ssl);
+ session_id = ssl.GetSessionId();
+
+ if (reconnect > 0)
+ {
+ ssl.Dispose();
+ client_sock.Close();
+
+ /* and reconnect */
+ client_sock = new Socket(AddressFamily.InterNetwork,
+ SocketType.Stream, ProtocolType.Tcp);
+ client_sock.Connect(ep);
+ }
+ }
+ }
+ else
+ {
+ ssl = ssl_ctx.Connect(client_sock, null);
+ }
+
+ /* check the return status */
+ if ((res = ssl.HandshakeStatus()) != axtls.SSL_OK)
+ {
+ if (!quiet)
+ {
+ SSLUtil.DisplayError(res);
+ }
+
+ Environment.Exit(1);
+ }
+
+ if (!quiet)
+ {
+ string common_name =
+ ssl.GetCertificateDN(axtls.SSL_X509_CERT_COMMON_NAME);
+
+ if (common_name != null)
+ {
+ Console.WriteLine("Common Name:\t\t\t" + common_name);
+ }
+
+ display_session_id(ssl);
+ display_cipher(ssl);
+ }
+
+ for (;;)
+ {
+ string user_input = Console.ReadLine();
+
+ if (user_input == null)
+ break;
+
+ byte[] buf = new byte[user_input.Length+2];
+ buf[buf.Length-2] = (byte)'\n'; /* add the carriage return */
+ buf[buf.Length-1] = 0; /* null terminate */
+
+ for (i = 0; i < buf.Length-2; i++)
+ {
+ buf[i] = (byte)user_input[i];
+ }
+
+ if ((res = ssl_ctx.Write(ssl, buf, buf.Length)) < axtls.SSL_OK)
+ {
+ if (!quiet)
+ {
+ SSLUtil.DisplayError(res);
+ }
+
+ break;
+ }
+ }
+
+ ssl_ctx.Dispose();
+ }
+
+ /**
+ * We've had some sort of command-line error. Print out the basic options.
+ */
+ private void print_options(string option)
+ {
+ Console.WriteLine("axssl: Error: '" + option +
+ "' is an invalid command.");
+ Console.WriteLine("usage: axssl.csharp [s_server|" +
+ "s_client|version] [args ...]");
+ Environment.Exit(1);
+ }
+
+ /**
+ * We've had some sort of command-line error. Print out the server options.
+ */
+ private void print_server_options(int build_mode, string option)
+ {
+ int cert_size = SSLUtil.MaxCerts();
+ int ca_cert_size = SSLUtil.MaxCACerts();
+
+ Console.WriteLine("unknown option " + option);
+ Console.WriteLine("usage: s_server [args ...]");
+ Console.WriteLine(" -accept arg\t- port to accept on (default " +
+ "is 4433)");
+ Console.WriteLine(" -quiet\t\t- No server output");
+
+ if (build_mode >= axtls.SSL_BUILD_SERVER_ONLY)
+ {
+ Console.WriteLine(" -cert arg\t- certificate file to add (in " +
+ "addition to default) to chain -");
+ Console.WriteLine("\t\t Can repeat up to " + cert_size + " times");
+ Console.WriteLine(" -key arg\t- Private key file to use");
+ Console.WriteLine(" -pass\t\t- private key file pass phrase source");
+ }
+
+ if (build_mode >= axtls.SSL_BUILD_ENABLE_VERIFICATION)
+ {
+ Console.WriteLine(" -verify\t- turn on peer certificate " +
+ "verification");
+ Console.WriteLine(" -CAfile arg\t- Certificate authority.");
+ Console.WriteLine("\t\t Can repeat up to " +
+ ca_cert_size + "times");
+ }
+
+ if (build_mode == axtls.SSL_BUILD_FULL_MODE)
+ {
+ Console.WriteLine(" -debug\t\t- Print more output");
+ Console.WriteLine(" -state\t\t- Show state messages");
+ Console.WriteLine(" -show-rsa\t- Show RSA state");
+ }
+
+ Environment.Exit(1);
+ }
+
+ /**
+ * We've had some sort of command-line error. Print out the client options.
+ */
+ private void print_client_options(int build_mode, string option)
+ {
+ int cert_size = SSLUtil.MaxCerts();
+ int ca_cert_size = SSLUtil.MaxCACerts();
+
+ Console.WriteLine("unknown option " + option);
+
+ if (build_mode >= axtls.SSL_BUILD_ENABLE_CLIENT)
+ {
+ Console.WriteLine("usage: s_client [args ...]");
+ Console.WriteLine(" -connect host:port - who to connect to " +
+ "(default is localhost:4433)");
+ Console.WriteLine(" -verify\t- turn on peer certificate " +
+ "verification");
+ Console.WriteLine(" -cert arg\t- certificate file to use");
+ Console.WriteLine("\t\t Can repeat up to %d times", cert_size);
+ Console.WriteLine(" -key arg\t- Private key file to use");
+ Console.WriteLine(" -CAfile arg\t- Certificate authority.");
+ Console.WriteLine("\t\t Can repeat up to " + ca_cert_size +
+ " times");
+ Console.WriteLine(" -quiet\t\t- No client output");
+ Console.WriteLine(" -pass\t\t- private key file pass " +
+ "phrase source");
+ Console.WriteLine(" -reconnect\t- Drop and re-make the " +
+ "connection with the same Session-ID");
+
+ if (build_mode == axtls.SSL_BUILD_FULL_MODE)
+ {
+ Console.WriteLine(" -debug\t\t- Print more output");
+ Console.WriteLine(" -state\t\t- Show state messages");
+ Console.WriteLine(" -show-rsa\t- Show RSA state");
+ }
+ }
+ else
+ {
+ Console.WriteLine("Change configuration to allow this feature");
+ }
+
+ Environment.Exit(1);
+ }
+
+ /**
+ * Display what cipher we are using
+ */
+ private void display_cipher(SSL ssl)
+ {
+ Console.Write("CIPHER is ");
+
+ switch (ssl.GetCipherId())
+ {
+ case axtls.SSL_AES128_SHA:
+ Console.WriteLine("AES128-SHA");
+ break;
+
+ case axtls.SSL_AES256_SHA:
+ Console.WriteLine("AES256-SHA");
+ break;
+
+ case axtls.SSL_RC4_128_SHA:
+ Console.WriteLine("RC4-SHA");
+ break;
+
+ case axtls.SSL_RC4_128_MD5:
+ Console.WriteLine("RC4-MD5");
+ break;
+
+ default:
+ Console.WriteLine("Unknown - " + ssl.GetCipherId());
+ break;
+ }
+ }
+
+ /**
+ * Display what session id we have.
+ */
+ private void display_session_id(SSL ssl)
+ {
+ byte[] session_id = ssl.GetSessionId();
+
+ if (session_id.Length > 0)
+ {
+ Console.WriteLine("-----BEGIN SSL SESSION PARAMETERS-----");
+ foreach (byte b in session_id)
+ {
+ Console.Write("{0:x02}", b);
+ }
+
+ Console.WriteLine("\n-----END SSL SESSION PARAMETERS-----");
+ }
+ }
+}
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+include ../../config/.config
+include ../../config/makefile.conf
+include ../../config/makefile.java.conf
+
+all : sample
+JAR=../../$(STAGE)/axtls.jar
+CLASSES=../../bindings/java/classes
+sample : $(JAR)
+
+$(JAR) : $(CLASSES)/axssl.class $(wildcard $(CLASSES)/axTLSj/*.class)
+ jar mcvf manifest.mf $@ -C $(CLASSES) axTLSj -C $(CLASSES) axssl.class
+
+JAVA_FILES=axssl.java
+JAVA_CLASSES:=$(JAVA_FILES:%.java=$(CLASSES)/axTLSj/%.class)
+
+$(CLASSES)/%.class : %.java
+ javac -d $(CLASSES) -classpath $(CLASSES) $^
+
+clean::
+ -@rm -f $(TARGET)
+
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Demonstrate the use of the axTLS library in Java with a set of
+ * command-line parameters similar to openssl. In fact, openssl clients
+ * should be able to communicate with axTLS servers and visa-versa. *
+ * This code has various bits enabled depending on the configuration. To enable
+ * the most interesting version, compile with the 'full mode' enabled.
+ *
+ * To see what options you have, run the following:
+ * > java -jar axtls.jar s_server -?
+ * > java -jar axtls.jar s_client -?
+ *
+ * The axtls/axtlsj shared libraries must be in the same directory or be found
+ * by the OS.
+ */
+
+import java.io.*;
+import java.util.*;
+import java.net.*;
+import axTLSj.*;
+
+public class axssl
+{
+ /*
+ * Main()
+ */
+ public static void main(String[] args)
+ {
+ if (args.length == 1 && args[0].equals("version"))
+ {
+ System.out.println("axtls.jar " + SSLUtil.version());
+ System.exit(0);
+ }
+
+ axssl runner = new axssl();
+
+ try
+ {
+ if (args.length < 1 ||
+ (!args[0].equals("s_server") &&
+ !args[0].equals("s_client")))
+ {
+ runner.print_options(args.length > 0 ? args[0] : "");
+ }
+
+ int build_mode = SSLUtil.buildMode();
+
+ if (args[0].equals("s_server"))
+ runner.do_server(build_mode, args);
+ else
+ runner.do_client(build_mode, args);
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+ }
+
+ /*
+ * do_server()
+ */
+ private void do_server(int build_mode, String[] args)
+ throws Exception
+ {
+ int i = 1;
+ int port = 4433;
+ int options = axtlsj.SSL_DISPLAY_CERTS;
+ boolean quiet = false;
+ String password = null;
+ String private_key_file = null;
+
+ /* organise the cert/ca_cert lists */
+ int cert_size = SSLUtil.maxCerts();
+ int ca_cert_size = SSLUtil.maxCACerts();
+ String[] cert = new String[cert_size];
+ String[] ca_cert = new String[ca_cert_size];
+ int cert_index = 0;
+ int ca_cert_index = 0;
+
+ while (i < args.length)
+ {
+ if (args[i].equals("-accept"))
+ {
+ if (i >= args.length-1)
+ {
+ print_server_options(build_mode, args[i]);
+ }
+
+ port = Integer.parseInt(args[++i]);
+ }
+ else if (args[i].equals("-quiet"))
+ {
+ quiet = true;
+ options &= ~(int)axtlsj.SSL_DISPLAY_CERTS;
+ }
+ else if (build_mode >= axtlsj.SSL_BUILD_SERVER_ONLY)
+ {
+ if (args[i].equals("-cert"))
+ {
+ if (i >= args.length-1 || cert_index >= cert_size)
+ {
+ print_server_options(build_mode, args[i]);
+ }
+
+ cert[cert_index++] = args[++i];
+ }
+ else if (args[i].equals("-key"))
+ {
+ if (i >= args.length-1)
+ {
+ print_server_options(build_mode, args[i]);
+ }
+
+ private_key_file = args[++i];
+ options |= axtlsj.SSL_NO_DEFAULT_KEY;
+ }
+ else if (args[i].equals("-pass"))
+ {
+ if (i >= args.length-1)
+ {
+ print_server_options(build_mode, args[i]);
+ }
+
+ password = args[++i];
+ }
+ else if (build_mode >= axtlsj.SSL_BUILD_ENABLE_VERIFICATION)
+ {
+ if (args[i].equals("-verify"))
+ {
+ options |= axtlsj.SSL_CLIENT_AUTHENTICATION;
+ }
+ else if (args[i].equals("-CAfile"))
+ {
+ if (i >= args.length-1 || ca_cert_index >= ca_cert_size)
+ {
+ print_server_options(build_mode, args[i]);
+ }
+
+ ca_cert[ca_cert_index++] = args[++i];
+ }
+ else if (build_mode == axtlsj.SSL_BUILD_FULL_MODE)
+ {
+ if (args[i].equals("-debug"))
+ {
+ options |= axtlsj.SSL_DISPLAY_BYTES;
+ }
+ else if (args[i].equals("-state"))
+ {
+ options |= axtlsj.SSL_DISPLAY_STATES;
+ }
+ else if (args[i].equals("-show-rsa"))
+ {
+ options |= axtlsj.SSL_DISPLAY_RSA;
+ }
+ else
+ print_server_options(build_mode, args[i]);
+ }
+ else
+ print_server_options(build_mode, args[i]);
+ }
+ else
+ print_server_options(build_mode, args[i]);
+ }
+ else
+ print_server_options(build_mode, args[i]);
+
+ i++;
+ }
+
+ /* Create socket for incoming connections */
+ ServerSocket server_sock = new ServerSocket(port);
+
+ /**********************************************************************
+ * This is where the interesting stuff happens. Up until now we've
+ * just been setting up sockets etc. Now we do the SSL handshake.
+ **********************************************************************/
+ SSLServer ssl_ctx = new SSLServer(options,
+ axtlsj.SSL_DEFAULT_SVR_SESS);
+
+ if (ssl_ctx == null)
+ throw new Exception("Error: Server context is invalid");
+
+ if (private_key_file != null)
+ {
+ int obj_type = axtlsj.SSL_OBJ_RSA_KEY;
+
+ if (private_key_file.endsWith(".p8"))
+ obj_type = axtlsj.SSL_OBJ_PKCS8;
+ else if (private_key_file.endsWith(".p12"))
+ obj_type = axtlsj.SSL_OBJ_PKCS12;
+
+ if (ssl_ctx.objLoad(obj_type,
+ private_key_file, password) != axtlsj.SSL_OK)
+ {
+ throw new Exception("Error: Private key '" + private_key_file +
+ "' is undefined.");
+ }
+ }
+
+ for (i = 0; i < cert_index; i++)
+ {
+ if (ssl_ctx.objLoad(axtlsj.SSL_OBJ_X509_CERT,
+ cert[i], null) != axtlsj.SSL_OK)
+ {
+ throw new Exception("Certificate '" + cert[i] +
+ "' is undefined.");
+ }
+ }
+
+ for (i = 0; i < ca_cert_index; i++)
+ {
+ if (ssl_ctx.objLoad(axtlsj.SSL_OBJ_X509_CACERT,
+ ca_cert[i], null) != axtlsj.SSL_OK)
+ {
+ throw new Exception("Certificate '" + ca_cert[i] +
+ "' is undefined.");
+ }
+ }
+
+ int res;
+ SSLReadHolder rh = new SSLReadHolder();
+
+ for (;;)
+ {
+ if (!quiet)
+ {
+ System.out.println("ACCEPT");
+ }
+
+ Socket client_sock = server_sock.accept();
+
+ SSL ssl = ssl_ctx.connect(client_sock);
+
+ while ((res = ssl_ctx.read(ssl, rh)) == axtlsj.SSL_OK)
+ {
+ /* check when the connection has been established */
+ if (ssl.handshakeStatus() == axtlsj.SSL_OK)
+ break;
+
+ /* could do something else here */
+ }
+
+ if (res == axtlsj.SSL_OK) /* connection established and ok */
+ {
+ if (!quiet)
+ {
+ display_session_id(ssl);
+ display_cipher(ssl);
+ }
+
+ /* now read (and display) whatever the client sends us */
+ for (;;)
+ {
+ /* keep reading until we get something interesting */
+ while ((res = ssl_ctx.read(ssl, rh)) == axtlsj.SSL_OK)
+ {
+ /* could do something else here */
+ }
+
+ if (res < axtlsj.SSL_OK)
+ {
+ if (!quiet)
+ {
+ System.out.println("CONNECTION CLOSED");
+ }
+
+ break;
+ }
+
+ /* convert to String */
+ byte[] buf = rh.getData();
+ char[] str = new char[res];
+
+ for (i = 0; i < res; i++)
+ {
+ str[i] = (char)buf[i];
+ }
+
+ System.out.print(str);
+ }
+ }
+ else if (!quiet)
+ {
+ SSLUtil.displayError(res);
+ }
+
+ /* client was disconnected or the handshake failed. */
+ ssl.dispose();
+ client_sock.close();
+ }
+
+ /* ssl_ctx.dispose(); */
+ }
+
+ /*
+ * do_client()
+ */
+ private void do_client(int build_mode, String[] args)
+ throws Exception
+ {
+ if (build_mode < axtlsj.SSL_BUILD_ENABLE_CLIENT)
+ print_client_options(build_mode, args[1]);
+
+ int i = 1, res;
+ int port = 4433;
+ boolean quiet = false;
+ String password = null;
+ int reconnect = 0;
+ String private_key_file = null;
+ String hostname = "127.0.0.1";
+
+ /* organise the cert/ca_cert lists */
+ int cert_index = 0;
+ int ca_cert_index = 0;
+ int cert_size = SSLUtil.maxCerts();
+ int ca_cert_size = SSLUtil.maxCACerts();
+ String[] cert = new String[cert_size];
+ String[] ca_cert = new String[ca_cert_size];
+
+ int options = axtlsj.SSL_SERVER_VERIFY_LATER|axtlsj.SSL_DISPLAY_CERTS;
+ byte[] session_id = null;
+
+ while (i < args.length)
+ {
+ if (args[i].equals("-connect"))
+ {
+ String host_port;
+
+ if (i >= args.length-1)
+ {
+ print_client_options(build_mode, args[i]);
+ }
+
+ host_port = args[++i];
+ int index_colon;
+
+ if ((index_colon = host_port.indexOf(':')) < 0)
+ print_client_options(build_mode, args[i]);
+
+ hostname = new String(host_port.toCharArray(),
+ 0, index_colon);
+ port = Integer.parseInt(new String(host_port.toCharArray(),
+ index_colon+1, host_port.length()-index_colon-1));
+ }
+ else if (args[i].equals("-cert"))
+ {
+ if (i >= args.length-1 || cert_index >= cert_size)
+ {
+ print_client_options(build_mode, args[i]);
+ }
+
+ cert[cert_index++] = args[++i];
+ }
+ else if (args[i].equals("-CAfile"))
+ {
+ if (i >= args.length-1 || ca_cert_index >= ca_cert_size)
+ {
+ print_client_options(build_mode, args[i]);
+ }
+
+ ca_cert[ca_cert_index++] = args[++i];
+ }
+ else if (args[i].equals("-key"))
+ {
+ if (i >= args.length-1)
+ {
+ print_client_options(build_mode, args[i]);
+ }
+
+ private_key_file = args[++i];
+ options |= axtlsj.SSL_NO_DEFAULT_KEY;
+ }
+ else if (args[i].equals("-verify"))
+ {
+ options &= ~(int)axtlsj.SSL_SERVER_VERIFY_LATER;
+ }
+ else if (args[i].equals("-reconnect"))
+ {
+ reconnect = 4;
+ }
+ else if (args[i].equals("-quiet"))
+ {
+ quiet = true;
+ options &= ~(int)axtlsj.SSL_DISPLAY_CERTS;
+ }
+ else if (args[i].equals("-pass"))
+ {
+ if (i >= args.length-1)
+ {
+ print_server_options(build_mode, args[i]);
+ }
+
+ password = args[++i];
+ }
+ else if (build_mode == axtlsj.SSL_BUILD_FULL_MODE)
+ {
+ if (args[i].equals("-debug"))
+ {
+ options |= axtlsj.SSL_DISPLAY_BYTES;
+ }
+ else if (args[i].equals("-state"))
+ {
+ options |= axtlsj.SSL_DISPLAY_STATES;
+ }
+ else if (args[i].equals("-show-rsa"))
+ {
+ options |= axtlsj.SSL_DISPLAY_RSA;
+ }
+ else
+ print_client_options(build_mode, args[i]);
+ }
+ else /* don't know what this is */
+ print_client_options(build_mode, args[i]);
+
+ i++;
+ }
+
+ Socket client_sock = new Socket(hostname, port);
+
+ if (!client_sock.isConnected())
+ {
+ System.out.println("could not connect");
+ throw new Exception();
+ }
+
+ if (!quiet)
+ {
+ System.out.println("CONNECTED");
+ }
+
+ /**********************************************************************
+ * This is where the interesting stuff happens. Up until now we've
+ * just been setting up sockets etc. Now we do the SSL handshake.
+ **********************************************************************/
+ SSLClient ssl_ctx = new SSLClient(options,
+ axtlsj.SSL_DEFAULT_CLNT_SESS);
+
+ if (ssl_ctx == null)
+ {
+ throw new Exception("Error: Client context is invalid");
+ }
+
+ if (private_key_file != null)
+ {
+ int obj_type = axtlsj.SSL_OBJ_RSA_KEY;
+
+ if (private_key_file.endsWith(".p8"))
+ obj_type = axtlsj.SSL_OBJ_PKCS8;
+ else if (private_key_file.endsWith(".p12"))
+ obj_type = axtlsj.SSL_OBJ_PKCS12;
+
+ if (ssl_ctx.objLoad(obj_type,
+ private_key_file, password) != axtlsj.SSL_OK)
+ {
+ throw new Exception("Error: Private key '" + private_key_file +
+ "' is undefined.");
+ }
+ }
+
+ for (i = 0; i < cert_index; i++)
+ {
+ if (ssl_ctx.objLoad(axtlsj.SSL_OBJ_X509_CERT,
+ cert[i], null) != axtlsj.SSL_OK)
+ {
+ throw new Exception("Certificate '" + cert[i] +
+ "' is undefined.");
+ }
+ }
+
+ for (i = 0; i < ca_cert_index; i++)
+ {
+ if (ssl_ctx.objLoad(axtlsj.SSL_OBJ_X509_CACERT,
+ ca_cert[i], null) != axtlsj.SSL_OK)
+ {
+ throw new Exception("Certificate '" + ca_cert[i] +
+ "' is undefined.");
+ }
+ }
+
+ SSL ssl = null;
+
+ /* Try session resumption? */
+ if (reconnect > 0)
+ {
+ while (reconnect-- > 0)
+ {
+ ssl = ssl_ctx.connect(client_sock, session_id);
+
+ if ((res = ssl.handshakeStatus()) != axtlsj.SSL_OK)
+ {
+ if (!quiet)
+ {
+ SSLUtil.displayError(res);
+ }
+
+ ssl.dispose();
+ throw new Exception();
+ }
+
+ display_session_id(ssl);
+ session_id = ssl.getSessionId();
+
+ if (reconnect > 0)
+ {
+ ssl.dispose();
+ client_sock.close();
+
+ /* and reconnect */
+ client_sock = new Socket(hostname, port);
+ }
+ }
+ }
+ else
+ {
+ ssl = ssl_ctx.connect(client_sock, null);
+ }
+
+ /* check the return status */
+ if ((res = ssl.handshakeStatus()) != axtlsj.SSL_OK)
+ {
+ if (!quiet)
+ {
+ SSLUtil.displayError(res);
+ }
+
+ throw new Exception();
+ }
+
+ if (!quiet)
+ {
+ String common_name =
+ ssl.getCertificateDN(axtlsj.SSL_X509_CERT_COMMON_NAME);
+
+ if (common_name != null)
+ {
+ System.out.println("Common Name:\t\t\t" + common_name);
+ }
+
+ display_session_id(ssl);
+ display_cipher(ssl);
+ }
+
+ BufferedReader in = new BufferedReader(
+ new InputStreamReader(System.in));
+
+ for (;;)
+ {
+ String user_input = in.readLine();
+
+ if (user_input == null)
+ break;
+
+ byte[] buf = new byte[user_input.length()+2];
+ buf[buf.length-2] = (byte)'\n'; /* add the carriage return */
+ buf[buf.length-1] = 0; /* null terminate */
+
+ for (i = 0; i < buf.length-2; i++)
+ {
+ buf[i] = (byte)user_input.charAt(i);
+ }
+
+ if ((res = ssl_ctx.write(ssl, buf)) < axtlsj.SSL_OK)
+ {
+ if (!quiet)
+ {
+ SSLUtil.displayError(res);
+ }
+
+ break;
+ }
+ }
+
+ ssl_ctx.dispose();
+ }
+
+ /**
+ * We've had some sort of command-line error. Print out the basic options.
+ */
+ private void print_options(String option)
+ {
+ System.out.println("axssl: Error: '" + option +
+ "' is an invalid command.");
+ System.out.println("usage: axtlsj.jar [s_server|s_client|version] " +
+ "[args ...]");
+ System.exit(1);
+ }
+
+ /**
+ * We've had some sort of command-line error. Print out the server options.
+ */
+ private void print_server_options(int build_mode, String option)
+ {
+ int cert_size = SSLUtil.maxCerts();
+ int ca_cert_size = SSLUtil.maxCACerts();
+
+ System.out.println("unknown option " + option);
+ System.out.println("usage: s_server [args ...]");
+ System.out.println(" -accept arg\t- port to accept on (default " +
+ "is 4433)");
+ System.out.println(" -quiet\t\t- No server output");
+
+ if (build_mode >= axtlsj.SSL_BUILD_SERVER_ONLY)
+ {
+ System.out.println(" -cert arg\t- certificate file to add (in " +
+ "addition to default) to chain -");
+ System.out.println("\t\t Can repeat up to " + cert_size + " times");
+ System.out.println(" -key arg\t- Private key file to use");
+ System.out.println(" -pass\t\t- private key file pass phrase source");
+ }
+
+ if (build_mode >= axtlsj.SSL_BUILD_ENABLE_VERIFICATION)
+ {
+ System.out.println(" -verify\t- turn on peer certificate " +
+ "verification");
+ System.out.println(" -CAfile arg\t- Certificate authority. ");
+ System.out.println("\t\t Can repeat up to " +
+ ca_cert_size + " times");
+ }
+
+ if (build_mode == axtlsj.SSL_BUILD_FULL_MODE)
+ {
+ System.out.println(" -debug\t\t- Print more output");
+ System.out.println(" -state\t\t- Show state messages");
+ System.out.println(" -show-rsa\t- Show RSA state");
+ }
+
+ System.exit(1);
+ }
+
+ /**
+ * We've had some sort of command-line error. Print out the client options.
+ */
+ private void print_client_options(int build_mode, String option)
+ {
+ int cert_size = SSLUtil.maxCerts();
+ int ca_cert_size = SSLUtil.maxCACerts();
+
+ System.out.println("unknown option " + option);
+
+ if (build_mode >= axtlsj.SSL_BUILD_ENABLE_CLIENT)
+ {
+ System.out.println("usage: s_client [args ...]");
+ System.out.println(" -connect host:port - who to connect to " +
+ "(default is localhost:4433)");
+ System.out.println(" -verify\t- turn on peer certificate " +
+ "verification");
+ System.out.println(" -cert arg\t- certificate file to use");
+ System.out.println(" -key arg\t- Private key file to use");
+ System.out.println("\t\t Can repeat up to " + cert_size +
+ " times");
+ System.out.println(" -CAfile arg\t- Certificate authority.");
+ System.out.println("\t\t Can repeat up to " + ca_cert_size +
+ " times");
+ System.out.println(" -quiet\t\t- No client output");
+ System.out.println(" -pass\t\t- private key file pass " +
+ "phrase source");
+ System.out.println(" -reconnect\t- Drop and re-make the " +
+ "connection with the same Session-ID");
+
+ if (build_mode == axtlsj.SSL_BUILD_FULL_MODE)
+ {
+ System.out.println(" -debug\t\t- Print more output");
+ System.out.println(" -state\t\t- Show state messages");
+ System.out.println(" -show-rsa\t- Show RSA state");
+ }
+ }
+ else
+ {
+ System.out.println("Change configuration to allow this feature");
+ }
+
+ System.exit(1);
+ }
+
+ /**
+ * Display what cipher we are using
+ */
+ private void display_cipher(SSL ssl)
+ {
+ System.out.print("CIPHER is ");
+
+ byte ciph_id = ssl.getCipherId();
+
+ if (ciph_id == axtlsj.SSL_AES128_SHA)
+ System.out.println("AES128-SHA");
+ else if (ciph_id == axtlsj.SSL_AES256_SHA)
+ System.out.println("AES256-SHA");
+ else if (ciph_id == axtlsj.SSL_RC4_128_SHA)
+ System.out.println("RC4-SHA");
+ else if (ciph_id == axtlsj.SSL_RC4_128_MD5)
+ System.out.println("RC4-MD5");
+ else
+ System.out.println("Unknown - " + ssl.getCipherId());
+ }
+
+ public char toHexChar(int i)
+ {
+ if ((0 <= i) && (i <= 9 ))
+ return (char)('0' + i);
+ else
+ return (char)('a' + (i-10));
+ }
+
+ public void bytesToHex(byte[] data)
+ {
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < data.length; i++ )
+ {
+ buf.append(toHexChar((data[i]>>>4)&0x0F));
+ buf.append(toHexChar(data[i]&0x0F));
+ }
+
+ System.out.println(buf);
+ }
+
+
+ /**
+ * Display what session id we have.
+ */
+ private void display_session_id(SSL ssl)
+ {
+ byte[] session_id = ssl.getSessionId();
+
+ if (session_id.length > 0)
+ {
+ System.out.println("-----BEGIN SSL SESSION PARAMETERS-----");
+ bytesToHex(session_id);
+ System.out.println("-----END SSL SESSION PARAMETERS-----");
+ }
+ }
+}
--- /dev/null
+Main-Class: axssl
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+include ../../config/.config
+include ../../config/makefile.conf
+
+all: samples
+TARGET=../../$(STAGE)/axssl.lua
+samples: $(TARGET)
+
+$(TARGET): axssl.lua
+ install $< $@
+
+clean::
+ -@rm -f $(TARGET)
+
--- /dev/null
+#!/usr/local/bin/lua
+
+--
+-- Copyright (c) 2007, Cameron Rich
+--
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions are met:
+--
+-- * Redistributions of source code must retain the above copyright notice,
+-- this list of conditions and the following disclaimer.
+-- * Redistributions in binary form must reproduce the above copyright
+-- notice, this list of conditions and the following disclaimer in the
+-- documentation and/or other materials provided with the distribution.
+-- * Neither the name of the axTLS project nor the names of its
+-- contributors may be used to endorse or promote products derived
+-- from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+-- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+-- TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+-- OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+-- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+
+--
+-- Demonstrate the use of the axTLS library in Lua with a set of
+-- command-line parameters similar to openssl. In fact, openssl clients
+-- should be able to communicate with axTLS servers and visa-versa.
+--
+-- This code has various bits enabled depending on the configuration. To enable
+-- the most interesting version, compile with the 'full mode' enabled.
+--
+-- To see what options you have, run the following:
+-- > [lua] axssl s_server -?
+-- > [lua] axssl s_client -?
+--
+-- The axtls/axtlsl shared libraries must be in the same directory or be found
+-- by the OS.
+--
+--
+require "bit"
+require("axtlsl")
+local socket = require("socket")
+
+-- print version?
+if #arg == 1 and arg[1] == "version" then
+ print("axssl.lua "..axtlsl.ssl_version())
+ os.exit(1)
+end
+
+--
+-- We've had some sort of command-line error. Print out the basic options.
+--
+function print_options(option)
+ print("axssl: Error: '"..option.."' is an invalid command.")
+ print("usage: axssl [s_server|s_client|version] [args ...]")
+ os.exit(1)
+end
+
+--
+-- We've had some sort of command-line error. Print out the server options.
+--
+function print_server_options(build_mode, option)
+ local cert_size = axtlsl.ssl_get_config(axtlsl.SSL_MAX_CERT_CFG_OFFSET)
+ local ca_cert_size = axtlsl.ssl_get_config(
+ axtlsl.SSL_MAX_CA_CERT_CFG_OFFSET)
+
+ print("unknown option "..option)
+ print("usage: s_server [args ...]")
+ print(" -accept\t- port to accept on (default is 4433)")
+ print(" -quiet\t\t- No server output")
+
+ if build_mode >= axtlsl.SSL_BUILD_SERVER_ONLY then
+ print(" -cert arg\t- certificate file to add (in addition to "..
+ "default) to chain -")
+ print("\t\t Can repeat up to "..cert_size.." times")
+ print(" -key arg\t- Private key file to use - default DER format")
+ print(" -pass\t\t- private key file pass phrase source")
+ end
+
+ if build_mode >= axtlsl.SSL_BUILD_ENABLE_VERIFICATION then
+ print(" -verify\t- turn on peer certificate verification")
+ print(" -CAfile arg\t- Certificate authority - default DER format")
+ print("\t\t Can repeat up to "..ca_cert_size.." times")
+ end
+
+ if build_mode == axtlsl.SSL_BUILD_FULL_MODE then
+ print(" -debug\t\t- Print more output")
+ print(" -state\t\t- Show state messages")
+ print(" -show-rsa\t- Show RSA state")
+ end
+
+ os.exit(1)
+end
+
+--
+-- We've had some sort of command-line error. Print out the client options.
+--
+function print_client_options(build_mode, option)
+ local cert_size = axtlsl.ssl_get_config(axtlsl.SSL_MAX_CERT_CFG_OFFSET)
+ local ca_cert_size = axtlsl.ssl_get_config(
+ axtlsl.SSL_MAX_CA_CERT_CFG_OFFSET)
+
+ print("unknown option "..option)
+
+ if build_mode >= axtlsl.SSL_BUILD_ENABLE_CLIENT then
+ print("usage: s_client [args ...]")
+ print(" -connect host:port - who to connect to (default "..
+ "is localhost:4433)")
+ print(" -verify\t- turn on peer certificate verification")
+ print(" -cert arg\t- certificate file to use - default DER format")
+ print(" -key arg\t- Private key file to use - default DER format")
+ print("\t\t Can repeat up to "..cert_size.." times")
+ print(" -CAfile arg\t- Certificate authority - default DER format")
+ print("\t\t Can repeat up to "..ca_cert_size.."times")
+ print(" -quiet\t\t- No client output")
+ print(" -pass\t\t- private key file pass phrase source")
+ print(" -reconnect\t- Drop and re-make the connection "..
+ "with the same Session-ID")
+
+ if build_mode == axtlsl.SSL_BUILD_FULL_MODE then
+ print(" -debug\t\t- Print more output")
+ print(" -state\t\t- Show state messages")
+ print(" -show-rsa\t- Show RSA state")
+ end
+ else
+ print("Change configuration to allow this feature")
+ end
+
+ os.exit(1)
+end
+
+-- Implement the SSL server logic.
+function do_server(build_mode)
+ local i = 2
+ local v
+ local port = 4433
+ local options = axtlsl.SSL_DISPLAY_CERTS
+ local quiet = false
+ local password = ""
+ local private_key_file = nil
+ local cert_size = axtlsl.ssl_get_config(axtlsl.SSL_MAX_CERT_CFG_OFFSET)
+ local ca_cert_size = axtlsl.
+ ssl_get_config(axtlsl.SSL_MAX_CA_CERT_CFG_OFFSET)
+ local cert = {}
+ local ca_cert = {}
+
+ while i <= #arg do
+ if arg[i] == "-accept" then
+ if i >= #arg then
+ print_server_options(build_mode, arg[i])
+ end
+
+ i = i + 1
+ port = arg[i]
+ elseif arg[i] == "-quiet" then
+ quiet = true
+ options = bit.band(options, bit.bnot(axtlsl.SSL_DISPLAY_CERTS))
+ elseif build_mode >= axtlsl.SSL_BUILD_SERVER_ONLY then
+ if arg[i] == "-cert" then
+ if i >= #arg or #cert >= cert_size then
+ print_server_options(build_mode, arg[i])
+ end
+
+ i = i + 1
+ table.insert(cert, arg[i])
+ elseif arg[i] == "-key" then
+ if i >= #arg then
+ print_server_options(build_mode, arg[i])
+ end
+
+ i = i + 1
+ private_key_file = arg[i]
+ options = bit.bor(options, axtlsl.SSL_NO_DEFAULT_KEY)
+ elseif arg[i] == "-pass" then
+ if i >= #arg then
+ print_server_options(build_mode, arg[i])
+ end
+
+ i = i + 1
+ password = arg[i]
+ elseif build_mode >= axtlsl.SSL_BUILD_ENABLE_VERIFICATION then
+ if arg[i] == "-verify" then
+ options = bit.bor(options, axtlsl.SSL_CLIENT_AUTHENTICATION)
+ elseif arg[i] == "-CAfile" then
+ if i >= #arg or #ca_cert >= ca_cert_size then
+ print_server_options(build_mode, arg[i])
+ end
+
+ i = i + 1
+ table.insert(ca_cert, arg[i])
+ elseif build_mode == axtlsl.SSL_BUILD_FULL_MODE then
+ if arg[i] == "-debug" then
+ options = bit.bor(options, axtlsl.SSL_DISPLAY_BYTES)
+ elseif arg[i] == "-state" then
+ options = bit.bor(options, axtlsl.SSL_DISPLAY_STATES)
+ elseif arg[i] == "-show-rsa" then
+ options = bit.bor(options, axtlsl.SSL_DISPLAY_RSA)
+ else
+ print_server_options(build_mode, arg[i])
+ end
+ else
+ print_server_options(build_mode, arg[i])
+ end
+ else
+ print_server_options(build_mode, arg[i])
+ end
+ else
+ print_server_options(build_mode, arg[i])
+ end
+
+ i = i + 1
+ end
+
+ -- Create socket for incoming connections
+ local server_sock = socket.try(socket.bind("*", port))
+
+ ---------------------------------------------------------------------------
+ -- This is where the interesting stuff happens. Up until now we've
+ -- just been setting up sockets etc. Now we do the SSL handshake.
+ ---------------------------------------------------------------------------
+ local ssl_ctx = axtlsl.ssl_ctx_new(options, axtlsl.SSL_DEFAULT_SVR_SESS)
+ if ssl_ctx == nil then error("Error: Server context is invalid") end
+
+ if private_key_file ~= nil then
+ local obj_type = axtlsl.SSL_OBJ_RSA_KEY
+
+ if string.find(private_key_file, ".p8") then
+ obj_type = axtlsl.SSL_OBJ_PKCS8
+ end
+
+ if string.find(private_key_file, ".p12") then
+ obj_type = axtlsl.SSL_OBJ_PKCS12
+ end
+
+ if axtlsl.ssl_obj_load(ssl_ctx, obj_type, private_key_file,
+ password) ~= axtlsl.SSL_OK then
+ error("Private key '" .. private_key_file .. "' is undefined.")
+ end
+ end
+
+ for _, v in ipairs(cert) do
+ if axtlsl.ssl_obj_load(ssl_ctx, axtlsl.SSL_OBJ_X509_CERT, v, "") ~=
+ axtlsl.SSL_OK then
+ error("Certificate '"..v .. "' is undefined.")
+ end
+ end
+
+ for _, v in ipairs(ca_cert) do
+ if axtlsl.ssl_obj_load(ssl_ctx, axtlsl.SSL_OBJ_X509_CACERT, v, "") ~=
+ axtlsl.SSL_OK then
+ error("Certificate '"..v .."' is undefined.")
+ end
+ end
+
+ while true do
+ if not quiet then print("ACCEPT") end
+ local client_sock = server_sock:accept();
+ local ssl = axtlsl.ssl_server_new(ssl_ctx, client_sock:getfd())
+
+ -- do the actual SSL handshake
+ local connected = false
+ local res
+ local buf
+
+ while true do
+ socket.select({client_sock}, nil)
+ res, buf = axtlsl.ssl_read(ssl)
+
+ if res == axtlsl.SSL_OK then -- connection established and ok
+ if axtlsl.ssl_handshake_status(ssl) == axtlsl.SSL_OK then
+ if not quiet and not connected then
+ display_session_id(ssl)
+ display_cipher(ssl)
+ end
+ connected = true
+ end
+ end
+
+ if res > axtlsl.SSL_OK then
+ for _, v in ipairs(buf) do
+ io.write(string.format("%c", v))
+ end
+ elseif res < axtlsl.SSL_OK then
+ if not quiet then
+ axtlsl.ssl_display_error(res)
+ end
+ break
+ end
+ end
+
+ -- client was disconnected or the handshake failed.
+ print("CONNECTION CLOSED")
+ axtlsl.ssl_free(ssl)
+ client_sock:close()
+ end
+
+ axtlsl.ssl_ctx_free(ssl_ctx)
+end
+
+--
+-- Implement the SSL client logic.
+--
+function do_client(build_mode)
+ local i = 2
+ local v
+ local port = 4433
+ local options =
+ bit.bor(axtlsl.SSL_SERVER_VERIFY_LATER, axtlsl.SSL_DISPLAY_CERTS)
+ local private_key_file = nil
+ local reconnect = 0
+ local quiet = false
+ local password = ""
+ local session_id = {}
+ local host = "127.0.0.1"
+ local cert_size = axtlsl.ssl_get_config(axtlsl.SSL_MAX_CERT_CFG_OFFSET)
+ local ca_cert_size = axtlsl.
+ ssl_get_config(axtlsl.SSL_MAX_CA_CERT_CFG_OFFSET)
+ local cert = {}
+ local ca_cert = {}
+
+ while i <= #arg do
+ if arg[i] == "-connect" then
+ if i >= #arg then
+ print_client_options(build_mode, arg[i])
+ end
+
+ i = i + 1
+ local t = string.find(arg[i], ":")
+ host = string.sub(arg[i], 1, t-1)
+ port = string.sub(arg[i], t+1)
+ elseif arg[i] == "-cert" then
+ if i >= #arg or #cert >= cert_size then
+ print_client_options(build_mode, arg[i])
+ end
+
+ i = i + 1
+ table.insert(cert, arg[i])
+ elseif arg[i] == "-key" then
+ if i >= #arg then
+ print_client_options(build_mode, arg[i])
+ end
+
+ i = i + 1
+ private_key_file = arg[i]
+ options = bit.bor(options, axtlsl.SSL_NO_DEFAULT_KEY)
+ elseif arg[i] == "-CAfile" then
+ if i >= #arg or #ca_cert >= ca_cert_size then
+ print_client_options(build_mode, arg[i])
+ end
+
+ i = i + 1
+ table.insert(ca_cert, arg[i])
+ elseif arg[i] == "-verify" then
+ options = bit.band(options,
+ bit.bnot(axtlsl.SSL_SERVER_VERIFY_LATER))
+ elseif arg[i] == "-reconnect" then
+ reconnect = 4
+ elseif arg[i] == "-quiet" then
+ quiet = true
+ options = bit.band(options, bnot(axtlsl.SSL_DISPLAY_CERTS))
+ elseif arg[i] == "-pass" then
+ if i >= #arg then
+ print_server_options(build_mode, arg[i])
+ end
+
+ i = i + 1
+ password = arg[i]
+ elseif build_mode == axtlsl.SSL_BUILD_FULL_MODE then
+ if arg[i] == "-debug" then
+ options = bit.bor(options, axtlsl.SSL_DISPLAY_BYTES)
+ elseif arg[i] == "-state" then
+ options = bit.bor(axtlsl.SSL_DISPLAY_STATES)
+ elseif arg[i] == "-show-rsa" then
+ options = bit.bor(axtlsl.SSL_DISPLAY_RSA)
+ else -- don't know what this is
+ print_client_options(build_mode, arg[i])
+ end
+ else -- don't know what this is
+ print_client_options(build_mode, arg[i])
+ end
+
+ i = i + 1
+ end
+
+ local client_sock = socket.try(socket.connect(host, port))
+ local ssl
+ local res
+
+ if not quiet then print("CONNECTED") end
+
+ ---------------------------------------------------------------------------
+ -- This is where the interesting stuff happens. Up until now we've
+ -- just been setting up sockets etc. Now we do the SSL handshake.
+ ---------------------------------------------------------------------------
+ local ssl_ctx = axtlsl.ssl_ctx_new(options, axtlsl.SSL_DEFAULT_CLNT_SESS)
+
+ if ssl_ctx == nil then
+ error("Error: Client context is invalid")
+ end
+
+ if private_key_file ~= nil then
+ local obj_type = axtlsl.SSL_OBJ_RSA_KEY
+
+ if string.find(private_key_file, ".p8") then
+ obj_type = axtlsl.SSL_OBJ_PKCS8
+ end
+
+ if string.find(private_key_file, ".p12") then
+ obj_type = axtlsl.SSL_OBJ_PKCS12
+ end
+
+ if axtlsl.ssl_obj_load(ssl_ctx, obj_type, private_key_file,
+ password) ~= axtlsl.SSL_OK then
+ error("Private key '"..private_key_file.."' is undefined.")
+ end
+ end
+
+ for _, v in ipairs(cert) do
+ if axtlsl.ssl_obj_load(ssl_ctx, axtlsl.SSL_OBJ_X509_CERT, v, "") ~=
+ axtlsl.SSL_OK then
+ error("Certificate '"..v .. "' is undefined.")
+ end
+ end
+
+ for _, v in ipairs(ca_cert) do
+ if axtlsl.ssl_obj_load(ssl_ctx, axtlsl.SSL_OBJ_X509_CACERT, v, "") ~=
+ axtlsl.SSL_OK then
+ error("Certificate '"..v .."' is undefined.")
+ end
+ end
+
+ -- Try session resumption?
+ if reconnect ~= 0 then
+ local session_id = nil
+ local sess_id_size = 0
+
+ while reconnect > 0 do
+ reconnect = reconnect - 1
+ ssl = axtlsl.ssl_client_new(ssl_ctx,
+ client_sock:getfd(), session_id, sess_id_size)
+
+ res = axtlsl.ssl_handshake_status(ssl)
+ if res ~= axtlsl.SSL_OK then
+ if not quiet then axtlsl.ssl_display_error(res) end
+ axtlsl.ssl_free(ssl)
+ os.exit(1)
+ end
+
+ display_session_id(ssl)
+ session_id = axtlsl.ssl_get_session_id(ssl)
+ sess_id_size = axtlsl.ssl_get_session_id_size(ssl)
+
+ if reconnect > 0 then
+ axtlsl.ssl_free(ssl)
+ client_sock:close()
+ client_sock = socket.try(socket.connect(host, port))
+ end
+
+ end
+ else
+ ssl = axtlsl.ssl_client_new(ssl_ctx, client_sock:getfd(), nil, 0)
+ end
+
+ -- check the return status
+ res = axtlsl.ssl_handshake_status(ssl)
+ if res ~= axtlsl.SSL_OK then
+ if not quiet then axtlsl.ssl_display_error(res) end
+ os.exit(1)
+ end
+
+ if not quiet then
+ local common_name = axtlsl.ssl_get_cert_dn(ssl,
+ axtlsl.SSL_X509_CERT_COMMON_NAME)
+
+ if common_name ~= nil then
+ print("Common Name:\t\t\t"..common_name)
+ end
+
+ display_session_id(ssl)
+ display_cipher(ssl)
+ end
+
+ while true do
+ local line = io.read()
+ if line == nil then break end
+ local bytes = {}
+
+ for i = 1, #line do
+ bytes[i] = line.byte(line, i)
+ end
+
+ bytes[#line+1] = 10 -- add carriage return, null
+ bytes[#line+2] = 0
+
+ res = axtlsl.ssl_write(ssl, bytes, #bytes)
+ if res < axtlsl.SSL_OK then
+ if not quiet then axtlsl.ssl_display_error(res) end
+ break
+ end
+ end
+
+ axtlsl.ssl_ctx_free(ssl_ctx)
+ client_sock:close()
+end
+
+--
+-- Display what cipher we are using
+--
+function display_cipher(ssl)
+ io.write("CIPHER is ")
+ local cipher_id = axtlsl.ssl_get_cipher_id(ssl)
+
+ if cipher_id == axtlsl.SSL_AES128_SHA then
+ print("AES128-SHA")
+ elseif cipher_id == axtlsl.SSL_AES256_SHA then
+ print("AES256-SHA")
+ elseif axtlsl.SSL_RC4_128_SHA then
+ print("RC4-SHA")
+ elseif axtlsl.SSL_RC4_128_MD5 then
+ print("RC4-MD5")
+ else
+ print("Unknown - "..cipher_id)
+ end
+end
+
+--
+-- Display what session id we have.
+--
+function display_session_id(ssl)
+ local session_id = axtlsl.ssl_get_session_id(ssl)
+ local v
+
+ if #session_id > 0 then
+ print("-----BEGIN SSL SESSION PARAMETERS-----")
+ for _, v in ipairs(session_id) do
+ io.write(string.format("%02x", v))
+ end
+ print("\n-----END SSL SESSION PARAMETERS-----")
+ end
+end
+
+--
+-- Main entry point. Doesn't do much except works out whether we are a client
+-- or a server.
+--
+if #arg == 0 or (arg[1] ~= "s_server" and arg[1] ~= "s_client") then
+ print_options(#arg > 0 and arg[1] or "")
+end
+
+local build_mode = axtlsl.ssl_get_config(axtlsl.SSL_BUILD_MODE)
+_ = arg[1] == "s_server" and do_server(build_mode) or do_client(build_mode)
+os.exit(0)
+
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+include ../../config/.config
+include ../../config/makefile.conf
+
+all: samples
+TARGET=../../$(STAGE)/axssl.pl
+samples: $(TARGET)
+
+$(TARGET): axssl.pl
+ install $< $@
+
+clean::
+ -@rm -f $(TARGET)
+
--- /dev/null
+#!/usr/bin/perl -w
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# Demonstrate the use of the axTLS library in Perl with a set of
+# command-line parameters similar to openssl. In fact, openssl clients
+# should be able to communicate with axTLS servers and visa-versa.
+#
+# This code has various bits enabled depending on the configuration. To enable
+# the most interesting version, compile with the 'full mode' enabled.
+#
+# To see what options you have, run the following:
+# > [perl] axssl s_server -?
+# > [perl] axssl s_client -?
+#
+# The axtls/axtlsp shared libraries must be in the same directory or be found
+# by the OS. axtlsp.pm must be in this directory or be in @INC.
+#
+# Under Win32, ActivePerl was used (see
+# http://www.activestate.com/Products/ActivePerl/?mp=1)
+#
+use axtlsp;
+use IO::Socket;
+
+# To get access to Win32 file descriptor stuff
+my $is_win32 = 0;
+
+if ($^O eq "MSWin32")
+{
+ eval("use Win32API::File 0.08 qw( :ALL )");
+ $is_win32 = 1;
+}
+
+use strict;
+
+#
+# Win32 has some problems with socket handles
+#
+sub get_native_sock
+{
+ my ($sock) = @_;
+ return $is_win32 ? FdGetOsFHandle($sock) : $sock;
+}
+
+# print version?
+if ($#ARGV == 0 && $ARGV[0] eq "version")
+{
+ printf("axssl.pl ".axtlsp::ssl_version()."\n");
+ exit 0;
+}
+
+#
+# Main entry point. Doesn't do much except works out whether we are a client
+# or a server.
+#
+print_options($#ARGV > -1 ? $ARGV[0] : "")
+ if ($#ARGV < 0 || ($ARGV[0] ne "s_server" && $ARGV[0] ne "s_client"));
+
+
+# Cygwin/Win32 issue - flush our output continuously
+select STDOUT;
+local $|=1;
+
+my $build_mode = axtlsp::ssl_get_config($axtlsp::SSL_BUILD_MODE);
+$ARGV[0] eq "s_server" ? do_server($build_mode) : do_client($build_mode);
+
+#
+# Implement the SSL server logic.
+#
+sub do_server
+{
+ my ($build_mode) = @_;
+ my $i = 1;
+ my $port = 4433;
+ my $options = $axtlsp::SSL_DISPLAY_CERTS;
+ my $quiet = 0;
+ my $password = undef;
+ my $private_key_file = undef;
+ my $cert_size = axtlsp::ssl_get_config($axtlsp::SSL_MAX_CERT_CFG_OFFSET);
+ my $ca_cert_size = axtlsp::ssl_get_config(
+ $axtlsp::SSL_MAX_CA_CERT_CFG_OFFSET);
+ my @cert;
+ my @ca_cert;
+
+ while ($i <= $#ARGV)
+ {
+ if ($ARGV[$i] eq "-accept")
+ {
+ print_server_options($build_mode, $ARGV[$i]) if $i >= $#ARGV;
+ $port = $ARGV[++$i];
+ }
+ elsif ($ARGV[$i] eq "-quiet")
+ {
+ $quiet = 1;
+ $options &= ~$axtlsp::SSL_DISPLAY_CERTS;
+ }
+ elsif ($build_mode >= $axtlsp::SSL_BUILD_SERVER_ONLY)
+ {
+ if ($ARGV[$i] eq "-cert")
+ {
+ print_server_options($build_mode, $ARGV[$i])
+ if $i >= $#ARGV || $#cert >= $cert_size-1;
+
+ push @cert, $ARGV[++$i];
+ }
+ elsif ($ARGV[$i] eq "-key")
+ {
+ print_server_options($build_mode, $ARGV[$i]) if $i >= $#ARGV;
+ $private_key_file = $ARGV[++$i];
+ $options |= $axtlsp::SSL_NO_DEFAULT_KEY;
+ }
+ elsif ($ARGV[$i] eq "-pass")
+ {
+ print_server_options($build_mode, $ARGV[$i]) if $i >= $#ARGV;
+ $password = $ARGV[++$i];
+ }
+ elsif ($build_mode >= $axtlsp::SSL_BUILD_ENABLE_VERIFICATION)
+ {
+ if ($ARGV[$i] eq "-verify")
+ {
+ $options |= $axtlsp::SSL_CLIENT_AUTHENTICATION;
+ }
+ elsif ($ARGV[$i] eq "-CAfile")
+ {
+ print_server_options($build_mode, $ARGV[$i])
+ if $i >= $#ARGV || $#ca_cert >= $ca_cert_size-1;
+ push @ca_cert, $ARGV[++$i];
+ }
+ elsif ($build_mode == $axtlsp::SSL_BUILD_FULL_MODE)
+ {
+ if ($ARGV[$i] eq "-debug")
+ {
+ $options |= $axtlsp::SSL_DISPLAY_BYTES;
+ }
+ elsif ($ARGV[$i] eq "-state")
+ {
+ $options |= $axtlsp::SSL_DISPLAY_STATES;
+ }
+ elsif ($ARGV[$i] eq "-show-rsa")
+ {
+ $options |= $axtlsp::SSL_DISPLAY_RSA;
+ }
+ else
+ {
+ print_server_options($build_mode, $ARGV[$i]);
+ }
+ }
+ else
+ {
+ print_server_options($build_mode, $ARGV[$i]);
+ }
+ }
+ else
+ {
+ print_server_options($build_mode, $ARGV[$i]);
+ }
+ }
+ else
+ {
+ print_server_options($build_mode, $ARGV[$i]);
+ }
+
+ $i++;
+ }
+
+ # Create socket for incoming connections
+ my $server_sock = IO::Socket::INET->new(Proto => 'tcp',
+ LocalPort => $port,
+ Listen => 1,
+ Reuse => 1) or die $!;
+
+ ###########################################################################
+ # This is where the interesting stuff happens. Up until now we've
+ # just been setting up sockets etc. Now we do the SSL handshake.
+ ###########################################################################
+ my $ssl_ctx = axtlsp::ssl_ctx_new($options, $axtlsp::SSL_DEFAULT_SVR_SESS);
+ die "Error: Server context is invalid" if not defined $ssl_ctx;
+
+ if (defined $private_key_file)
+ {
+ my $obj_type = $axtlsp::SSL_OBJ_RSA_KEY;
+
+ $obj_type = $axtlsp::SSL_OBJ_PKCS8 if $private_key_file =~ /.p8$/;
+ $obj_type = $axtlsp::SSL_OBJ_PKCS12 if $private_key_file =~ /.p12$/;
+
+ die "Private key '$private_key_file' is undefined." if
+ axtlsp::ssl_obj_load($ssl_ctx, $obj_type,
+ $private_key_file, $password);
+ }
+
+ foreach (@cert)
+ {
+ die "Certificate '$_' is undefined."
+ if axtlsp::ssl_obj_load($ssl_ctx, $axtlsp::SSL_OBJ_X509_CERT,
+ $_, undef) != $axtlsp::SSL_OK;
+ }
+
+ foreach (@ca_cert)
+ {
+ die "Certificate '$_' is undefined."
+ if axtlsp::ssl_obj_load($ssl_ctx, $axtlsp::SSL_OBJ_X509_CACERT,
+ $_, undef) != $axtlsp::SSL_OK;
+ }
+
+ for (;;)
+ {
+ printf("ACCEPT\n") if not $quiet;
+ my $client_sock = $server_sock->accept;
+ my $native_sock = get_native_sock($client_sock->fileno);
+
+ # This doesn't work in Win32 - need to get file descriptor from socket.
+ my $ssl = axtlsp::ssl_server_new($ssl_ctx, $native_sock);
+
+ # do the actual SSL handshake
+ my $res;
+ my $buf;
+ my $connected = 0;
+
+ while (1)
+ {
+ ($res, $buf) = axtlsp::ssl_read($ssl, undef);
+ last if $res < $axtlsp::SSL_OK;
+
+ if ($res == $axtlsp::SSL_OK) # connection established and ok
+ {
+ if (axtlsp::ssl_handshake_status($ssl) == $axtlsp::SSL_OK)
+ {
+ if (!$quiet && !$connected)
+ {
+ display_session_id($ssl);
+ display_cipher($ssl);
+ }
+
+ $connected = 1;
+ }
+ }
+
+ if ($res > $axtlsp::SSL_OK)
+ {
+ printf($$buf);
+ }
+ elsif ($res < $axtlsp::SSL_OK)
+ {
+ axtlsp::ssl_display_error($res) if not $quiet;
+ last;
+ }
+ }
+
+ # client was disconnected or the handshake failed.
+ printf("CONNECTION CLOSED\n") if not $quiet;
+ axtlsp::ssl_free($ssl);
+ $client_sock->close;
+ }
+
+ axtlsp::ssl_ctx_free($ssl_ctx);
+}
+
+#
+# Implement the SSL client logic.
+#
+sub do_client
+{
+ my ($build_mode) = @_;
+ my $i = 1;
+ my $port = 4433;
+ my $options = $axtlsp::SSL_SERVER_VERIFY_LATER|$axtlsp::SSL_DISPLAY_CERTS;
+ my $private_key_file = undef;
+ my $reconnect = 0;
+ my $quiet = 0;
+ my $password = undef;
+ my @session_id;
+ my $host = "127.0.0.1";
+ my @cert;
+ my @ca_cert;
+ my $cert_size = axtlsp::ssl_get_config(
+ $axtlsp::SSL_MAX_CERT_CFG_OFFSET);
+ my $ca_cert_size = axtlsp::ssl_get_config(
+ $axtlsp::SSL_MAX_CA_CERT_CFG_OFFSET);
+
+ while ($i <= $#ARGV)
+ {
+ if ($ARGV[$i] eq "-connect")
+ {
+ print_client_options($build_mode, $ARGV[$i]) if $i >= $#ARGV;
+ ($host, $port) = split(':', $ARGV[++$i]);
+ }
+ elsif ($ARGV[$i] eq "-cert")
+ {
+ print_client_options($build_mode, $ARGV[$i])
+ if $i >= $#ARGV || $#cert >= $cert_size-1;
+
+ push @cert, $ARGV[++$i];
+ }
+ elsif ($ARGV[$i] eq "-key")
+ {
+ print_client_options($build_mode, $ARGV[$i]) if $i >= $#ARGV;
+ $private_key_file = $ARGV[++$i];
+ $options |= $axtlsp::SSL_NO_DEFAULT_KEY;
+ }
+ elsif ($ARGV[$i] eq "-CAfile")
+ {
+ print_client_options($build_mode, $ARGV[$i])
+ if $i >= $#ARGV || $#ca_cert >= $ca_cert_size-1;
+
+ push @ca_cert, $ARGV[++$i];
+ }
+ elsif ($ARGV[$i] eq "-verify")
+ {
+ $options &= ~$axtlsp::SSL_SERVER_VERIFY_LATER;
+ }
+ elsif ($ARGV[$i] eq "-reconnect")
+ {
+ $reconnect = 4;
+ }
+ elsif ($ARGV[$i] eq "-quiet")
+ {
+ $quiet = 1;
+ $options &= ~$axtlsp::SSL_DISPLAY_CERTS;
+ }
+ elsif ($ARGV[$i] eq "-pass")
+ {
+ print_server_options($build_mode, $ARGV[$i]) if $i >= $#ARGV;
+ $password = $ARGV[++$i];
+ }
+ elsif ($build_mode == $axtlsp::SSL_BUILD_FULL_MODE)
+ {
+ if ($ARGV[$i] eq "-debug")
+ {
+ $options |= $axtlsp::SSL_DISPLAY_BYTES;
+ }
+ elsif ($ARGV[$i] eq "-state")
+ {
+ $options |= $axtlsp::SSL_DISPLAY_STATES;
+ }
+ elsif ($ARGV[$i] eq "-show-rsa")
+ {
+ $options |= $axtlsp::SSL_DISPLAY_RSA;
+ }
+ else # don't know what this is
+ {
+ print_client_options($build_mode, $ARGV[$i]);
+ }
+ }
+ else # don't know what this is
+ {
+ print_client_options($build_mode, $ARGV[$i]);
+ }
+
+ $i++;
+ }
+
+ my $client_sock = new IO::Socket::INET (
+ PeerAddr => $host, PeerPort => $port, Proto => 'tcp')
+ || die ("no socket: $!");
+ my $ssl;
+ my $res;
+ my $native_sock = get_native_sock($client_sock->fileno);
+
+ printf("CONNECTED\n") if not $quiet;
+
+ ###########################################################################
+ # This is where the interesting stuff happens. Up until now we've
+ # just been setting up sockets etc. Now we do the SSL handshake.
+ ###########################################################################
+ my $ssl_ctx = axtlsp::ssl_ctx_new($options, $axtlsp::SSL_DEFAULT_CLNT_SESS);
+ die "Error: Client context is invalid" if not defined $ssl_ctx;
+
+ if (defined $private_key_file)
+ {
+ my $obj_type = $axtlsp::SSL_OBJ_RSA_KEY;
+
+ $obj_type = $axtlsp::SSL_OBJ_PKCS8 if $private_key_file =~ /.p8$/;
+ $obj_type = $axtlsp::SSL_OBJ_PKCS12 if $private_key_file =~ /.p12$/;
+
+ die "Private key '$private_key_file' is undefined." if
+ axtlsp::ssl_obj_load($ssl_ctx, $obj_type,
+ $private_key_file, $password);
+ }
+
+ foreach (@cert)
+ {
+ die "Certificate '$_' is undefined."
+ if axtlsp::ssl_obj_load($ssl_ctx, $axtlsp::SSL_OBJ_X509_CERT,
+ $_, undef) != $axtlsp::SSL_OK;
+ }
+
+ foreach (@ca_cert)
+ {
+ die "Certificate '$_' is undefined."
+ if axtlsp::ssl_obj_load($ssl_ctx, $axtlsp::SSL_OBJ_X509_CACERT,
+ $_, undef) != $axtlsp::SSL_OK;
+ }
+
+ # Try session resumption?
+ if ($reconnect)
+ {
+ my $session_id = undef;
+ my $sess_id_size = 0;
+
+ while ($reconnect--)
+ {
+ $ssl = axtlsp::ssl_client_new($ssl_ctx, $native_sock,
+ $session_id, $sess_id_size);
+
+ $res = axtlsp::ssl_handshake_status($ssl);
+ if ($res != $axtlsp::SSL_OK)
+ {
+ axtlsp::ssl_display_error($res) if !$quiet;
+ axtlsp::ssl_free($ssl);
+ exit 1;
+ }
+
+ display_session_id($ssl);
+ $session_id = axtlsp::ssl_get_session_id($ssl);
+
+ if ($reconnect)
+ {
+ axtlsp::ssl_free($ssl);
+ $client_sock->close;
+ $client_sock = new IO::Socket::INET (
+ PeerAddr => $host, PeerPort => $port, Proto => 'tcp')
+ || die ("no socket: $!");
+
+ }
+ }
+ }
+ else
+ {
+ $ssl = axtlsp::ssl_client_new($ssl_ctx, $native_sock, undef, 0);
+ }
+
+ # check the return status
+ $res = axtlsp::ssl_handshake_status($ssl);
+ if ($res != $axtlsp::SSL_OK)
+ {
+ axtlsp::ssl_display_error($res) if not $quiet;
+ exit 1;
+ }
+
+ if (!$quiet)
+ {
+ my $common_name = axtlsp::ssl_get_cert_dn($ssl,
+ $axtlsp::SSL_X509_CERT_COMMON_NAME);
+
+ printf("Common Name:\t\t\t%s\n", $common_name) if defined $common_name;
+ display_session_id($ssl);
+ display_cipher($ssl);
+ }
+
+ while (<STDIN>)
+ {
+ my $cstring = pack("a*x", $_); # add null terminator
+ $res = axtlsp::ssl_write($ssl, \$cstring, length($cstring));
+ if ($res < $axtlsp::SSL_OK)
+ {
+ axtlsp::ssl_display_error($res) if not $quiet;
+ last;
+ }
+ }
+
+ axtlsp::ssl_ctx_free($ssl_ctx);
+ $client_sock->close;
+}
+
+#
+# We've had some sort of command-line error. Print out the basic options.
+#
+sub print_options
+{
+ my ($option) = @_;
+ printf("axssl: Error: '%s' is an invalid command.\n", $option);
+ printf("usage: axssl [s_server|s_client|version] [args ...]\n");
+ exit 1;
+}
+
+#
+# We've had some sort of command-line error. Print out the server options.
+#
+sub print_server_options
+{
+ my ($build_mode, $option) = @_;
+ my $cert_size = axtlsp::ssl_get_config($axtlsp::SSL_MAX_CERT_CFG_OFFSET);
+ my $ca_cert_size = axtlsp::ssl_get_config(
+ $axtlsp::SSL_MAX_CA_CERT_CFG_OFFSET);
+
+ printf("unknown option %s\n", $option);
+ printf("usage: s_server [args ...]\n");
+ printf(" -accept arg\t- port to accept on (default is 4433)\n");
+ printf(" -quiet\t\t- No server output\n");
+
+ if ($build_mode >= $axtlsp::SSL_BUILD_SERVER_ONLY)
+ {
+ printf(" -cert arg\t- certificate file to add (in addition to default)".
+ " to chain -\n".
+ "\t\t Can repeat up to %d times\n", $cert_size);
+ printf(" -key arg\t- Private key file to use - default DER format\n");
+ printf(" -pass\t\t- private key file pass phrase source\n");
+ }
+
+ if ($build_mode >= $axtlsp::SSL_BUILD_ENABLE_VERIFICATION)
+ {
+ printf(" -verify\t- turn on peer certificate verification\n");
+ printf(" -CAfile arg\t- Certificate authority - default DER format\n");
+ printf("\t\t Can repeat up to %d times\n", $ca_cert_size);
+ }
+
+ if ($build_mode == $axtlsp::SSL_BUILD_FULL_MODE)
+ {
+ printf(" -debug\t\t- Print more output\n");
+ printf(" -state\t\t- Show state messages\n");
+ printf(" -show-rsa\t- Show RSA state\n");
+ }
+
+ exit 1;
+}
+
+#
+# We've had some sort of command-line error. Print out the client options.
+#
+sub print_client_options
+{
+ my ($build_mode, $option) = @_;
+ my $cert_size = axtlsp::ssl_get_config($axtlsp::SSL_MAX_CERT_CFG_OFFSET);
+ my $ca_cert_size = axtlsp::ssl_get_config(
+ $axtlsp::SSL_MAX_CA_CERT_CFG_OFFSET);
+
+ printf("unknown option %s\n", $option);
+
+ if ($build_mode >= $axtlsp::SSL_BUILD_ENABLE_CLIENT)
+ {
+ printf("usage: s_client [args ...]\n");
+ printf(" -connect host:port - who to connect to (default ".
+ "is localhost:4433)\n");
+ printf(" -verify\t- turn on peer certificate verification\n");
+ printf(" -cert arg\t- certificate file to use - default DER format\n");
+ printf(" -key arg\t- Private key file to use - default DER format\n");
+ printf("\t\t Can repeat up to %d times\n", $cert_size);
+ printf(" -CAfile arg\t- Certificate authority - default DER format\n");
+ printf("\t\t Can repeat up to %d times\n", $ca_cert_size);
+ printf(" -quiet\t\t- No client output\n");
+ printf(" -pass\t\t- private key file pass phrase source\n");
+ printf(" -reconnect\t- Drop and re-make the connection ".
+ "with the same Session-ID\n");
+
+ if ($build_mode == $axtlsp::SSL_BUILD_FULL_MODE)
+ {
+ printf(" -debug\t\t- Print more output\n");
+ printf(" -state\t\t- Show state messages\n");
+ printf(" -show-rsa\t- Show RSA state\n");
+ }
+ }
+ else
+ {
+ printf("Change configuration to allow this feature\n");
+ }
+
+ exit 1;
+}
+
+#
+# Display what cipher we are using
+#
+sub display_cipher
+{
+ my ($ssl) = @_;
+ printf("CIPHER is ");
+ my $cipher_id = axtlsp::ssl_get_cipher_id($ssl);
+
+ if ($cipher_id == $axtlsp::SSL_AES128_SHA)
+ {
+ printf("AES128-SHA");
+ }
+ elsif ($cipher_id == $axtlsp::SSL_AES256_SHA)
+ {
+ printf("AES256-SHA");
+ }
+ elsif ($axtlsp::SSL_RC4_128_SHA)
+ {
+ printf("RC4-SHA");
+ }
+ elsif ($axtlsp::SSL_RC4_128_MD5)
+ {
+ printf("RC4-MD5");
+ }
+ else
+ {
+ printf("Unknown - %d", $cipher_id);
+ }
+
+ printf("\n");
+}
+
+#
+# Display what session id we have.
+#
+sub display_session_id
+{
+ my ($ssl) = @_;
+ my $session_id = axtlsp::ssl_get_session_id($ssl);
+ if (length($$session_id) > 0)
+ {
+ printf("-----BEGIN SSL SESSION PARAMETERS-----\n");
+ printf(unpack("H*", $$session_id));
+ printf("\n-----END SSL SESSION PARAMETERS-----\n");
+ }
+}
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+include ../../config/.config
+include ../../config/makefile.conf
+include ../../config/makefile.dotnet.conf
+
+# only build on Win32 platforms
+ifdef GO_DOT_NET
+all : sample
+TARGET=../../$(STAGE)/axssl.vbnet.exe
+sample : $(TARGET)
+
+$(TARGET): ../../bindings/vbnet/axTLSvb.vb ../../bindings/vbnet/axInterface.vb axssl.vb
+ vbc.exe /r:"`cygpath -w "$(CONFIG_DOT_NET_FRAMEWORK_BASE)/System.dll"`" /nologo /t:exe /out:"`cygpath -w $@`" $(foreach file, $^, "`cygpath -w $(file)`")
+
+endif # ARCH
+
+clean::
+ -@rm -f $(TARGET)
+
--- /dev/null
+'
+' Copyright (c) 2007, Cameron Rich
+'
+' All rights reserved.
+'
+' Redistribution and use in source and binary forms, with or without
+' modification, are permitted provided that the following conditions are met:
+'
+' * Redistributions of source code must retain the above copyright notice,
+' this list of conditions and the following disclaimer.
+' * Redistributions in binary form must reproduce the above copyright
+' notice, this list of conditions and the following disclaimer in the
+' documentation and/or other materials provided with the distribution.
+' * Neither the name of the axTLS project nor the names of its
+' contributors may be used to endorse or promote products derived
+' from this software without specific prior written permission.
+'
+' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+' CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+' TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+' OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+' NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+' THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'
+
+'
+' Demonstrate the use of the axTLS library in VB.NET with a set of
+' command-line parameters similar to openssl. In fact, openssl clients
+' should be able to communicate with axTLS servers and visa-versa.
+'
+' This code has various bits enabled depending on the configuration. To enable
+' the most interesting version, compile with the 'full mode' enabled.
+'
+' To see what options you have, run the following:
+' > axssl.vbnet.exe s_server -?
+' > axssl.vbnet.exe s_client -?
+'
+' The axtls shared library must be in the same directory or be found
+' by the OS.
+'
+
+Imports System
+Imports System.Net
+Imports System.Net.Sockets
+Imports Microsoft.VisualBasic
+Imports axTLSvb
+
+Public Class axssl
+ '
+ ' do_server()
+ '
+ Public Sub do_server(ByVal build_mode As Integer, _
+ ByVal args() As String)
+ Dim i As Integer = 1
+ Dim port As Integer = 4433
+ Dim options As Integer = axtls.SSL_DISPLAY_CERTS
+ Dim quiet As Boolean = False
+ Dim password As String = Nothing
+ Dim private_key_file As String = Nothing
+
+ ' organise the cert/ca_cert lists
+ Dim cert_size As Integer = SSLUtil.MaxCerts()
+ Dim ca_cert_size As Integer = SSLUtil.MaxCACerts()
+ Dim cert(cert_size) As String
+ Dim ca_cert(ca_cert_size) As String
+ Dim cert_index As Integer = 0
+ Dim ca_cert_index As Integer = 0
+
+ While i < args.Length
+ If args(i) = "-accept" Then
+ If i >= args.Length-1
+ print_server_options(build_mode, args(i))
+ End If
+
+ i += 1
+ port = Int32.Parse(args(i))
+ ElseIf args(i) = "-quiet"
+ quiet = True
+ options = options And Not axtls.SSL_DISPLAY_CERTS
+ ElseIf build_mode >= axtls.SSL_BUILD_SERVER_ONLY
+ If args(i) = "-cert"
+ If i >= args.Length-1 Or cert_index >= cert_size
+ print_server_options(build_mode, args(i))
+ End If
+
+ i += 1
+ cert(cert_index) = args(i)
+ cert_index += 1
+ ElseIf args(i) = "-key"
+ If i >= args.Length-1
+ print_server_options(build_mode, args(i))
+ End If
+
+ i += 1
+ private_key_file = args(i)
+ options = options Or axtls.SSL_NO_DEFAULT_KEY
+ ElseIf args(i) = "-pass"
+ If i >= args.Length-1
+ print_server_options(build_mode, args(i))
+ End If
+
+ i += 1
+ password = args(i)
+ ElseIf build_mode >= axtls.SSL_BUILD_ENABLE_VERIFICATION
+ If args(i) = "-verify" Then
+ options = options Or axtls.SSL_CLIENT_AUTHENTICATION
+ ElseIf args(i) = "-CAfile"
+ If i >= args.Length-1 Or _
+ ca_cert_index >= ca_cert_size Then
+ print_server_options(build_mode, args(i))
+ End If
+
+ i += 1
+ ca_cert(ca_cert_index) = args(i)
+ ca_cert_index += 1
+ ElseIf build_mode = axtls.SSL_BUILD_FULL_MODE
+ If args(i) = "-debug" Then
+ options = options Or axtls.SSL_DISPLAY_BYTES
+ ElseIf args(i) = "-state"
+ options = options Or axtls.SSL_DISPLAY_STATES
+ ElseIf args(i) = "-show-rsa"
+ options = options Or axtls.SSL_DISPLAY_RSA
+ Else
+ print_server_options(build_mode, args(i))
+ End If
+ Else
+ print_server_options(build_mode, args(i))
+ End If
+ Else
+ print_server_options(build_mode, args(i))
+ End If
+ End If
+
+ i += 1
+ End While
+
+ ' Create socket for incoming connections
+ Dim ep As IPEndPoint = New IPEndPoint(IPAddress.Any, port)
+ Dim server_sock As TcpListener = New TcpListener(ep)
+ server_sock.Start()
+
+ '*********************************************************************
+ ' This is where the interesting stuff happens. Up until now we've
+ ' just been setting up sockets etc. Now we do the SSL handshake.
+ '*********************************************************************/
+ Dim ssl_ctx As SSLServer = New SSLServer(options, _
+ axtls.SSL_DEFAULT_SVR_SESS)
+
+ If ssl_ctx Is Nothing Then
+ Console.Error.WriteLine("Error: Server context is invalid")
+ Environment.Exit(1)
+ End If
+
+ If private_key_file <> Nothing Then
+ Dim obj_type As Integer = axtls.SSL_OBJ_RSA_KEY
+
+ If private_key_file.EndsWith(".p8") Then
+ obj_type = axtls.SSL_OBJ_PKCS8
+ Else If (private_key_file.EndsWith(".p12"))
+ obj_type = axtls.SSL_OBJ_PKCS12
+ End If
+
+ If ssl_ctx.ObjLoad(obj_type, private_key_file, _
+ password) <> axtls.SSL_OK Then
+ Console.Error.WriteLine("Error: Private key '" & _
+ private_key_file & "' is undefined.")
+ Environment.Exit(1)
+ End If
+ End If
+
+ For i = 0 To cert_index-1
+ If ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CERT, _
+ cert(i), Nothing) <> axtls.SSL_OK Then
+ Console.WriteLine("Certificate '" & cert(i) & _
+ "' is undefined.")
+ Environment.Exit(1)
+ End If
+ Next
+
+ For i = 0 To ca_cert_index-1
+ If ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CACERT, _
+ ca_cert(i), Nothing) <> axtls.SSL_OK Then
+ Console.WriteLine("Certificate '" & ca_cert(i) & _
+ "' is undefined.")
+ Environment.Exit(1)
+ End If
+ Next
+
+ Dim buf As Byte() = Nothing
+ Dim res As Integer
+ Dim ssl As SSL
+
+ While 1
+ If Not quiet Then
+ Console.WriteLine("ACCEPT")
+ End If
+
+ Dim client_sock As Socket = server_sock.AcceptSocket()
+
+ ssl = ssl_ctx.Connect(client_sock)
+
+ ' do the actual SSL handshake
+ While 1
+ res = ssl_ctx.Read(ssl, buf)
+ If res <> axtls.SSL_OK Then
+ Exit While
+ End If
+
+ ' check when the connection has been established
+ If ssl.HandshakeStatus() = axtls.SSL_OK
+ Exit While
+ End If
+
+ ' could do something else here
+ End While
+
+ If res = axtls.SSL_OK Then ' connection established and ok
+ If Not quiet
+ display_session_id(ssl)
+ display_cipher(ssl)
+ End If
+
+ ' now read (and display) whatever the client sends us
+ While 1
+ ' keep reading until we get something interesting
+ While 1
+ res = ssl_ctx.Read(ssl, buf)
+ If res <> axtls.SSL_OK Then
+ Exit While
+ End If
+
+ ' could do something else here
+ End While
+
+ If res < axtls.SSL_OK
+ If Not quiet
+ Console.WriteLine("CONNECTION CLOSED")
+ End If
+
+ Exit While
+ End If
+
+ ' convert to String
+ Dim str(res) As Char
+ For i = 0 To res-1
+ str(i) = Chr(buf(i))
+ Next
+
+ Console.Write(str)
+ End While
+ ElseIf Not quiet
+ SSLUtil.DisplayError(res)
+ End If
+
+ ' client was disconnected or the handshake failed. */
+ ssl.Dispose()
+ client_sock.Close()
+ End While
+
+ ssl_ctx.Dispose()
+ End Sub
+
+ '
+ ' do_client()
+ '
+ Public Sub do_client(ByVal build_mode As Integer, _
+ ByVal args() As String)
+
+ If build_mode < axtls.SSL_BUILD_ENABLE_CLIENT Then
+ print_client_options(build_mode, args(1))
+ End If
+
+ Dim i As Integer = 1
+ Dim res As Integer
+ Dim port As Integer = 4433
+ Dim quiet As Boolean = False
+ Dim password As String = Nothing
+ Dim reconnect As Integer = 0
+ Dim private_key_file As String = Nothing
+ Dim hostname As String = "127.0.0.1"
+
+ ' organise the cert/ca_cert lists
+ Dim ssl As SSL = Nothing
+ Dim cert_size As Integer = SSLUtil.MaxCerts()
+ Dim ca_cert_size As Integer = SSLUtil.MaxCACerts()
+ Dim cert(cert_size) As String
+ Dim ca_cert(ca_cert_size) As String
+ Dim cert_index As Integer = 0
+ Dim ca_cert_index As Integer = 0
+
+ Dim options As Integer = _
+ axtls.SSL_SERVER_VERIFY_LATER Or axtls.SSL_DISPLAY_CERTS
+ Dim session_id As Byte() = Nothing
+
+ While i < args.Length
+ If args(i) = "-connect" Then
+ Dim host_port As String
+
+ If i >= args.Length-1
+ print_client_options(build_mode, args(i))
+ End If
+
+ i += 1
+ host_port = args(i)
+
+ Dim index_colon As Integer = host_port.IndexOf(":"C)
+ If index_colon < 0 Then
+ print_client_options(build_mode, args(i))
+ End If
+
+ hostname = New String(host_port.ToCharArray(), _
+ 0, index_colon)
+ port = Int32.Parse(New String(host_port.ToCharArray(), _
+ index_colon+1, host_port.Length-index_colon-1))
+ ElseIf args(i) = "-cert"
+ If i >= args.Length-1 Or cert_index >= cert_size Then
+ print_client_options(build_mode, args(i))
+ End If
+
+ i += 1
+ cert(cert_index) = args(i)
+ cert_index += 1
+ ElseIf args(i) = "-key"
+ If i >= args.Length-1
+ print_client_options(build_mode, args(i))
+ End If
+
+ i += 1
+ private_key_file = args(i)
+ options = options Or axtls.SSL_NO_DEFAULT_KEY
+ ElseIf args(i) = "-CAfile"
+ If i >= args.Length-1 Or ca_cert_index >= ca_cert_size
+ print_client_options(build_mode, args(i))
+ End If
+
+ i += 1
+ ca_cert(ca_cert_index) = args(i)
+ ca_cert_index += 1
+ ElseIf args(i) = "-verify"
+ options = options And Not axtls.SSL_SERVER_VERIFY_LATER
+ ElseIf args(i) = "-reconnect"
+ reconnect = 4
+ ElseIf args(i) = "-quiet"
+ quiet = True
+ options = options And Not axtls.SSL_DISPLAY_CERTS
+ ElseIf args(i) = "-pass"
+ If i >= args.Length-1
+ print_client_options(build_mode, args(i))
+ End If
+
+ i += 1
+ password = args(i)
+ ElseIf build_mode = axtls.SSL_BUILD_FULL_MODE
+ If args(i) = "-debug" Then
+ options = options Or axtls.SSL_DISPLAY_BYTES
+ ElseIf args(i) = "-state"
+ options = options Or axtls.SSL_DISPLAY_STATES
+ ElseIf args(i) = "-show-rsa"
+ options = options Or axtls.SSL_DISPLAY_RSA
+ Else
+ print_client_options(build_mode, args(i))
+ End If
+ Else ' don't know what this is
+ print_client_options(build_mode, args(i))
+ End If
+
+ i += 1
+ End While
+
+ 'Dim hostInfo As IPHostEntry = Dns.Resolve(hostname)
+ Dim hostInfo As IPHostEntry = Dns.GetHostEntry(hostname)
+ Dim addresses As IPAddress() = hostInfo.AddressList
+ Dim ep As IPEndPoint = New IPEndPoint(addresses(0), port)
+ Dim client_sock As Socket = New Socket(AddressFamily.InterNetwork, _
+ SocketType.Stream, ProtocolType.Tcp)
+ client_sock.Connect(ep)
+
+ If Not client_sock.Connected Then
+ Console.WriteLine("could not connect")
+ Environment.Exit(1)
+ End If
+
+ If Not quiet Then
+ Console.WriteLine("CONNECTED")
+ End If
+
+ '*********************************************************************
+ ' This is where the interesting stuff happens. Up until now we've
+ ' just been setting up sockets etc. Now we do the SSL handshake.
+ '*********************************************************************/
+ Dim ssl_ctx As SSLClient = New SSLClient(options, _
+ axtls.SSL_DEFAULT_CLNT_SESS)
+
+ If ssl_ctx Is Nothing Then
+ Console.Error.WriteLine("Error: Client context is invalid")
+ Environment.Exit(1)
+ End If
+
+ If private_key_file <> Nothing Then
+ Dim obj_type As Integer = axtls.SSL_OBJ_RSA_KEY
+
+ If private_key_file.EndsWith(".p8") Then
+ obj_type = axtls.SSL_OBJ_PKCS8
+ Else If (private_key_file.EndsWith(".p12"))
+ obj_type = axtls.SSL_OBJ_PKCS12
+ End If
+
+ If ssl_ctx.ObjLoad(obj_type, private_key_file, _
+ password) <> axtls.SSL_OK Then
+ Console.Error.WriteLine("Error: Private key '" & _
+ private_key_file & "' is undefined.")
+ Environment.Exit(1)
+ End If
+ End If
+
+ For i = 0 To cert_index-1
+ If ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CERT, _
+ cert(i), Nothing) <> axtls.SSL_OK Then
+ Console.WriteLine("Certificate '" & cert(i) & _
+ "' is undefined.")
+ Environment.Exit(1)
+ End If
+ Next
+
+ For i = 0 To ca_cert_index-1
+ If ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CACERT, _
+ ca_cert(i), Nothing) <> axtls.SSL_OK Then
+ Console.WriteLine("Certificate '" & ca_cert(i) & _
+ "' is undefined.")
+ Environment.Exit(1)
+ End If
+ Next
+
+ ' Try session resumption?
+ If reconnect > 0 Then
+ While reconnect > 0
+ reconnect -= 1
+ ssl = ssl_ctx.Connect(client_sock, session_id)
+
+ res = ssl.HandshakeStatus()
+ If res <> axtls.SSL_OK Then
+ If Not quiet Then
+ SSLUtil.DisplayError(res)
+ End If
+
+ ssl.Dispose()
+ Environment.Exit(1)
+ End If
+
+ display_session_id(ssl)
+ session_id = ssl.GetSessionId()
+
+ If reconnect > 0 Then
+ ssl.Dispose()
+ client_sock.Close()
+
+ ' and reconnect
+ client_sock = New Socket(AddressFamily.InterNetwork, _
+ SocketType.Stream, ProtocolType.Tcp)
+ client_sock.Connect(ep)
+ End If
+ End While
+ Else
+ ssl = ssl_ctx.Connect(client_sock, Nothing)
+ End If
+
+ ' check the return status
+ res = ssl.HandshakeStatus()
+ If res <> axtls.SSL_OK Then
+ If Not quiet Then
+ SSLUtil.DisplayError(res)
+ End If
+
+ Environment.Exit(1)
+ End If
+
+ If Not quiet Then
+ Dim common_name As String = _
+ ssl.GetCertificateDN(axtls.SSL_X509_CERT_COMMON_NAME)
+
+ If common_name <> Nothing
+ Console.WriteLine("Common Name:" & _
+ ControlChars.Tab & ControlChars.Tab & _
+ ControlChars.Tab & common_name)
+ End If
+
+ display_session_id(ssl)
+ display_cipher(ssl)
+ End If
+
+ While (1)
+ Dim user_input As String = Console.ReadLine()
+
+ If user_input = Nothing Then
+ Exit While
+ End If
+
+ Dim buf(user_input.Length+1) As Byte
+ buf(buf.Length-2) = Asc(ControlChars.Lf) ' add the carriage return
+ buf(buf.Length-1) = 0 ' null terminate
+
+ For i = 0 To user_input.Length-1
+ buf(i) = Asc(user_input.Chars(i))
+ Next
+
+ res = ssl_ctx.Write(ssl, buf, buf.Length)
+ If res < axtls.SSL_OK Then
+ If Not quiet Then
+ SSLUtil.DisplayError(res)
+ End If
+
+ Exit While
+ End If
+ End While
+
+ ssl_ctx.Dispose()
+ End Sub
+
+ '
+ ' Display what cipher we are using
+ '
+ Private Sub display_cipher(ByVal ssl As SSL)
+ Console.Write("CIPHER is ")
+
+ Select ssl.GetCipherId()
+ Case axtls.SSL_AES128_SHA
+ Console.WriteLine("AES128-SHA")
+
+ Case axtls.SSL_AES256_SHA
+ Console.WriteLine("AES256-SHA")
+
+ Case axtls.SSL_RC4_128_SHA
+ Console.WriteLine("RC4-SHA")
+
+ Case axtls.SSL_RC4_128_MD5
+ Console.WriteLine("RC4-MD5")
+
+ Case Else
+ Console.WriteLine("Unknown - " & ssl.GetCipherId())
+ End Select
+ End Sub
+
+ '
+ ' Display what session id we have.
+ '
+ Private Sub display_session_id(ByVal ssl As SSL)
+ Dim session_id As Byte() = ssl.GetSessionId()
+
+ If session_id.Length > 0 Then
+ Console.WriteLine("-----BEGIN SSL SESSION PARAMETERS-----")
+ Dim b As Byte
+ For Each b In session_id
+ Console.Write("{0:x02}", b)
+ Next
+
+ Console.WriteLine()
+ Console.WriteLine("-----END SSL SESSION PARAMETERS-----")
+ End If
+ End Sub
+
+ '
+ ' We've had some sort of command-line error. Print out the basic options.
+ '
+ Public Sub print_options(ByVal options As String)
+ Console.WriteLine("axssl: Error: '" & options & _
+ "' is an invalid command.")
+ Console.WriteLine("usage: axssl.vbnet [s_server|s_client|" & _
+ "version] [args ...]")
+ Environment.Exit(1)
+ End Sub
+
+ '
+ ' We've had some sort of command-line error. Print out the server options.
+ '
+ Private Sub print_server_options(ByVal build_mode As Integer, _
+ ByVal options As String)
+ Dim cert_size As Integer = SSLUtil.MaxCerts()
+ Dim ca_cert_size As Integer = SSLUtil.MaxCACerts()
+
+ Console.WriteLine("unknown option " & options)
+ Console.WriteLine("usage: s_server [args ...]")
+ Console.WriteLine(" -accept arg" & ControlChars.Tab & _
+ "- port to accept on (default is 4433)")
+ Console.WriteLine(" -quiet" & ControlChars.Tab & ControlChars.Tab & _
+ "- No server output")
+ If build_mode >= axtls.SSL_BUILD_SERVER_ONLY
+ Console.WriteLine(" -cert arg" & ControlChars.Tab & _
+ "- certificate file to add (in addition to default) to chain -")
+ Console.WriteLine(ControlChars.Tab & ControlChars.Tab & _
+ " Can repeat up to " & cert_size & " times")
+ Console.WriteLine(" -key arg" & ControlChars.Tab & _
+ "- Private key file to use")
+ Console.WriteLine(" -pass" & ControlChars.Tab & ControlChars.Tab & _
+ "- private key file pass phrase source")
+ End If
+
+ If build_mode >= axtls.SSL_BUILD_ENABLE_VERIFICATION
+ Console.WriteLine(" -verify" & ControlChars.Tab & _
+ "- turn on peer certificate verification")
+ Console.WriteLine(" -CAfile arg" & ControlChars.Tab & _
+ "- Certificate authority")
+ Console.WriteLine(ControlChars.Tab & ControlChars.Tab & _
+ " Can repeat up to " & ca_cert_size & " times")
+ End If
+
+ If build_mode = axtls.SSL_BUILD_FULL_MODE
+ Console.WriteLine(" -debug" & _
+ ControlChars.Tab & ControlChars.Tab & _
+ "- Print more output")
+ Console.WriteLine(" -state" & _
+ ControlChars.Tab & ControlChars.Tab & _
+ "- Show state messages")
+ Console.WriteLine(" -show-rsa" & _
+ ControlChars.Tab & "- Show RSA state")
+ End If
+
+ Environment.Exit(1)
+ End Sub
+
+ '
+ ' We've had some sort of command-line error. Print out the client options.
+ '
+ Private Sub print_client_options(ByVal build_mode As Integer, _
+ ByVal options As String)
+ Dim cert_size As Integer = SSLUtil.MaxCerts()
+ Dim ca_cert_size As Integer = SSLUtil.MaxCACerts()
+
+ Console.WriteLine("unknown option " & options)
+
+ If build_mode >= axtls.SSL_BUILD_ENABLE_CLIENT Then
+ Console.WriteLine("usage: s_client [args ...]")
+ Console.WriteLine(" -connect host:port - who to connect to " & _
+ "(default is localhost:4433)")
+ Console.WriteLine(" -verify" & ControlChars.Tab & _
+ "- turn on peer certificate verification")
+ Console.WriteLine(" -cert arg" & ControlChars.Tab & _
+ "- certificate file to use")
+ Console.WriteLine(ControlChars.Tab & ControlChars.Tab & _
+ " Can repeat up to " & cert_size & " times")
+ Console.WriteLine(" -key arg" & ControlChars.Tab & _
+ "- Private key file to use")
+ Console.WriteLine(" -CAfile arg" & ControlChars.Tab & _
+ "- Certificate authority")
+ Console.WriteLine(ControlChars.Tab & ControlChars.Tab & _
+ " Can repeat up to " & ca_cert_size & " times")
+ Console.WriteLine(" -quiet" & _
+ ControlChars.Tab & ControlChars.Tab & "- No client output")
+ Console.WriteLine(" -pass" & ControlChars.Tab & _
+ ControlChars.Tab & _
+ "- private key file pass phrase source")
+ Console.WriteLine(" -reconnect" & ControlChars.Tab & _
+ "- Drop and re-make the " & _
+ "connection with the same Session-ID")
+
+ If build_mode = axtls.SSL_BUILD_FULL_MODE Then
+ Console.WriteLine(" -debug" & _
+ ControlChars.Tab & ControlChars.Tab & _
+ "- Print more output")
+ Console.WriteLine(" -state" & _
+ ControlChars.Tab & ControlChars.Tab & _
+ "- Show state messages")
+ Console.WriteLine(" -show-rsa" & ControlChars.Tab & _
+ "- Show RSA state")
+ End If
+ Else
+ Console.WriteLine("Change configuration to allow this feature")
+ End If
+
+ Environment.Exit(1)
+ End Sub
+
+End Class
+
+Public Module MyMain
+ Function Main(ByVal args() As String) As Integer
+ Dim runner As axssl = New axssl()
+
+ If args.Length = 1 And args(0) = "version" Then
+ Console.WriteLine("axssl.vbnet " & SSLUtil.Version())
+ Environment.Exit(0)
+ End If
+
+ If args.Length < 1
+ runner.print_options("")
+ ElseIf args(0) <> "s_server" And args(0) <> "s_client"
+ runner.print_options(args(0))
+ End If
+
+ Dim build_mode As Integer = SSLUtil.BuildMode()
+
+ If args(0) = "s_server" Then
+ runner.do_server(build_mode, args)
+ Else
+ runner.do_client(build_mode, args)
+ End If
+ End Function
+End Module
--- /dev/null
+asn1.o: asn1.c os_port.h ../crypto/crypto.h ../config/config.h \
+ ../ssl/os_port.h ../crypto/bigint_impl.h ../crypto/bigint.h \
+ ../crypto/crypto.h crypto_misc.h ../crypto/bigint.h
+gen_cert.o: gen_cert.c ../config/config.h ssl.h tls1.h version.h \
+ ../crypto/crypto.h ../ssl/os_port.h ../crypto/bigint_impl.h \
+ ../crypto/bigint.h ../crypto/crypto.h os_port.h crypto_misc.h \
+ ../crypto/bigint.h
+loader.o: loader.c ssl.h tls1.h version.h ../crypto/crypto.h \
+ ../config/config.h ../ssl/os_port.h ../crypto/bigint_impl.h \
+ ../crypto/bigint.h ../crypto/crypto.h os_port.h crypto_misc.h \
+ ../crypto/bigint.h private_key.h
+openssl.o: openssl.c ../config/config.h
+os_port.o: os_port.c os_port.h
+p12.o: p12.c ssl.h tls1.h version.h ../crypto/crypto.h ../config/config.h \
+ ../ssl/os_port.h ../crypto/bigint_impl.h ../crypto/bigint.h \
+ ../crypto/crypto.h os_port.h crypto_misc.h ../crypto/bigint.h
+tls1.o: tls1.c ssl.h tls1.h version.h ../crypto/crypto.h \
+ ../config/config.h ../ssl/os_port.h ../crypto/bigint_impl.h \
+ ../crypto/bigint.h ../crypto/crypto.h os_port.h crypto_misc.h \
+ ../crypto/bigint.h
+tls1_clnt.o: tls1_clnt.c ssl.h tls1.h version.h ../crypto/crypto.h \
+ ../config/config.h ../ssl/os_port.h ../crypto/bigint_impl.h \
+ ../crypto/bigint.h ../crypto/crypto.h os_port.h crypto_misc.h \
+ ../crypto/bigint.h
+tls1_svr.o: tls1_svr.c ssl.h tls1.h version.h ../crypto/crypto.h \
+ ../config/config.h ../ssl/os_port.h ../crypto/bigint_impl.h \
+ ../crypto/bigint.h ../crypto/crypto.h os_port.h crypto_misc.h \
+ ../crypto/bigint.h
+x509.o: x509.c os_port.h crypto_misc.h ../crypto/crypto.h \
+ ../config/config.h ../ssl/os_port.h ../crypto/bigint_impl.h \
+ ../crypto/bigint.h ../crypto/crypto.h ../crypto/bigint.h
--- /dev/null
+#
+# For a description of the syntax of this configuration file,
+# see scripts/config/Kconfig-language.txt
+#
+
+menu "BigInt Options"
+ depends on !CONFIG_SSL_SKELETON_MODE
+
+choice
+ prompt "Reduction Algorithm"
+ default CONFIG_BIGINT_BARRETT
+
+config CONFIG_BIGINT_CLASSICAL
+ bool "Classical"
+ help
+ Classical uses standard division. It has no limitations and is
+ theoretically the slowest due to the divisions used. For this particular
+ implementation it is surprisingly quite fast.
+
+config CONFIG_BIGINT_MONTGOMERY
+ bool "Montgomery"
+ help
+ Montgomery uses simple addition and multiplication to achieve its
+ performance. In this implementation it is slower than classical,
+ and it has the limitation that 0 <= x, y < m, and so is not used
+ when CRT is active.
+
+ This option will not be normally selected.
+
+config CONFIG_BIGINT_BARRETT
+ bool "Barrett"
+ help
+ Barrett performs expensive precomputation before reduction and partial
+ multiplies for computational speed. It can't be used with some of the
+ calculations when CRT is used, and so defaults to classical when this
+ occurs.
+
+ It is about 40% faster than Classical/Montgomery with the expense of
+ about 2kB, and so this option is normally selected.
+
+endchoice
+
+config CONFIG_BIGINT_CRT
+ bool "Chinese Remainder Theorem (CRT)"
+ default y
+ help
+ Allow the Chinese Remainder Theorem (CRT) to be used.
+
+ Uses a number of extra coefficients from the private key to improve the
+ performance of a decryption. This feature is one of the most
+ significant performance improvements (it reduces a decryption time by
+ over 3 times).
+
+ This option should be selected.
+
+config CONFIG_BIGINT_KARATSUBA
+ bool "Karatsuba Multiplication"
+ default n
+ help
+ Allow Karasuba multiplication to be used.
+
+ Uses 3 multiplications (plus a number of additions/subtractions)
+ instead of 4. Multiplications are O(N^2) but addition/subtraction
+ is O(N) hence for large numbers is beneficial. For this project, the
+ effect was only useful for 4096 bit keys. As these aren't likely to
+ be used, the feature is disabled by default.
+
+ It costs about 2kB to enable it.
+
+config MUL_KARATSUBA_THRESH
+ int "Karatsuba Multiplication Theshold"
+ default 20
+ depends on CONFIG_BIGINT_KARATSUBA
+ help
+ The minimum number of components needed before Karasuba muliplication
+ is used.
+
+ This is very dependent on the speed/implementation of bi_add()/
+ bi_subtract(). There is a bit of trial and error here and will be
+ at a different point for different architectures.
+
+config SQU_KARATSUBA_THRESH
+ int "Karatsuba Square Threshold"
+ default 40
+ depends on CONFIG_BIGINT_KARATSUBA && CONFIG_BIGINT_SQUARE
+ help
+ The minimum number of components needed before Karatsuba squaring
+ is used.
+
+ This is very dependent on the speed/implementation of bi_add()/
+ bi_subtract(). There is a bit of trial and error here and will be
+ at a different point for different architectures.
+
+config CONFIG_BIGINT_SLIDING_WINDOW
+ bool "Sliding Window Exponentiation"
+ default y
+ help
+ Allow Sliding-Window Exponentiation to be used.
+
+ Potentially processes more than 1 bit at a time when doing
+ exponentiation. The sliding-window technique reduces the number of
+ precomputations compared to other precomputed techniques.
+
+ It results in a considerable performance improvement with it enabled
+ (it halves the decryption time) and so should be selected.
+
+config CONFIG_BIGINT_SQUARE
+ bool "Square Algorithm"
+ default y
+ help
+ Allow squaring to be used instead of a multiplication.
+
+ Squaring is theoretically 50% faster than a standard multiply
+ (but is actually about 25% faster).
+
+ It gives a 20% speed improvement and so should be selected.
+
+config CONFIG_BIGINT_CHECK_ON
+ bool "BigInt Integrity Checking"
+ default n if !CONFIG_DEBUG
+ default y if CONFIG_DEBUG
+ help
+ This is used when developing bigint algorithms. It performs a sanity
+ check on all operations at the expense of speed.
+
+ This option is only selected when developing and should normally be
+ turned off.
+
+endmenu
+
+
+
--- /dev/null
+#
+# For a description of the syntax of this configuration file,
+# see scripts/config/Kconfig-language.txt
+#
+
+menu "SSL Library"
+
+choice
+ prompt "Mode"
+ default CONFIG_SSL_FULL_MODE
+
+config CONFIG_SSL_SERVER_ONLY
+ bool "Server only - no verification"
+ help
+ Enable server functionality (no client functionality).
+ This mode still supports sessions and chaining (which can be turned
+ off in configuration).
+
+ The axssl sample runs with the minimum of features.
+
+ This is the most space efficient of the modes with the library
+ about 45kB in size. Use this mode if you are doing standard SSL server
+ work.
+
+config CONFIG_SSL_CERT_VERIFICATION
+ bool "Server only - with verification"
+ help
+ Enable server functionality with client authentication (no client
+ functionality).
+
+ The axssl sample runs with the "-verify" and "-CAfile" options.
+
+ This mode produces a library about 49kB in size. Use this mode if you
+ have an SSL server which requires client authentication (which is
+ uncommon in browser applications).
+
+config CONFIG_SSL_ENABLE_CLIENT
+ bool "Client/Server enabled"
+ help
+ Enable client/server functionality (including peer authentication).
+
+ The axssl sample runs with the "s_client" option enabled.
+
+ This mode produces a library about 51kB in size. Use this mode if you
+ require axTLS to use SSL client functionality (the SSL server code
+ is always enabled).
+
+config CONFIG_SSL_FULL_MODE
+ bool "Client/Server enabled with diagnostics"
+ help
+ Enable client/server functionality including diagnostics. Most of the
+ extra size in this mode is due to the storage of various strings that
+ are used.
+
+ The axssl sample has 3 more options, "-debug", "-state" and "-show-rsa"
+
+ This mode produces a library about 58kB in size. It is suggested that
+ this mode is used only during development, or systems that have more
+ generous memory limits.
+
+ It is the default to demonstrate the features of axTLS.
+
+config CONFIG_SSL_SKELETON_MODE
+ bool "Skeleton mode - the smallest server mode"
+ help
+ This is an experiment to build the smallest library at the expense of
+ features and speed.
+
+ * Server mode only.
+ * The AES cipher is disabled.
+ * No session resumption.
+ * No external keys/certificates are supported.
+ * The bigint library has most of the performance features disabled.
+ * Some other features/API calls may not work.
+
+ This mode produces a library about 37kB in size. The main
+ disadvantage of this mode is speed - it will be much slower than the
+ other build modes.
+
+endchoice
+
+choice
+ prompt "Protocol Preference"
+ depends on !CONFIG_SSL_SKELETON_MODE
+ default CONFIG_SSL_PROT_MEDIUM
+
+config CONFIG_SSL_PROT_LOW
+ bool "Low"
+ help
+ Chooses the cipher in the order of RC4-SHA, AES128-SHA, AES256-SHA.
+
+ This will use the fastest cipher(s) but at the expense of security.
+
+config CONFIG_SSL_PROT_MEDIUM
+ bool "Medium"
+ help
+ Chooses the cipher in the order of AES128-SHA, AES256-SHA, RC4-SHA.
+
+ This mode is a balance between speed and security and is the default.
+
+config CONFIG_SSL_PROT_HIGH
+ bool "High"
+ help
+ Chooses the cipher in the order of AES256-SHA, AES128-SHA, RC4-SHA.
+
+ This will use the strongest cipher(s) at the cost of speed.
+
+endchoice
+
+config CONFIG_SSL_USE_DEFAULT_KEY
+ bool "Enable default key"
+ depends on !CONFIG_SSL_SKELETON_MODE
+ default y
+ help
+ Some applications will not require the default private key/certificate
+ that is built in. This is one way to save on a couple of kB's if an
+ external private key/certificate is used.
+
+ The private key is in ssl/private_key.h and the certificate is in
+ ssl/cert.h.
+
+ The advantage of a built-in private key/certificate is that no file
+ system is required for access. Both the certificate and the private
+ key will be automatically loaded on a ssl_ctx_new().
+
+ However this private key/certificate can never be changed (without a
+ code update).
+
+ This mode is enabled by default. Disable this mode if the
+ built-in key/certificate is not used.
+
+config CONFIG_SSL_PRIVATE_KEY_LOCATION
+ string "Private key file location"
+ depends on !CONFIG_SSL_USE_DEFAULT_KEY && !CONFIG_SSL_SKELETON_MODE
+ help
+ The file location of the private key which will be automatically
+ loaded on a ssl_ctx_new().
+
+config CONFIG_SSL_PRIVATE_KEY_PASSWORD
+ string "Private key password"
+ depends on !CONFIG_SSL_USE_DEFAULT_KEY && CONFIG_SSL_HAS_PEM
+ help
+ The password required to decrypt a PEM-encoded password file.
+
+config CONFIG_SSL_X509_CERT_LOCATION
+ string "X.509 certificate file location"
+ depends on !CONFIG_SSL_GENERATE_X509_CERT && !CONFIG_SSL_USE_DEFAULT_KEY && !CONFIG_SSL_SKELETON_MODE
+ help
+ The file location of the X.509 certificate which will be automatically
+ loaded on a ssl_ctx_new().
+
+config CONFIG_SSL_GENERATE_X509_CERT
+ bool "Generate X.509 Certificate"
+ default n
+ help
+ An X.509 certificate can be automatically generated on a
+ ssl_ctx_new(). A private key still needs to be provided (the private
+ key in ss/private_key.h will be used unless
+ CONFIG_SSL_PRIVATE_KEY_LOCATION is set).
+
+ The certificate is generated on the fly, and so a minor start-up time
+ penalty is to be expected. This feature adds around 5kB to the
+ library.
+
+ This feature is disabled by default.
+
+config CONFIG_SSL_X509_COMMON_NAME
+ string "X.509 Common Name"
+ depends on CONFIG_SSL_GENERATE_X509_CERT
+ help
+ The common name for the X.509 certificate. This should be the fully
+ qualified domain name (FQDN), e.g. www.foo.com.
+
+ If this is blank, then this will be value from gethostname() and
+ getdomainname().
+
+config CONFIG_SSL_X509_ORGANIZATION_NAME
+ string "X.509 Organization Name"
+ depends on CONFIG_SSL_GENERATE_X509_CERT
+ help
+ The organization name for the generated X.509 certificate.
+
+ This field is optional.
+
+config CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME
+ string "X.509 Organization Unit Name"
+ depends on CONFIG_SSL_GENERATE_X509_CERT
+ help
+ The organization unit name for the generated X.509 certificate.
+
+ This field is optional.
+
+config CONFIG_SSL_ENABLE_V23_HANDSHAKE
+ bool "Enable v23 Handshake"
+ default y
+ help
+ Some browsers use the v23 handshake client hello message
+ (an SSL2 format message which all SSL servers can understand).
+ It may be used if SSL2 is enabled in the browser.
+
+ Since this feature takes a kB or so, this feature may be disabled - at
+ the risk of making it incompatible with some browsers (IE6 is ok,
+ Firefox 1.5 and below use it).
+
+ Disable if backwards compatibility is not an issue (i.e. the client is
+ always using TLS1.0)
+
+config CONFIG_SSL_HAS_PEM
+ bool "Enable PEM"
+ default n if !CONFIG_SSL_FULL_MODE
+ default y if CONFIG_SSL_FULL_MODE
+ depends on !CONFIG_SSL_SKELETON_MODE
+ help
+ Enable the use of PEM format for certificates and private keys.
+
+ PEM is not normally needed - PEM files can be converted into DER files
+ quite easily. However they have the convenience of allowing multiple
+ certificates/keys in the same file.
+
+ This feature will add a couple of kB to the library.
+
+ Disable if PEM is not used (which will be in most cases).
+
+config CONFIG_SSL_USE_PKCS12
+ bool "Use PKCS8/PKCS12"
+ default n if !CONFIG_SSL_FULL_MODE
+ default y if CONFIG_SSL_FULL_MODE
+ depends on !CONFIG_SSL_SERVER_ONLY && !CONFIG_SSL_SKELETON_MODE
+ help
+ PKCS#12 certificates combine private keys and certificates together in
+ one file.
+
+ PKCS#8 private keys are also suppported (as it is a subset of PKCS#12).
+
+ The decryption of these certificates uses RC4-128 (and these
+ certificates must be encrypted using this cipher). The actual
+ algorithm is "PBE-SHA1-RC4-128".
+
+ Disable if PKCS#12 is not used (which will be in most cases).
+
+config CONFIG_SSL_EXPIRY_TIME
+ int "Session expiry time (in hours)"
+ depends on !CONFIG_SSL_SKELETON_MODE
+ default 24
+ help
+ The time (in hours) before a session expires.
+
+ A longer time means that the expensive parts of a handshake don't
+ need to be run when a client reconnects later.
+
+ The default is 1 day.
+
+config CONFIG_X509_MAX_CA_CERTS
+ int "Maximum number of certificate authorites"
+ default 4
+ depends on !CONFIG_SSL_SERVER_ONLY && !CONFIG_SSL_SKELETON_MODE
+ help
+ Determines the number of CA's allowed.
+
+ Increase this figure if more trusted sites are allowed. Each
+ certificate adds about 300 bytes (when added).
+
+ The default is to allow four certification authorities.
+
+config CONFIG_SSL_MAX_CERTS
+ int "Maximum number of chained certificates"
+ default 2
+ help
+ Determines the number of certificates used in a certificate
+ chain. The chain length must be at least 1.
+
+ Increase this figure if more certificates are to be added to the
+ chain. Each certificate adds about 300 bytes (when added).
+
+ The default is to allow one certificate + 1 certificate in the chain
+ (which may be the certificate authority certificate).
+
+config CONFIG_SSL_CTX_MUTEXING
+ bool "Enable SSL_CTX mutexing"
+ default n
+ help
+ Normally mutexing is not required - each SSL_CTX object can deal with
+ many SSL objects (as long as each SSL_CTX object is using a single
+ thread).
+
+ If the SSL_CTX object is not thread safe e.g. the case where a
+ new thread is created for each SSL object, then mutexing is required.
+
+ Select y when a mutex on the SSL_CTX object is required.
+
+config CONFIG_USE_DEV_URANDOM
+ bool "Use /dev/urandom"
+ default y
+ depends on !CONFIG_PLATFORM_WIN32
+ help
+ Use /dev/urandom. Otherwise a custom RNG is used.
+
+ This will be the default on most Linux systems.
+
+config CONFIG_WIN32_USE_CRYPTO_LIB
+ bool "Use Win32 Crypto Library"
+ depends on CONFIG_PLATFORM_WIN32
+ help
+ Microsoft produce a Crypto API which requires the Platform SDK to be
+ installed. It's used for the RNG.
+
+ This will be the default on most Win32 systems.
+
+config CONFIG_OPENSSL_COMPATIBLE
+ bool "Enable openssl API compatibility"
+ default n
+ help
+ To ease the porting of openssl applications, a subset of the openssl
+ API is wrapped around the axTLS API.
+
+ Note: not all the API is implemented, so parts may still break. And
+ it's definitely not 100% compatible.
+
+config CONFIG_PERFORMANCE_TESTING
+ bool "Build the bigint performance test tool"
+ default n
+ help
+ Used for performance testing of bigint.
+
+ This is a testing tool and is normally disabled.
+
+config CONFIG_SSL_TEST
+ bool "Build the SSL testing tool"
+ default n
+ depends on CONFIG_SSL_FULL_MODE && !CONFIG_SSL_GENERATE_X509_CERT
+ help
+ Used for sanity checking the SSL handshaking.
+
+ This is a testing tool and is normally disabled.
+
+endmenu
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+AXTLS_HOME=..
+
+include $(AXTLS_HOME)/config/.config
+include $(AXTLS_HOME)/config/makefile.conf
+
+all: libs
+ifdef CONFIG_PERFORMANCE_TESTING
+ $(MAKE) -C test
+else
+ifdef CONFIG_SSL_TEST
+ $(MAKE) -C test
+endif
+endif
+
+ifndef CONFIG_PLATFORM_WIN32
+TARGET1=$(AXTLS_HOME)/$(STAGE)/libaxtls.a
+BASETARGET=libaxtls.so
+CRYPTO_PATH=$(AXTLS_HOME)/crypto/
+ifdef CONFIG_PLATFORM_CYGWIN
+TARGET2=$(AXTLS_HOME)/$(STAGE)/libaxtls.dll.a
+else
+TARGET2=$(AXTLS_HOME)/$(STAGE)/$(LIBMINOR)
+endif
+
+# shared library major/minor numbers
+LIBMAJOR=$(BASETARGET).1
+LIBMINOR=$(BASETARGET).1.2
+else
+TARGET1=$(AXTLS_HOME)/$(STAGE)/axtls.lib
+TARGET2=$(AXTLS_HOME)/$(STAGE)/axtls.dll
+STATIC_LIB=$(AXTLS_HOME)/$(STAGE)/axtls.static.lib
+CRYPTO_PATH=$(AXTLS_HOME)\\crypto\\
+endif
+
+libs: $(TARGET1) $(TARGET2)
+
+CRYPTO_OBJ=\
+ $(CRYPTO_PATH)aes.o \
+ $(CRYPTO_PATH)bigint.o \
+ $(CRYPTO_PATH)crypto_misc.o \
+ $(CRYPTO_PATH)hmac.o \
+ $(CRYPTO_PATH)md2.o \
+ $(CRYPTO_PATH)md5.o \
+ $(CRYPTO_PATH)rc4.o \
+ $(CRYPTO_PATH)rsa.o \
+ $(CRYPTO_PATH)sha1.o
+
+OBJ=\
+ asn1.o \
+ gen_cert.o \
+ loader.o \
+ openssl.o \
+ os_port.o \
+ p12.o \
+ tls1.o \
+ tls1_svr.o \
+ tls1_clnt.o \
+ x509.o
+
+include $(AXTLS_HOME)/config/makefile.post
+
+ifndef CONFIG_PLATFORM_WIN32 # Linux/Unix/Cygwin
+
+$(TARGET1) : $(OBJ)
+ $(AR) -r $@ $(CRYPTO_OBJ) $(OBJ)
+
+$(TARGET2) : $(OBJ)
+ifndef CONFIG_PLATFORM_CYGWIN
+ $(LD) $(LDFLAGS) $(LDSHARED) -Wl,-soname,$(LIBMAJOR) -o $(AXTLS_HOME)/$(STAGE)/$(LIBMINOR) $(CRYPTO_OBJ) $(OBJ)
+ cd $(AXTLS_HOME)/$(STAGE); ln -sf $(LIBMINOR) $(LIBMAJOR); ln -sf $(LIBMAJOR) $(BASETARGET); cd -
+else
+ $(LD) $(LDFLAGS) $(LDSHARED) -o $(AXTLS_HOME)/$(STAGE)/cygaxtls.dll \
+ -Wl,--out-implib=$(AXTLS_HOME)/$(STAGE)/libaxtls.dll.a \
+ -Wl,--export-all-symbols \
+ -Wl,--enable-auto-import $(CRYPTO_OBJ) $(OBJ)
+endif
+
+else # Win32
+CRYPTO_OBJ:=$(CRYPTO_OBJ:.o=.obj)
+
+$(TARGET1) : $(OBJ)
+ $(AR) /out:$@ $(CRYPTO_OBJ) $(OBJ)
+
+$(TARGET2) : $(OBJ)
+ cp $(TARGET1) $(STATIC_LIB)
+ $(LD) $(LDFLAGS) $(LDSHARED) /out:$@ $(CRYPTO_OBJ) $(OBJ)
+
+endif
+
+clean::
+ $(MAKE) -C test clean
+ -@rm -f $(AXTLS_HOME)/$(STAGE)/* *.a $(TARGET1) $(TARGET2)
+
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Some primitive asn methods for extraction ASN.1 data.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "os_port.h"
+#include "crypto.h"
+#include "crypto_misc.h"
+
+#define SIG_OID_PREFIX_SIZE 8
+#define SIG_IIS6_OID_SIZE 5
+
+/* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */
+static const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] =
+{
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01
+};
+
+static const uint8_t sig_iis6_oid[SIG_IIS6_OID_SIZE] =
+{
+ 0x2b, 0x0e, 0x03, 0x02, 0x1d
+};
+
+/* CN, O, OU */
+static const uint8_t g_dn_types[] = { 3, 10, 11 };
+
+int get_asn1_length(const uint8_t *buf, int *offset)
+{
+ int len, i;
+
+ if (!(buf[*offset] & 0x80)) /* short form */
+ {
+ len = buf[(*offset)++];
+ }
+ else /* long form */
+ {
+ int length_bytes = buf[(*offset)++]&0x7f;
+ len = 0;
+ for (i = 0; i < length_bytes; i++)
+ {
+ len <<= 8;
+ len += buf[(*offset)++];
+ }
+ }
+
+ return len;
+}
+
+/**
+ * Skip the ASN1.1 object type and its length. Get ready to read the object's
+ * data.
+ */
+int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type)
+{
+ if (buf[*offset] != obj_type)
+ return X509_NOT_OK;
+ (*offset)++;
+ return get_asn1_length(buf, offset);
+}
+
+/**
+ * Skip over an ASN.1 object type completely. Get ready to read the next
+ * object.
+ */
+int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type)
+{
+ int len;
+
+ if (buf[*offset] != obj_type)
+ return X509_NOT_OK;
+ (*offset)++;
+ len = get_asn1_length(buf, offset);
+ *offset += len;
+ return 0;
+}
+
+/**
+ * Read an integer value for ASN.1 data
+ * Note: This function allocates memory which must be freed by the user.
+ */
+int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object)
+{
+ int len;
+
+ if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0)
+ goto end_int_array;
+
+ if (len > 1 && buf[*offset] == 0x00) /* ignore the negative byte */
+ {
+ len--;
+ (*offset)++;
+ }
+
+ *object = (uint8_t *)malloc(len);
+ memcpy(*object, &buf[*offset], len);
+ *offset += len;
+
+end_int_array:
+ return len;
+}
+
+/**
+ * Get all the RSA private key specifics from an ASN.1 encoded file
+ */
+int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx)
+{
+ int offset = 7;
+ uint8_t *modulus = NULL, *priv_exp = NULL, *pub_exp = NULL;
+ int mod_len, priv_len, pub_len;
+#ifdef CONFIG_BIGINT_CRT
+ uint8_t *p = NULL, *q = NULL, *dP = NULL, *dQ = NULL, *qInv = NULL;
+ int p_len, q_len, dP_len, dQ_len, qInv_len;
+#endif
+
+ /* not in der format */
+ if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: This is not a valid ASN.1 file\n");
+#endif
+ return X509_INVALID_PRIV_KEY;
+ }
+
+ /* initialise the RNG */
+ RNG_initialize(buf, len);
+
+ mod_len = asn1_get_int(buf, &offset, &modulus);
+ pub_len = asn1_get_int(buf, &offset, &pub_exp);
+ priv_len = asn1_get_int(buf, &offset, &priv_exp);
+
+ if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0)
+ return X509_INVALID_PRIV_KEY;
+
+#ifdef CONFIG_BIGINT_CRT
+ p_len = asn1_get_int(buf, &offset, &p);
+ q_len = asn1_get_int(buf, &offset, &q);
+ dP_len = asn1_get_int(buf, &offset, &dP);
+ dQ_len = asn1_get_int(buf, &offset, &dQ);
+ qInv_len = asn1_get_int(buf, &offset, &qInv);
+
+ if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0)
+ return X509_INVALID_PRIV_KEY;
+
+ RSA_priv_key_new(rsa_ctx,
+ modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len,
+ p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len);
+
+ free(p);
+ free(q);
+ free(dP);
+ free(dQ);
+ free(qInv);
+#else
+ RSA_priv_key_new(rsa_ctx,
+ modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len);
+#endif
+
+ free(modulus);
+ free(priv_exp);
+ free(pub_exp);
+ return X509_OK;
+}
+
+/**
+ * Get the time of a certificate. Ignore hours/minutes/seconds.
+ */
+static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t)
+{
+ int ret = X509_NOT_OK, len, t_offset;
+ struct tm tm;
+
+ if (buf[(*offset)++] != ASN1_UTC_TIME)
+ goto end_utc_time;
+ len = get_asn1_length(buf, offset);
+ t_offset = *offset;
+
+ memset(&tm, 0, sizeof(struct tm));
+ tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0');
+
+ if (tm.tm_year <= 50) /* 1951-2050 thing */
+ {
+ tm.tm_year += 100;
+ }
+
+ tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1;
+ tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0');
+ *t = mktime(&tm);
+ *offset += len;
+ ret = X509_OK;
+
+end_utc_time:
+ return ret;
+}
+
+/**
+ * Get the version type of a certificate (which we don't actually care about)
+ */
+int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+ int ret = X509_NOT_OK;
+
+ (*offset) += 2; /* get past explicit tag */
+ if (asn1_skip_obj(cert, offset, ASN1_INTEGER))
+ goto end_version;
+
+ ret = X509_OK;
+end_version:
+ return ret;
+}
+
+/**
+ * Retrieve the notbefore and notafter certificate times.
+ */
+int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+ return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
+ asn1_get_utc_time(cert, offset, &x509_ctx->not_before) ||
+ asn1_get_utc_time(cert, offset, &x509_ctx->not_after));
+}
+
+/**
+ * Get the components of a distinguished name
+ */
+static int asn1_get_oid_x520(const uint8_t *buf, int *offset)
+{
+ int dn_type = 0;
+ int len;
+
+ if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
+ goto end_oid;
+
+ /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name
+ components we are interested in. */
+ if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04)
+ dn_type = buf[(*offset)++];
+ else
+ {
+ *offset += len; /* skip over it */
+ }
+
+end_oid:
+ return dn_type;
+}
+
+/**
+ * Obtain an ASN.1 printable string type.
+ */
+static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str)
+{
+ int len = X509_NOT_OK;
+
+ /* some certs have this awful crud in them for some reason */
+ if (buf[*offset] != ASN1_PRINTABLE_STR &&
+ buf[*offset] != ASN1_TELETEX_STR &&
+ buf[*offset] != ASN1_IA5_STR &&
+ buf[*offset] != ASN1_UNICODE_STR)
+ goto end_pnt_str;
+
+ (*offset)++;
+ len = get_asn1_length(buf, offset);
+
+ if (buf[*offset - 1] == ASN1_UNICODE_STR)
+ {
+ int i;
+ *str = (char *)malloc(len/2+1); /* allow for null */
+
+ for (i = 0; i < len; i += 2)
+ (*str)[i/2] = buf[*offset + i + 1];
+
+ (*str)[len/2] = 0; /* null terminate */
+ }
+ else
+ {
+ *str = (char *)malloc(len+1); /* allow for null */
+ memcpy(*str, &buf[*offset], len);
+ (*str)[len] = 0; /* null terminate */
+ }
+
+ *offset += len;
+
+end_pnt_str:
+ return len;
+}
+
+/**
+ * Get the subject name (or the issuer) of a certificate.
+ */
+int asn1_name(const uint8_t *cert, int *offset, char *dn[])
+{
+ int ret = X509_NOT_OK;
+ int dn_type;
+ char *tmp = NULL;
+
+ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
+ goto end_name;
+
+ while (asn1_next_obj(cert, offset, ASN1_SET) >= 0)
+ {
+ int i, found = 0;
+
+ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
+ (dn_type = asn1_get_oid_x520(cert, offset)) < 0)
+ goto end_name;
+
+ if (asn1_get_printable_str(cert, offset, &tmp) < 0)
+ {
+ free(tmp);
+ goto end_name;
+ }
+
+ /* find the distinguished named type */
+ for (i = 0; i < X509_NUM_DN_TYPES; i++)
+ {
+ if (dn_type == g_dn_types[i])
+ {
+ if (dn[i] == NULL)
+ {
+ dn[i] = tmp;
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ if (found == 0) /* not found so get rid of it */
+ {
+ free(tmp);
+ }
+ }
+
+ ret = X509_OK;
+end_name:
+ return ret;
+}
+
+/**
+ * Read the modulus and public exponent of a certificate.
+ */
+int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+ int ret = X509_NOT_OK, mod_len, pub_len;
+ uint8_t *modulus = NULL, *pub_exp = NULL;
+
+ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(cert, offset, ASN1_SEQUENCE) ||
+ asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0)
+ goto end_pub_key;
+
+ (*offset)++; /* ignore the padding bit field */
+
+ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
+ goto end_pub_key;
+
+ mod_len = asn1_get_int(cert, offset, &modulus);
+ pub_len = asn1_get_int(cert, offset, &pub_exp);
+
+ RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len);
+
+ free(modulus);
+ free(pub_exp);
+ ret = X509_OK;
+
+end_pub_key:
+ return ret;
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Read the signature of the certificate.
+ */
+int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+ int ret = X509_NOT_OK;
+
+ if (cert[(*offset)++] != ASN1_BIT_STRING)
+ goto end_sig;
+
+ x509_ctx->sig_len = get_asn1_length(cert, offset)-1;
+ (*offset)++; /* ignore bit string padding bits */
+ x509_ctx->signature = (uint8_t *)malloc(x509_ctx->sig_len);
+ memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len);
+ *offset += x509_ctx->sig_len;
+ ret = X509_OK;
+
+end_sig:
+ return ret;
+}
+
+/*
+ * Compare 2 distinguished name components for equality
+ * @return 0 if a match
+ */
+static int asn1_compare_dn_comp(const char *dn1, const char *dn2)
+{
+ int ret = 1;
+
+ if ((dn1 && dn2 == NULL) || (dn1 == NULL && dn2)) goto err_no_match;
+
+ ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 0;
+
+err_no_match:
+ return ret;
+}
+
+/**
+ * Clean up all of the CA certificates.
+ */
+void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx)
+{
+ int i = 0;
+
+ if (ca_cert_ctx == NULL)
+ return;
+
+ while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
+ {
+ x509_free(ca_cert_ctx->cert[i]);
+ ca_cert_ctx->cert[i++] = NULL;
+ }
+
+ free(ca_cert_ctx);
+}
+
+/*
+ * Compare 2 distinguished names for equality
+ * @return 0 if a match
+ */
+int asn1_compare_dn(char * const dn1[], char * const dn2[])
+{
+ int i;
+
+ for (i = 0; i < X509_NUM_DN_TYPES; i++)
+ {
+ if (asn1_compare_dn_comp(dn1[i], dn2[i]))
+ return 1;
+ }
+
+ return 0; /* all good */
+}
+
+#endif
+
+/**
+ * Read the signature type of the certificate. We only support RSA-MD5 and
+ * RSA-SHA1 signature types.
+ */
+int asn1_signature_type(const uint8_t *cert,
+ int *offset, X509_CTX *x509_ctx)
+{
+ int ret = X509_NOT_OK, len;
+
+ if (cert[(*offset)++] != ASN1_OID)
+ goto end_check_sig;
+
+ len = get_asn1_length(cert, offset);
+
+ if (len == 5 && memcmp(sig_iis6_oid, &cert[*offset],
+ SIG_IIS6_OID_SIZE) == 0)
+ {
+ x509_ctx->sig_type = SIG_TYPE_SHA1;
+ }
+ else
+ {
+ if (memcmp(sig_oid_prefix, &cert[*offset], SIG_OID_PREFIX_SIZE))
+ goto end_check_sig; /* unrecognised cert type */
+
+ x509_ctx->sig_type = cert[*offset + SIG_OID_PREFIX_SIZE];
+ }
+
+ *offset += len;
+ asn1_skip_obj(cert, offset, ASN1_NULL); /* if it's there */
+ ret = X509_OK;
+
+end_check_sig:
+ return ret;
+}
+
--- /dev/null
+unsigned char default_certificate[] = {
+ 0x30, 0x82, 0x01, 0xd7, 0x30, 0x82, 0x01, 0x40, 0x02, 0x09, 0x00, 0xf1,
+ 0xc3, 0x87, 0xc0, 0xd4, 0xf4, 0x57, 0xc3, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x34,
+ 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x29, 0x61,
+ 0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+ 0x20, 0x44, 0x6f, 0x64, 0x67, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+ 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+ 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x36,
+ 0x30, 0x37, 0x31, 0x31, 0x34, 0x34, 0x33, 0x32, 0x5a, 0x17, 0x0d, 0x33,
+ 0x33, 0x31, 0x30, 0x32, 0x33, 0x31, 0x31, 0x34, 0x34, 0x33, 0x32, 0x5a,
+ 0x30, 0x2c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+ 0x0d, 0x61, 0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65,
+ 0x63, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81,
+ 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02,
+ 0x81, 0x81, 0x00, 0xd8, 0xe0, 0xbf, 0x15, 0xde, 0xea, 0xaf, 0xe8, 0xd5,
+ 0xfd, 0x0b, 0xa8, 0xa8, 0xb3, 0xd7, 0x46, 0x5d, 0xa7, 0x26, 0x6c, 0x0c,
+ 0xb5, 0xd9, 0xbc, 0xc6, 0xf8, 0xc0, 0x78, 0xd0, 0xf6, 0x56, 0x65, 0xf8,
+ 0x29, 0x48, 0x0e, 0x7b, 0x0b, 0xa6, 0x25, 0x7e, 0xe8, 0x7b, 0x79, 0x6f,
+ 0x38, 0xe5, 0xb5, 0xb7, 0xf4, 0xe0, 0x9c, 0x91, 0x60, 0xf4, 0x06, 0xf3,
+ 0x40, 0x1e, 0xf9, 0x91, 0x19, 0xa9, 0x2f, 0x47, 0x43, 0xb5, 0x9b, 0x1e,
+ 0xdc, 0xf6, 0xaa, 0x1c, 0x49, 0x79, 0x21, 0x28, 0xcb, 0xaa, 0x49, 0x73,
+ 0xd9, 0x09, 0x05, 0x4c, 0x02, 0xf2, 0x4c, 0x4d, 0x6c, 0x1c, 0x80, 0xa7,
+ 0x14, 0x91, 0x44, 0xfc, 0x12, 0xb3, 0xe1, 0xe7, 0xe3, 0x4f, 0x44, 0xba,
+ 0x8c, 0xc3, 0x74, 0x39, 0xe8, 0x4c, 0xd0, 0xd4, 0x4c, 0x24, 0x61, 0xb4,
+ 0x40, 0x95, 0x8c, 0xc0, 0x0a, 0xb7, 0x02, 0x39, 0x31, 0x85, 0x93, 0x02,
+ 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x0b,
+ 0x47, 0x24, 0x52, 0x7d, 0xb6, 0x63, 0x78, 0xbc, 0x80, 0xdd, 0x87, 0x6c,
+ 0x90, 0x4c, 0x33, 0xc3, 0x5c, 0xa7, 0x97, 0x09, 0x1c, 0x09, 0x4f, 0x9b,
+ 0x6e, 0xb3, 0x5a, 0x3e, 0x46, 0x92, 0x1a, 0xc7, 0x87, 0x15, 0x59, 0xe1,
+ 0x88, 0x5c, 0xce, 0x6a, 0xe2, 0x96, 0xaa, 0x32, 0xec, 0xc2, 0xed, 0x78,
+ 0x8b, 0xe0, 0x90, 0x66, 0x93, 0x14, 0xc3, 0x98, 0xab, 0x33, 0x35, 0xd3,
+ 0x7d, 0x5d, 0x51, 0x0a, 0x9c, 0xb9, 0x10, 0x58, 0x47, 0x7a, 0x98, 0x95,
+ 0x64, 0xff, 0x4c, 0x5d, 0x82, 0x19, 0xf9, 0xea, 0x0f, 0x5e, 0x9a, 0xcb,
+ 0x32, 0x27, 0x64, 0xca, 0x6f, 0x58, 0x8a, 0xd0, 0xc0, 0x36, 0xf4, 0xb9,
+ 0x63, 0x34, 0xa5, 0xda, 0x36, 0x50, 0x36, 0x49, 0xd2, 0xb7, 0x3a, 0x21,
+ 0x33, 0x5b, 0x3e, 0xd6, 0x5f, 0x0c, 0x99, 0x83, 0xb7, 0xb2, 0xf7, 0x8b,
+ 0x44, 0xc4, 0x5e, 0x73, 0x41, 0xa9, 0x02
+};
+unsigned int default_certificate_len = 475;
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file crypto_misc.h
+ */
+
+#ifndef HEADER_CRYPTO_MISC_H
+#define HEADER_CRYPTO_MISC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "crypto.h"
+#include "bigint.h"
+
+/**************************************************************************
+ * X509 declarations
+ **************************************************************************/
+#define X509_OK 0
+#define X509_NOT_OK -1
+#define X509_VFY_ERROR_NO_TRUSTED_CERT -2
+#define X509_VFY_ERROR_BAD_SIGNATURE -3
+#define X509_VFY_ERROR_NOT_YET_VALID -4
+#define X509_VFY_ERROR_EXPIRED -5
+#define X509_VFY_ERROR_SELF_SIGNED -6
+#define X509_VFY_ERROR_INVALID_CHAIN -7
+#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8
+#define X509_INVALID_PRIV_KEY -9
+
+/*
+ * The Distinguished Name
+ */
+#define X509_NUM_DN_TYPES 3
+#define X509_COMMON_NAME 0
+#define X509_ORGANIZATION 1
+#define X509_ORGANIZATIONAL_UNIT 2
+
+struct _x509_ctx
+{
+ char *ca_cert_dn[X509_NUM_DN_TYPES];
+ char *cert_dn[X509_NUM_DN_TYPES];
+ time_t not_before;
+ time_t not_after;
+ uint8_t *signature;
+ uint16_t sig_len;
+ uint8_t sig_type;
+ RSA_CTX *rsa_ctx;
+ bigint *digest;
+ struct _x509_ctx *next;
+};
+
+typedef struct _x509_ctx X509_CTX;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+typedef struct
+{
+ X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS];
+} CA_CERT_CTX;
+#endif
+
+int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx);
+void x509_free(X509_CTX *x509_ctx);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
+#endif
+#ifdef CONFIG_SSL_FULL_MODE
+void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx);
+const char * x509_display_error(int error);
+#endif
+
+/**************************************************************************
+ * ASN1 declarations
+ **************************************************************************/
+#define ASN1_INTEGER 0x02
+#define ASN1_BIT_STRING 0x03
+#define ASN1_OCTET_STRING 0x04
+#define ASN1_NULL 0x05
+#define ASN1_OID 0x06
+#define ASN1_PRINTABLE_STR 0x13
+#define ASN1_TELETEX_STR 0x14
+#define ASN1_IA5_STR 0x16
+#define ASN1_UTC_TIME 0x17
+#define ASN1_UNICODE_STR 0x1e
+#define ASN1_SEQUENCE 0x30
+#define ASN1_SET 0x31
+#define ASN1_IMPLICIT_TAG 0x80
+#define ASN1_EXPLICIT_TAG 0xa0
+
+#define SIG_TYPE_MD2 0x02
+#define SIG_TYPE_MD5 0x04
+#define SIG_TYPE_SHA1 0x05
+
+int get_asn1_length(const uint8_t *buf, int *offset);
+int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx);
+int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type);
+int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type);
+int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object);
+int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
+int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
+int asn1_name(const uint8_t *cert, int *offset, char *dn[]);
+int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
+int asn1_compare_dn(char * const dn1[], char * const dn2[]);
+#endif
+int asn1_signature_type(const uint8_t *cert,
+ int *offset, X509_CTX *x509_ctx);
+
+/**************************************************************************
+ * MISC declarations
+ **************************************************************************/
+#define SALT_SIZE 8
+
+extern const char * const unsupported_str;
+
+typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int);
+typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest);
+
+int get_file(const char *filename, uint8_t **buf);
+
+#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG)
+EXP_FUNC void STDCALL print_blob(const char *format, const uint8_t *data, int size, ...);
+#else
+ #define print_blob(...)
+#endif
+
+EXP_FUNC int STDCALL base64_decode(const char *in, int len,
+ uint8_t *out, int *outlen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#ifdef CONFIG_SSL_GENERATE_X509_CERT
+#include <string.h>
+#include <stdlib.h>
+#include "ssl.h"
+
+/**
+ * Generate a basic X.509 certificate
+ */
+
+static uint8_t set_gen_length(int len, uint8_t *buf, int *offset)
+{
+ if (len < 0x80) /* short form */
+ {
+ buf[(*offset)++] = len;
+ return 1;
+ }
+ else /* long form */
+ {
+ int i, length_bytes = 0;
+
+ if (len & 0x00FF0000)
+ length_bytes = 3;
+ else if (len & 0x0000FF00)
+ length_bytes = 2;
+ else if (len & 0x000000FF)
+ length_bytes = 1;
+
+ buf[(*offset)++] = 0x80 + length_bytes;
+
+ for (i = length_bytes-1; i >= 0; i--)
+ {
+ buf[*offset+i] = len & 0xFF;
+ len >>= 8;
+ }
+
+ *offset += length_bytes;
+ return length_bytes+1;
+ }
+}
+
+static int pre_adjust_with_size(uint8_t type,
+ int *seq_offset, uint8_t *buf, int *offset)
+{
+ buf[(*offset)++] = type;
+ *seq_offset = *offset;
+ *offset += 4; /* fill in later */
+ return *offset;
+}
+
+static void adjust_with_size(int seq_size, int seq_start,
+ uint8_t *buf, int *offset)
+{
+ uint8_t seq_byte_size;
+ int orig_seq_size = seq_size;
+ int orig_seq_start = seq_start;
+
+ seq_size = *offset-seq_size;
+ seq_byte_size = set_gen_length(seq_size, buf, &seq_start);
+
+ if (seq_byte_size != 4)
+ {
+ memmove(&buf[orig_seq_start+seq_byte_size],
+ &buf[orig_seq_size], seq_size);
+ *offset -= 4-seq_byte_size;
+ }
+}
+
+static void gen_serial_number(uint8_t *buf, int *offset)
+{
+ static const uint8_t ser_oid[] = { ASN1_INTEGER, 1, 0x7F };
+ memcpy(&buf[*offset], ser_oid , sizeof(ser_oid));
+ *offset += sizeof(ser_oid);
+}
+
+static void gen_signature_alg(uint8_t *buf, int *offset)
+{
+ /* OBJECT IDENTIFIER sha1withRSAEncryption (1 2 840 113549 1 1 5) */
+ static const uint8_t sig_oid[] =
+ {
+ ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+ ASN1_NULL, 0x00
+ };
+
+ memcpy(&buf[*offset], sig_oid, sizeof(sig_oid));
+ *offset += sizeof(sig_oid);
+}
+
+static int gen_dn(const char *name, uint8_t dn_type,
+ uint8_t *buf, int *offset)
+{
+ int ret = X509_OK;
+ int name_size = strlen(name);
+
+ if (name_size > 0x70) /* just too big */
+ {
+ ret = X509_NOT_OK;
+ goto error;
+ }
+
+ buf[(*offset)++] = ASN1_SET;
+ set_gen_length(9+name_size, buf, offset);
+ buf[(*offset)++] = ASN1_SEQUENCE;
+ set_gen_length(7+name_size, buf, offset);
+ buf[(*offset)++] = ASN1_OID;
+ buf[(*offset)++] = 3;
+ buf[(*offset)++] = 0x55;
+ buf[(*offset)++] = 0x04;
+ buf[(*offset)++] = dn_type;
+ buf[(*offset)++] = ASN1_PRINTABLE_STR;
+ buf[(*offset)++] = name_size;
+ strcpy(&buf[*offset], name);
+ *offset += name_size;
+
+error:
+ return ret;
+}
+
+static int gen_issuer(const char * dn[], uint8_t *buf, int *offset)
+{
+ int ret = X509_OK;
+ int seq_offset;
+ int seq_size = pre_adjust_with_size(
+ ASN1_SEQUENCE, &seq_offset, buf, offset);
+ char fqdn[128];
+
+ /* we need the common name, so if not configured, work out the fully
+ * qualified domain name */
+ if (dn[X509_COMMON_NAME] == NULL || strlen(dn[X509_COMMON_NAME]) == 0)
+ {
+ int fqdn_len;
+ gethostname(fqdn, sizeof(fqdn));
+ fqdn_len = strlen(fqdn);
+ fqdn[fqdn_len++] = '.';
+ getdomainname(&fqdn[fqdn_len], sizeof(fqdn)-fqdn_len);
+ fqdn_len = strlen(fqdn);
+
+ if (fqdn[fqdn_len-1] == '.') /* ensure '.' is not last char */
+ fqdn[fqdn_len-1] = 0;
+
+ dn[X509_COMMON_NAME] = fqdn;
+ }
+
+ if ((ret = gen_dn(dn[X509_COMMON_NAME], 3, buf, offset)))
+ goto error;
+
+ if (dn[X509_ORGANIZATION] != NULL && strlen(dn[X509_ORGANIZATION]) > 0)
+ {
+ if ((ret = gen_dn(dn[X509_ORGANIZATION], 10, buf, offset)))
+ goto error;
+ }
+
+ if (dn[X509_ORGANIZATIONAL_UNIT] != NULL &&
+ strlen(dn[X509_ORGANIZATIONAL_UNIT]) > 0)
+ {
+ if ((ret = gen_dn(dn[X509_ORGANIZATIONAL_UNIT], 11, buf, offset)))
+ goto error;
+ }
+
+ adjust_with_size(seq_size, seq_offset, buf, offset);
+
+error:
+ return ret;
+}
+
+static void gen_utc_time(uint8_t *buf, int *offset)
+{
+ static const uint8_t time_seq[] =
+ {
+ ASN1_SEQUENCE, 30,
+ ASN1_UTC_TIME, 13,
+ '0', '7', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z',
+ ASN1_UTC_TIME, 13, /* make it good for 30 or so years */
+ '3', '8', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z'
+ };
+
+ /* fixed time */
+ memcpy(&buf[*offset], time_seq, sizeof(time_seq));
+ *offset += sizeof(time_seq);
+}
+
+static void gen_pub_key2(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
+{
+ static const uint8_t pub_key_seq[] =
+ {
+ ASN1_INTEGER, 0x03, 0x01, 0x00, 0x01 /* INTEGER 65537 */
+ };
+
+ int seq_offset;
+ int pub_key_size = rsa_ctx->num_octets;
+ uint8_t *block = (uint8_t *)alloca(pub_key_size);
+ int seq_size = pre_adjust_with_size(
+ ASN1_SEQUENCE, &seq_offset, buf, offset);
+ buf[(*offset)++] = ASN1_INTEGER;
+ bi_export(rsa_ctx->bi_ctx, rsa_ctx->m, block, pub_key_size);
+
+ if (*block & 0x80) /* make integer positive */
+ {
+ set_gen_length(pub_key_size+1, buf, offset);
+ buf[(*offset)++] = 0;
+ }
+ else
+ set_gen_length(pub_key_size, buf, offset);
+
+ memcpy(&buf[*offset], block, pub_key_size);
+ *offset += pub_key_size;
+ memcpy(&buf[*offset], pub_key_seq, sizeof(pub_key_seq));
+ *offset += sizeof(pub_key_seq);
+ adjust_with_size(seq_size, seq_offset, buf, offset);
+}
+
+static void gen_pub_key1(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
+{
+ int seq_offset;
+ int seq_size = pre_adjust_with_size(
+ ASN1_BIT_STRING, &seq_offset, buf, offset);
+ buf[(*offset)++] = 0; /* bit string is multiple of 8 */
+ gen_pub_key2(rsa_ctx, buf, offset);
+ adjust_with_size(seq_size, seq_offset, buf, offset);
+}
+
+static void gen_pub_key(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)
+{
+ /* OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) */
+ static const uint8_t rsa_enc_oid[] =
+ {
+ ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+ ASN1_NULL, 0x00
+ };
+
+ int seq_offset;
+ int seq_size = pre_adjust_with_size(
+ ASN1_SEQUENCE, &seq_offset, buf, offset);
+
+ memcpy(&buf[*offset], rsa_enc_oid, sizeof(rsa_enc_oid));
+ *offset += sizeof(rsa_enc_oid);
+ gen_pub_key1(rsa_ctx, buf, offset);
+ adjust_with_size(seq_size, seq_offset, buf, offset);
+}
+
+static void gen_signature(const RSA_CTX *rsa_ctx, const uint8_t *sha_dgst,
+ uint8_t *buf, int *offset)
+{
+ static const uint8_t asn1_sig[] =
+ {
+ ASN1_SEQUENCE, 0x21, ASN1_SEQUENCE, 0x09, ASN1_OID, 0x05,
+ 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* sha1 (1 3 14 3 2 26) */
+ ASN1_NULL, 0x00, ASN1_OCTET_STRING, 0x14
+ };
+
+ uint8_t *enc_block = (uint8_t *)alloca(rsa_ctx->num_octets);
+ uint8_t *block = (uint8_t *)alloca(sizeof(asn1_sig) + SHA1_SIZE);
+ int sig_size;
+
+ /* add the digest as an embedded asn.1 sequence */
+ memcpy(block, asn1_sig, sizeof(asn1_sig));
+ memcpy(&block[sizeof(asn1_sig)], sha_dgst, SHA1_SIZE);
+
+ sig_size = RSA_encrypt(rsa_ctx, block,
+ sizeof(asn1_sig) + SHA1_SIZE, enc_block, 1);
+
+ buf[(*offset)++] = ASN1_BIT_STRING;
+ set_gen_length(sig_size+1, buf, offset);
+ buf[(*offset)++] = 0; /* bit string is multiple of 8 */
+ memcpy(&buf[*offset], enc_block, sig_size);
+ *offset += sig_size;
+}
+
+static int gen_tbs_cert(const char * dn[],
+ const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset,
+ uint8_t *sha_dgst)
+{
+ int ret = X509_OK;
+ SHA1_CTX sha_ctx;
+ int seq_offset;
+ int begin_tbs = *offset;
+ int seq_size = pre_adjust_with_size(
+ ASN1_SEQUENCE, &seq_offset, buf, offset);
+
+ gen_serial_number(buf, offset);
+ gen_signature_alg(buf, offset);
+
+ /* CA certicate issuer */
+ if ((ret = gen_issuer(dn, buf, offset)))
+ goto error;
+
+ gen_utc_time(buf, offset);
+
+ /* certificate issuer */
+ if ((ret = gen_issuer(dn, buf, offset)))
+ goto error;
+
+ gen_pub_key(rsa_ctx, buf, offset);
+ adjust_with_size(seq_size, seq_offset, buf, offset);
+
+ SHA1_Init(&sha_ctx);
+ SHA1_Update(&sha_ctx, &buf[begin_tbs], *offset-begin_tbs);
+ SHA1_Final(sha_dgst, &sha_ctx);
+
+error:
+ return ret;
+}
+
+/**
+ * Create a new certificate.
+ */
+EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data)
+{
+ int ret = X509_OK, offset = 0, seq_offset;
+ /* allocate enough space to load a new certificate */
+ uint8_t *buf = (uint8_t *)alloca(ssl_ctx->rsa_ctx->num_octets*2 + 512);
+ uint8_t sha_dgst[SHA1_SIZE];
+ int seq_size = pre_adjust_with_size(ASN1_SEQUENCE,
+ &seq_offset, buf, &offset);
+
+ if ((ret = gen_tbs_cert(dn, ssl_ctx->rsa_ctx, buf, &offset, sha_dgst)) < 0)
+ goto error;
+
+ gen_signature_alg(buf, &offset);
+ gen_signature(ssl_ctx->rsa_ctx, sha_dgst, buf, &offset);
+ adjust_with_size(seq_size, seq_offset, buf, &offset);
+ *cert_data = (uint8_t *)malloc(offset); /* create the exact memory for it */
+ memcpy(*cert_data, buf, offset);
+
+error:
+ return ret < 0 ? ret : offset;
+}
+
+#endif
+
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Load certificates/keys into memory. These can be in many different formats.
+ * PEM support and other formats can be processed here.
+ *
+ * The PEM private keys may be optionally encrypted with AES128 or AES256.
+ * The encrypted PEM keys were generated with something like:
+ *
+ * openssl genrsa -aes128 -passout pass:abcd -out axTLS.key_aes128.pem 512
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "ssl.h"
+
+static int do_obj(SSL_CTX *ssl_ctx, int obj_type,
+ SSLObjLoader *ssl_obj, const char *password);
+#ifdef CONFIG_SSL_HAS_PEM
+static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type,
+ SSLObjLoader *ssl_obj, const char *password);
+#endif
+
+/*
+ * Load a file into memory that is in binary DER (or ascii PEM) format.
+ */
+EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type,
+ const char *filename, const char *password)
+{
+#ifndef CONFIG_SSL_SKELETON_MODE
+ static const char * const begin = "-----BEGIN";
+ int ret = SSL_OK;
+ SSLObjLoader *ssl_obj = NULL;
+
+ if (filename == NULL)
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto error;
+ }
+
+ ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
+ ssl_obj->len = get_file(filename, &ssl_obj->buf);
+ if (ssl_obj->len <= 0)
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto error;
+ }
+
+ /* is the file a PEM file? */
+ if (strncmp((char *)ssl_obj->buf, begin, strlen(begin)) == 0)
+ {
+#ifdef CONFIG_SSL_HAS_PEM
+ ret = ssl_obj_PEM_load(ssl_ctx, obj_type, ssl_obj, password);
+#else
+ printf(unsupported_str);
+ ret = SSL_ERROR_NOT_SUPPORTED;
+#endif
+ }
+ else
+ ret = do_obj(ssl_ctx, obj_type, ssl_obj, password);
+
+error:
+ ssl_obj_free(ssl_obj);
+ return ret;
+#else
+ printf(unsupported_str);
+ return SSL_ERROR_NOT_SUPPORTED;
+#endif /* CONFIG_SSL_SKELETON_MODE */
+}
+
+/*
+ * Transfer binary data into the object loader.
+ */
+EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int mem_type,
+ const uint8_t *data, int len, const char *password)
+{
+ int ret;
+ SSLObjLoader *ssl_obj;
+
+ ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
+ ssl_obj->buf = (uint8_t *)malloc(len);
+ memcpy(ssl_obj->buf, data, len);
+ ssl_obj->len = len;
+ ret = do_obj(ssl_ctx, mem_type, ssl_obj, password);
+ ssl_obj_free(ssl_obj);
+ return ret;
+}
+
+/*
+ * Actually work out what we are doing
+ */
+static int do_obj(SSL_CTX *ssl_ctx, int obj_type,
+ SSLObjLoader *ssl_obj, const char *password)
+{
+ int ret = SSL_OK;
+
+ switch (obj_type)
+ {
+ case SSL_OBJ_RSA_KEY:
+ ret = add_private_key(ssl_ctx, ssl_obj);
+ break;
+
+ case SSL_OBJ_X509_CERT:
+ ret = add_cert(ssl_ctx, ssl_obj->buf, ssl_obj->len);
+ break;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ case SSL_OBJ_X509_CACERT:
+ ret = add_cert_auth(ssl_ctx, ssl_obj->buf, ssl_obj->len);
+ break;
+#endif
+
+#ifdef CONFIG_SSL_USE_PKCS12
+ case SSL_OBJ_PKCS8:
+ ret = pkcs8_decode(ssl_ctx, ssl_obj, password);
+ break;
+
+ case SSL_OBJ_PKCS12:
+ ret = pkcs12_decode(ssl_ctx, ssl_obj, password);
+ break;
+#endif
+ default:
+ printf(unsupported_str);
+ ret = SSL_ERROR_NOT_SUPPORTED;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Clean up our mess.
+ */
+void ssl_obj_free(SSLObjLoader *ssl_obj)
+{
+ if (ssl_obj)
+ {
+ free(ssl_obj->buf);
+ free(ssl_obj);
+ }
+}
+
+/*
+ * Support for PEM encoded keys/certificates.
+ */
+#ifdef CONFIG_SSL_HAS_PEM
+
+#define NUM_PEM_TYPES 3
+#define IV_SIZE 16
+#define IS_RSA_PRIVATE_KEY 0
+#define IS_ENCRYPTED_PRIVATE_KEY 1
+#define IS_CERTIFICATE 2
+
+static const char * const begins[NUM_PEM_TYPES] =
+{
+ "-----BEGIN RSA PRIVATE KEY-----",
+ "-----BEGIN ENCRYPTED PRIVATE KEY-----",
+ "-----BEGIN CERTIFICATE-----",
+};
+
+static const char * const ends[NUM_PEM_TYPES] =
+{
+ "-----END RSA PRIVATE KEY-----",
+ "-----END ENCRYPTED PRIVATE KEY-----",
+ "-----END CERTIFICATE-----",
+};
+
+static const char * const aes_str[2] =
+{
+ "DEK-Info: AES-128-CBC,",
+ "DEK-Info: AES-256-CBC,"
+};
+
+/**
+ * Take a base64 blob of data and decrypt it (using AES) into its
+ * proper ASN.1 form.
+ */
+static int pem_decrypt(const char *where, const char *end,
+ const char *password, SSLObjLoader *ssl_obj)
+{
+ int ret = -1;
+ int is_aes_256 = 0;
+ char *start = NULL;
+ uint8_t iv[IV_SIZE];
+ int i, pem_size;
+ MD5_CTX md5_ctx;
+ AES_CTX aes_ctx;
+ uint8_t key[32]; /* AES256 size */
+
+ if (password == NULL || strlen(password) == 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: Need a password for this PEM file\n"); TTY_FLUSH();
+#endif
+ goto error;
+ }
+
+ if ((start = strstr((const char *)where, aes_str[0]))) /* AES128? */
+ {
+ start += strlen(aes_str[0]);
+ }
+ else if ((start = strstr((const char *)where, aes_str[1]))) /* AES256? */
+ {
+ is_aes_256 = 1;
+ start += strlen(aes_str[1]);
+ }
+ else
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: Unsupported password cipher\n"); TTY_FLUSH();
+#endif
+ goto error;
+ }
+
+ /* convert from hex to binary - assumes uppercase hex */
+ for (i = 0; i < IV_SIZE; i++)
+ {
+ char c = *start++ - '0';
+ iv[i] = (c > 9 ? c + '0' - 'A' + 10 : c) << 4;
+ c = *start++ - '0';
+ iv[i] += (c > 9 ? c + '0' - 'A' + 10 : c);
+ }
+
+ while (*start == '\r' || *start == '\n')
+ start++;
+
+ /* turn base64 into binary */
+ pem_size = (int)(end-start);
+ if (base64_decode(start, pem_size, ssl_obj->buf, &ssl_obj->len) != 0)
+ goto error;
+
+ /* work out the key */
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password));
+ MD5_Update(&md5_ctx, iv, SALT_SIZE);
+ MD5_Final(key, &md5_ctx);
+
+ if (is_aes_256)
+ {
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, key, MD5_SIZE);
+ MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password));
+ MD5_Update(&md5_ctx, iv, SALT_SIZE);
+ MD5_Final(&key[MD5_SIZE], &md5_ctx);
+ }
+
+ /* decrypt using the key/iv */
+ AES_set_key(&aes_ctx, key, iv, is_aes_256 ? AES_MODE_256 : AES_MODE_128);
+ AES_convert_key(&aes_ctx);
+ AES_cbc_decrypt(&aes_ctx, ssl_obj->buf, ssl_obj->buf, ssl_obj->len);
+ ret = 0;
+
+error:
+ return ret;
+}
+
+/**
+ * Take a base64 blob of data and turn it into its proper ASN.1 form.
+ */
+static int new_pem_obj(SSL_CTX *ssl_ctx, int is_cacert, char *where,
+ int remain, const char *password)
+{
+ int ret = SSL_OK;
+ SSLObjLoader *ssl_obj = NULL;
+ int i, pem_size, obj_type;
+ char *start = NULL, *end = NULL;
+
+ for (i = 0; i < NUM_PEM_TYPES; i++)
+ {
+ if ((start = strstr(where, begins[i])) &&
+ (end = strstr(where, ends[i])))
+ {
+ remain -= (int)(end-start);
+ start += strlen(begins[i]);
+ pem_size = (int)(end-start);
+
+ ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
+
+ /* 4/3 bigger than what we need but so what */
+ ssl_obj->buf = (uint8_t *)calloc(1, pem_size);
+
+ if (i == IS_RSA_PRIVATE_KEY &&
+ strstr(start, "Proc-Type:") &&
+ strstr(start, "4,ENCRYPTED"))
+ {
+ /* check for encrypted PEM file */
+ if (pem_decrypt(start, end, password, ssl_obj) < 0)
+ goto error;
+ }
+ else if (base64_decode(start, pem_size,
+ ssl_obj->buf, &ssl_obj->len) != 0)
+ goto error;
+
+ switch (i)
+ {
+ case IS_RSA_PRIVATE_KEY:
+ obj_type = SSL_OBJ_RSA_KEY;
+ break;
+
+ case IS_ENCRYPTED_PRIVATE_KEY:
+ obj_type = SSL_OBJ_PKCS8;
+ break;
+
+ case IS_CERTIFICATE:
+ obj_type = is_cacert ?
+ SSL_OBJ_X509_CACERT : SSL_OBJ_X509_CERT;
+ break;
+
+ default:
+ goto error;
+ }
+
+ /* In a format we can now understand - so process it */
+ if ((ret = do_obj(ssl_ctx, obj_type, ssl_obj, password)))
+ goto error;
+
+ end += strlen(ends[i]);
+ remain -= strlen(ends[i]);
+ while (remain > 0 && (*end == '\r' || *end == '\n'))
+ {
+ end++;
+ remain--;
+ }
+
+ break;
+ }
+ }
+
+ if (i == NUM_PEM_TYPES)
+ goto error;
+
+ /* more PEM stuff to process? */
+ if (remain)
+ ret = new_pem_obj(ssl_ctx, is_cacert, end, remain, password);
+
+error:
+ ssl_obj_free(ssl_obj);
+ return ret;
+}
+
+/*
+ * Load a file into memory that is in ASCII PEM format.
+ */
+static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type,
+ SSLObjLoader *ssl_obj, const char *password)
+{
+ char *start;
+
+ /* add a null terminator */
+ ssl_obj->len++;
+ ssl_obj->buf = (uint8_t *)realloc(ssl_obj->buf, ssl_obj->len);
+ ssl_obj->buf[ssl_obj->len-1] = 0;
+ start = (char *)ssl_obj->buf;
+ return new_pem_obj(ssl_ctx, obj_type == SSL_OBJ_X509_CACERT,
+ start, ssl_obj->len, password);
+}
+#endif /* CONFIG_SSL_HAS_PEM */
+
+/**
+ * Load the key/certificates in memory depending on compile-time and user
+ * options.
+ */
+int load_key_certs(SSL_CTX *ssl_ctx)
+{
+ int ret = SSL_OK;
+ uint32_t options = ssl_ctx->options;
+#ifdef CONFIG_SSL_GENERATE_X509_CERT
+ uint8_t *cert_data = NULL;
+ int cert_size;
+ static const char *dn[] =
+ {
+ CONFIG_SSL_X509_COMMON_NAME,
+ CONFIG_SSL_X509_ORGANIZATION_NAME,
+ CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME
+ };
+#endif
+
+ /* do the private key first */
+ if (strlen(CONFIG_SSL_PRIVATE_KEY_LOCATION) > 0)
+ {
+ if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY,
+ CONFIG_SSL_PRIVATE_KEY_LOCATION,
+ CONFIG_SSL_PRIVATE_KEY_PASSWORD)) < 0)
+ goto error;
+ }
+ else if (!(options & SSL_NO_DEFAULT_KEY))
+ {
+#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
+ static const /* saves a few more bytes */
+#include "private_key.h"
+
+ ssl_obj_memory_load(ssl_ctx, SSL_OBJ_RSA_KEY, default_private_key,
+ default_private_key_len, NULL);
+#endif
+ }
+
+ /* now load the certificate */
+#ifdef CONFIG_SSL_GENERATE_X509_CERT
+ if ((cert_size = ssl_x509_create(ssl_ctx, 0, dn, &cert_data)) < 0)
+ {
+ ret = cert_size;
+ goto error;
+ }
+
+ ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, cert_data, cert_size, NULL);
+ free(cert_data);
+#else
+ if (strlen(CONFIG_SSL_X509_CERT_LOCATION))
+ {
+ if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT,
+ CONFIG_SSL_X509_CERT_LOCATION, NULL)) < 0)
+ goto error;
+ }
+ else if (!(options & SSL_NO_DEFAULT_KEY))
+ {
+#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
+ static const /* saves a few bytes and RAM */
+#include "cert.h"
+ ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT,
+ default_certificate, default_certificate_len, NULL);
+#endif
+ }
+#endif
+
+error:
+#ifdef CONFIG_SSL_FULL_MODE
+ if (ret)
+ {
+ printf("Error: Certificate or key not loaded\n"); TTY_FLUSH();
+ }
+#endif
+
+ return ret;
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Enable a subset of openssl compatible functions. We don't aim to be 100%
+ * compatible - just to be able to do basic ports etc.
+ *
+ * Only really tested on mini_httpd, so I'm not too sure how extensive this
+ * port is.
+ */
+
+#include "config.h"
+
+#ifdef CONFIG_OPENSSL_COMPATIBLE
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "ssl.h"
+
+#define OPENSSL_CTX_ATTR ((OPENSSL_CTX *)ssl_ctx->bonus_attr)
+
+static char *key_password = NULL;
+
+void *SSLv23_server_method(void) { return NULL; }
+void *SSLv3_server_method(void) { return NULL; }
+void *TLSv1_server_method(void) { return NULL; }
+void *SSLv23_client_method(void) { return NULL; }
+void *SSLv3_client_method(void) { return NULL; }
+void *TLSv1_client_method(void) { return NULL; }
+
+typedef void * (*ssl_func_type_t)(void);
+typedef void * (*bio_func_type_t)(void);
+
+typedef struct
+{
+ ssl_func_type_t ssl_func_type;
+} OPENSSL_CTX;
+
+SSL_CTX * SSL_CTX_new(ssl_func_type_t meth)
+{
+ SSL_CTX *ssl_ctx = ssl_ctx_new(0, 5);
+ ssl_ctx->bonus_attr = malloc(sizeof(OPENSSL_CTX));
+ OPENSSL_CTX_ATTR->ssl_func_type = meth;
+ return ssl_ctx;
+}
+
+void SSL_CTX_free(SSL_CTX * ssl_ctx)
+{
+ free(ssl_ctx->bonus_attr);
+ ssl_ctx_free(ssl_ctx);
+}
+
+SSL * SSL_new(SSL_CTX *ssl_ctx)
+{
+ SSL *ssl;
+ ssl_func_type_t ssl_func_type;
+
+ ssl = ssl_new(ssl_ctx, -1); /* fd is set later */
+ ssl_func_type = OPENSSL_CTX_ATTR->ssl_func_type;
+
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+ if (ssl_func_type == SSLv23_client_method ||
+ ssl_func_type == SSLv3_client_method ||
+ ssl_func_type == TLSv1_client_method)
+ {
+ SET_SSL_FLAG(SSL_IS_CLIENT);
+ }
+ else
+#endif
+ {
+ ssl->next_state = HS_CLIENT_HELLO;
+ }
+
+ return ssl;
+}
+
+int SSL_set_fd(SSL *s, int fd)
+{
+ s->client_fd = fd;
+ return 1; /* always succeeds */
+}
+
+int SSL_accept(SSL *ssl)
+{
+ while (ssl_read(ssl, NULL) == SSL_OK)
+ {
+ if (ssl->next_state == HS_CLIENT_HELLO)
+ return 1; /* we're done */
+ }
+
+ return -1;
+}
+
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+int SSL_connect(SSL *ssl)
+{
+ return do_client_connect(ssl) == SSL_OK ? 1 : -1;
+}
+#endif
+
+void SSL_free(SSL *ssl)
+{
+ ssl_free(ssl);
+}
+
+int SSL_read(SSL *ssl, void *buf, int num)
+{
+ uint8_t *read_buf;
+ int ret;
+
+ while ((ret = ssl_read(ssl, &read_buf)) == SSL_OK);
+
+ if (ret > SSL_OK)
+ {
+ memcpy(buf, read_buf, ret > num ? num : ret);
+ }
+
+ return ret;
+}
+
+int SSL_write(SSL *ssl, const void *buf, int num)
+{
+ return ssl_write(ssl, buf, num);
+}
+
+int SSL_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type)
+{
+ return (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, file, NULL) == SSL_OK);
+}
+
+int SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type)
+{
+ return (ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, file, key_password) == SSL_OK);
+}
+
+int SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d)
+{
+ return (ssl_obj_memory_load(ssl_ctx,
+ SSL_OBJ_X509_CERT, d, len, NULL) == SSL_OK);
+}
+
+int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx,
+ unsigned int sid_ctx_len)
+{
+ return 1;
+}
+
+int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)
+{
+ return 1;
+}
+
+int SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file)
+{
+ return (ssl_obj_load(ssl_ctx,
+ SSL_OBJ_X509_CERT, file, NULL) == SSL_OK);
+}
+
+int SSL_shutdown(SSL *ssl)
+{
+ return 1;
+}
+
+/*** get/set session ***/
+SSL_SESSION *SSL_get1_session(SSL *ssl)
+{
+ return (SSL_SESSION *)ssl_get_session_id(ssl); /* note: wrong cast */
+}
+
+int SSL_set_session(SSL *ssl, SSL_SESSION *session)
+{
+ memcpy(ssl->session_id, (uint8_t *)session, SSL_SESSION_ID_SIZE);
+ return 1;
+}
+
+void SSL_SESSION_free(SSL_SESSION *session) { }
+/*** end get/set session ***/
+
+long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
+{
+ return 0;
+}
+
+void SSL_CTX_set_verify(SSL_CTX *ctx, int mode,
+ int (*verify_callback)(int, void *)) { }
+
+void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth) { }
+
+int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
+ const char *CApath)
+{
+ return 1;
+}
+
+void *SSL_load_client_CA_file(const char *file)
+{
+ return (void *)file;
+}
+
+void SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file)
+{
+
+ ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, (const char *)file, NULL);
+}
+
+void SSLv23_method(void) { }
+
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb) { }
+
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u)
+{
+ key_password = (char *)u;
+}
+
+int SSL_peek(SSL *ssl, void *buf, int num)
+{
+ memcpy(buf, ssl->bm_data, num);
+ return num;
+}
+
+void SSL_set_bio(SSL *ssl, void *rbio, void *wbio) { }
+
+long SSL_get_verify_result(const SSL *ssl)
+{
+ return ssl_handshake_status(ssl);
+}
+
+int SSL_state(SSL *ssl)
+{
+ return 0x03; // ok state
+}
+
+/** end of could do better list */
+
+void *SSL_get_peer_certificate(const SSL *ssl)
+{
+ return &ssl->ssl_ctx->certs[0];
+}
+
+int SSL_clear(SSL *ssl)
+{
+ return 1;
+}
+
+
+int SSL_CTX_check_private_key(const SSL_CTX *ctx)
+{
+ return 1;
+}
+
+int SSL_CTX_set_cipher_list(SSL *s, const char *str)
+{
+ return 1;
+}
+
+int SSL_get_error(const SSL *ssl, int ret)
+{
+ ssl_display_error(ret);
+ return 0; /* TODO: return proper return code */
+}
+
+void SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option) {}
+int SSL_library_init(void ) { return 1; }
+void SSL_load_error_strings(void ) {}
+void ERR_print_errors_fp(FILE *fp) {}
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+long SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx) {
+ return CONFIG_SSL_EXPIRY_TIME*3600; }
+long SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t) {
+ return SSL_CTX_get_timeout(ssl_ctx); }
+#endif
+void BIO_printf(FILE *f, const char *format, ...)
+{
+ va_list(ap);
+ va_start(ap, format);
+ vfprintf(f, format, ap);
+ va_end(ap);
+}
+
+void* BIO_s_null(void) { return NULL; }
+FILE *BIO_new(bio_func_type_t func)
+{
+ if (func == BIO_s_null)
+ return fopen("/dev/null", "r");
+ else
+ return NULL;
+}
+
+FILE *BIO_new_fp(FILE *stream, int close_flag) { return stream; }
+int BIO_free(FILE *a) { if (a != stdout && a != stderr) fclose(a); return 1; }
+
+
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file os_port.c
+ *
+ * OS specific functions.
+ */
+#include <time.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include "os_port.h"
+
+#ifdef WIN32
+/**
+ * gettimeofday() not in Win32
+ */
+EXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone)
+{
+#if defined(_WIN32_WCE)
+ t->tv_sec = time(NULL);
+ t->tv_usec = 0; /* 1sec precision only */
+#else
+ struct _timeb timebuffer;
+ _ftime(&timebuffer);
+ t->tv_sec = (long)timebuffer.time;
+ t->tv_usec = 1000 * timebuffer.millitm; /* 1ms precision */
+#endif
+}
+
+/**
+ * strcasecmp() not in Win32
+ */
+EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2)
+{
+ while (tolower(*s1) == tolower(*s2++))
+ {
+ if (*s1++ == '\0')
+ {
+ return 0;
+ }
+ }
+
+ return *(unsigned char *)s1 - *(unsigned char *)(s2 - 1);
+}
+
+
+EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size)
+{
+ HKEY hKey;
+ unsigned long datatype;
+ unsigned long bufferlength = buf_size;
+
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"),
+ 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
+ return -1;
+
+ RegQueryValueEx(hKey, "Domain", NULL, &datatype, buf, &bufferlength);
+ RegCloseKey(hKey);
+ return 0;
+}
+#endif
+
+#undef malloc
+#undef realloc
+#undef calloc
+
+static const char * out_of_mem_str = "out of memory";
+static const char * file_open_str = "Could not open file \"%s\"";
+
+/*
+ * Some functions that call display some error trace and then call abort().
+ * This just makes life much easier on embedded systems, since we're
+ * suffering major trauma...
+ */
+EXP_FUNC void * STDCALL ax_malloc(size_t s)
+{
+ void *x;
+
+ if ((x = malloc(s)) == NULL)
+ exit_now(out_of_mem_str);
+
+ return x;
+}
+
+EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s)
+{
+ void *x;
+
+ if ((x = realloc(y, s)) == NULL)
+ exit_now(out_of_mem_str);
+
+ return x;
+}
+
+EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s)
+{
+ void *x;
+
+ if ((x = calloc(n, s)) == NULL)
+ exit_now(out_of_mem_str);
+
+ return x;
+}
+
+EXP_FUNC int STDCALL ax_open(const char *pathname, int flags)
+{
+ int x;
+
+ if ((x = open(pathname, flags)) < 0)
+ exit_now(file_open_str, pathname);
+
+ return x;
+}
+
+/**
+ * This is a call which will deliberately exit an application, but will
+ * display some information before dying.
+ */
+void exit_now(const char *format, ...)
+{
+ va_list argp;
+
+ va_start(argp, format);
+ vfprintf(stderr, format, argp);
+ va_end(argp);
+ abort();
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file os_port.h
+ *
+ * Some stuff to minimise the differences between windows and linux/unix
+ */
+
+#ifndef HEADER_OS_PORT_H
+#define HEADER_OS_PORT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+#if defined(WIN32)
+#define STDCALL __stdcall
+#define EXP_FUNC __declspec(dllexport)
+#else
+#define STDCALL
+#define EXP_FUNC
+#endif
+
+#if defined(_WIN32_WCE)
+#undef WIN32
+#define WIN32
+#endif
+
+#ifdef WIN32
+
+/* Windows CE stuff */
+#if defined(_WIN32_WCE)
+#include <basetsd.h>
+#define abort() exit(1)
+#else
+#include <io.h>
+#include <process.h>
+#include <sys/timeb.h>
+#include <fcntl.h>
+#endif /* _WIN32_WCE */
+
+#include <winsock.h>
+#include <direct.h>
+#undef getpid
+#undef open
+#undef close
+#undef sleep
+#undef gettimeofday
+#undef dup2
+#undef unlink
+
+#define SOCKET_READ(A,B,C) recv(A,B,C,0)
+#define SOCKET_WRITE(A,B,C) send(A,B,C,0)
+#define SOCKET_CLOSE(A) closesocket(A)
+#define SOCKET_BLOCK(A) u_long argp = 0; \
+ ioctlsocket(A, FIONBIO, &argp)
+#define srandom(A) srand(A)
+#define random() rand()
+#define getpid() _getpid()
+#define snprintf _snprintf
+#define open(A,B) _open(A,B)
+#define dup2(A,B) _dup2(A,B)
+#define unlink(A) _unlink(A)
+#define close(A) _close(A)
+#define read(A,B,C) _read(A,B,C)
+#define write(A,B,C) _write(A,B,C)
+#define sleep(A) Sleep(A*1000)
+#define usleep(A) Sleep(A/1000)
+#define strdup(A) _strdup(A)
+#define chroot(A) _chdir(A)
+#define chdir(A) _chdir(A)
+#define alloca(A) _alloca(A)
+#ifndef lseek
+#define lseek(A,B,C) _lseek(A,B,C)
+#endif
+
+/* This fix gets around a problem where a win32 application on a cygwin xterm
+ doesn't display regular output (until a certain buffer limit) - but it works
+ fine under a normal DOS window. This is a hack to get around the issue -
+ see http://www.khngai.com/emacs/tty.php */
+#define TTY_FLUSH() if (!_isatty(_fileno(stdout))) fflush(stdout);
+
+/*
+ * automatically build some library dependencies.
+ */
+#pragma comment(lib, "WS2_32.lib")
+#pragma comment(lib, "AdvAPI32.lib")
+
+typedef UINT8 uint8_t;
+typedef INT8 int8_t;
+typedef UINT16 uint16_t;
+typedef INT16 int16_t;
+typedef UINT32 uint32_t;
+typedef INT32 int32_t;
+typedef UINT64 uint64_t;
+typedef INT64 int64_t;
+typedef int socklen_t;
+
+EXP_FUNC void STDCALL gettimeofday(struct timeval* t,void* timezone);
+EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2);
+EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size);
+
+#else /* Not Win32 */
+
+#ifdef CONFIG_PLATFORM_SOLARIS
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif /* Not Solaris */
+
+#include <unistd.h>
+#include <pwd.h>
+#include <netdb.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define SOCKET_READ(A,B,C) read(A,B,C)
+#define SOCKET_WRITE(A,B,C) write(A,B,C)
+#define SOCKET_CLOSE(A) close(A)
+#define SOCKET_BLOCK(A) int fd = fcntl(A, F_GETFL, NULL); \
+ fcntl(A, F_SETFL, fd & ~O_NONBLOCK)
+#define TTY_FLUSH()
+
+#endif /* Not Win32 */
+
+/* some functions to mutate the way these work */
+#define malloc(A) ax_malloc(A)
+#ifndef realloc
+#define realloc(A,B) ax_realloc(A,B)
+#endif
+#define calloc(A,B) ax_calloc(A,B)
+
+EXP_FUNC void * STDCALL ax_malloc(size_t s);
+EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s);
+EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s);
+EXP_FUNC int STDCALL ax_open(const char *pathname, int flags);
+
+#ifdef CONFIG_PLATFORM_LINUX
+void exit_now(const char *format, ...) __attribute((noreturn));
+#else
+void exit_now(const char *format, ...);
+#endif
+
+/* Mutexing definitions */
+#if defined(CONFIG_SSL_CTX_MUTEXING)
+#if defined(WIN32)
+#define SSL_CTX_MUTEX_TYPE HANDLE
+#define SSL_CTX_MUTEX_INIT(A) A=CreateMutex(0, FALSE, 0)
+#define SSL_CTX_MUTEX_DESTROY(A) CloseHandle(A)
+#define SSL_CTX_LOCK(A) WaitForSingleObject(A, INFINITE)
+#define SSL_CTX_UNLOCK(A) ReleaseMutex(A)
+#else
+#include <pthread.h>
+#define SSL_CTX_MUTEX_TYPE pthread_mutex_t
+#define SSL_CTX_MUTEX_INIT(A) pthread_mutex_init(&A, NULL)
+#define SSL_CTX_MUTEX_DESTROY(A) pthread_mutex_destroy(&A)
+#define SSL_CTX_LOCK(A) pthread_mutex_lock(&A)
+#define SSL_CTX_UNLOCK(A) pthread_mutex_unlock(&A)
+#endif
+#else /* no mutexing */
+#define SSL_CTX_MUTEX_INIT(A)
+#define SSL_CTX_MUTEX_DESTROY(A)
+#define SSL_CTX_LOCK(A)
+#define SSL_CTX_UNLOCK(A)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Process PKCS#8/PKCS#12 keys.
+ *
+ * The decoding of a PKCS#12 key is fairly specific - this code was tested on a
+ * key generated with:
+ *
+ * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
+ * -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128
+ * -name "p12_withoutCA" -out axTLS.withoutCA.p12 -password pass:abcd
+ *
+ * or with a certificate chain:
+ *
+ * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem
+ * -certfile axTLS.ca_x509.pem -keypbe PBE-SHA1-RC4-128 -certpbe
+ * PBE-SHA1-RC4-128 -name "p12_withCA" -out axTLS.withCA.p12 -password pass:abcd
+ *
+ * Note that the PBE has to be specified with PBE-SHA1-RC4-128. The
+ * private/public keys/certs have to use RSA encryption. Both the integrity
+ * and privacy passwords are the same.
+ *
+ * The PKCS#8 files were generated with something like:
+ *
+ * PEM format:
+ * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -v1
+ * PBE-SHA1-RC4-128 -out axTLS.encrypted_pem.p8
+ *
+ * DER format:
+ * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -outform DER
+ * -v1 PBE-SHA1-RC4-128 -out axTLS.encrypted.p8
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "ssl.h"
+
+/* all commented out if not used */
+#ifdef CONFIG_SSL_USE_PKCS12
+
+#define BLOCK_SIZE 64
+#define PKCS12_KEY_ID 1
+#define PKCS12_IV_ID 2
+#define PKCS12_MAC_ID 3
+
+static char *make_uni_pass(const char *password, int *uni_pass_len);
+static int p8_decrypt(const char *uni_pass, int uni_pass_len,
+ const uint8_t *salt, int iter,
+ uint8_t *priv_key, int priv_key_len, int id);
+static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key);
+static int get_pbe_params(uint8_t *buf, int *offset,
+ const uint8_t **salt, int *iterations);
+
+/*
+ * Take a raw pkcs8 block and then decrypt it and turn it into a normal key.
+ */
+int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
+{
+ uint8_t *buf = ssl_obj->buf;
+ int len, offset = 0;
+ int iterations;
+ int ret = SSL_NOT_OK;
+ uint8_t *version = NULL;
+ const uint8_t *salt;
+ uint8_t *priv_key;
+ int uni_pass_len;
+ char *uni_pass = make_uni_pass(password, &uni_pass_len);
+
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: Invalid p8 ASN.1 file\n");
+#endif
+ goto error;
+ }
+
+ /* unencrypted key? */
+ if (asn1_get_int(buf, &offset, &version) > 0 && *version == 0)
+ {
+ ret = p8_add_key(ssl_ctx, buf);
+ goto error;
+ }
+
+ if (get_pbe_params(buf, &offset, &salt, &iterations) < 0)
+ goto error;
+
+ if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
+ goto error;
+
+ priv_key = &buf[offset];
+
+ p8_decrypt(uni_pass, uni_pass_len, salt,
+ iterations, priv_key, len, PKCS12_KEY_ID);
+ ret = p8_add_key(ssl_ctx, priv_key);
+
+error:
+ free(version);
+ free(uni_pass);
+ return ret;
+}
+
+/*
+ * Take the unencrypted pkcs8 and turn it into a private key
+ */
+static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key)
+{
+ uint8_t *buf = priv_key;
+ int len, offset = 0;
+ int ret = SSL_NOT_OK;
+
+ /* Skip the preamble and go straight to the private key.
+ We only support rsaEncryption (1.2.840.113549.1.1.1) */
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||
+ asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
+ goto error;
+
+ ret = asn1_get_private_key(&buf[offset], len, &ssl_ctx->rsa_ctx);
+
+error:
+ return ret;
+}
+
+/*
+ * Create the unicode password
+ */
+static char *make_uni_pass(const char *password, int *uni_pass_len)
+{
+ int pass_len = 0, i;
+ char *uni_pass;
+
+ if (password == NULL)
+ {
+ password = "";
+ }
+
+ uni_pass = (char *)malloc((strlen(password)+1)*2);
+
+ /* modify the password into a unicode version */
+ for (i = 0; i < (int)strlen(password); i++)
+ {
+ uni_pass[pass_len++] = 0;
+ uni_pass[pass_len++] = password[i];
+ }
+
+ uni_pass[pass_len++] = 0; /* null terminate */
+ uni_pass[pass_len++] = 0;
+ *uni_pass_len = pass_len;
+ return uni_pass;
+}
+
+/*
+ * Decrypt a pkcs8 block.
+ */
+static int p8_decrypt(const char *uni_pass, int uni_pass_len,
+ const uint8_t *salt, int iter,
+ uint8_t *priv_key, int priv_key_len, int id)
+{
+ uint8_t p[BLOCK_SIZE*2];
+ uint8_t d[BLOCK_SIZE];
+ uint8_t Ai[SHA1_SIZE];
+ SHA1_CTX sha_ctx;
+ RC4_CTX rc4_ctx;
+ int i;
+
+ for (i = 0; i < BLOCK_SIZE; i++)
+ {
+ p[i] = salt[i % SALT_SIZE];
+ p[BLOCK_SIZE+i] = uni_pass[i % uni_pass_len];
+ d[i] = id;
+ }
+
+ /* get the key - no IV since we are using RC4 */
+ SHA1_Init(&sha_ctx);
+ SHA1_Update(&sha_ctx, d, sizeof(d));
+ SHA1_Update(&sha_ctx, p, sizeof(p));
+ SHA1_Final(Ai, &sha_ctx);
+
+ for (i = 1; i < iter; i++)
+ {
+ SHA1_Init(&sha_ctx);
+ SHA1_Update(&sha_ctx, Ai, SHA1_SIZE);
+ SHA1_Final(Ai, &sha_ctx);
+ }
+
+ /* do the decryption */
+ if (id == PKCS12_KEY_ID)
+ {
+ RC4_setup(&rc4_ctx, Ai, 16);
+ RC4_crypt(&rc4_ctx, priv_key, priv_key, priv_key_len);
+ }
+ else /* MAC */
+ memcpy(priv_key, Ai, SHA1_SIZE);
+
+ return 0;
+}
+
+/*
+ * Take a raw pkcs12 block and the decrypt it and turn it into a certificate(s)
+ * and keys.
+ */
+int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
+{
+ uint8_t *buf = ssl_obj->buf;
+ int all_ok = 0, len, iterations, auth_safes_start,
+ auth_safes_end, auth_safes_len, key_offset, offset = 0;
+ int all_certs = 0;
+ uint8_t *version = NULL, *auth_safes = NULL, *cert, *orig_mac;
+ uint8_t key[SHA1_SIZE];
+ uint8_t mac[SHA1_SIZE];
+ const uint8_t *salt;
+ int uni_pass_len, ret;
+ int error_code = SSL_ERROR_NOT_SUPPORTED;
+ char *uni_pass = make_uni_pass(password, &uni_pass_len);
+ static const uint8_t pkcs_data[] = /* pkc7 data */
+ { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 };
+ static const uint8_t pkcs_encrypted[] = /* pkc7 encrypted */
+ { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06 };
+ static const uint8_t pkcs8_key_bag[] = /* 1.2.840.113549.1.12.10.1.2 */
+ { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02 };
+
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: Invalid p12 ASN.1 file\n");
+#endif
+ goto error;
+ }
+
+ if (asn1_get_int(buf, &offset, &version) < 0 || *version != 3)
+ {
+ error_code = SSL_ERROR_INVALID_VERSION;
+ goto error;
+ }
+
+ /* remove all the boring pcks7 bits */
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+ len != sizeof(pkcs_data) ||
+ memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
+ goto error;
+
+ offset += len;
+
+ if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0)
+ goto error;
+
+ /* work out the MAC start/end points (done on AuthSafes) */
+ auth_safes_start = offset;
+ auth_safes_end = offset;
+ if (asn1_skip_obj(buf, &auth_safes_end, ASN1_SEQUENCE) < 0)
+ goto error;
+
+ auth_safes_len = auth_safes_end - auth_safes_start;
+ auth_safes = malloc(auth_safes_len);
+
+ memcpy(auth_safes, &buf[auth_safes_start], auth_safes_len);
+
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+ (len != sizeof(pkcs_encrypted) ||
+ memcmp(&buf[offset], pkcs_encrypted, sizeof(pkcs_encrypted))))
+ goto error;
+
+ offset += len;
+
+ if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+ len != sizeof(pkcs_data) ||
+ memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
+ goto error;
+
+ offset += len;
+
+ /* work out the salt for the certificate */
+ if (get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_IMPLICIT_TAG)) < 0)
+ goto error;
+
+ /* decrypt the certificate */
+ cert = &buf[offset];
+ if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert,
+ len, PKCS12_KEY_ID)) < 0)
+ goto error;
+
+ offset += len;
+
+ /* load the certificate */
+ key_offset = 0;
+ all_certs = asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE);
+
+ /* keep going until all certs are loaded */
+ while (key_offset < all_certs)
+ {
+ int cert_offset = key_offset;
+
+ if (asn1_skip_obj(cert, &cert_offset, ASN1_SEQUENCE) < 0 ||
+ asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||
+ asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||
+ asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||
+ asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||
+ (len = asn1_next_obj(cert, &key_offset, ASN1_OCTET_STRING)) < 0)
+ goto error;
+
+ if ((ret = add_cert(ssl_ctx, &cert[key_offset], len)) < 0)
+ goto error;
+
+ key_offset = cert_offset;
+ }
+
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+ len != sizeof(pkcs_data) ||
+ memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))
+ goto error;
+
+ offset += len;
+
+ if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||
+ (len != sizeof(pkcs8_key_bag)) ||
+ memcmp(&buf[offset], pkcs8_key_bag, sizeof(pkcs8_key_bag)))
+ goto error;
+
+ offset += len;
+
+ /* work out the salt for the private key */
+ if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)
+ goto error;
+
+ /* decrypt the private key */
+ cert = &buf[offset];
+ if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert,
+ len, PKCS12_KEY_ID)) < 0)
+ goto error;
+
+ offset += len;
+
+ /* load the private key */
+ if ((ret = p8_add_key(ssl_ctx, cert)) < 0)
+ goto error;
+
+ /* miss out on friendly name, local key id etc */
+ if (asn1_skip_obj(buf, &offset, ASN1_SET) < 0)
+ goto error;
+
+ /* work out the MAC */
+ if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 ||
+ len != SHA1_SIZE)
+ goto error;
+
+ orig_mac = &buf[offset];
+ offset += len;
+
+ /* get the salt */
+ if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || len != 8)
+ goto error;
+
+ salt = &buf[offset];
+
+ /* work out what the mac should be */
+ if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations,
+ key, SHA1_SIZE, PKCS12_MAC_ID)) < 0)
+ goto error;
+
+ hmac_sha1(auth_safes, auth_safes_len, key, SHA1_SIZE, mac);
+
+ if (memcmp(mac, orig_mac, SHA1_SIZE))
+ {
+ error_code = SSL_ERROR_INVALID_HMAC;
+ goto error;
+ }
+
+ all_ok = 1;
+
+error:
+ free(version);
+ free(uni_pass);
+ free(auth_safes);
+ return all_ok ? SSL_OK : error_code;
+}
+
+/*
+ * Retrieve the salt/iteration details from a PBE block.
+ */
+static int get_pbe_params(uint8_t *buf, int *offset,
+ const uint8_t **salt, int *iterations)
+{
+ static const uint8_t pbeSH1RC4[] = /* pbeWithSHAAnd128BitRC4 */
+ { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01 };
+
+ int i, len;
+ uint8_t *iter = NULL;
+ int error_code = SSL_ERROR_NOT_SUPPORTED;
+
+ /* Get the PBE type */
+ if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
+ goto error;
+
+ /* we expect pbeWithSHAAnd128BitRC4 (1.2.840.113549.1.12.1.1)
+ which is the only algorithm we support */
+ if (len != sizeof(pbeSH1RC4) ||
+ memcmp(&buf[*offset], pbeSH1RC4, sizeof(pbeSH1RC4)))
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: pkcs8/pkcs12 must use \"PBE-SHA1-RC4-128\"\n");
+#endif
+ goto error;
+ }
+
+ *offset += len;
+
+ if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||
+ (len = asn1_next_obj(buf, offset, ASN1_OCTET_STRING)) < 0 ||
+ len != 8)
+ goto error;
+
+ *salt = &buf[*offset];
+ *offset += len;
+
+ if ((len = asn1_get_int(buf, offset, &iter)) < 0)
+ goto error;
+
+ *iterations = 0;
+ for (i = 0; i < len; i++)
+ {
+ (*iterations) <<= 8;
+ (*iterations) += iter[i];
+ }
+
+ free(iter);
+ error_code = SSL_OK; /* got here - we are ok */
+
+error:
+ return error_code;
+}
+
+#endif
--- /dev/null
+unsigned char default_private_key[] = {
+ 0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xd8,
+ 0xe0, 0xbf, 0x15, 0xde, 0xea, 0xaf, 0xe8, 0xd5, 0xfd, 0x0b, 0xa8, 0xa8,
+ 0xb3, 0xd7, 0x46, 0x5d, 0xa7, 0x26, 0x6c, 0x0c, 0xb5, 0xd9, 0xbc, 0xc6,
+ 0xf8, 0xc0, 0x78, 0xd0, 0xf6, 0x56, 0x65, 0xf8, 0x29, 0x48, 0x0e, 0x7b,
+ 0x0b, 0xa6, 0x25, 0x7e, 0xe8, 0x7b, 0x79, 0x6f, 0x38, 0xe5, 0xb5, 0xb7,
+ 0xf4, 0xe0, 0x9c, 0x91, 0x60, 0xf4, 0x06, 0xf3, 0x40, 0x1e, 0xf9, 0x91,
+ 0x19, 0xa9, 0x2f, 0x47, 0x43, 0xb5, 0x9b, 0x1e, 0xdc, 0xf6, 0xaa, 0x1c,
+ 0x49, 0x79, 0x21, 0x28, 0xcb, 0xaa, 0x49, 0x73, 0xd9, 0x09, 0x05, 0x4c,
+ 0x02, 0xf2, 0x4c, 0x4d, 0x6c, 0x1c, 0x80, 0xa7, 0x14, 0x91, 0x44, 0xfc,
+ 0x12, 0xb3, 0xe1, 0xe7, 0xe3, 0x4f, 0x44, 0xba, 0x8c, 0xc3, 0x74, 0x39,
+ 0xe8, 0x4c, 0xd0, 0xd4, 0x4c, 0x24, 0x61, 0xb4, 0x40, 0x95, 0x8c, 0xc0,
+ 0x0a, 0xb7, 0x02, 0x39, 0x31, 0x85, 0x93, 0x02, 0x03, 0x01, 0x00, 0x01,
+ 0x02, 0x81, 0x81, 0x00, 0x94, 0x07, 0x72, 0xe5, 0xbe, 0xad, 0x79, 0x3b,
+ 0xf7, 0x33, 0x2c, 0x8e, 0x05, 0xf8, 0x1a, 0x6b, 0xd0, 0xe8, 0x91, 0xf5,
+ 0x16, 0x07, 0xd9, 0x82, 0x5c, 0x5c, 0xd5, 0x22, 0xa1, 0x9e, 0x42, 0x02,
+ 0x7f, 0x8b, 0xcd, 0xbe, 0xf4, 0x85, 0x52, 0xf6, 0x2c, 0xd5, 0x09, 0xd2,
+ 0x2c, 0xf4, 0x2c, 0xf6, 0x07, 0x85, 0x80, 0xf9, 0xdc, 0xd0, 0xcc, 0x3f,
+ 0x22, 0x31, 0x15, 0xf3, 0x49, 0xf2, 0xb5, 0xe2, 0x69, 0x99, 0x04, 0x04,
+ 0x49, 0x21, 0xdb, 0x9f, 0xa1, 0x54, 0x5a, 0xfa, 0xe4, 0xd9, 0xf9, 0x07,
+ 0x05, 0xff, 0x9a, 0x65, 0xa4, 0xeb, 0xf2, 0x47, 0xce, 0x56, 0xc7, 0x72,
+ 0x49, 0x48, 0x5c, 0xe8, 0x14, 0xd7, 0x8f, 0x25, 0xcc, 0x49, 0x29, 0x06,
+ 0x6a, 0x54, 0x7b, 0x17, 0xdc, 0x9e, 0xd4, 0x53, 0xf0, 0xf5, 0x9e, 0x85,
+ 0x25, 0xa1, 0xeb, 0x3d, 0xe9, 0x2f, 0xb9, 0x9c, 0xf6, 0xe1, 0x80, 0x81,
+ 0x02, 0x41, 0x00, 0xee, 0x02, 0x78, 0xc7, 0x78, 0x85, 0x04, 0x97, 0xcc,
+ 0x36, 0xbd, 0xd6, 0x11, 0xe2, 0xc7, 0x39, 0xd9, 0x34, 0x51, 0x72, 0x6f,
+ 0x8a, 0x0f, 0xcd, 0x88, 0x32, 0x33, 0x9b, 0xc7, 0xa7, 0x03, 0x77, 0xd9,
+ 0x82, 0x35, 0xb6, 0xdd, 0x1f, 0xc2, 0xc1, 0x13, 0x40, 0x83, 0x55, 0xeb,
+ 0x60, 0xeb, 0x81, 0x8e, 0x0c, 0x16, 0x62, 0xb4, 0xb4, 0x3c, 0xeb, 0x08,
+ 0x80, 0x9c, 0x79, 0xd3, 0x38, 0xca, 0xf1, 0x02, 0x41, 0x00, 0xe9, 0x45,
+ 0x5f, 0x2e, 0x16, 0xcc, 0x93, 0x50, 0x40, 0xb6, 0x79, 0xbc, 0x38, 0xe0,
+ 0x56, 0x68, 0x50, 0xd3, 0x2f, 0x73, 0x8c, 0x8c, 0x2a, 0x0e, 0x81, 0x4a,
+ 0x8a, 0xbb, 0xcc, 0xf0, 0x64, 0x34, 0x46, 0x9f, 0x07, 0x7d, 0x22, 0xb6,
+ 0xf9, 0x46, 0xac, 0x57, 0x23, 0x8c, 0x1e, 0xeb, 0xd3, 0x05, 0x4d, 0xa8,
+ 0x83, 0x6a, 0x67, 0xf6, 0xa6, 0xb1, 0xab, 0x8e, 0xc1, 0xef, 0xef, 0x7d,
+ 0xf0, 0xc3, 0x02, 0x40, 0x2f, 0xc6, 0x59, 0x3e, 0x18, 0xe8, 0x02, 0x73,
+ 0x01, 0xef, 0xdf, 0x0d, 0x30, 0x4b, 0xe8, 0x17, 0xa9, 0x8c, 0xc1, 0xe8,
+ 0x89, 0x91, 0x19, 0xf8, 0xf4, 0xa4, 0xb7, 0x0d, 0x46, 0xf7, 0x34, 0x50,
+ 0x03, 0x5e, 0x0a, 0xb0, 0x29, 0x14, 0xae, 0x00, 0x19, 0x80, 0x32, 0x9c,
+ 0xb5, 0x81, 0x9f, 0xe4, 0x42, 0x82, 0x14, 0xa0, 0x3d, 0x8b, 0x8c, 0x4a,
+ 0xd5, 0x4b, 0x13, 0x9d, 0xb4, 0x93, 0x4a, 0xd1, 0x02, 0x40, 0x64, 0x8c,
+ 0x83, 0x77, 0x61, 0x5a, 0x73, 0x11, 0x3f, 0xa3, 0xa8, 0x1b, 0x8a, 0xc4,
+ 0xa0, 0x5a, 0x3c, 0xa4, 0x9b, 0x2a, 0x8a, 0x65, 0x8c, 0x67, 0x4e, 0x31,
+ 0xac, 0x55, 0x41, 0x04, 0x49, 0x9d, 0x02, 0xe7, 0xdf, 0x99, 0x7f, 0xd2,
+ 0x30, 0xe6, 0xd6, 0xb8, 0x84, 0xd9, 0x0c, 0x27, 0x08, 0x81, 0x9b, 0xb4,
+ 0xcc, 0x58, 0x9c, 0x51, 0x84, 0x0e, 0xc7, 0x6d, 0x34, 0x89, 0x50, 0xc9,
+ 0x0f, 0x73, 0x02, 0x41, 0x00, 0xda, 0xde, 0x5e, 0x1a, 0xac, 0x1d, 0x1d,
+ 0xd7, 0xb9, 0x65, 0x26, 0x00, 0xf5, 0xd4, 0xe4, 0x28, 0x84, 0x86, 0x2f,
+ 0x00, 0x9c, 0x41, 0x00, 0x52, 0xe1, 0x47, 0x91, 0xc0, 0x52, 0x05, 0x4e,
+ 0x0f, 0x2f, 0x0d, 0xca, 0x9b, 0x3d, 0x89, 0x41, 0xbf, 0xee, 0x9f, 0xa1,
+ 0xe6, 0x9d, 0xa4, 0xeb, 0x45, 0x7f, 0xe3, 0xcb, 0xa4, 0x6b, 0x0a, 0xe2,
+ 0x7e, 0xb0, 0x87, 0x5c, 0x40, 0xb1, 0x51, 0x11, 0x1d
+};
+unsigned int default_private_key_len = 609;
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @mainpage axTLS API
+ *
+ * @image html axolotl.jpg
+ *
+ * The axTLS library has features such as:
+ * - The TLSv1 SSL client/server protocol
+ * - No requirement to use any openssl libraries.
+ * - A choice between AES block (128/256 bit) and RC4 (128 bit) stream ciphers.
+ * - RSA encryption/decryption with variable sized keys (up to 4096 bits).
+ * - Certificate chaining and peer authentication.
+ * - Session resumption, session renegotiation.
+ * - ASN.1, X.509, PKCS#8, PKCS#12 keys/certificates with DER/PEM encoding.
+ * - Highly configurable compile time options.
+ * - Portable across many platforms (written in ANSI C), and has language
+ * bindings in C, C#, VB.NET, Java, Perl and Lua.
+ * - Partial openssl API compatibility (via a wrapper).
+ * - A very small footprint (around 50-60kB for the library in 'server-only'
+ * mode).
+ * - No dependencies on sockets - can use serial connections for example.
+ * - A very simple API - ~ 20 functions/methods.
+ *
+ * A list of these functions/methods are described below.
+ *
+ * @ref c_api
+ *
+ * @ref bigint_api
+ *
+ * @ref csharp_api
+ *
+ * @ref java_api
+ */
+#ifndef HEADER_SSL_H
+#define HEADER_SSL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+//#include "crypto.h"
+
+/* need to predefine before ssl_lib.h gets to it */
+#define SSL_SESSION_ID_SIZE 32
+
+#include "tls1.h"
+
+/* The optional parameters that can be given to the client/server SSL engine */
+#define SSL_CLIENT_AUTHENTICATION 0x00010000
+#define SSL_SERVER_VERIFY_LATER 0x00020000
+#define SSL_NO_DEFAULT_KEY 0x00040000
+#define SSL_DISPLAY_STATES 0x00080000
+#define SSL_DISPLAY_BYTES 0x00100000
+#define SSL_DISPLAY_CERTS 0x00200000
+#define SSL_DISPLAY_RSA 0x00400000
+
+/* errors that can be generated */
+#define SSL_OK 0
+#define SSL_NOT_OK -1
+#define SSL_ERROR_DEAD -2
+#define SSL_ERROR_CONN_LOST -256
+#define SSL_ERROR_SOCK_SETUP_FAILURE -258
+#define SSL_ERROR_INVALID_HANDSHAKE -260
+#define SSL_ERROR_INVALID_PROT_MSG -261
+#define SSL_ERROR_INVALID_HMAC -262
+#define SSL_ERROR_INVALID_VERSION -263
+#define SSL_ERROR_INVALID_SESSION -265
+#define SSL_ERROR_NO_CIPHER -266
+#define SSL_ERROR_BAD_CERTIFICATE -268
+#define SSL_ERROR_INVALID_KEY -269
+#define SSL_ERROR_FINISHED_INVALID -271
+#define SSL_ERROR_NO_CERT_DEFINED -272
+#define SSL_ERROR_NOT_SUPPORTED -274
+#define SSL_X509_OFFSET -512
+#define SSL_X509_ERROR(A) (SSL_X509_OFFSET+A)
+
+/* these are all the alerts that are recognized */
+#define SSL_ALERT_CLOSE_NOTIFY 0
+#define SSL_ALERT_UNEXPECTED_MESSAGE 10
+#define SSL_ALERT_BAD_RECORD_MAC 20
+#define SSL_ALERT_HANDSHAKE_FAILURE 40
+#define SSL_ALERT_BAD_CERTIFICATE 42
+#define SSL_ALERT_ILLEGAL_PARAMETER 47
+#define SSL_ALERT_DECODE_ERROR 50
+#define SSL_ALERT_DECRYPT_ERROR 51
+#define SSL_ALERT_INVALID_VERSION 70
+
+/* The ciphers that are supported */
+#define SSL_AES128_SHA 0x2f
+#define SSL_AES256_SHA 0x35
+#define SSL_RC4_128_SHA 0x05
+#define SSL_RC4_128_MD5 0x04
+
+/* build mode ids' */
+#define SSL_BUILD_SKELETON_MODE 0x01
+#define SSL_BUILD_SERVER_ONLY 0x02
+#define SSL_BUILD_ENABLE_VERIFICATION 0x03
+#define SSL_BUILD_ENABLE_CLIENT 0x04
+#define SSL_BUILD_FULL_MODE 0x05
+
+/* offsets to retrieve configuration information */
+#define SSL_BUILD_MODE 0
+#define SSL_MAX_CERT_CFG_OFFSET 1
+#define SSL_MAX_CA_CERT_CFG_OFFSET 2
+#define SSL_HAS_PEM 3
+
+/* default session sizes */
+#define SSL_DEFAULT_SVR_SESS 5
+#define SSL_DEFAULT_CLNT_SESS 1
+
+/* X.509/X.520 distinguished name types */
+#define SSL_X509_CERT_COMMON_NAME 0
+#define SSL_X509_CERT_ORGANIZATION 1
+#define SSL_X509_CERT_ORGANIZATIONAL_NAME 2
+#define SSL_X509_CA_CERT_COMMON_NAME 3
+#define SSL_X509_CA_CERT_ORGANIZATION 4
+#define SSL_X509_CA_CERT_ORGANIZATIONAL_NAME 5
+
+/* SSL object loader types */
+#define SSL_OBJ_X509_CERT 1
+#define SSL_OBJ_X509_CACERT 2
+#define SSL_OBJ_RSA_KEY 3
+#define SSL_OBJ_PKCS8 4
+#define SSL_OBJ_PKCS12 5
+
+/**
+ * @defgroup c_api Standard C API
+ * @brief The standard interface in C.
+ * @{
+ */
+
+/**
+ * @brief Establish a new client/server context.
+ *
+ * This function is called before any client/server SSL connections are made.
+ *
+ * Each new connection will use the this context's private key and
+ * certificate chain. If a different certificate chain is required, then a
+ * different context needs to be be used.
+ *
+ * There are two threading models supported - a single thread with one
+ * SSL_CTX can support any number of SSL connections - and multiple threads can
+ * support one SSL_CTX object each (the default). But if a single SSL_CTX
+ * object uses many SSL objects in individual threads, then the
+ * CONFIG_SSL_CTX_MUTEXING option needs to be configured.
+ *
+ * @param options [in] Any particular options. At present the options
+ * supported are:
+ * - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if the server
+ * authentication fails. The certificate can be authenticated later with a
+ * call to ssl_verify_cert().
+ * - SSL_CLIENT_AUTHENTICATION (server only): Enforce client authentication
+ * i.e. each handshake will include a "certificate request" message from the
+ * server. Only available if verification has been enabled.
+ * - SSL_DISPLAY_BYTES (full mode build only): Display the byte sequences
+ * during the handshake.
+ * - SSL_DISPLAY_STATES (full mode build only): Display the state changes
+ * during the handshake.
+ * - SSL_DISPLAY_CERTS (full mode build only): Display the certificates that
+ * are passed during a handshake.
+ * - SSL_DISPLAY_RSA (full mode build only): Display the RSA key details that
+ * are passed during a handshake.
+ *
+ * @param num_sessions [in] The number of sessions to be used for session
+ * caching. If this value is 0, then there is no session caching. This option
+ * is not used in skeleton mode.
+ * @return A client/server context.
+ */
+EXP_FUNC SSL_CTX * STDCALL ssl_ctx_new(uint32_t options, int num_sessions);
+
+/**
+ * @brief Remove a client/server context.
+ *
+ * Frees any used resources used by this context. Each connection will be
+ * sent a "Close Notify" alert (if possible).
+ * @param ssl_ctx [in] The client/server context.
+ */
+EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx);
+
+/**
+ * @brief (server only) Establish a new SSL connection to an SSL client.
+ *
+ * It is up to the application to establish the logical connection (whether it
+ * is a socket, serial connection etc).
+ * @param ssl_ctx [in] The server context.
+ * @param client_fd [in] The client's file descriptor.
+ * @return An SSL object reference.
+ */
+EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd);
+
+/**
+ * @brief (client only) Establish a new SSL connection to an SSL server.
+ *
+ * It is up to the application to establish the initial logical connection
+ * (whether it is a socket, serial connection etc).
+ *
+ * This is a blocking call - it will finish when the handshake is complete (or
+ * has failed).
+ * @param ssl_ctx [in] The client context.
+ * @param client_fd [in] The client's file descriptor.
+ * @param session_id [in] A 32 byte session id for session resumption. This
+ * can be null if no session resumption is being used or required. This option
+ * is not used in skeleton mode.
+ * @param sess_id_size The size of the session id (max 32)
+ * @return An SSL object reference. Use ssl_handshake_status() to check
+ * if a handshake succeeded.
+ */
+EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const uint8_t *session_id, uint8_t sess_id_size);
+
+/**
+ * @brief Free any used resources on this connection.
+
+ * A "Close Notify" message is sent on this connection (if possible). It is up
+ * to the application to close the socket or file descriptor.
+ * @param ssl [in] The ssl object reference.
+ */
+EXP_FUNC void STDCALL ssl_free(SSL *ssl);
+
+/**
+ * @brief Read the SSL data stream.
+ * The socket must be in blocking mode.
+ * @param ssl [in] An SSL object reference.
+ * @param in_data [out] If the read was successful, a pointer to the read
+ * buffer will be here. Do NOT ever free this memory as this buffer is used in
+ * sucessive calls. If the call was unsuccessful, this value will be null.
+ * @return The number of decrypted bytes:
+ * - if > 0, then the handshaking is complete and we are returning the number
+ * of decrypted bytes.
+ * - SSL_OK if the handshaking stage is successful (but not yet complete).
+ * - < 0 if an error.
+ * @see ssl.h for the error code list.
+ * @note Use in_data before doing any successive ssl calls.
+ */
+EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data);
+
+/**
+ * @brief Write to the SSL data stream.
+ * The socket must be in blocking mode.
+ * @param ssl [in] An SSL obect reference.
+ * @param out_data [in] The data to be written
+ * @param out_len [in] The number of bytes to be written.
+ * @return The number of bytes sent, or if < 0 if an error.
+ * @see ssl.h for the error code list.
+ */
+EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len);
+
+/**
+ * @brief Find an ssl object based on a file descriptor.
+ *
+ * Goes through the list of SSL objects maintained in a client/server context
+ * to look for a file descriptor match.
+ * @param ssl_ctx [in] The client/server context.
+ * @param client_fd [in] The file descriptor.
+ * @return A reference to the SSL object. Returns null if the object could not
+ * be found.
+ */
+EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd);
+
+/**
+ * @brief Get the session id for a handshake.
+ *
+ * This will be a 32 byte sequence and is available after the first
+ * handshaking messages are sent.
+ * @param ssl [in] An SSL object reference.
+ * @return The session id as a 32 byte sequence.
+ * @note A SSLv23 handshake may have only 16 valid bytes.
+ */
+EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl);
+
+/**
+ * @brief Get the session id size for a handshake.
+ *
+ * This will normally be 32 but could be 0 (no session id) or something else.
+ * @param ssl [in] An SSL object reference.
+ * @return The size of the session id.
+ */
+EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl);
+
+/**
+ * @brief Return the cipher id (in the SSL form).
+ * @param ssl [in] An SSL object reference.
+ * @return The cipher id. This will be one of the following:
+ * - SSL_AES128_SHA (0x2f)
+ * - SSL_AES256_SHA (0x35)
+ * - SSL_RC4_128_SHA (0x05)
+ * - SSL_RC4_128_MD5 (0x04)
+ */
+EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl);
+
+/**
+ * @brief Return the status of the handshake.
+ * @param ssl [in] An SSL object reference.
+ * @return SSL_OK if the handshake is complete and ok.
+ * @see ssl.h for the error code list.
+ */
+EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl);
+
+/**
+ * @brief Retrieve various parameters about the axTLS engine.
+ * @param offset [in] The configuration offset. It will be one of the following:
+ * - SSL_BUILD_MODE The build mode. This will be one of the following:
+ * - SSL_BUILD_SERVER_ONLY (basic server mode)
+ * - SSL_BUILD_ENABLE_VERIFICATION (server can do client authentication)
+ * - SSL_BUILD_ENABLE_CLIENT (client/server capabilties)
+ * - SSL_BUILD_FULL_MODE (client/server with diagnostics)
+ * - SSL_BUILD_SKELETON_MODE (skeleton mode)
+ * - SSL_MAX_CERT_CFG_OFFSET The maximum number of certificates allowed.
+ * - SSL_MAX_CA_CERT_CFG_OFFSET The maximum number of CA certificates allowed.
+ * - SSL_HAS_PEM 1 if supported
+ * @return The value of the requested parameter.
+ */
+EXP_FUNC int STDCALL ssl_get_config(int offset);
+
+/**
+ * @brief Display why the handshake failed.
+ *
+ * This call is only useful in a 'full mode' build. The output is to stdout.
+ * @param error_code [in] An error code.
+ * @see ssl.h for the error code list.
+ */
+EXP_FUNC void STDCALL ssl_display_error(int error_code);
+
+/**
+ * @brief Authenticate a received certificate.
+ *
+ * This call is usually made by a client after a handshake is complete and the
+ * context is in SSL_SERVER_VERIFY_LATER mode.
+ * @param ssl [in] An SSL object reference.
+ * @return SSL_OK if the certificate is verified.
+ */
+EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl);
+
+/**
+ * @brief Retrieve an X.509 distinguished name component.
+ *
+ * When a handshake is complete and a certificate has been exchanged, then the
+ * details of the remote certificate can be retrieved.
+ *
+ * This will usually be used by a client to check that the server's common
+ * name matches the URL.
+ *
+ * A full handshake needs to occur for this call to work properly.
+ *
+ * @param ssl [in] An SSL object reference.
+ * @param component [in] one of:
+ * - SSL_X509_CERT_COMMON_NAME
+ * - SSL_X509_CERT_ORGANIZATION
+ * - SSL_X509_CERT_ORGANIZATIONAL_NAME
+ * - SSL_X509_CA_CERT_COMMON_NAME
+ * - SSL_X509_CA_CERT_ORGANIZATION
+ * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME
+ * @return The appropriate string (or null if not defined)
+ * @note Verification build mode must be enabled.
+ */
+EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component);
+
+/**
+ * @brief Force the client to perform its handshake again.
+ *
+ * For a client this involves sending another "client hello" message.
+ * For the server is means sending a "hello request" message.
+ *
+ * This is a blocking call on the client (until the handshake completes).
+ *
+ * @param ssl [in] An SSL object reference.
+ * @return SSL_OK if renegotiation instantiation was ok
+ */
+EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl);
+
+/**
+ * @brief Process a file that is in binary DER or ASCII PEM format.
+ *
+ * These are temporary objects that are used to load private keys,
+ * certificates etc into memory.
+ * @param ssl_ctx [in] The client/server context.
+ * @param obj_type [in] The format of the file. Can be one of:
+ * - SSL_OBJ_X509_CERT (no password required)
+ * - SSL_OBJ_X509_CACERT (no password required)
+ * - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported)
+ * - SSL_OBJ_PKCS8 (RC4-128 encrypted data supported)
+ * - SSL_OBJ_PKCS12 (RC4-128 encrypted data supported)
+ *
+ * PEM files are automatically detected (if supported). The object type is
+ * also detected, and so is not relevant for these types of files.
+ * @param filename [in] The location of a file in DER/PEM format.
+ * @param password [in] The password used. Can be null if not required.
+ * @return SSL_OK if all ok
+ * @note Not available in skeleton build mode.
+ */
+EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, const char *filename, const char *password);
+
+/**
+ * @brief Process binary data.
+ *
+ * These are temporary objects that are used to load private keys,
+ * certificates etc into memory.
+ * @param ssl_ctx [in] The client/server context.
+ * @param obj_type [in] The format of the memory data.
+ * @param data [in] The binary data to be loaded.
+ * @param len [in] The amount of data to be loaded.
+ * @param password [in] The password used. Can be null if not required.
+ * @return SSL_OK if all ok
+ * @see ssl_obj_load for more details on obj_type.
+ */
+EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int obj_type, const uint8_t *data, int len, const char *password);
+
+#ifdef CONFIG_SSL_GENERATE_X509_CERT
+/**
+ * @brief Create an X.509 certificate.
+ *
+ * This certificate is a self-signed v1 cert with a fixed start/stop validity
+ * times. It is signed with an internal private key in ssl_ctx.
+ *
+ * @param ssl_ctx [in] The client/server context.
+ * @param options [in] Not used yet.
+ * @param dn [in] An array of distinguished name strings. The array is defined
+ * by:
+ * - SSL_X509_CERT_COMMON_NAME (0)
+ * - If SSL_X509_CERT_COMMON_NAME is empty or not defined, then the
+ * hostname will be used.
+ * - SSL_X509_CERT_ORGANIZATION (1)
+ * - If SSL_X509_CERT_ORGANIZATION is empty or not defined, then $USERNAME
+ * will be used.
+ * - SSL_X509_CERT_ORGANIZATIONAL_NAME (2)
+ * - SSL_X509_CERT_ORGANIZATIONAL_NAME is optional.
+ * @param cert_data [out] The certificate as a sequence of bytes.
+ * @return < 0 if an error, or the size of the certificate in bytes.
+ * @note cert_data must be freed when there is no more need for it.
+ */
+EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data);
+#endif
+
+/**
+ * @brief Return the axTLS library version as a string.
+ */
+EXP_FUNC const char * STDCALL ssl_version(void);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+all:
+
+AXTLS_HOME=../..
+
+include $(AXTLS_HOME)/config/.config
+include $(AXTLS_HOME)/config/makefile.conf
+
+ifdef CONFIG_PERFORMANCE_TESTING
+all: performance
+endif
+
+ifdef CONFIG_SSL_TEST
+all: ssltesting
+endif
+
+include $(AXTLS_HOME)/config/makefile.post
+
+ifndef CONFIG_PLATFORM_WIN32
+performance: $(AXTLS_HOME)/$(STAGE)/perf_bigint
+ssltesting: $(AXTLS_HOME)/$(STAGE)/ssltest
+LIBS=$(AXTLS_HOME)/$(STAGE)
+
+$(AXTLS_HOME)/$(STAGE)/perf_bigint: perf_bigint.o $(LIBS)/libaxtls.a
+ $(CC) $(LDFLAGS) -o $@ $^ -L $(LIBS) -laxtls
+
+$(AXTLS_HOME)/$(STAGE)/ssltest: ssltest.o $(LIBS)/libaxtls.a
+ $(CC) $(LDFLAGS) -o $@ $^ -lpthread -L $(LIBS) -laxtls
+else
+performance: $(AXTLS_HOME)/$(STAGE)/perf_bigint.exe
+ssltesting: $(AXTLS_HOME)/$(STAGE)/ssltest.exe
+
+CRYPTO_PATH="$(AXTLS_INCLUDE)crypto\\"
+AXTLS_SSL_PATH="$(AXTLS_INCLUDE)ssl\\"
+
+CRYPTO_OBJ=\
+ $(CRYPTO_PATH)aes.obj \
+ $(CRYPTO_PATH)bigint.obj \
+ $(CRYPTO_PATH)crypto_misc.obj \
+ $(CRYPTO_PATH)hmac.obj \
+ $(CRYPTO_PATH)md2.obj \
+ $(CRYPTO_PATH)md5.obj \
+ $(CRYPTO_PATH)rc4.obj \
+ $(CRYPTO_PATH)rsa.obj \
+ $(CRYPTO_PATH)sha1.obj
+
+OBJ=\
+ $(AXTLS_SSL_PATH)asn1.obj \
+ $(AXTLS_SSL_PATH)gen_cert.obj \
+ $(AXTLS_SSL_PATH)loader.obj \
+ $(AXTLS_SSL_PATH)openssl.obj \
+ $(AXTLS_SSL_PATH)os_port.obj \
+ $(AXTLS_SSL_PATH)p12.obj \
+ $(AXTLS_SSL_PATH)x509.obj \
+ $(AXTLS_SSL_PATH)tls1.obj \
+ $(AXTLS_SSL_PATH)tls1_svr.obj \
+ $(AXTLS_SSL_PATH)tls1_clnt.obj
+
+$(AXTLS_HOME)/$(STAGE)/perf_bigint.exe: perf_bigint.obj
+ $(LD) $(LDFLAGS) /out:$@ $? $(CRYPTO_OBJ) $(OBJ)
+
+$(AXTLS_HOME)/$(STAGE)/ssltest.exe: ssltest.obj
+ $(LD) $(LDFLAGS) /out:$@ $? $(CRYPTO_OBJ) $(OBJ)
+endif
+
+clean::
+ -@rm -f $(AXTLS_HOME)/$(STAGE)/perf_bigint* $(AXTLS_HOME)/$(STAGE)/ssltest*
+
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQCnZdk20fYWh8O6kDTt0AuJWyp0YIrb7W1UNNMPXI5wA4J59IVj
+Nmk5wocm9+Hqzbg7rORAN/mHPBhzLAjhnm1HODs36hW15DtbDkkH4wCM/Tsyv79m
+n0xq1V6peK3t9vi2D4p/IRjHkYR2jm+BeknopijhY0kHHfpGTHa2DnVirwIDAQAB
+AoGAd4Ia5SxYiBU9A0BYyT8yPUm8sYELIaAL4YYk+F6Xwhh/Whnb8MyzquzaGFP4
+Ee30jYYNHlvX5VheDDtvy8OTN5FgKNNdzvW15iA4Hxje04ZI7W87G7OIxm7aYRid
+sG4XqZBtsOdj33IRd9hgozywGJ2qRqS6nn2KxRv1w07RniECQQDZAlKxijdn+vQ7
+8/8mXzC+FwQtzeTUCuLrBJcos9I/591ABoxYkWcYLxpFqgCEVwb1qfPBJkL07JPt
+Fu6CTnBFAkEAxXmUBs47x5QM99qyBO5UwW0Ksrm/WD4guaaxzQShMt/HzgJl613z
+/x4FtxiQJHAr6r2K0t5xTJx89LVKuouYYwJAImue6DAvJ5wDfzrtXo28snn+HLHK
+uONdKL/apgcXszE4w74GJsoxWwGlniUf3d3b6b1iP2GtPyIDOJjpjduZLQJAE4jS
+VtYB3d1MZxxQLeKxqayyuTlcr0r+C79sqT5C//hZGIzuLhlOMLd0k0cvwxsBjSgQ
+2ok8pfp49fAVI1z5xwJAVmJgLc/mSti5A2q3c8HW8qvMJEDPWbpb7p8pg4ePtpa8
+EE3TO4O4J2H+k40C397km4yZXdkNQsiT1zVljJZpiw==
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIB3zCCAUgCCQCdbnM4pjqlWjANBgkqhkiG9w0BAQUFADA0MTIwMAYDVQQKEylh
+eFRMUyBQcm9qZWN0IERvZGd5IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNjA2
+MDcxMTQ0MzJaFw0zMzEwMjMxMTQ0MzJaMDQxMjAwBgNVBAoTKWF4VExTIFByb2pl
+Y3QgRG9kZ3kgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQCnZdk20fYWh8O6kDTt0AuJWyp0YIrb7W1UNNMPXI5wA4J59IVj
+Nmk5wocm9+Hqzbg7rORAN/mHPBhzLAjhnm1HODs36hW15DtbDkkH4wCM/Tsyv79m
+n0xq1V6peK3t9vi2D4p/IRjHkYR2jm+BeknopijhY0kHHfpGTHa2DnVirwIDAQAB
+MA0GCSqGSIb3DQEBBQUAA4GBAB0LgNo0oCcwIie5plgwwFybQ8x95q6e3wndM/Mp
+3gjcAFbGuchpo3dfFlTcRI0KyERb3q1MVxPM4sff9nT7EdHVyK9s8/ITkP2dcTKc
+flbcTEfJVIeM8L2P5F41Hvn9GuGcMW8EmsC06gdbp1LLnqsdrXdMNBsAUBXfgPrU
++UcZ
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDUIg4NEiu/diDAlbsWbTAhMKw4iBf2X5ohGJdTO6vhGQdEkhBR
+Bgzdl9+0LbVDJY8YStUghwnuztT+IpNCrUtXtRK8Cn3QP+buzSe2ZGPVoEJIbvV/
+QudK/WuUDyTNSRTtW4S3RO36KqtbT6xh1QGTXV3I8sp7qwmcysklqZW8GwIDAQAB
+AoGBAKBEDkuPw9+Ftp7pQIxj963LoQGgyEHJ3p9Mfd9TQLrydsw2cf9Uy9mKiWcN
+9VkCgkZ/Gt/VRgrW1pIduxXv6O+8S14An+2mTayy3Ga1N6MulD7OHQP9kqR4j8TT
+xaYPR/1skjhQ+Y0Uw4NEa3OkQp6lAUEp1aVX/mTfIZBguaUxAkEA/H543Ha6wbUV
+iB+pHaBgj1nzarmuEey6kqqs7X0zoZory1X6bdpJ6l0/4qICa6aq+pt/7ywJCNoI
+CPK3mL2zGQJBANcUHRBe7/HRWrJNIqB2WDA/gJshq4xOAiIBXWk1wpabvpkCnUjQ
+rip5CAL3hXDnCQswZxRN/v7B4IlSxkKiY1MCQQCsL0MUdRMejfLFBXI6defjWiAZ
+I86FAr6oziNnQP44sf4zh8pjp3zIihbK4lhsORhYFjrES29NzgG0uHBjhNnhAj97
+gBEwVVNyh8SMnb5EZbA+BDjU24CmECUpYZ9Bypzx3nyTX+zw4uMfgGAZVAhLzF5l
+DmYiQqcpoipMsDsoCBcCQQCxBYSicXIPG8G6ZuFbgXFcZR7llgq74mbhfGuVEGbP
+qS6ldhJb/IG9O3MFlRwdU44YyJ8QGpBKWF94OpIduF6w
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBfTAcBgoqhkiG9w0BDAEBMA4ECN+YmhCv0ILdAgIIAASCAVu0QEfMkp0xUsNq
+0Ek4Nsa/uxcs8N/2P7Ae7qCakkvsdRvvPPH0y+wuj5NgrG6WpPeeEx9fI2oNNTfC
+pwncH0Xm99ofVrgMX6XC45LDZtzXNSZd4TdBP6xvlYXbuGegp5GPJ8emzscHCFhC
+JfPHemRAcB7DhiWukPosuSUr5R8OluEMJrQLHuQtlDAvMjLEI98lSchPxF8LKCk3
+SS2uCcmc+4WiR0nHG9BOaGi38+PytHAnbfo1mfVSQzLfgLicMAVGysfQ9QOgpQOO
+ygYfM/s7Duwbl0rshyXVJP+7BpYJnPtHvO4BTiizU7ZEr4WBiEnnANDrupSdsxeH
++cxZo70YJVdoPdgMd2ke6EIkUhp7HughFg+okldlEtJA4muKeEzwAxZu0TqxOtZ8
+UYRS4Ygk+rN7Y0qTKSYwSkrFBwUDkpctYjRUOeAZ/mYMKWmMn1ejAb5Is7bjEIxl
+tw==
+-----END ENCRYPTED PRIVATE KEY-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDY4L8V3uqv6NX9C6ios9dGXacmbAy12bzG+MB40PZWZfgpSA57
+C6Ylfuh7eW845bW39OCckWD0BvNAHvmRGakvR0O1mx7c9qocSXkhKMuqSXPZCQVM
+AvJMTWwcgKcUkUT8ErPh5+NPRLqMw3Q56EzQ1EwkYbRAlYzACrcCOTGFkwIDAQAB
+AoGBAJQHcuW+rXk79zMsjgX4GmvQ6JH1FgfZglxc1SKhnkICf4vNvvSFUvYs1QnS
+LPQs9geFgPnc0Mw/IjEV80nyteJpmQQESSHbn6FUWvrk2fkHBf+aZaTr8kfOVsdy
+SUhc6BTXjyXMSSkGalR7F9ye1FPw9Z6FJaHrPekvuZz24YCBAkEA7gJ4x3iFBJfM
+Nr3WEeLHOdk0UXJvig/NiDIzm8enA3fZgjW23R/CwRNAg1XrYOuBjgwWYrS0POsI
+gJx50zjK8QJBAOlFXy4WzJNQQLZ5vDjgVmhQ0y9zjIwqDoFKirvM8GQ0Rp8HfSK2
++UasVyOMHuvTBU2og2pn9qaxq47B7+998MMCQC/GWT4Y6AJzAe/fDTBL6BepjMHo
+iZEZ+PSktw1G9zRQA14KsCkUrgAZgDKctYGf5EKCFKA9i4xK1UsTnbSTStECQGSM
+g3dhWnMRP6OoG4rEoFo8pJsqimWMZ04xrFVBBEmdAuffmX/SMObWuITZDCcIgZu0
+zFicUYQOx200iVDJD3MCQQDa3l4arB0d17llJgD11OQohIYvAJxBAFLhR5HAUgVO
+Dy8Nyps9iUG/7p+h5p2k60V/48ukawrifrCHXECxUREd
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAwqC/2/rPcAZEs5/ejT3ZL8Q3Pfdna2WC44i6HYCnCnbOIcW+
+6Xub2IXGwRwQBFy+mRE9WjqJ8kuOEkSt6e+8wAhLdag7WXJ6cxoag110t5FEHSyd
+GfvFFyUNjMJhLd+EmaQTTpEv9MJPJj0Zdruh1EjyRxa4HJmiD9t7XmWyCfSmM0qM
+kgJ0J6s62rRMBX+l/NEEX2VzJugdZAU671RWYOncuxX/2jUYlvIqI1l3SP8acMU5
+BtfLsYMj08lNHOjgZCPRwkdjsl6U5EqIizKZygw1FNugVEDHnL2MAYXwqzX3pGr/
+72Biy+J4TSH6lt0stszS5m8BirMgYr2FFHslrQIDAQABAoIBAQDBTa0gzEupJOCp
+UvhUagBDO+vuBMJX3XuRh6PqV3QQpYz36BJEjXttIvkTpU6XNpIrLv8zlX6bAsW5
+iTL+bRiX1eU0l4FSxqutlFiO7oxVIdd37m6edvv6j9eUXR7t09k8S8TNPNBXlYHN
+JdQbpCIH2OehCYSVC1X1z/UI/ZJF5VSn7UsYgwReK102svfHtll85K0TgHMir9Rx
+Dlh0vYx3IJi2nDOTyJ4JekkyEAcYd3D6JUd0JujcN3Ev3EOsns5GXzN6KYvinmYf
+Z1bA/HEMNb9ZS9bdsoAvyeJAeGp8ejzuJVHGL0kATgrAamb58fPS+A8Guk5eN5KY
+5zvzNrJVAoGBAPVWvPrDOJX2ZI7poJ269xFteTWWIYA+r+YRRkhMBMcD08H5gs6e
+QMWU9w8qjgSmbNkx8skkhn/gV5R3CbVYYRR2osrZIoOayWAsJmY0bHFTIvooYhfp
+3lPVNIPzUpRObFksamtrsK+zpx5qOdigNhComXLsGWKfrN9Yvkb7YzIDAoGBAMsV
+4UVH9WH0IKV1vx3QtrGEb69SZMpbmM8ZsPvaPgq00In9udY4w5V2ZygfTiq0ChUY
+fYy6BeO6Gyp2DSABdz1AUH+0wcnNrHJghFtxtsq4Thu4MHU6ftc+JCGfSeWUapfh
+KiHS0TEguRFcYSHnM1IDEiU4aTHY59FRUWMI2hKPAoGAIVfviTk9GIyLMC0qaiV9
+7L1vKsxDs1VRvLf+UFcckxu/DO7nS0OQ1Amh5krHUHR5+K7kK1gue3S3EnN3O1FO
+qGRTTbRjD3XbBpoZgeyADIrbBxqz8kITuFsSrxhD0eoyqY/yyrSxJ8AH54dSY1Gq
+52qyqD7UWGYRLa229pi165cCgYAd7/rGWMY+i1toqMPkpEjaQFiqcq3y+q+7D+F8
+Lv7oWyFGxkVn4/RJCyxHyN2gA+xckcCoRx/pIx0wFDj5F945BEsZmE7c7dnW/o1k
+YY39sk+pXGygS2A5YKq43h9pnYhdHU81rzsxT86YVZLoCYoSM+uv2vH+7Ce4PpGN
+1Nc41wKBgDUrYyfDB1RzdB63FwPRax5uLjewnuMXyZhy70ZkiGh0XBuQt2aCLeCZ
+HpAyGcJryxdDFYA+UwJoSWjaW9ku0lp+GxX1F+cResrRHTi70w9czwGVaKmcG3kI
+fFjG7w8nkiw5J7IRH7SxmNbmAv8L0Iy6jvoWLFB+EdUGWllkjCmJ
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEA/Ce0mV0qytAwDPrjXRBlUh2gdKs2thDw3N18owXVrSUFq9Sw
+AaMNrmep9DR9MEALcdMm3GCEJ7sOOiEQcqTz25di36WJDe+jo1z5nD2XZsPIsp9+
+k51Vz+W3B4vsXJAgzV+XZbmv9L0598VEwkpeI3Uc9et8ZhGvDPoHZyBQG1KAj6h3
+AKZ1+NthrhajxlrndQZ5Du/R5DSUQOBcCHHdzZgihdfF97Yn/kp1mele1ElZMlqg
+BtpDi1TEQJ9XBtjCW0epFAm5THQ3gMx5DCcqB/cNYdZWqpZ0AuwATm61+46m4fFK
+g3YAYPOi/74aKFuIQBw/lc8W//SV1x8SL/hf2XIdvSa9QhroNN0d3Xu2EUQzXZxo
+PRMKzOqKfwlZW7ozT6hFBwPMh8yfhoPugq2TvqBjke1s3gmvwTgEcf+gY97qXiZC
+X5bh/ehmnZ7vIblYFUD2yMlsKaXGJYweh3WKJlQnh71wQUg2Mxa6ig8ijrEozNlw
+YfPCQFrNLqQfJOwdx90dy7hpUyUn1wo39p6wmC6n9ex4zeKbO4ndSp+/AJ+d5Qp8
+zoMzwneYV9LBQG8ry4uwzDkSWKb/WghsEbQ9O3sGIuI13SlT/B64v3bLb5AHagI8
+zS3kPsshjKhkcc2W9MKRBU2wIeCsNS052kaUq3rPMSBROrALmLk3en/Dq48CAwEA
+AQKCAgEArPMy7So5Cqjm/FAtGI0BYeRORReWTCSsgGEudsauu7a0ABq+qjDDVodl
+y8kgwLJ85xKUCf3tRy8G4BoDpQ688DYSrCFnMvbWP1urHV4ldWf+RX4eHHODAzil
+ZHi1ovt8dEEHn89P/8a2dtqIgdbuYNWYCpj9Vyjz7yujXjmMmGDrKx26meiS7CDV
+C8odhRSewuawq+0UArmJokIA/g3Tu4uIylKoR3JaVhGOPgYSc/rnQiFkt66HO47l
+mQlxcJHGJUOulb7hqK3hz+bvc8V9D7+FH0EbaqANbF+hCirniWZb0odku2x5cAZM
+G6uxV1MIzihR+Jf1R5PkHowCNoLegfM45tnuadP1+8Kezv1SsqkrkMEwfb0QN19C
+2+bmnwYXagUgg/A2q2Shg9h4/3cpwdrDzGHD8IttGlzLR8HnlHkcAK3qRNqy9h60
+JDEW/tOurUSZBXjU9ZyoZSukcK3+yUjCDWS92wMOBlUQGh4/HCOOizahe6lhn2nT
++jkBvl38c+7GBKR0VyCisFi++FukMBbyU/hNNFByZxOj0b/+YVYI0qwM5oDzLhJH
+69/VhxMx0xVt9/kOOO3yhdGjKCZztPZZm5mg2OzzXmf4im+hPSg0/OrdXrVNk4v/
+w7ouUQHSa3+rAAu8BJFF2rTWA7rjecVEnk6c77I6dEVYXdCfz8kCggEBAP+IJLHo
+7Cs51qPcRKQc633phJa3pFGf6O8xN6pl8z1ZQX0voZyROKJLTytSH+zmPdmggUeg
+7CRoV8BKY49YiOxO2Kx8BPfftItS9yvA3O9ztcdzQa72nYusMWwvj0yFU8DbYfnx
+yYw59F/1pdPKFN83Sj4MJAOb4nAxBP1GiZvsPAgcTpf/197NLNHwUDdk/TXDtTLa
+lx4uTn/SJDQuvsCCLBKyx7FdN5NPRN2kIKUWZLd7HRu2EhcSlATwf4TUPZz7atKN
+2FD0svErpPOAspNPtnNj3RgeunGVqS2oi/XueuveNNCYLkcV8/UaZm85LBrPoEre
+23qK9/ZN0SD534sCggEBAPyd+nD71pScrM0TI4Lc3jMNUKeZj3sT5rlhlkWlARhQ
+WPEWYYg5vs3zDiRpG4Xy3n9ey+M6Tuw+/XpcJZxhrLYFOqparxXPP4qc+3EvtzpF
+OskLR/2/bVnESf6+pQspmwW6G4IJ9vOmIJeUj9zeU0txuxKkjhAmInCnMxJOlYRm
+xeLymuo5LZxrXmSXcX4cyZ0/4bF2L3IE5vH7ffdWXWYzW9wP7M4sFp+0iKjHuhC1
+gB6Qg0Mp0TVNUt0ZEelFLEJdA2lbbZ5yHhNXuhOxW/l3ASSe9tjTpy7yBSwBOpFG
+l7QGISfJVEFfjyn7yWBYj5LDGnitlP4TtN8zyy6cJI0CggEAPRwY8ncqq7e8Thmq
+TLkh1E3ZSJYIdQDSGwnhLx4MirpiwAZ5FtFgAugRueF9AxGY7wfEgxXIA3j0q2be
+4nQg4qqEhNNv+LuGGN+xfsQz0gwRB+7XYXlW+gUnGKFTGtCz0+ZjSvv44FEn0R8V
+Fk44qZ02YxpSLo7EG2KNt+h7lk9rl+D1JsKnpH/a3SYkeOrs50OzfMLr6urWGRlv
+UQ9wzOcUlTAuM4uAc/k8FelfaTuuwHZv4qWrM9tcjMXbKS/8wCMcS9hiSBINDUIL
+w7QegL5KetQCFveaTPmmqOWq+xiaSvgsF0qdnqBwZEh5ANZiZtMKmX0sbeT4Ie5A
+OiunuwKCAQBlSlrvDqu9rwzCtdfZUwJtaftbGIGlkhdDYdPFXSIRQ7ZGBPlai/zr
+y3dyNgrpLLb2T2ZlWC3pIGC2vVf/WlLMMVCSmgX2MsGBrOxNOBq57KRjlHhrUGRi
+SAh7cqnuzeHw6+y3uZMhow0Semks4KB5ccLW+NBVvVS14vThdE0TZ7oVA74GCKM3
+Qv34S5kgPh7BRKoUZBUmHL0VbgfWMvUEU7eTh3cmPBteMh9RvbPnmz8iAkP/nDbc
+roJ5UOITrL7QZUdG6XgMvik9DEH6P3Vnk8YLjwnfaw5wDm7wdBWtxqZxcru8nkeA
+ZvaamPDoBtqauExW8xL4xaISlUv1BnrJAoIBAQCiEZk93GeRzYJFCO1YafsGYueX
+Pffgd9wM2TpObgaEw8OIfEpGQKDiR35fb0uVzNyI5fVU5D5tP0b3LfvtQXV12ryQ
+sVTA5YJcb8mRuUGy/AkjL54kNiZthUnlGHQjY3lqSyI1r5WxRIZBBRn5+g1eSZVq
+CYCGjEryKm7vw8Qcvy1+H2crcZ0rRyLTcfFCr1ZXlyEZu48ScOtxcIDHc7j4J0LO
+Peq2z0tbBojGkxFLX94J7zpRkWMPX9VHorEavDv7ZJwtgoXn3Lom0xHhO+JQaxY9
+FtJ79Ps9+SquXAnkhna4bbkrqrPM3+MAAV/S7bd1T1/8d4YiRQyaMHGS4Yr8
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIBPQIBAAJBANE7MF+pAUI9hm1yvkBuUcFJf1d1oS025cE9DyAa0SNt+nTSPiOw
+cPygat7sQYiE/lQVa2HFFmK4k0HxTz3/Lr0CAwEAAQJBAJF5xO2ONajX3GK2+B8W
+VVO+BYNK71DfranJCX46BxXI/Ra7wOSY0UWZYHVsZGWJxx41os0UBTg5FRq4DwWW
+AQECIQDo69eo39iQqjwhpAQxatMh2CWYT7gokyu56V+5o2V3fQIhAOX2b+tQxDsB
+w0J9UDN6CdwI5XbzveoP5fHTPS9j4rhBAiEA3c+y6Zx6dZHYf8TdRV5QwDtB2iGY
+4/L7Qimvwm6Lc1UCIQDDXWrVsocTTjsReJ6zLOHFcjVnqklU2W7T1E8tvKE3QQIh
+AMRpCFM7MrS2axuc8/HzGkqW/3AlIBqdZbilj5zHd2R0
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,B3A0D2BCEF4DE916D0BBA30A6885251B
+
+v8y74AGReaPLmDt6O8wir6hX1Ze8K4fVNkrLqfDMdW5E7jBXKO8riCMNmSjQ9fyh
+eTicej93+8krcIvSXKW18TdO+EWezQevgnLrAZQWaNPH2j4B+K5gm701uiiKFKVa
+1zngAOByePYlN6z4JLbiCyJRhxSo5zCaUYkKC2eGh8mlE64QmokPSCAj0wcCDzGh
+hdhBg1vm0GmaQwIDVn+8zMfahscXVMtBmyQf5YP4PQW2nqOt7aZHjBNdg9qnBpGw
+b6YuY7eZ4FgQvYcsNCi34NroJb9pkTrrF2F9Meb6+3So7jtMFG/YaJdCuXtf01g/
+Qm+XA5pJUtIUr/hLQjhkaOVUtXv/k0o/MR4k5CbAmboLt6YHf5V8+01vk0bvv5dI
+70pVdXMmx26xDZOGmjYzd93PWc+75jak3GN2fbWryQs=
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,F076229CDC2BCB3B8722E3865855B45C
+
+WFV9QWzr4tNmD+1OeQ7BceQg5LVQHp20Jo1Ax29lq8JTPzeObhtaU2MUHlcPKHUS
+vK4FyQxJ25CyMubbnaZqCCz9pNbseFuJ1tob9UqRmXkZ8HV3snRjJRbcctD+V9x+
+Ymi1GreXoDQtMp0FtMiFjPvIYciBQnaRv2ChMAnGXNbZXCxWWA9E5S3a+yWzo+gd
+wEcowL+SUac1PEDGHokhKn7nctvI9cC4hE6JmKM1sD68/U3rRPXMGqmC7umqyT5P
+gjWBb1uu0iRjFC9eQUsaKPxey5Be710GFlyf/Ff/tep7RhkryIWEPvIzYCBf6rhk
+3pysFgTjfiUuBYUNumjXr/q5hgdtb75788XUDxKwAoUx+m8gi0nJg35CN2nmQ054
+VJxcZlNv0wqnJ+GTTZeN6fiAhTpVtHsqHQomRSfaBiw=
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN PRIVATE KEY-----
+MIIBVwIBADANBgkqhkiG9w0BAQEFAASCAUEwggE9AgEAAkEA0TswX6kBQj2GbXK+
+QG5RwUl/V3WhLTblwT0PIBrRI236dNI+I7Bw/KBq3uxBiIT+VBVrYcUWYriTQfFP
+Pf8uvQIDAQABAkEAkXnE7Y41qNfcYrb4HxZVU74Fg0rvUN+tqckJfjoHFcj9FrvA
+5JjRRZlgdWxkZYnHHjWizRQFODkVGrgPBZYBAQIhAOjr16jf2JCqPCGkBDFq0yHY
+JZhPuCiTK7npX7mjZXd9AiEA5fZv61DEOwHDQn1QM3oJ3AjldvO96g/l8dM9L2Pi
+uEECIQDdz7LpnHp1kdh/xN1FXlDAO0HaIZjj8vtCKa/CbotzVQIhAMNdatWyhxNO
+OxF4nrMs4cVyNWeqSVTZbtPUTy28oTdBAiEAxGkIUzsytLZrG5zz8fMaSpb/cCUg
+Gp1luKWPnMd3ZHQ=
+-----END PRIVATE KEY-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIB1zCCAUACCQDxw4fA1PRXwzANBgkqhkiG9w0BAQUFADA0MTIwMAYDVQQKEylh
+eFRMUyBQcm9qZWN0IERvZGd5IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNjA2
+MDcxMTQ0MzJaFw0zMzEwMjMxMTQ0MzJaMCwxFjAUBgNVBAoTDWF4VExTIFByb2pl
+Y3QxEjAQBgNVBAMTCTEyNy4wLjAuMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
+gYEA2OC/Fd7qr+jV/QuoqLPXRl2nJmwMtdm8xvjAeND2VmX4KUgOewumJX7oe3lv
+OOW1t/TgnJFg9AbzQB75kRmpL0dDtZse3PaqHEl5ISjLqklz2QkFTALyTE1sHICn
+FJFE/BKz4efjT0S6jMN0OehM0NRMJGG0QJWMwAq3AjkxhZMCAwEAATANBgkqhkiG
+9w0BAQUFAAOBgQALRyRSfbZjeLyA3YdskEwzw1ynlwkcCU+bbrNaPkaSGseHFVnh
+iFzOauKWqjLswu14i+CQZpMUw5irMzXTfV1RCpy5EFhHepiVZP9MXYIZ+eoPXprL
+Midkym9YitDANvS5YzSl2jZQNknStzohM1s+1l8MmYO3sveLRMRec0GpAg==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIICWzCCAcQCCQDxw4fA1PRXxDANBgkqhkiG9w0BAQQFADA0MTIwMAYDVQQKEylh
+eFRMUyBQcm9qZWN0IERvZGd5IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNjA2
+MDcxMTQ0MzJaFw0zMzEwMjMxMTQ0MzJaMCwxFjAUBgNVBAoTDWF4VExTIFByb2pl
+Y3QxEjAQBgNVBAMTCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAMKgv9v6z3AGRLOf3o092S/ENz33Z2tlguOIuh2Apwp2ziHFvul7m9iF
+xsEcEARcvpkRPVo6ifJLjhJErenvvMAIS3WoO1lyenMaGoNddLeRRB0snRn7xRcl
+DYzCYS3fhJmkE06RL/TCTyY9GXa7odRI8kcWuByZog/be15lsgn0pjNKjJICdCer
+Otq0TAV/pfzRBF9lcyboHWQFOu9UVmDp3LsV/9o1GJbyKiNZd0j/GnDFOQbXy7GD
+I9PJTRzo4GQj0cJHY7JelORKiIsymcoMNRTboFRAx5y9jAGF8Ks196Rq/+9gYsvi
+eE0h+pbdLLbM0uZvAYqzIGK9hRR7Ja0CAwEAATANBgkqhkiG9w0BAQQFAAOBgQA8
+L1Zz9K6M/PQCYWrfnTjbPKY2rTB1OvSV0Uwy5KKPQRS1+oK9dx4K0miX+1ZvI1bo
+f7/1aFXOsW3dpTwYUSjJvTMjSwNUPKiB/q/xwA1mzsbIZsbnhIITU95mOJ3xFhgc
+YFdJ4saL7pppTzfOxZ+h9jWbDwgJJAwx/q+O72uE5w==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIDWzCCAsQCCQDxw4fA1PRXxTANBgkqhkiG9w0BAQQFADA0MTIwMAYDVQQKEylh
+eFRMUyBQcm9qZWN0IERvZGd5IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNjA2
+MDcxMTQ0MzJaFw0zMzEwMjMxMTQ0MzJaMCwxFjAUBgNVBAoTDWF4VExTIFByb2pl
+Y3QxEjAQBgNVBAMTCTEyNy4wLjAuMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
+AgoCggIBAPwntJldKsrQMAz6410QZVIdoHSrNrYQ8NzdfKMF1a0lBavUsAGjDa5n
+qfQ0fTBAC3HTJtxghCe7DjohEHKk89uXYt+liQ3vo6Nc+Zw9l2bDyLKffpOdVc/l
+tweL7FyQIM1fl2W5r/S9OffFRMJKXiN1HPXrfGYRrwz6B2cgUBtSgI+odwCmdfjb
+Ya4Wo8Za53UGeQ7v0eQ0lEDgXAhx3c2YIoXXxfe2J/5KdZnpXtRJWTJaoAbaQ4tU
+xECfVwbYwltHqRQJuUx0N4DMeQwnKgf3DWHWVqqWdALsAE5utfuOpuHxSoN2AGDz
+ov++GihbiEAcP5XPFv/0ldcfEi/4X9lyHb0mvUIa6DTdHd17thFEM12caD0TCszq
+in8JWVu6M0+oRQcDzIfMn4aD7oKtk76gY5HtbN4Jr8E4BHH/oGPe6l4mQl+W4f3o
+Zp2e7yG5WBVA9sjJbCmlxiWMHod1iiZUJ4e9cEFINjMWuooPIo6xKMzZcGHzwkBa
+zS6kHyTsHcfdHcu4aVMlJ9cKN/aesJgup/XseM3imzuJ3UqfvwCfneUKfM6DM8J3
+mFfSwUBvK8uLsMw5Elim/1oIbBG0PTt7BiLiNd0pU/weuL92y2+QB2oCPM0t5D7L
+IYyoZHHNlvTCkQVNsCHgrDUtOdpGlKt6zzEgUTqwC5i5N3p/w6uPAgMBAAEwDQYJ
+KoZIhvcNAQEEBQADgYEAcrCtPXmZyPX01uNMh2X1VkgmUn/zLemierou7WD/h7xL
+dOl4eeKjFBqIiC19382m1DK4h1F8MceqaMgTueCJpLM7A2cwN3ta8/pGP2yEVhdp
+h10PkdRPF/AU8JmxnFaADsc6+6xWbbrdNv5xcvP1bJKWWW+30EhRF9PxjXiETXc=
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIBkjCB/AIJAPHDh8DU9FfCMA0GCSqGSIb3DQEBBQUAMDQxMjAwBgNVBAoTKWF4
+VExTIFByb2plY3QgRG9kZ3kgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTA2MDYw
+NzExNDQzMloXDTMzMTAyMzExNDQzMlowLDEWMBQGA1UEChMNYXhUTFMgUHJvamVj
+dDESMBAGA1UEAxMJMTI3LjAuMC4xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANE7
+MF+pAUI9hm1yvkBuUcFJf1d1oS025cE9DyAa0SNt+nTSPiOwcPygat7sQYiE/lQV
+a2HFFmK4k0HxTz3/Lr0CAwEAATANBgkqhkiG9w0BAQUFAAOBgQAKRT6LwFr1xedJ
+b4qrvjB+EwV/0p4TNNXUS9S30rMSFvRar7VxvLP1lpYj9PR1JGSZMG/B6hR4yumF
+Rjwel9FPgNcWCW4DXAWqz3UQF7oZtJL6K+XJpQ0gwC+Nxc+RRGNLMlK7dLiqFh/V
+qZLej5Xy93M0JyZBiLV88P+c08gd7A==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIBkjCB/AIJAPHDh8DU9FfHMA0GCSqGSIb3DQEBBQUAMDQxMjAwBgNVBAoTKWF4
+VExTIFByb2plY3QgRG9kZ3kgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTA2MDYw
+NzExNDQzMloXDTMzMTAyMzExNDQzMlowLDEWMBQGA1UEChMNYXhUTFMgUHJvamVj
+dDESMBAGA1UEAxMJMTI3LjAuMC4xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMDo
+g6K2iXFftW+Qk+rrzkMGWrtfY6YSxPstPRrI7akluUEoyWGITXbK6L3QfERrf2eu
+CnWyciQiHVRoHC0EgZUCAwEAATANBgkqhkiG9w0BAQUFAAOBgQBT6YhR8x/bBteK
+lr8E0l4mATOnYlsmge+z/SFYs4bDBofqlwQCVJXNSBA4ZsEjgP9qIWTu/85QrVGq
+LrkewSM6Oeh95LGnE+uhJVtIX++O+Hsex3H1UL067dCG99XmDhqbEU9AI6YSZu2p
+cjoSowFELtOoG667+id9QObfV3EQoQ==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIBkjCB/AIJAPHDh8DU9FfIMA0GCSqGSIb3DQEBBQUAMDQxMjAwBgNVBAoTKWF4
+VExTIFByb2plY3QgRG9kZ3kgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTA2MDYw
+NzExNDQzMloXDTMzMTAyMzExNDQzMlowLDEWMBQGA1UEChMNYXhUTFMgUHJvamVj
+dDESMBAGA1UEAxMJMTI3LjAuMC4xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANAW
+9PdXa5u4gWi5VB5p/eQmOtteRq9/54JkiEs8cVNrTQgZsjjU1LGedE3JwBqZ1EIW
+HGPjcGg5dVxFjkn7RekCAwEAATANBgkqhkiG9w0BAQUFAAOBgQBmJMt0Crdd/BPn
+EdmzsVXou0zTizTC8wyUPMVpg/KzzP7fhZux/ZIrH9/RVcJd9y+B2/mXc3C+K99+
+TXQoYKsLGArfDPzmpy1wPrdEcB1A9gkWDl1Uq6xRyvrVm3gX8NTITRuGKL9njgWx
+2SrApIBtOOUOinYtfH3745cVVl5HOA==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIBkjCB/AIJAPHDh8DU9FfKMA0GCSqGSIb3DQEBBQUAMDQxMjAwBgNVBAoTKWF4
+VExTIFByb2plY3QgRG9kZ3kgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTA2MDYw
+NzExNDQzMloXDTA1MDYwNzExNDQzMlowLDEWMBQGA1UEChMNYXhUTFMgUHJvamVj
+dDESMBAGA1UEAxMJMTI3LjAuMC4xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANE7
+MF+pAUI9hm1yvkBuUcFJf1d1oS025cE9DyAa0SNt+nTSPiOwcPygat7sQYiE/lQV
+a2HFFmK4k0HxTz3/Lr0CAwEAATANBgkqhkiG9w0BAQUFAAOBgQCmPSs9EceViMZD
+ZTXDZpQWJFcXaeInrXWgYWyVgnHBY/eSuqNCxkV/ehv/Wc5pWBGnrX+4cSvQ+TpQ
+FdZegeOjvgipjtJb/0TJCcvgcdHTntEM0h7VXjfbsJXAHwJPFzWIKxV4jeFXnaaw
+W+YHrj9GQ8PnFmapPuh4h/y6LyHAcg==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIBkjCB/AIJAPHDh8DU9FfJMA0GCSqGSIb3DQEBBQUAMDQxMjAwBgNVBAoTKWF4
+VExTIFByb2plY3QgRG9kZ3kgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTI0MTIz
+MTE0MDAwMFoXDTI1MTIzMTE0MDAwMFowLDEWMBQGA1UEChMNYXhUTFMgUHJvamVj
+dDESMBAGA1UEAxMJMTI3LjAuMC4xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANE7
+MF+pAUI9hm1yvkBuUcFJf1d1oS025cE9DyAa0SNt+nTSPiOwcPygat7sQYiE/lQV
+a2HFFmK4k0HxTz3/Lr0CAwEAATANBgkqhkiG9w0BAQUFAAOBgQApbldYefE8A0ez
+SYvAuCtYxx/2KHwBRD/cR0q7widl9WGjVC/dsnbFo109vHEr3FP1HVYSI0aweiaK
+XZmpUyJ9DprbbWQqaLuDnqIH8X7kfiMuO7/LGQc812iDJI2Akxp9cIlPBFBD8GVx
++0EphzSodDDlLD8bPqLaWTE+8Ydtjw==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIBjTCCATcCCQDxw4fA1PRXxjANBgkqhkiG9w0BAQUFADAsMRYwFAYDVQQKEw1h
+eFRMUyBQcm9qZWN0MRIwEAYDVQQDEwkxMjcuMC4wLjEwHhcNMDYwNjA3MTE0NDMy
+WhcNMzMxMDIzMTE0NDMyWjArMSkwJwYDVQQKEyBheFRMUyBQcm9qZWN0IERldmlj
+ZSBDZXJ0aWZpY2F0ZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1CIODRIr
+v3YgwJW7Fm0wITCsOIgX9l+aIRiXUzur4RkHRJIQUQYM3ZfftC21QyWPGErVIIcJ
+7s7U/iKTQq1LV7USvAp90D/m7s0ntmRj1aBCSG71f0LnSv1rlA8kzUkU7VuEt0Tt
++iqrW0+sYdUBk11dyPLKe6sJnMrJJamVvBsCAwEAATANBgkqhkiG9w0BAQUFAANB
+ABC3Uc6uImIpcLl1WYu8K8qkGnVT4K9JkdXHQFbhFZs37lvITrOHQ3j2oGXTbdAx
+JFJ3II9xXkm+nc7oLHqhXlc=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIB3zCCAUgCCQCdbnM4pjqlWjANBgkqhkiG9w0BAQUFADA0MTIwMAYDVQQKEylh
+eFRMUyBQcm9qZWN0IERvZGd5IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNjA2
+MDcxMTQ0MzJaFw0zMzEwMjMxMTQ0MzJaMDQxMjAwBgNVBAoTKWF4VExTIFByb2pl
+Y3QgRG9kZ3kgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQCnZdk20fYWh8O6kDTt0AuJWyp0YIrb7W1UNNMPXI5wA4J59IVj
+Nmk5wocm9+Hqzbg7rORAN/mHPBhzLAjhnm1HODs36hW15DtbDkkH4wCM/Tsyv79m
+n0xq1V6peK3t9vi2D4p/IRjHkYR2jm+BeknopijhY0kHHfpGTHa2DnVirwIDAQAB
+MA0GCSqGSIb3DQEBBQUAA4GBAB0LgNo0oCcwIie5plgwwFybQ8x95q6e3wndM/Mp
+3gjcAFbGuchpo3dfFlTcRI0KyERb3q1MVxPM4sff9nT7EdHVyK9s8/ITkP2dcTKc
+flbcTEfJVIeM8L2P5F41Hvn9GuGcMW8EmsC06gdbp1LLnqsdrXdMNBsAUBXfgPrU
++UcZ
+-----END CERTIFICATE-----
--- /dev/null
+
+#include <string.h>
+#include <stdlib.h>
+#include "ssl.h"
+
+int main(int argc, char *argv[])
+{
+ bigint *m1, *m2, *d;
+ BI_CTX *ctx = bi_initialize();
+ char cmp1[1024], cmp2[1024];
+
+ const char *plaintext = /* 128 byte number */
+ "01aaaaaaaaaabbbbbbbbbbbbbbbccccccccccccccdddddddddddddeeeeeeeeee"
+ "01aaaaaaaaaabbbbbbbbbbbbbbbccccccccccccccdddddddddddddeeeeeeeeee";
+ d = bi_import(ctx, (uint8_t *)plaintext, strlen(plaintext));
+ memset(cmp1, 0, sizeof(cmp1));
+
+ while (1)
+ {
+ bi_set_mod(ctx, bi_clone(ctx, d), 0);
+ m1 = bi_square(ctx, bi_copy(d));
+ m2 = bi_residue(ctx, m1);
+ bi_free_mod(ctx, 0);
+
+ //bi_export(ctx, bi_copy(d), cmp1, sizeof(cmp1));
+ bi_export(ctx, m2, cmp2, sizeof(cmp2));
+
+ if (memcmp(cmp1, cmp2, sizeof(cmp1)) != 0)
+ {
+ printf("Error!\n"); TTY_FLUSH();
+ break;
+ }
+
+ d = bi_add(ctx, d, int_to_bi(ctx, 1));
+ }
+
+ bi_free(ctx, d);
+ bi_terminate(ctx);
+ printf("all good\n"); TTY_FLUSH();
+ return 0;
+
+}
+
--- /dev/null
+#include "crypto.h"
+
+#include <string.h>
+#include <stdlib.h>
+//#define DEBUG_TEST
+
+typedef enum {
+ encrypt, decrypt
+} CryptoMode;
+
+void hex_dump(const char* header, const unsigned char* data, const unsigned int data_length)
+{
+ unsigned int byte_count;
+ printf("%s (%d bytes):\n", header, data_length);
+ for(byte_count = 0; byte_count < data_length; ++byte_count)
+ {
+ printf("%02X", data[byte_count]);
+ }
+ printf("\n");
+}
+
+void do_rsa(const CryptoMode crypto_mode,
+ const unsigned char* data, const unsigned int data_length,
+ const unsigned char* modulus, const unsigned int modulus_length,
+ const unsigned char* exponent, const unsigned int exponent_length,
+ unsigned char* result, const unsigned int result_length)
+{
+ RSA_CTX* rsa_context = NULL;
+ BI_CTX *bi_ctx;
+ bigint *plaintext_bi;
+ bigint *enc_data_bi, *dec_data_bi;
+
+#ifdef DEBUG_TEST
+ printf("do_rsa:\n");
+ hex_dump("data", data, data_length);
+ hex_dump("modulus", modulus, modulus_length);
+ hex_dump("exponent", exponent, exponent_length);
+#endif
+
+ RSA_priv_key_new(&rsa_context, modulus, modulus_length, exponent, exponent_length, exponent, exponent_length);
+ memset(result, 0, result_length);
+ bi_ctx = rsa_context->bi_ctx;
+
+ switch(crypto_mode)
+ {
+ case encrypt:
+#ifdef DEBUG_TEST
+ printf("encrypt\n");
+#endif
+ plaintext_bi = bi_import(bi_ctx, data, data_length);
+ enc_data_bi = RSA_public(rsa_context, plaintext_bi);
+ bi_export(bi_ctx, enc_data_bi, result, result_length);
+ break;
+
+ case decrypt:
+
+#ifdef DEBUG_TEST
+ printf("decrypt\n");
+#endif
+ plaintext_bi = bi_import(bi_ctx, data, data_length);
+ dec_data_bi = RSA_private(rsa_context, plaintext_bi);
+ bi_export(bi_ctx, dec_data_bi, result, result_length);
+ break;
+ }
+#ifdef DEBUG_TEST
+ hex_dump("result", result, result_length);
+#endif
+
+ RSA_free(rsa_context);
+}
+
+void test_matching(char* test_description,
+ const unsigned char* expected, const unsigned int expected_length,
+ const unsigned char* result, const unsigned int result_length)
+{
+ int test_result = memcmp(expected, result, expected_length);
+ printf("Testing %s ... ", test_description);
+ if(test_result == 0)
+ {
+ printf("ok.\n");
+ }
+ else
+ {
+ printf("failed!\n");
+ hex_dump("should be", expected, expected_length);
+ hex_dump("but is", result, result_length);
+ }
+}
+
+void encrypt_decrypt_should_yield_original(char* test_description,
+ const unsigned char* data, const unsigned int data_length,
+ const unsigned char* modulus, const unsigned int modulus_length,
+ const unsigned char* private_exponent, const unsigned int private_exponent_length,
+ const unsigned char* public_exponent, const unsigned int public_exponent_length,
+ const unsigned char* cryptogram, const unsigned int cryptogram_length)
+{
+ const unsigned int calculated_cryptogram_length = modulus_length;
+ unsigned char* calculated_cryptogram = malloc(calculated_cryptogram_length);
+ const unsigned int decrypted_data_length = modulus_length;
+ unsigned char* decrypted_data = malloc(decrypted_data_length);
+
+ printf("\nRunning \"%s\" ...\n", test_description);
+
+#ifdef DEBUG_TEST
+ printf("encrypt_decrypt_should_yield_original:\n");
+ hex_dump("data", data, data_length);
+ hex_dump("modulus", modulus, modulus_length);
+ hex_dump("private_exponent", private_exponent, private_exponent_length);
+ hex_dump("public_exponent", public_exponent, public_exponent_length);
+ hex_dump("cryptogram", cryptogram, cryptogram_length);
+#endif
+
+ do_rsa(encrypt, data, data_length,
+ modulus, modulus_length,
+ private_exponent, private_exponent_length,
+ calculated_cryptogram, calculated_cryptogram_length);
+
+#ifdef DEBUG_TEST
+ hex_dump("calculated_cryptogram", calculated_cryptogram, calculated_cryptogram_length);
+#endif
+
+ if(cryptogram != NULL)
+ {
+ test_matching("cryptogram", cryptogram, cryptogram_length,
+ calculated_cryptogram, calculated_cryptogram_length);
+ }
+
+ do_rsa(decrypt, calculated_cryptogram, calculated_cryptogram_length,
+ modulus, modulus_length,
+ public_exponent, public_exponent_length,
+ decrypted_data, decrypted_data_length);
+
+ test_matching("decrypted plaintext", data, data_length,
+ decrypted_data, decrypted_data_length);
+
+ free(calculated_cryptogram);
+ free(decrypted_data);
+}
+
+/* configure without CRT!
+
+ prepare data with:
+ > echo "<string>" |
+ ruby -ne '$_.gsub!(/ /, "").scan(/../).each_with_index \
+ { |b, i| print "\"\n\"" if i % 16 == 0; print "\\x" + b;}' */
+int main(int argc, char *argv[])
+{
+#if 0
+ unsigned char stuff[] = {
+ 0x22, 0x33, 0x44, 0x81,
+ 0xF1, 0xFF, 0xAA, 0xBB,
+ 0xCC, 0xDD, 0xEE , 0x01,
+ 0x45, 0x44, 0xfa, 0x8d,
+ 0xfa, 0x20, 0x99, 0xFF,
+ 0xab, 0xda, 0xac, 0x40 };
+ unsigned char resA[sizeof(stuff)*2], resB[sizeof(stuff)*2];
+
+ BI_CTX *bi_ctx = bi_initialize();
+ bigint *bi_data1, *bi_data2, *res1, *res2;
+ bi_data1 = bi_import(bi_ctx, stuff, sizeof(stuff));
+ bi_data2 = bi_import(bi_ctx, stuff, sizeof(stuff));
+
+ res1 = bi_multiply(bi_ctx, bi_copy(bi_data1), bi_copy(bi_data2));
+ res2 = bi_multiply(bi_ctx, bi_data1, bi_data2);
+ bi_print("MULTIPLY", res1);
+ bi_print("SQUARE", res2);
+ bi_export(bi_ctx, res1, resA, sizeof(resA));
+ bi_export(bi_ctx, res2, resB, sizeof(resB));
+ if (memcmp(resA, resB, sizeof(resA)))
+ printf("OUCH - difference!\n");
+ bi_terminate(bi_ctx);
+
+ exit(0);
+#endif
+ encrypt_decrypt_should_yield_original("Works only with Montgomery",
+ (const unsigned char*) /* data */
+ "\xBC\xD3\x12\x6C\x93\x13\x14\x4C\x00\x5D\xFD\xBF\xDE\xE4\xD3\x60"
+ "\x29\xB8\xAE\x47\xBE\x0B\xB6\x0A\x39\x88\xB7\x93\x19\x14\xE8\x88"
+ "\x4A\xDE\x00\x46\x89\x5A\x11\x1A\xC4\x8F\xE8\xF7\x27\xAC\x59\x80"
+ "\x03\xC1\x93\x14\x01\x00\x93\x15\x07\x00\x00\x00\x01\x01\x05\x20"
+ "\x93\x16\x0F\x42\x34\x33\x3A\x58\x30\x30\x30\x31\x30\x31\x30\x30"
+ "\x30\x31\x92\x6B\x10\x6C\x69\x62\x65\x6C\x6D\x65\x74\x72\x65\x65"
+ "\x2E\x73\x6F\x2E\x30\x93\x18\x02\xA5\x92\x92\x6C\x03\x96\xE3\x0C"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xB7\xBE", 128,
+ (const unsigned char*) /* modulus */
+ "\xc4\x5a\xcb\x35\x95\xad\x32\x4a\xcf\x9c\x82\x45\x13\xb7\x42\x35"
+ "\x22\x32\x6d\x2e\x6d\x26\x2e\x6d\x00\x9b\xae\x2d\x9e\x78\x1e\xdd"
+ "\x40\x23\x17\xa8\xbb\xa1\x07\x86\xb4\x3c\xbc\xe8\xd5\xfc\xd9\xeb"
+ "\x3c\xad\x63\x11\xf3\x1d\x64\x81\x96\xf2\xf5\xfe\xca\x5a\xf7\x8a"
+ "\x15\xcb\x90\x81\x68\xae\x59\xb4\xe1\xa4\x41\x99\xcd\xf3\x98\xbd"
+ "\x3c\x48\x37\xdb\xa1\xc3\x1c\x6f\x43\xd1\x89\x23\xe5\x3d\xa3\xa5"
+ "\x92\x7b\x19\x14\x1e\x7a\xf3\x88\x8a\x36\x21\x3e\x16\x40\x3c\xd7"
+ "\xd3\xdb\x13\xaf\xc9\x68\x45\x84\xb3\x39\x8f\x02\xed\x28\x02\x5f", 128,
+ (const unsigned char*) /* private exponent */
+ "\x5d\x19\xb7\xb4\x66\x8d\xc2\x84\xda\x3f\x99\x3c\xeb\x86\x3e\xec"
+ "\x36\x94\xb6\x54\x07\x08\xcd\x86\x7d\x7d\x53\x6e\xe9\xee\x86\xa3"
+ "\xdd\x5f\x46\x3e\x89\x08\x67\x2b\x25\x96\x8e\xf3\xcf\x52\x9e\x78"
+ "\xfd\x42\x30\xf1\x37\xd6\xbd\xea\xfc\x09\xa3\x3d\xf5\xf0\x7f\xe1"
+ "\xb1\xe0\x69\x13\x44\xf9\x8b\x95\x58\x2a\x81\xb3\xa8\x15\xce\x7e"
+ "\xd3\xea\x97\x0a\xa2\x14\xd4\xae\xc7\x75\xbb\x9f\x68\xa5\x53\x0e"
+ "\x85\x29\x88\x48\x6c\xc9\xcc\xde\x72\x40\x3a\x4c\x82\xde\x3c\xfb"
+ "\x08\xf8\x2c\x26\xb5\xd4\xea\xc4\xca\x98\x6e\x43\x3e\x67\x54\xc1", 128,
+ (const unsigned char*) /* public exponent */
+ "\x01\x00\x01", 3,
+ (const unsigned char*) /* precalculated encrypted data */
+ "\x93\xE8\x1F\xF9\x70\xFA\xAA\xED\x54\xFD\x48\x37\xC9\x71\x9A\x11"
+ "\x69\x80\xB4\x22\x0C\xAD\x5A\x95\x65\xCA\x7C\xF7\x70\x56\x92\xCB"
+ "\x45\x6D\x58\x84\x21\x80\x23\x76\x21\x4A\x61\x99\xC1\x11\x9C\x0F"
+ "\x40\xED\x80\x9C\x8F\x3A\x4F\x01\xB5\x72\xC3\x24\xAE\xF3\x6B\x98"
+ "\xA8\x60\xAC\xAF\x95\x98\x9A\xAA\xA4\x28\xF2\x02\x05\xFC\xF3\xDD"
+ "\xB0\x5A\x4E\xDE\x3C\x41\x4B\x1C\x5B\x1F\xF6\x3D\xAF\x93\x43\xCB"
+ "\xD8\xC7\x24\x97\x8F\x49\xE5\x5B\x10\x51\x3B\x1E\xA6\x39\xEA\x4E"
+ "\xA5\xE0\x71\x8C\xCA\x34\x8C\x2F\x6C\x5C\x78\x34\x86\x7C\x54\x6A", 128);
+
+ encrypt_decrypt_should_yield_original("Works only with Barrett",
+ (const unsigned char*) /* data */
+ "\x36\x42\x32\xe4\x1e\x78\x02\x8e\xfb\x64\x5f\x0c\xfc\x5a\xd7\x5c"
+ "\xe4\xb5\x91\x5c\x4b\x00\x87\x28\x87\x9b\xa0\x4b\x09\xc2\x6b\x64"
+ "\xac\x4b\xcf\xa5\xee\x8a\xb7\xc9\xc9\x90\x02\xc1\xa3\x47\x5c\x6b"
+ "\x71\x5d\x5d\x49\x27\xe1\x15\xc6\xcf\x37\x9e\xa7\x0f\xa1\xad\x96"
+ "\x83\xef\x4b\x53\x68\xcd\x77\xfc\x14\x5f\xf5\xb7\x78\xb0\x10\xeb"
+ "\x0d\x61\x94\x01\xf6\xaa\x1b\x19\x23\x39\xa7\xcc\x6c\x42\x4a\x87"
+ "\x79\x27\x04\xc6\xec\x8e\x50\xba\xb9\x26\x89\xd4\x00\x01\x25\xe5"
+ "\xf3\x9e\x98\x0c\x8d\x2e\x43\x1e\xe9\x29\x90\xd2\x75\x61\x85\xe7", 128,
+ (const unsigned char*) /* modulus */
+ "\x37\x0c\x32\xe4\x1e\x78\x02\x8e\xfb\x64\x5f\x0c\xfc\x5a\xd7\x5c"
+ "\xe4\xb5\x91\x5c\x4b\x00\x87\x28\x87\x9b\xa0\x4b\x09\xc2\x6b\x64"
+ "\xac\x4b\xcf\xa5\xee\x8a\xb7\xc9\xc9\x90\x02\xc1\xa3\x47\x5c\x6b"
+ "\x71\x5d\x5d\x49\x27\xe1\x15\xc6\xcf\x37\x9e\xa7\x0f\xa1\xad\x96"
+ "\x83\xef\x4b\x53\x68\xcd\x77\xfc\x14\x5f\xf5\xb7\x78\xb0\x10\xeb"
+ "\x0d\x61\x94\x01\xf6\xaa\x1b\x19\x23\x39\xa7\xcc\x6c\x42\x4a\x87"
+ "\x79\x27\x04\xc6\xec\x8e\x50\xba\xb9\x26\x89\xd4\x00\x01\x25\xe5"
+ "\xf3\x9e\x98\x0c\x8d\x2e\x43\x1e\xe9\x29\x90\xd2\x75\x61\x85\xe7", 128,
+ (const unsigned char*) /* private exponent */
+ "\x16\x3a\x76\xd2\x66\xfb\x4f\x0d\x2d\xb6\x7a\x2b\x64\x3b\xca\x7b"
+ "\x58\x5f\x79\x33\x2b\x96\x2a\xfd\xd2\xc4\xa5\x15\xa7\xfb\x3a\x22"
+ "\x8c\xf0\x90\x09\x11\x2a\x32\xcc\xe8\xf7\x9e\x25\x53\x29\x9d\xc8"
+ "\x45\x1e\xce\x6c\x9c\x0d\xe8\x1d\x3f\xcf\xd5\xe0\xe0\x0f\x09\x69"
+ "\x2d\xe7\xd5\xe6\xe5\x10\xd9\x4e\x20\xdb\xbd\xa1\x04\x6b\xe6\x1d"
+ "\x4c\x79\x28\x47\x30\x11\xde\x14\xb4\x6e\x35\x98\x38\x50\x44\x82"
+ "\xbd\xc4\xfb\x03\xb3\xf6\x5e\x5a\x29\xfa\x29\xaa\xde\xe4\xfd\x15"
+ "\xbe\xed\x4f\x93\x9d\x0d\x29\xe8\xd7\xa3\xf4\x18\xc8\x98\xb1\x01", 128,
+ (const unsigned char*) /* public exponent */
+ "\x01\x00\x01", 3,
+ NULL, 0);
+
+ encrypt_decrypt_should_yield_original("Works always",
+ (const unsigned char*) /* data */
+ "\xB9\x42\x32\xe4\x1e\x78\x02\x8e\xfb\x64\x5f\x0c\xfc\x5a\xd7\x5c"
+ "\xe4\xb5\x91\x5c\x4b\x00\x87\x28\x87\x9b\xa0\x4b\x09\xc2\x6b\x64"
+ "\xac\x4b\xcf\xa5\xee\x8a\xb7\xc9\xc9\x90\x02\xc1\xa3\x47\x5c\x6b"
+ "\x71\x5d\x5d\x49\x27\xe1\x15\xc6\xcf\x37\x9e\xa7\x0f\xa1\xad\x96"
+ "\x83\xef\x4b\x53\x68\xcd\x77\xfc\x14\x5f\xf5\xb7\x78\xb0\x10\xeb"
+ "\x0d\x61\x94\x01\xf6\xaa\x1b\x19\x23\x39\xa7\xcc\x6c\x42\x4a\x87"
+ "\x79\x27\x04\xc6\xec\x8e\x50\xba\xb9\x26\x89\xd4\x00\x01\x25\xe5"
+ "\xf3\x9e\x98\x0c\x8d\x2e\x43\x1e\xe9\x29\x90\xd2\x75\x61\x85\xe7", 128,
+ (const unsigned char*) /* modulus */
+ "\xB9\x77\xEC\x83\x95\xAF\xB1\xF8\x21\x21\xFF\x05\x5E\x0C\x91\x0C"
+ "\x2E\xD5\xD2\x94\x1C\x38\x5E\xED\x5A\xCF\x84\xD0\x12\x8B\xAA\x4B"
+ "\x3A\x63\x65\x78\x13\xED\x24\x4E\x83\xF2\xF5\x02\x66\x5D\xFC\xC1"
+ "\x80\x5B\x78\x78\xB4\x0B\x45\xE5\x22\xC6\xCD\xEB\xCC\x74\x0B\x0B"
+ "\xD8\x8B\x91\x99\x48\x8E\x74\xA9\xD0\x1A\x39\x94\xC2\xD4\x2E\x9A"
+ "\x8C\x0C\x35\x0D\x97\x8F\xC4\x62\x20\xE9\x78\x40\x97\x05\x98\xE6"
+ "\x22\x48\x3D\x3D\xCA\x6A\x3F\xEF\xB0\x23\x14\x30\xDA\x35\x46\x65"
+ "\x55\xEF\xEB\xA1\xA9\xCF\x83\xE7\xEF\xF2\x83\x6D\x38\xEA\x88\xED", 128,
+ (const unsigned char*) /* private exponent */
+ "\x52\x2A\x68\xE3\x9A\xAA\xED\xA3\x49\xBA\x6F\xEA\x86\xD1\xF6\x68"
+ "\x79\x4F\x4D\x2D\x44\x9B\x4C\xA2\xC6\xBA\x6C\xD2\x69\x84\xEA\x7A"
+ "\xCD\x71\x3F\x80\xC5\x03\x28\x34\x88\x8C\x58\x33\x29\xFA\xB5\x81"
+ "\x5C\x46\x29\xC6\xFF\xAC\x86\xD8\x8E\x61\x98\xD4\xC0\x0D\x20\xDE"
+ "\xEB\x61\x1C\x0C\x3C\x19\xA3\x75\x10\x7D\xDA\xA9\x55\xA7\x64\x5F"
+ "\xE0\xB6\x35\x62\x00\xD9\xD2\xF7\xA4\xDF\x85\xFF\xDF\x86\x75\x29"
+ "\x66\x16\x03\x8C\xC0\xB0\x3F\xAB\xBA\x41\xB3\x3C\x76\x58\xB6\xE2"
+ "\x1F\x36\x47\x5F\x1F\x0E\x4C\xB5\x29\x90\xDC\xA1\xF8\xFA\x58\x19", 128,
+ (const unsigned char*) /* public exponent */
+ "\x01\x00\x01", 3,
+ NULL, 0);
+
+ return 0;
+}
--- /dev/null
+#!/bin/sh
+ps -ef|grep openssl | /usr/bin/awk '{print $2}' |xargs kill -9
--- /dev/null
+#!/bin/sh
+
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# Generate the certificates and keys for testing.
+#
+
+PROJECT_NAME="axTLS Project"
+
+# Generate the openssl configuration files.
+cat > ca_cert.conf << EOF
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+
+[ req_distinguished_name ]
+ O = $PROJECT_NAME Dodgy Certificate Authority
+EOF
+
+cat > certs.conf << EOF
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+
+[ req_distinguished_name ]
+ O = $PROJECT_NAME
+ CN = 127.0.0.1
+EOF
+
+cat > device_cert.conf << EOF
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+
+[ req_distinguished_name ]
+ O = $PROJECT_NAME Device Certificate
+EOF
+
+# private key generation
+openssl genrsa -out axTLS.ca_key.pem 1024
+openssl genrsa -out axTLS.key_512.pem 512
+openssl genrsa -out axTLS.key_1024.pem 1024
+openssl genrsa -out axTLS.key_2048.pem 2048
+openssl genrsa -out axTLS.key_4096.pem 4096
+openssl genrsa -out axTLS.device_key.pem 1024
+openssl genrsa -aes128 -passout pass:abcd -out axTLS.key_aes128.pem 512
+openssl genrsa -aes256 -passout pass:abcd -out axTLS.key_aes256.pem 512
+
+# convert private keys into DER format
+openssl rsa -in axTLS.key_512.pem -out axTLS.key_512 -outform DER
+openssl rsa -in axTLS.key_1024.pem -out axTLS.key_1024 -outform DER
+openssl rsa -in axTLS.key_2048.pem -out axTLS.key_2048 -outform DER
+openssl rsa -in axTLS.key_4096.pem -out axTLS.key_4096 -outform DER
+openssl rsa -in axTLS.device_key.pem -out axTLS.device_key -outform DER
+
+# cert requests
+openssl req -out axTLS.ca_x509.req -key axTLS.ca_key.pem -new \
+ -config ./ca_cert.conf
+openssl req -out axTLS.x509_512.req -key axTLS.key_512.pem -new \
+ -config ./certs.conf
+openssl req -out axTLS.x509_1024.req -key axTLS.key_1024.pem -new \
+ -config ./certs.conf
+openssl req -out axTLS.x509_2048.req -key axTLS.key_2048.pem -new \
+ -config ./certs.conf
+openssl req -out axTLS.x509_4096.req -key axTLS.key_4096.pem -new \
+ -config ./certs.conf
+openssl req -out axTLS.x509_device.req -key axTLS.device_key.pem -new \
+ -config ./device_cert.conf
+openssl req -out axTLS.x509_aes128.req -key axTLS.key_aes128.pem \
+ -new -config ./certs.conf -passin pass:abcd
+openssl req -out axTLS.x509_aes256.req -key axTLS.key_aes256.pem \
+ -new -config ./certs.conf -passin pass:abcd
+
+# generate the actual certs.
+openssl x509 -req -in axTLS.ca_x509.req -out axTLS.ca_x509.pem \
+ -sha1 -days 10000 -signkey axTLS.ca_key.pem
+openssl x509 -req -in axTLS.x509_512.req -out axTLS.x509_512.pem \
+ -sha1 -CAcreateserial -days 10000 \
+ -CA axTLS.ca_x509.pem -CAkey axTLS.ca_key.pem
+openssl x509 -req -in axTLS.x509_1024.req -out axTLS.x509_1024.pem \
+ -sha1 -CAcreateserial -days 10000 \
+ -CA axTLS.ca_x509.pem -CAkey axTLS.ca_key.pem
+openssl x509 -req -in axTLS.x509_2048.req -out axTLS.x509_2048.pem \
+ -md5 -CAcreateserial -days 10000 \
+ -CA axTLS.ca_x509.pem -CAkey axTLS.ca_key.pem
+openssl x509 -req -in axTLS.x509_4096.req -out axTLS.x509_4096.pem \
+ -md5 -CAcreateserial -days 10000 \
+ -CA axTLS.ca_x509.pem -CAkey axTLS.ca_key.pem
+openssl x509 -req -in axTLS.x509_device.req -out axTLS.x509_device.pem \
+ -sha1 -CAcreateserial -days 10000 \
+ -CA axTLS.x509_512.pem -CAkey axTLS.key_512.pem
+openssl x509 -req -in axTLS.x509_aes128.req \
+ -out axTLS.x509_aes128.pem \
+ -sha1 -CAcreateserial -days 10000 \
+ -CA axTLS.ca_x509.pem -CAkey axTLS.ca_key.pem
+openssl x509 -req -in axTLS.x509_aes256.req \
+ -out axTLS.x509_aes256.pem \
+ -sha1 -CAcreateserial -days 10000 \
+ -CA axTLS.ca_x509.pem -CAkey axTLS.ca_key.pem
+
+# note: must be root to do this
+DATE_NOW=`date`
+if date -s "Jan 1 2025"; then
+openssl x509 -req -in axTLS.x509_512.req -out axTLS.x509_bad_before.pem \
+ -sha1 -CAcreateserial -days 365 \
+ -CA axTLS.ca_x509.pem -CAkey axTLS.ca_key.pem
+date -s "$DATE_NOW"
+touch axTLS.x509_bad_before.pem
+fi
+openssl x509 -req -in axTLS.x509_512.req -out axTLS.x509_bad_after.pem \
+ -sha1 -CAcreateserial -days -365 \
+ -CA axTLS.ca_x509.pem -CAkey axTLS.ca_key.pem
+
+# some cleanup
+rm axTLS*.req
+rm axTLS.srl
+rm *.conf
+
+# need this for the client tests
+openssl x509 -in axTLS.ca_x509.pem -outform DER -out axTLS.ca_x509.cer
+openssl x509 -in axTLS.x509_512.pem -outform DER -out axTLS.x509_512.cer
+openssl x509 -in axTLS.x509_1024.pem -outform DER -out axTLS.x509_1024.cer
+openssl x509 -in axTLS.x509_2048.pem -outform DER -out axTLS.x509_2048.cer
+openssl x509 -in axTLS.x509_4096.pem -outform DER -out axTLS.x509_4096.cer
+openssl x509 -in axTLS.x509_device.pem -outform DER -out axTLS.x509_device.cer
+
+# generate pkcs8 files (use RC4-128 for encryption)
+openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -v1 PBE-SHA1-RC4-128 -out axTLS.encrypted_pem.p8
+openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -outform DER -v1 PBE-SHA1-RC4-128 -out axTLS.encrypted.p8
+openssl pkcs8 -in axTLS.key_512.pem -nocrypt -topk8 -out axTLS.unencrypted_pem.p8
+openssl pkcs8 -in axTLS.key_512.pem -nocrypt -topk8 -outform DER -out axTLS.unencrypted.p8
+
+# generate pkcs12 files (use RC4-128 for encryption)
+openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem -certfile axTLS.ca_x509.pem -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128 -name "p12_with_CA" -out axTLS.withCA.p12 -password pass:abcd
+openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128 -name "p12_without_CA" -out axTLS.withoutCA.p12 -password pass:abcd
+openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128 -out axTLS.noname.p12 -password pass:abcd
+
+# PEM certificate chain
+cat axTLS.ca_x509.pem >> axTLS.x509_device.pem
+
+# set default key/cert for use in the server
+xxd -i axTLS.x509_1024.cer | sed -e \
+ "s/axTLS_x509_1024_cer/default_certificate/" > ../../ssl/cert.h
+xxd -i axTLS.key_1024 | sed -e \
+ "s/axTLS_key_1024/default_private_key/" > ../../ssl/private_key.h
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIEEjCCAvqgAwIBAgIPAMEAizw8iBHRPvZj7N9AMA0GCSqGSIb3DQEBBAUAMHAx
+KzApBgNVBAsTIkNvcHlyaWdodCAoYykgMTk5NyBNaWNyb3NvZnQgQ29ycC4xHjAc
+BgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEhMB8GA1UEAxMYTWljcm9zb2Z0
+IFJvb3QgQXV0aG9yaXR5MB4XDTk3MDExMDA3MDAwMFoXDTIwMTIzMTA3MDAwMFow
+cDErMCkGA1UECxMiQ29weXJpZ2h0IChjKSAxOTk3IE1pY3Jvc29mdCBDb3JwLjEe
+MBwGA1UECxMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEwHwYDVQQDExhNaWNyb3Nv
+ZnQgUm9vdCBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCpAr3BcOY78k4bKJ+XeF4w6qKpjSVf+P6VTKO3/p2iID58UaKboo9gMmvRQmR5
+7qx2yVTa8uuchhyPn4Rms8VremIj1h083g8BkuiWxL8tZpqaaCaZ0Dosvwy1WCbB
+RucKPjiWLKkoOajsSYNC44QPu5psVWGsgnyhYC13TOmZtGQ7mlAcMQgkFJ+p55Er
+GOY9mGMUYFgFZZ8dN1KH96fvlALGG9O/VUWziYC/OuxUlE6u/ad6bXROrxjMlgko
+IQBXkGBpN7tLEgc8Vv9b+6RmCgim0oFWV++2O14WgXcE2va+roCV/rDNf9anGnJc
+PMq88AijIjCzBoXJsyB3E4XfAgMBAAGjgagwgaUwgaIGA1UdAQSBmjCBl4AQW9Bw
+72lyniNRfhSyTY7/y6FyMHAxKzApBgNVBAsTIkNvcHlyaWdodCAoYykgMTk5NyBN
+aWNyb3NvZnQgQ29ycC4xHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEh
+MB8GA1UEAxMYTWljcm9zb2Z0IFJvb3QgQXV0aG9yaXR5gg8AwQCLPDyIEdE+9mPs
+30AwDQYJKoZIhvcNAQEEBQADggEBAJXoC8CN85cYNe24ASTYdxHzXGAyn54Lyz4F
+kYiPyTrmIfLwV5MstaBHyGLv/NfMOztaqTZUaf4kbT/JzKreBXzdMY09nxBwarv+
+Ek8YacD80EPjEVogT+pie6+qGcgrNyUtvmWhEoolD2Oj91Qc+SHJ1hXzUqxuQzIH
+/YIX+OVnbA1R9r3xUse958Qw/CAxCYgdlSkaTdUdAqXxgOADtFv0sd3IV+5lScdS
+VLa0AygS/5DW8AiPfriXxas3LOR65Kh343agANBqP8HSNorgQRKoNWobats14dQc
+BOSoRQTIWjM4bk0cDWK3CqKM09VUP0bNHFWmcNsSOoeTdZ+n0qA=
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----\r
+MIIB5jCCAVOgAwIBAgIQWPe7KyA+U7lLUohulwW2HDAJBgUrDgMCHQUAMCExHzAd\r
+BgNVBAMTFmF4dGxzLmNlcm9jY2x1Yi5jb20uYXUwHhcNMDgwMzE3MTAyMTA2WhcN\r
+MDkwMzE3MTAyMTA2WjAhMR8wHQYDVQQDExZheHRscy5jZXJvY2NsdWIuY29tLmF1\r
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9JqHlQjrQMt3JW8yxcGhFagDa\r
+D4QiIY8+KItTt13fIBt5g1AG4VXniaylSqKKYNPwVzqSWl7WhxMmoFU73veF8o4M\r
+G0Zc5qbVB6ukrSV4WaTgHrIO6pWkyiaQ4L/eYfCo/2pByhl0IUKkf/TMN346/rFg\r
+JgrElx01l6QHNQrzVQIDAQABoycwJTATBgNVHSUEDDAKBggrBgEFBQcDATAOBgNV\r
+HQ8EBwMFALAAAAAwCQYFKw4DAh0FAAOBgQAbH94H1fryngROJ//Oa0D3vvTO8CJ3\r
+8VW+3gQEwrPBOWmN6RV8OM0dE6pf8wD3s7PTCcM5+/HI1Qk53nUGrNiOmKM1s0JB\r
+bvsO9RT+UF8mtdbo/n30M0MHMWPCC76baW3R+ANBp/V/z4l1ytpUTt+MHvz0VlUs\r
+J4uJA3s3uh23Tg==\r
+-----END CERTIFICATE-----\r
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Some performance testing of bigint.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ssl.h"
+
+/**************************************************************************
+ * BIGINT tests
+ *
+ **************************************************************************/
+
+int main(int argc, char *argv[])
+{
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ RSA_CTX *rsa_ctx;
+ BI_CTX *ctx;
+ bigint *bi_data, *bi_res;
+ int diff, res = 1;
+ struct timeval tv_old, tv_new;
+ const char *plaintext;
+ uint8_t compare[MAX_KEY_BYTE_SIZE];
+ int i, max_biggie = 10; /* really crank performance */
+ int len;
+ uint8_t *buf;
+
+ /**
+ * 512 bit key
+ */
+ plaintext = /* 64 byte number */
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^";
+
+ len = get_file("../ssl/test/axTLS.key_512", &buf);
+ asn1_get_private_key(buf, len, &rsa_ctx);
+ ctx = rsa_ctx->bi_ctx;
+ bi_data = bi_import(ctx, (uint8_t *)plaintext, strlen(plaintext));
+ bi_res = RSA_public(rsa_ctx, bi_data);
+ bi_data = bi_res; /* reuse again */
+
+ gettimeofday(&tv_old, NULL);
+ for (i = 0; i < max_biggie; i++)
+ {
+ bi_res = RSA_private(rsa_ctx, bi_copy(bi_data));
+ if (i < max_biggie-1)
+ {
+ bi_free(ctx, bi_res);
+ }
+ }
+
+ gettimeofday(&tv_new, NULL);
+ bi_free(ctx, bi_data);
+
+ diff = (tv_new.tv_sec-tv_old.tv_sec)*1000 +
+ (tv_new.tv_usec-tv_old.tv_usec)/1000;
+ printf("512 bit decrypt time: %dms\n", diff/max_biggie);
+ TTY_FLUSH();
+ bi_export(ctx, bi_res, compare, 64);
+ RSA_free(rsa_ctx);
+ free(buf);
+ if (memcmp(plaintext, compare, 64) != 0)
+ goto end;
+
+ /**
+ * 1024 bit key
+ */
+ plaintext = /* 128 byte number */
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^"
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^";
+
+ len = get_file("../ssl/test/axTLS.key_1024", &buf);
+ asn1_get_private_key(buf, len, &rsa_ctx);
+ ctx = rsa_ctx->bi_ctx;
+ bi_data = bi_import(ctx, (uint8_t *)plaintext, strlen(plaintext));
+ bi_res = RSA_public(rsa_ctx, bi_data);
+ bi_data = bi_res; /* reuse again */
+
+ gettimeofday(&tv_old, NULL);
+ for (i = 0; i < max_biggie; i++)
+ {
+ bi_res = RSA_private(rsa_ctx, bi_copy(bi_data));
+ if (i < max_biggie-1)
+ {
+ bi_free(ctx, bi_res);
+ }
+ }
+
+ gettimeofday(&tv_new, NULL);
+ bi_free(ctx, bi_data);
+
+ diff = (tv_new.tv_sec-tv_old.tv_sec)*1000 +
+ (tv_new.tv_usec-tv_old.tv_usec)/1000;
+ printf("1024 bit decrypt time: %dms\n", diff/max_biggie);
+ TTY_FLUSH();
+ bi_export(ctx, bi_res, compare, 128);
+ RSA_free(rsa_ctx);
+ free(buf);
+ if (memcmp(plaintext, compare, 128) != 0)
+ goto end;
+
+ /**
+ * 2048 bit key
+ */
+ plaintext = /* 256 byte number */
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^"
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^"
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^"
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^";
+
+ len = get_file("../ssl/test/axTLS.key_2048", &buf);
+ asn1_get_private_key(buf, len, &rsa_ctx);
+ ctx = rsa_ctx->bi_ctx;
+ bi_data = bi_import(ctx, (uint8_t *)plaintext, strlen(plaintext));
+ bi_res = RSA_public(rsa_ctx, bi_data);
+ bi_data = bi_res; /* reuse again */
+
+ gettimeofday(&tv_old, NULL);
+ for (i = 0; i < max_biggie; i++)
+ {
+ bi_res = RSA_private(rsa_ctx, bi_copy(bi_data));
+ if (i < max_biggie-1)
+ {
+ bi_free(ctx, bi_res);
+ }
+ }
+ gettimeofday(&tv_new, NULL);
+ bi_free(ctx, bi_data);
+
+ diff = (tv_new.tv_sec-tv_old.tv_sec)*1000 +
+ (tv_new.tv_usec-tv_old.tv_usec)/1000;
+ printf("2048 bit decrypt time: %dms\n", diff/max_biggie);
+ TTY_FLUSH();
+ bi_export(ctx, bi_res, compare, 256);
+ RSA_free(rsa_ctx);
+ free(buf);
+ if (memcmp(plaintext, compare, 256) != 0)
+ goto end;
+
+ /**
+ * 4096 bit key
+ */
+ plaintext = /* 512 byte number */
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^"
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^"
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^"
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^"
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^"
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^"
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^"
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*^";
+
+ len = get_file("../ssl/test/axTLS.key_4096", &buf);
+ asn1_get_private_key(buf, len, &rsa_ctx);
+ ctx = rsa_ctx->bi_ctx;
+ bi_data = bi_import(ctx, (uint8_t *)plaintext, strlen(plaintext));
+ gettimeofday(&tv_old, NULL);
+ bi_res = RSA_public(rsa_ctx, bi_data);
+ gettimeofday(&tv_new, NULL);
+ diff = (tv_new.tv_sec-tv_old.tv_sec)*1000 +
+ (tv_new.tv_usec-tv_old.tv_usec)/1000;
+ printf("4096 bit encrypt time: %dms\n", diff);
+ TTY_FLUSH();
+ bi_data = bi_res; /* reuse again */
+
+ gettimeofday(&tv_old, NULL);
+ for (i = 0; i < max_biggie; i++)
+ {
+ bi_res = RSA_private(rsa_ctx, bi_copy(bi_data));
+ if (i < max_biggie-1)
+ {
+ bi_free(ctx, bi_res);
+ }
+ }
+
+ gettimeofday(&tv_new, NULL);
+ bi_free(ctx, bi_data);
+
+ diff = (tv_new.tv_sec-tv_old.tv_sec)*1000 +
+ (tv_new.tv_usec-tv_old.tv_usec)/1000;
+ printf("4096 bit decrypt time: %dms\n", diff/max_biggie);
+ TTY_FLUSH();
+ bi_export(ctx, bi_res, compare, 512);
+ RSA_free(rsa_ctx);
+ free(buf);
+ if (memcmp(plaintext, compare, 512) != 0)
+ goto end;
+
+ /* done */
+ printf("Bigint performance testing complete\n");
+ res = 0;
+
+end:
+ return res;
+#else
+ return 0;
+#endif
+}
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The testing of the crypto and ssl stuff goes here. Keeps the individual code
+ * modules from being uncluttered with test code.
+ *
+ * This is test code - I make no apologies for the quality!
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifndef WIN32
+#include <pthread.h>
+#endif
+
+#include "ssl.h"
+
+#define DEFAULT_CERT "../ssl/test/axTLS.x509_512.cer"
+#define DEFAULT_KEY "../ssl/test/axTLS.key_512"
+//#define DEFAULT_SVR_OPTION SSL_DISPLAY_BYTES|SSL_DISPLAY_STATES
+#define DEFAULT_SVR_OPTION 0
+#define DEFAULT_CLNT_OPTION 0
+//#define DEFAULT_CLNT_OPTION SSL_DISPLAY_BYTES|SSL_DISPLAY_STATES
+
+static int g_port = 19001;
+
+/**************************************************************************
+ * AES tests
+ *
+ * Run through a couple of the RFC3602 tests to verify that AES is correct.
+ **************************************************************************/
+#define TEST1_SIZE 16
+#define TEST2_SIZE 32
+
+static int AES_test(BI_CTX *bi_ctx)
+{
+ AES_CTX aes_key;
+ int res = 1;
+ uint8_t key[TEST1_SIZE];
+ uint8_t iv[TEST1_SIZE];
+
+ {
+ /*
+ Case #1: Encrypting 16 bytes (1 block) using AES-CBC
+ Key : 0x06a9214036b8a15b512e03d534120006
+ IV : 0x3dafba429d9eb430b422da802c9fac41
+ Plaintext : "Single block msg"
+ Ciphertext: 0xe353779c1079aeb82708942dbe77181a
+
+ */
+ char *in_str = "Single block msg";
+ uint8_t ct[TEST1_SIZE];
+ uint8_t enc_data[TEST1_SIZE];
+ uint8_t dec_data[TEST1_SIZE];
+
+ bigint *key_bi = bi_str_import(
+ bi_ctx, "06A9214036B8A15B512E03D534120006");
+ bigint *iv_bi = bi_str_import(
+ bi_ctx, "3DAFBA429D9EB430B422DA802C9FAC41");
+ bigint *ct_bi = bi_str_import(
+ bi_ctx, "E353779C1079AEB82708942DBE77181A");
+ bi_export(bi_ctx, key_bi, key, TEST1_SIZE);
+ bi_export(bi_ctx, iv_bi, iv, TEST1_SIZE);
+ bi_export(bi_ctx, ct_bi, ct, TEST1_SIZE);
+
+ AES_set_key(&aes_key, key, iv, AES_MODE_128);
+ AES_cbc_encrypt(&aes_key, (const uint8_t *)in_str,
+ enc_data, sizeof(enc_data));
+ if (memcmp(enc_data, ct, sizeof(ct)))
+ {
+ printf("Error: AES ENCRYPT #1 failed\n");
+ goto end;
+ }
+
+ AES_set_key(&aes_key, key, iv, AES_MODE_128);
+ AES_convert_key(&aes_key);
+ AES_cbc_decrypt(&aes_key, enc_data, dec_data, sizeof(enc_data));
+
+ if (memcmp(dec_data, in_str, sizeof(dec_data)))
+ {
+ printf("Error: AES DECRYPT #1 failed\n");
+ goto end;
+ }
+ }
+
+ {
+ /*
+ Case #2: Encrypting 32 bytes (2 blocks) using AES-CBC
+ Key : 0xc286696d887c9aa0611bbb3e2025a45a
+ IV : 0x562e17996d093d28ddb3ba695a2e6f58
+ Plaintext : 0x000102030405060708090a0b0c0d0e0f
+ 101112131415161718191a1b1c1d1e1f
+ Ciphertext: 0xd296cd94c2cccf8a3a863028b5e1dc0a
+ 7586602d253cfff91b8266bea6d61ab1
+ */
+ uint8_t in_data[TEST2_SIZE];
+ uint8_t ct[TEST2_SIZE];
+ uint8_t enc_data[TEST2_SIZE];
+ uint8_t dec_data[TEST2_SIZE];
+
+ bigint *in_bi = bi_str_import(bi_ctx,
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+ bigint *key_bi = bi_str_import(
+ bi_ctx, "C286696D887C9AA0611BBB3E2025A45A");
+ bigint *iv_bi = bi_str_import(
+ bi_ctx, "562E17996D093D28DDB3BA695A2E6F58");
+ bigint *ct_bi = bi_str_import(bi_ctx,
+ "D296CD94C2CCCF8A3A863028B5E1DC0A7586602D253CFFF91B8266BEA6D61AB1");
+ bi_export(bi_ctx, in_bi, in_data, TEST2_SIZE);
+ bi_export(bi_ctx, key_bi, key, TEST1_SIZE);
+ bi_export(bi_ctx, iv_bi, iv, TEST1_SIZE);
+ bi_export(bi_ctx, ct_bi, ct, TEST2_SIZE);
+
+ AES_set_key(&aes_key, key, iv, AES_MODE_128);
+ AES_cbc_encrypt(&aes_key, (const uint8_t *)in_data,
+ enc_data, sizeof(enc_data));
+
+ if (memcmp(enc_data, ct, sizeof(ct)))
+ {
+ printf("Error: ENCRYPT #2 failed\n");
+ goto end;
+ }
+
+ AES_set_key(&aes_key, key, iv, AES_MODE_128);
+ AES_convert_key(&aes_key);
+ AES_cbc_decrypt(&aes_key, enc_data, dec_data, sizeof(enc_data));
+ if (memcmp(dec_data, in_data, sizeof(dec_data)))
+ {
+ printf("Error: DECRYPT #2 failed\n");
+ goto end;
+ }
+ }
+
+ res = 0;
+ printf("All AES tests passed\n");
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * RC4 tests
+ *
+ * ARC4 tests vectors from OpenSSL (crypto/rc4/rc4test.c)
+ **************************************************************************/
+static const uint8_t keys[7][30]=
+{
+ {8,0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef},
+ {8,0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef},
+ {8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {4,0xef,0x01,0x23,0x45},
+ {8,0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef},
+ {4,0xef,0x01,0x23,0x45},
+};
+
+static const uint8_t data_len[7]={8,8,8,20,28,10};
+static uint8_t data[7][30]=
+{
+ {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xff},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0xff},
+ {0x12,0x34,0x56,0x78,0x9A,0xBC,0xDE,0xF0,
+ 0x12,0x34,0x56,0x78,0x9A,0xBC,0xDE,0xF0,
+ 0x12,0x34,0x56,0x78,0x9A,0xBC,0xDE,0xF0,
+ 0x12,0x34,0x56,0x78,0xff},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff},
+ {0},
+};
+
+static const uint8_t output[7][30]=
+{
+ {0x75,0xb7,0x87,0x80,0x99,0xe0,0xc5,0x96,0x00},
+ {0x74,0x94,0xc2,0xe7,0x10,0x4b,0x08,0x79,0x00},
+ {0xde,0x18,0x89,0x41,0xa3,0x37,0x5d,0x3a,0x00},
+ {0xd6,0xa1,0x41,0xa7,0xec,0x3c,0x38,0xdf,
+ 0xbd,0x61,0x5a,0x11,0x62,0xe1,0xc7,0xba,
+ 0x36,0xb6,0x78,0x58,0x00},
+ {0x66,0xa0,0x94,0x9f,0x8a,0xf7,0xd6,0x89,
+ 0x1f,0x7f,0x83,0x2b,0xa8,0x33,0xc0,0x0c,
+ 0x89,0x2e,0xbe,0x30,0x14,0x3c,0xe2,0x87,
+ 0x40,0x01,0x1e,0xcf,0x00},
+ {0xd6,0xa1,0x41,0xa7,0xec,0x3c,0x38,0xdf,0xbd,0x61,0x00},
+ {0},
+};
+
+static int RC4_test(BI_CTX *bi_ctx)
+{
+ int i, res = 1;
+ RC4_CTX s;
+
+ for (i = 0; i < 6; i++)
+ {
+ RC4_setup(&s, &keys[i][1], keys[i][0]);
+ RC4_crypt(&s, data[i], data[i], data_len[i]);
+
+ if (memcmp(data[i], output[i], data_len[i]))
+ {
+ printf("Error: RC4 CRYPT #%d failed\n", i);
+ goto end;
+ }
+ }
+
+ res = 0;
+ printf("All RC4 tests passed\n");
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * SHA1 tests
+ *
+ * Run through a couple of the RFC3174 tests to verify that SHA1 is correct.
+ **************************************************************************/
+static int SHA1_test(BI_CTX *bi_ctx)
+{
+ SHA1_CTX ctx;
+ uint8_t ct[SHA1_SIZE];
+ uint8_t digest[SHA1_SIZE];
+ int res = 1;
+
+ {
+ const char *in_str = "abc";
+ bigint *ct_bi = bi_str_import(bi_ctx,
+ "A9993E364706816ABA3E25717850C26C9CD0D89D");
+ bi_export(bi_ctx, ct_bi, ct, SHA1_SIZE);
+
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, (const uint8_t *)in_str, strlen(in_str));
+ SHA1_Final(digest, &ctx);
+
+ if (memcmp(digest, ct, sizeof(ct)))
+ {
+ printf("Error: SHA1 #1 failed\n");
+ goto end;
+ }
+ }
+
+ {
+ const char *in_str =
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+ bigint *ct_bi = bi_str_import(bi_ctx,
+ "84983E441C3BD26EBAAE4AA1F95129E5E54670F1");
+ bi_export(bi_ctx, ct_bi, ct, SHA1_SIZE);
+
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, (const uint8_t *)in_str, strlen(in_str));
+ SHA1_Final(digest, &ctx);
+
+ if (memcmp(digest, ct, sizeof(ct)))
+ {
+ printf("Error: SHA1 #2 failed\n");
+ goto end;
+ }
+ }
+
+ res = 0;
+ printf("All SHA1 tests passed\n");
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * MD5 tests
+ *
+ * Run through a couple of the RFC1321 tests to verify that MD5 is correct.
+ **************************************************************************/
+static int MD5_test(BI_CTX *bi_ctx)
+{
+ MD5_CTX ctx;
+ uint8_t ct[MD5_SIZE];
+ uint8_t digest[MD5_SIZE];
+ int res = 1;
+
+ {
+ const char *in_str = "abc";
+ bigint *ct_bi = bi_str_import(bi_ctx,
+ "900150983CD24FB0D6963F7D28E17F72");
+ bi_export(bi_ctx, ct_bi, ct, MD5_SIZE);
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, (const uint8_t *)in_str, strlen(in_str));
+ MD5_Final(digest, &ctx);
+
+ if (memcmp(digest, ct, sizeof(ct)))
+ {
+ printf("Error: MD5 #1 failed\n");
+ goto end;
+ }
+ }
+
+ {
+ const char *in_str =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ bigint *ct_bi = bi_str_import(
+ bi_ctx, "D174AB98D277D9F5A5611C2C9F419D9F");
+ bi_export(bi_ctx, ct_bi, ct, MD5_SIZE);
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, (const uint8_t *)in_str, strlen(in_str));
+ MD5_Final(digest, &ctx);
+
+ if (memcmp(digest, ct, sizeof(ct)))
+ {
+ printf("Error: MD5 #2 failed\n");
+ goto end;
+ }
+ }
+ res = 0;
+ printf("All MD5 tests passed\n");
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * HMAC tests
+ *
+ * Run through a couple of the RFC2202 tests to verify that HMAC is correct.
+ **************************************************************************/
+static int HMAC_test(BI_CTX *bi_ctx)
+{
+ uint8_t key[SHA1_SIZE];
+ uint8_t ct[SHA1_SIZE];
+ uint8_t dgst[SHA1_SIZE];
+ int res = 1;
+ const char *key_str;
+
+ const char *data_str = "Hi There";
+ bigint *key_bi = bi_str_import(bi_ctx, "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B");
+ bigint *ct_bi = bi_str_import(bi_ctx, "9294727A3638BB1C13F48EF8158BFC9D");
+ bi_export(bi_ctx, key_bi, key, MD5_SIZE);
+ bi_export(bi_ctx, ct_bi, ct, MD5_SIZE);
+ hmac_md5((const uint8_t *)data_str, 8, key, MD5_SIZE, dgst);
+ if (memcmp(dgst, ct, MD5_SIZE))
+ {
+ printf("HMAC MD5 #1 failed\n");
+ goto end;
+ }
+
+ data_str = "what do ya want for nothing?";
+ key_str = "Jefe";
+ ct_bi = bi_str_import(bi_ctx, "750C783E6AB0B503EAA86E310A5DB738");
+ bi_export(bi_ctx, ct_bi, ct, MD5_SIZE);
+ hmac_md5((const uint8_t *)data_str, 28, (const uint8_t *)key_str, 4, dgst);
+ if (memcmp(dgst, ct, MD5_SIZE))
+ {
+ printf("HMAC MD5 #2 failed\n");
+ goto end;
+ }
+
+ data_str = "Hi There";
+ key_bi = bi_str_import(bi_ctx, "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B");
+ bi_export(bi_ctx, key_bi, key, SHA1_SIZE);
+ ct_bi = bi_str_import(bi_ctx, "B617318655057264E28BC0B6FB378C8EF146BE00");
+ bi_export(bi_ctx, ct_bi, ct, SHA1_SIZE);
+
+ hmac_sha1((const uint8_t *)data_str, 8,
+ (const uint8_t *)key, SHA1_SIZE, dgst);
+ if (memcmp(dgst, ct, SHA1_SIZE))
+ {
+ printf("HMAC SHA1 #1 failed\n");
+ goto end;
+ }
+
+ data_str = "what do ya want for nothing?";
+ key_str = "Jefe";
+ ct_bi = bi_str_import(bi_ctx, "EFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79");
+ bi_export(bi_ctx, ct_bi, ct, SHA1_SIZE);
+
+ hmac_sha1((const uint8_t *)data_str, 28, (const uint8_t *)key_str, 5, dgst);
+ if (memcmp(dgst, ct, SHA1_SIZE))
+ {
+ printf("HMAC SHA1 failed\n");
+ exit(1);
+ }
+
+ res = 0;
+ printf("All HMAC tests passed\n");
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * BIGINT tests
+ *
+ **************************************************************************/
+static int BIGINT_test(BI_CTX *ctx)
+{
+ int res = 1;
+ bigint *bi_data, *bi_exp, *bi_res;
+ const char *expnt, *plaintext, *mod;
+ uint8_t compare[MAX_KEY_BYTE_SIZE];
+
+ /**
+ * 512 bit key
+ */
+ plaintext = /* 64 byte number */
+ "01aaaaaaaaaabbbbbbbbbbbbbbbccccccccccccccdddddddddddddeeeeeeeeee";
+
+ mod = "C30773C8ABE09FCC279EE0E5343370DE"
+ "8B2FFDB6059271E3005A7CEEF0D35E0A"
+ "1F9915D95E63560836CC2EB2C289270D"
+ "BCAE8CAF6F5E907FC2759EE220071E1B";
+
+ expnt = "A1E556CD1738E10DF539E35101334E97"
+ "BE8D391C57A5C89A7AD9A2EA2ACA1B3D"
+ "F3140F5091CC535CBAA47CEC4159EE1F"
+ "B6A3661AFF1AB758426EAB158452A9B9";
+
+ bi_data = bi_import(ctx, (uint8_t *)plaintext, strlen(plaintext));
+ bi_exp = int_to_bi(ctx, 0x10001);
+ bi_set_mod(ctx, bi_str_import(ctx, mod), 0);
+ bi_res = bi_mod_power(ctx, bi_data, bi_exp);
+
+ bi_data = bi_res; /* resuse again - see if we get the original */
+
+ bi_exp = bi_str_import(ctx, expnt);
+ bi_res = bi_mod_power(ctx, bi_data, bi_exp);
+ bi_free_mod(ctx, 0);
+
+ bi_export(ctx, bi_res, compare, 64);
+ if (memcmp(plaintext, compare, 64) != 0)
+ goto end;
+
+ printf("All BIGINT tests passed\n");
+ res = 0;
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * RSA tests
+ *
+ * Use the results from openssl to verify PKCS1 etc
+ **************************************************************************/
+static int RSA_test(void)
+{
+ int res = 1;
+ const char *plaintext = /* 128 byte hex number */
+ "1aaaaaaaaaabbbbbbbbbbbbbbbccccccccccccccdddddddddddddeeeeeeeeee2"
+ "1aaaaaaaaaabbbbbbbbbbbbbbbccccccccccccccdddddddddddddeeeeeeeee2\012";
+ uint8_t enc_data[128], dec_data[128];
+ RSA_CTX *rsa_ctx = NULL;
+ BI_CTX *bi_ctx;
+ bigint *plaintext_bi;
+ bigint *enc_data_bi, *dec_data_bi;
+ uint8_t enc_data2[128], dec_data2[128];
+ int size;
+ int len;
+ uint8_t *buf;
+
+ /* extract the private key elements */
+ len = get_file("../ssl/test/axTLS.key_1024", &buf);
+ if (asn1_get_private_key(buf, len, &rsa_ctx) < 0)
+ {
+ goto end;
+ }
+
+ free(buf);
+ bi_ctx = rsa_ctx->bi_ctx;
+ plaintext_bi = bi_import(bi_ctx,
+ (const uint8_t *)plaintext, strlen(plaintext));
+
+ /* basic rsa encrypt */
+ enc_data_bi = RSA_public(rsa_ctx, plaintext_bi);
+ bi_export(bi_ctx, bi_copy(enc_data_bi), enc_data, sizeof(enc_data));
+
+ /* basic rsa decrypt */
+ dec_data_bi = RSA_private(rsa_ctx, enc_data_bi);
+ bi_export(bi_ctx, dec_data_bi, dec_data, sizeof(dec_data));
+
+ if (memcmp(dec_data, plaintext, strlen(plaintext)))
+ {
+ printf("Error: DECRYPT #1 failed\n");
+ goto end;
+ }
+
+ RSA_encrypt(rsa_ctx, (const uint8_t *)"abc", 3, enc_data2, 0);
+ size = RSA_decrypt(rsa_ctx, enc_data2, dec_data2, 1);
+ if (memcmp("abc", dec_data2, 3))
+ {
+ printf("Error: ENCRYPT/DECRYPT #2 failed\n");
+ goto end;
+ }
+
+ RSA_free(rsa_ctx);
+ res = 0;
+ printf("All RSA tests passed\n");
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * Cert Testing
+ *
+ **************************************************************************/
+static int cert_tests(void)
+{
+ int res = -1, len;
+ X509_CTX *x509_ctx;
+ SSL_CTX *ssl_ctx;
+ uint8_t *buf;
+
+ /* check a bunch of 3rd party certificates */
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/microsoft.x509_ca", &buf);
+ if ((res = add_cert_auth(ssl_ctx, buf, len)) < 0)
+ {
+ printf("Cert #1\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/thawte.x509_ca", &buf);
+ if ((res = add_cert_auth(ssl_ctx, buf, len)) < 0)
+ {
+ printf("Cert #2\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/deutsche_telecom.x509_ca", &buf);
+ if ((res = add_cert_auth(ssl_ctx, buf, len)) < 0)
+ {
+ printf("Cert #3\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/equifax.x509_ca", &buf);
+ if ((res = add_cert_auth(ssl_ctx, buf, len)) < 0)
+ {
+ printf("Cert #4\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/gnutls.cer", &buf);
+ if ((res = add_cert(ssl_ctx, buf, len)) < 0)
+ {
+ printf("Cert #5\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/socgen.cer", &buf);
+ if ((res = add_cert(ssl_ctx, buf, len)) < 0)
+ {
+ printf("Cert #6\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/verisign.x509_ca", &buf);
+ if ((res = add_cert_auth(ssl_ctx, buf, len)) <0)
+ {
+ printf("Cert #7\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ if (get_file("../ssl/test/verisign.x509_my_cert", &buf) < 0 ||
+ x509_new(buf, &len, &x509_ctx))
+ {
+ printf("Cert #8\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ x509_free(x509_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ if ((res = ssl_obj_load(ssl_ctx,
+ SSL_OBJ_X509_CERT, "../ssl/test/ms_iis.cer", NULL)) != SSL_OK)
+ {
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ res = 0; /* all ok */
+ printf("All Certificate tests passed\n");
+
+bad_cert:
+ if (res)
+ printf("Error: A certificate test failed\n");
+ return res;
+}
+
+/**
+ * init a server socket.
+ */
+static int server_socket_init(int *port)
+{
+ struct sockaddr_in serv_addr;
+ int server_fd;
+ char yes = 1;
+
+ /* Create socket for incoming connections */
+ if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ return -1;
+ }
+
+ setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
+
+go_again:
+ /* Construct local address structure */
+ memset(&serv_addr, 0, sizeof(serv_addr)); /* Zero out structure */
+ serv_addr.sin_family = AF_INET; /* Internet address family */
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
+ serv_addr.sin_port = htons(*port); /* Local port */
+
+ /* Bind to the local address */
+ if (bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
+ {
+ (*port)++;
+ goto go_again;
+ }
+ /* Mark the socket so it will listen for incoming connections */
+ if (listen(server_fd, 3000) < 0)
+ {
+ return -1;
+ }
+
+ return server_fd;
+}
+
+/**
+ * init a client socket.
+ */
+static int client_socket_init(uint16_t port)
+{
+ struct sockaddr_in address;
+ int client_fd;
+
+ address.sin_family = AF_INET;
+ address.sin_port = htons(port);
+ address.sin_addr.s_addr = inet_addr("127.0.0.1");
+ client_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (connect(client_fd, (struct sockaddr *)&address, sizeof(address)) < 0)
+ {
+ perror("socket");
+ SOCKET_CLOSE(client_fd);
+ client_fd = -1;
+ }
+
+ return client_fd;
+}
+
+/**************************************************************************
+ * SSL Server Testing
+ *
+ **************************************************************************/
+typedef struct
+{
+ /* not used as yet */
+ int dummy;
+} SVR_CTX;
+
+typedef struct
+{
+ const char *testname;
+ const char *openssl_option;
+} client_t;
+
+static void do_client(client_t *clnt)
+{
+ char openssl_buf[2048];
+
+ /* make sure the main thread goes first */
+ sleep(0);
+
+ /* show the session ids in the reconnect test */
+ if (strcmp(clnt->testname, "Session Reuse") == 0)
+ {
+ sprintf(openssl_buf, "echo \"hello client\" | openssl s_client "
+ "-connect localhost:%d %s 2>&1 | grep \"Session-ID:\"",
+ g_port, clnt->openssl_option);
+ }
+ else
+ {
+ sprintf(openssl_buf, "echo \"hello client\" | openssl s_client "
+#ifdef WIN32
+ "-connect localhost:%d -quiet %s",
+#else
+ "-connect localhost:%d -quiet %s > /dev/null 2>&1",
+#endif
+ g_port, clnt->openssl_option);
+ }
+
+ system(openssl_buf);
+}
+
+static int SSL_server_test(
+ const char *testname,
+ const char *openssl_option,
+ const char *device_cert,
+ const char *product_cert,
+ const char *private_key,
+ const char *ca_cert,
+ const char *password,
+ int axtls_option)
+{
+ int server_fd, ret = 0;
+ SSL_CTX *ssl_ctx = NULL;
+ struct sockaddr_in client_addr;
+ uint8_t *read_buf;
+ socklen_t clnt_len = sizeof(client_addr);
+ client_t client_data;
+#ifndef WIN32
+ pthread_t thread;
+#endif
+ g_port++;
+
+ client_data.testname = testname;
+ client_data.openssl_option = openssl_option;
+
+ if ((server_fd = server_socket_init(&g_port)) < 0)
+ goto error;
+
+ if (private_key)
+ {
+ axtls_option |= SSL_NO_DEFAULT_KEY;
+ }
+
+ if ((ssl_ctx = ssl_ctx_new(axtls_option, SSL_DEFAULT_SVR_SESS)) == NULL)
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto error;
+ }
+
+ if (private_key)
+ {
+ int obj_type = SSL_OBJ_RSA_KEY;
+
+ if (strstr(private_key, ".p8"))
+ obj_type = SSL_OBJ_PKCS8;
+ else if (strstr(private_key, ".p12"))
+ obj_type = SSL_OBJ_PKCS12;
+
+ if (ssl_obj_load(ssl_ctx, obj_type, private_key, password))
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto error;
+ }
+ }
+
+ if (device_cert) /* test chaining */
+ {
+ if ((ret = ssl_obj_load(ssl_ctx,
+ SSL_OBJ_X509_CERT, device_cert, NULL)) != SSL_OK)
+ goto error;
+ }
+
+ if (product_cert) /* test chaining */
+ {
+ if ((ret = ssl_obj_load(ssl_ctx,
+ SSL_OBJ_X509_CERT, product_cert, NULL)) != SSL_OK)
+ goto error;
+ }
+
+ if (ca_cert) /* test adding certificate authorities */
+ {
+ if ((ret = ssl_obj_load(ssl_ctx,
+ SSL_OBJ_X509_CACERT, ca_cert, NULL)) != SSL_OK)
+ goto error;
+ }
+
+#ifndef WIN32
+ pthread_create(&thread, NULL,
+ (void *(*)(void *))do_client, (void *)&client_data);
+ pthread_detach(thread);
+#else
+ CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)do_client,
+ (LPVOID)&client_data, 0, NULL);
+#endif
+
+ for (;;)
+ {
+ int client_fd, size = 0;
+ SSL *ssl;
+
+ /* Wait for a client to connect */
+ if ((client_fd = accept(server_fd,
+ (struct sockaddr *)&client_addr, &clnt_len)) < 0)
+ {
+ ret = SSL_ERROR_SOCK_SETUP_FAILURE;
+ goto error;
+ }
+
+ /* we are ready to go */
+ ssl = ssl_server_new(ssl_ctx, client_fd);
+ while ((size = ssl_read(ssl, &read_buf)) == SSL_OK);
+ SOCKET_CLOSE(client_fd);
+
+ if (size < SSL_OK) /* got some alert or something nasty */
+ {
+ ret = size;
+
+ if (ret == SSL_ERROR_CONN_LOST)
+ {
+ ret = SSL_OK;
+ continue;
+ }
+
+ break; /* we've got a problem */
+ }
+ else /* looks more promising */
+ {
+ if (strstr("hello client", (char *)read_buf) == NULL)
+ {
+ printf("SSL server test \"%s\" passed\n", testname);
+ TTY_FLUSH();
+ ret = 0;
+ break;
+ }
+ }
+
+ ssl_free(ssl);
+ }
+
+ SOCKET_CLOSE(server_fd);
+
+error:
+ ssl_ctx_free(ssl_ctx);
+ return ret;
+}
+
+int SSL_server_tests(void)
+{
+ int ret = -1;
+ struct stat stat_buf;
+ SVR_CTX svr_test_ctx;
+ memset(&svr_test_ctx, 0, sizeof(SVR_CTX));
+
+ printf("### starting server tests\n"); TTY_FLUSH();
+
+ /* Go through the algorithms */
+
+ /*
+ * TLS1 client hello
+ */
+ if ((ret = SSL_server_test("TLSv1", "-cipher RC4-SHA -tls1",
+ NULL, NULL, NULL, NULL, NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * AES128-SHA
+ */
+ if ((ret = SSL_server_test("AES256-SHA", "-cipher AES128-SHA",
+ DEFAULT_CERT, NULL, DEFAULT_KEY, NULL, NULL,
+ DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * AES256-SHA
+ */
+ if ((ret = SSL_server_test("AES256-SHA", "-cipher AES128-SHA",
+ DEFAULT_CERT, NULL, DEFAULT_KEY, NULL, NULL,
+ DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * RC4-SHA
+ */
+ if ((ret = SSL_server_test("RC4-SHA", "-cipher RC4-SHA",
+ DEFAULT_CERT, NULL, DEFAULT_KEY, NULL, NULL,
+ DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * RC4-MD5
+ */
+ if ((ret = SSL_server_test("RC4-MD5", "-cipher RC4-MD5",
+ DEFAULT_CERT, NULL, DEFAULT_KEY, NULL, NULL,
+ DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * Session Reuse
+ * all the session id's should match for session resumption.
+ */
+ if ((ret = SSL_server_test("Session Reuse",
+ "-cipher RC4-SHA -reconnect",
+ DEFAULT_CERT, NULL, DEFAULT_KEY, NULL, NULL,
+ DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * 512 bit RSA key
+ */
+ if ((ret = SSL_server_test("512 bit key", "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_512.cer", NULL,
+ "../ssl/test/axTLS.key_512",
+ NULL, NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * 1024 bit RSA key (check certificate chaining)
+ */
+ if ((ret = SSL_server_test("1024 bit key",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_device.cer",
+ "../ssl/test/axTLS.x509_512.cer",
+ "../ssl/test/axTLS.device_key",
+ NULL, NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * 2048 bit RSA key
+ */
+ if ((ret = SSL_server_test("2048 bit key",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_2048.cer", NULL,
+ "../ssl/test/axTLS.key_2048",
+ NULL, NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * 4096 bit RSA key
+ */
+ if ((ret = SSL_server_test("4096 bit key",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_4096.cer", NULL,
+ "../ssl/test/axTLS.key_4096",
+ NULL, NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * Client Verification
+ */
+ if ((ret = SSL_server_test("Client Verification",
+ "-cipher RC4-SHA -tls1 "
+ "-cert ../ssl/test/axTLS.x509_2048.pem "
+ "-key ../ssl/test/axTLS.key_2048.pem ",
+ NULL, NULL, NULL,
+ "../ssl/test/axTLS.ca_x509.cer", NULL,
+ DEFAULT_SVR_OPTION|SSL_CLIENT_AUTHENTICATION)))
+ goto cleanup;
+
+ /* this test should fail */
+ if (stat("../ssl/test/axTLS.x509_bad_before.pem", &stat_buf) >= 0)
+ {
+ if ((ret = SSL_server_test("Error: Bad Before Cert",
+ "-cipher RC4-SHA -tls1 "
+ "-cert ../ssl/test/axTLS.x509_bad_before.pem "
+ "-key ../ssl/test/axTLS.key_512.pem ",
+ NULL, NULL, NULL,
+ "../ssl/test/axTLS.ca_x509.cer", NULL,
+ DEFAULT_SVR_OPTION|SSL_CLIENT_AUTHENTICATION)) !=
+ SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID))
+ goto cleanup;
+
+ printf("SSL server test \"%s\" passed\n", "Bad Before Cert");
+ TTY_FLUSH();
+ ret = 0; /* is ok */
+ }
+
+ /* this test should fail */
+ if ((ret = SSL_server_test("Error: Bad After Cert",
+ "-cipher RC4-SHA -tls1 "
+ "-cert ../ssl/test/axTLS.x509_bad_after.pem "
+ "-key ../ssl/test/axTLS.key_512.pem ",
+ NULL, NULL, NULL,
+ "../ssl/test/axTLS.ca_x509.cer", NULL,
+ DEFAULT_SVR_OPTION|SSL_CLIENT_AUTHENTICATION)) !=
+ SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED))
+ goto cleanup;
+
+ printf("SSL server test \"%s\" passed\n", "Bad After Cert");
+ TTY_FLUSH();
+
+ /*
+ * No trusted cert
+ */
+ if ((ret = SSL_server_test("Error: No trusted certificate",
+ "-cipher RC4-SHA -tls1 "
+ "-cert ../ssl/test/axTLS.x509_512.pem "
+ "-key ../ssl/test/axTLS.key_512.pem ",
+ NULL, NULL, NULL,
+ NULL, NULL,
+ DEFAULT_SVR_OPTION|SSL_CLIENT_AUTHENTICATION)) !=
+ SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT))
+ goto cleanup;
+
+ printf("SSL server test \"%s\" passed\n", "No trusted certificate");
+ TTY_FLUSH();
+
+ /*
+ * Self-signed (from the server)
+ */
+ if ((ret = SSL_server_test("Error: Self-signed certificate (from server)",
+ "-cipher RC4-SHA -tls1 "
+ "-cert ../ssl/test/axTLS.x509_512.pem "
+ "-key ../ssl/test/axTLS.key_512.pem "
+ "-CAfile ../ssl/test/axTLS.ca_x509.pem ",
+ NULL, NULL, NULL,
+ NULL, NULL,
+ DEFAULT_SVR_OPTION|SSL_CLIENT_AUTHENTICATION)) !=
+ SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED))
+ goto cleanup;
+
+ printf("SSL server test \"%s\" passed\n",
+ "Self-signed certificate (from server)");
+ TTY_FLUSH();
+
+ /*
+ * Self-signed (from the client)
+ */
+ if ((ret = SSL_server_test("Self-signed certificate (from client)",
+ "-cipher RC4-SHA -tls1 "
+ "-cert ../ssl/test/axTLS.x509_512.pem "
+ "-key ../ssl/test/axTLS.key_512.pem ",
+ NULL, NULL, NULL,
+ "../ssl/test/axTLS.ca_x509.cer",
+ NULL,
+ DEFAULT_SVR_OPTION|SSL_CLIENT_AUTHENTICATION)))
+ goto cleanup;
+
+ /*
+ * Key in PEM format
+ */
+ if ((ret = SSL_server_test("Key in PEM format",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_512.cer", NULL,
+ "../ssl/test/axTLS.key_512.pem", NULL,
+ NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * Cert in PEM format
+ */
+ if ((ret = SSL_server_test("Cert in PEM format",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_512.pem", NULL,
+ "../ssl/test/axTLS.key_512.pem", NULL,
+ NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * Cert chain in PEM format
+ */
+ if ((ret = SSL_server_test("Cert chain in PEM format",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_device.pem",
+ NULL, "../ssl/test/axTLS.device_key.pem",
+ "../ssl/test/axTLS.ca_x509.pem", NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * AES128 Encrypted key
+ */
+ if ((ret = SSL_server_test("AES128 encrypted key",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_aes128.pem", NULL,
+ "../ssl/test/axTLS.key_aes128.pem",
+ NULL, "abcd", DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * AES256 Encrypted key
+ */
+ if ((ret = SSL_server_test("AES256 encrypted key",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_aes256.pem", NULL,
+ "../ssl/test/axTLS.key_aes256.pem",
+ NULL, "abcd", DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * AES128 Encrypted invalid key
+ */
+ if ((ret = SSL_server_test("AES128 encrypted invalid key",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_aes128.pem", NULL,
+ "../ssl/test/axTLS.key_aes128.pem",
+ NULL, "xyz", DEFAULT_SVR_OPTION)) != SSL_ERROR_INVALID_KEY)
+ goto cleanup;
+
+ printf("SSL server test \"%s\" passed\n", "AES128 encrypted invalid key");
+ TTY_FLUSH();
+
+ /*
+ * PKCS#8 key (encrypted)
+ */
+ if ((ret = SSL_server_test("pkcs#8 encrypted", "-cipher RC4-SHA",
+ DEFAULT_CERT, NULL, "../ssl/test/axTLS.encrypted.p8",
+ NULL, "abcd", DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * PKCS#8 key (unencrypted)
+ */
+ if ((ret = SSL_server_test("pkcs#8 unencrypted", "-cipher RC4-SHA",
+ DEFAULT_CERT, NULL, "../ssl/test/axTLS.unencrypted.p8",
+ NULL, NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * PKCS#12 key/certificate
+ */
+ if ((ret = SSL_server_test("pkcs#12 with CA", "-cipher RC4-SHA",
+ NULL, NULL, "../ssl/test/axTLS.withCA.p12",
+ NULL, "abcd", DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ if ((ret = SSL_server_test("pkcs#12 no CA", "-cipher RC4-SHA",
+ DEFAULT_CERT, NULL, "../ssl/test/axTLS.withoutCA.p12",
+ NULL, "abcd", DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ if (ret)
+ {
+ printf("Error: A server test failed\n");
+ ssl_display_error(ret);
+ exit(1);
+ }
+ else
+ {
+ printf("All server tests passed\n"); TTY_FLUSH();
+ }
+
+ return ret;
+}
+
+/**************************************************************************
+ * SSL Client Testing
+ *
+ **************************************************************************/
+typedef struct
+{
+ uint8_t session_id[SSL_SESSION_ID_SIZE];
+#ifndef WIN32
+ pthread_t server_thread;
+#endif
+ int start_server;
+ int stop_server;
+ int do_reneg;
+} CLNT_SESSION_RESUME_CTX;
+
+typedef struct
+{
+ const char *testname;
+ const char *openssl_option;
+} server_t;
+
+static void do_server(server_t *svr)
+{
+ char openssl_buf[2048];
+#ifndef WIN32
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+#endif
+ sprintf(openssl_buf, "openssl s_server -tls1 "
+ "-accept %d -quiet %s ", g_port, svr->openssl_option);
+ system(openssl_buf);
+}
+
+static int SSL_client_test(
+ const char *test,
+ SSL_CTX **ssl_ctx,
+ const char *openssl_option,
+ CLNT_SESSION_RESUME_CTX *sess_resume,
+ uint32_t client_options,
+ const char *private_key,
+ const char *password,
+ const char *cert)
+{
+ server_t server_data;
+ SSL *ssl = NULL;
+ int client_fd = -1;
+ uint8_t *session_id = NULL;
+ int ret = 1;
+#ifndef WIN32
+ pthread_t thread;
+#endif
+
+ if (sess_resume == NULL || sess_resume->start_server)
+ {
+ g_port++;
+ server_data.openssl_option = openssl_option;
+
+#ifndef WIN32
+ pthread_create(&thread, NULL,
+ (void *(*)(void *))do_server, (void *)&server_data);
+ pthread_detach(thread);
+#else
+ CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)do_server,
+ (LPVOID)&server_data, 0, NULL);
+#endif
+ }
+
+ usleep(200000); /* allow server to start */
+
+ if (*ssl_ctx == NULL)
+ {
+ if (private_key)
+ {
+ client_options |= SSL_NO_DEFAULT_KEY;
+ }
+
+ if ((*ssl_ctx = ssl_ctx_new(
+ client_options, SSL_DEFAULT_CLNT_SESS)) == NULL)
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto client_test_exit;
+ }
+
+ if (private_key)
+ {
+ int obj_type = SSL_OBJ_RSA_KEY;
+
+ if (strstr(private_key, ".p8"))
+ obj_type = SSL_OBJ_PKCS8;
+ else if (strstr(private_key, ".p12"))
+ obj_type = SSL_OBJ_PKCS12;
+
+ if (ssl_obj_load(*ssl_ctx, obj_type, private_key, password))
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto client_test_exit;
+ }
+ }
+
+ if (cert)
+ {
+ if ((ret = ssl_obj_load(*ssl_ctx,
+ SSL_OBJ_X509_CERT, cert, NULL)) != SSL_OK)
+ {
+ printf("could not add cert %s (%d)\n", cert, ret);
+ TTY_FLUSH();
+ goto client_test_exit;
+ }
+ }
+
+ if (ssl_obj_load(*ssl_ctx, SSL_OBJ_X509_CACERT,
+ "../ssl/test/axTLS.ca_x509.cer", NULL))
+ {
+ printf("could not add cert auth\n"); TTY_FLUSH();
+ goto client_test_exit;
+ }
+ }
+
+ if (sess_resume && !sess_resume->start_server)
+ {
+ session_id = sess_resume->session_id;
+ }
+
+ if ((client_fd = client_socket_init(g_port)) < 0)
+ {
+ printf("could not start socket on %d\n", g_port); TTY_FLUSH();
+ goto client_test_exit;
+ }
+
+ ssl = ssl_client_new(*ssl_ctx, client_fd, session_id, sizeof(session_id));
+
+ /* check the return status */
+ if ((ret = ssl_handshake_status(ssl)))
+ goto client_test_exit;
+
+ /* renegotiate client */
+ if (sess_resume && sess_resume->do_reneg)
+ {
+ if (ssl_renegotiate(ssl) < 0)
+ goto client_test_exit;
+ }
+
+ if (sess_resume)
+ {
+ memcpy(sess_resume->session_id,
+ ssl_get_session_id(ssl), SSL_SESSION_ID_SIZE);
+ }
+
+ if (IS_SET_SSL_FLAG(SSL_SERVER_VERIFY_LATER) &&
+ (ret = ssl_verify_cert(ssl)))
+ {
+ goto client_test_exit;
+ }
+
+ ssl_write(ssl, (uint8_t *)"hello world\n", 13);
+ if (sess_resume)
+ {
+ const uint8_t *sess_id = ssl_get_session_id(ssl);
+ int i;
+
+ printf(" Session-ID: ");
+ for (i = 0; i < SSL_SESSION_ID_SIZE; i++)
+ {
+ printf("%02X", sess_id[i]);
+ }
+ printf("\n");
+ TTY_FLUSH();
+ }
+
+ ret = 0;
+
+client_test_exit:
+ ssl_free(ssl);
+ SOCKET_CLOSE(client_fd);
+ usleep(200000); /* allow openssl to say something */
+
+ if (sess_resume)
+ {
+ if (sess_resume->stop_server)
+ {
+ ssl_ctx_free(*ssl_ctx);
+ *ssl_ctx = NULL;
+#ifndef WIN32
+ pthread_cancel(sess_resume->server_thread);
+#endif
+ }
+ else if (sess_resume->start_server)
+ {
+#ifndef WIN32
+ sess_resume->server_thread = thread;
+#endif
+ }
+ }
+ else
+ {
+ ssl_ctx_free(*ssl_ctx);
+ *ssl_ctx = NULL;
+#ifndef WIN32
+ pthread_cancel(thread);
+#endif
+ }
+
+ if (ret == 0)
+ {
+ printf("SSL client test \"%s\" passed\n", test);
+ TTY_FLUSH();
+ }
+
+ return ret;
+}
+
+int SSL_client_tests(void)
+{
+ int ret = -1;
+ SSL_CTX *ssl_ctx = NULL;
+ CLNT_SESSION_RESUME_CTX sess_resume;
+ memset(&sess_resume, 0, sizeof(CLNT_SESSION_RESUME_CTX));
+
+ sess_resume.start_server = 1;
+ printf("### starting client tests\n");
+
+ if ((ret = SSL_client_test("512 bit key",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_512.pem "
+ "-key ../ssl/test/axTLS.key_512.pem", &sess_resume,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ /* all the session id's should match for session resumption */
+ sess_resume.start_server = 0;
+ if ((ret = SSL_client_test("Client session resumption #1",
+ &ssl_ctx, NULL, &sess_resume,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ sess_resume.do_reneg = 1;
+ if ((ret = SSL_client_test("Client renegotiation",
+ &ssl_ctx, NULL, &sess_resume,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+ sess_resume.do_reneg = 0;
+
+ sess_resume.stop_server = 1;
+ if ((ret = SSL_client_test("Client session resumption #2",
+ &ssl_ctx, NULL, &sess_resume,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ if ((ret = SSL_client_test("1024 bit key",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_1024.pem "
+ "-key ../ssl/test/axTLS.key_1024.pem", NULL,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ if ((ret = SSL_client_test("2048 bit key",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_2048.pem "
+ "-key ../ssl/test/axTLS.key_2048.pem", NULL,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ if ((ret = SSL_client_test("4096 bit key",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_4096.pem "
+ "-key ../ssl/test/axTLS.key_4096.pem", NULL,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ if ((ret = SSL_client_test("Server cert chaining",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_device.pem "
+ "-key ../ssl/test/axTLS.device_key.pem "
+ "-CAfile ../ssl/test/axTLS.x509_512.pem ", NULL,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ /* Check the server can verify the client */
+ if ((ret = SSL_client_test("Client peer authentication",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_2048.pem "
+ "-key ../ssl/test/axTLS.key_2048.pem "
+ "-CAfile ../ssl/test/axTLS.ca_x509.pem "
+ "-verify 1 ", NULL, DEFAULT_CLNT_OPTION,
+ "../ssl/test/axTLS.key_1024", NULL,
+ "../ssl/test/axTLS.x509_1024.cer")))
+ goto cleanup;
+
+ /* Should get an "ERROR" from openssl (as the handshake fails as soon as
+ * the certificate verification fails) */
+ if ((ret = SSL_client_test("Error: Expired cert (verify now)",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_bad_after.pem "
+ "-key ../ssl/test/axTLS.key_512.pem", NULL,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)) !=
+ SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED))
+ {
+ printf("*** Error: %d\n", ret);
+ goto cleanup;
+ }
+
+ printf("SSL client test \"Expired cert (verify now)\" passed\n");
+
+ /* There is no "ERROR" from openssl */
+ if ((ret = SSL_client_test("Error: Expired cert (verify later)",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_bad_after.pem "
+ "-key ../ssl/test/axTLS.key_512.pem", NULL,
+ DEFAULT_CLNT_OPTION|SSL_SERVER_VERIFY_LATER, NULL,
+ NULL, NULL)) != SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED))
+ {
+ printf("*** Error: %d\n", ret);
+ goto cleanup;
+ }
+
+ printf("SSL client test \"Expired cert (verify later)\" passed\n");
+ ret = 0;
+
+cleanup:
+ if (ret)
+ {
+ ssl_display_error(ret);
+ printf("Error: A client test failed\n");
+ exit(1);
+ }
+ else
+ {
+ printf("All client tests passed\n"); TTY_FLUSH();
+ }
+
+ return ret;
+}
+
+/**************************************************************************
+ * SSL Basic Testing (test a big packet handshake)
+ *
+ **************************************************************************/
+static uint8_t basic_buf[256*1024];
+
+static void do_basic(void)
+{
+ int client_fd;
+ SSL *ssl_clnt;
+ SSL_CTX *ssl_clnt_ctx = ssl_ctx_new(
+ DEFAULT_CLNT_OPTION, SSL_DEFAULT_CLNT_SESS);
+ usleep(200000); /* allow server to start */
+
+ if ((client_fd = client_socket_init(g_port)) < 0)
+ goto error;
+
+ if (ssl_obj_load(ssl_clnt_ctx, SSL_OBJ_X509_CACERT,
+ "../ssl/test/axTLS.ca_x509.cer", NULL))
+ goto error;
+
+ ssl_clnt = ssl_client_new(ssl_clnt_ctx, client_fd, NULL, 0);
+
+ /* check the return status */
+ if (ssl_handshake_status(ssl_clnt) < 0)
+ {
+ printf("YA YA\n");
+ ssl_display_error(ssl_handshake_status(ssl_clnt));
+ goto error;
+ }
+
+ ssl_write(ssl_clnt, basic_buf, sizeof(basic_buf));
+ ssl_free(ssl_clnt);
+
+error:
+ ssl_ctx_free(ssl_clnt_ctx);
+ SOCKET_CLOSE(client_fd);
+
+ /* exit this thread */
+}
+
+static int SSL_basic_test(void)
+{
+ int server_fd, client_fd, ret = 0, size = 0, offset = 0;
+ SSL_CTX *ssl_svr_ctx = NULL;
+ struct sockaddr_in client_addr;
+ uint8_t *read_buf;
+ socklen_t clnt_len = sizeof(client_addr);
+ SSL *ssl_svr;
+#ifndef WIN32
+ pthread_t thread;
+#endif
+ memset(basic_buf, 0xA5, sizeof(basic_buf)/2);
+ memset(&basic_buf[sizeof(basic_buf)/2], 0x5A, sizeof(basic_buf)/2);
+
+ if ((server_fd = server_socket_init(&g_port)) < 0)
+ goto error;
+
+ ssl_svr_ctx = ssl_ctx_new(DEFAULT_SVR_OPTION, SSL_DEFAULT_SVR_SESS);
+
+#ifndef WIN32
+ pthread_create(&thread, NULL,
+ (void *(*)(void *))do_basic, NULL);
+ pthread_detach(thread);
+#else
+ CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)do_basic, NULL, 0, NULL);
+#endif
+
+ /* Wait for a client to connect */
+ if ((client_fd = accept(server_fd,
+ (struct sockaddr *) &client_addr, &clnt_len)) < 0)
+ {
+ ret = SSL_ERROR_SOCK_SETUP_FAILURE;
+ goto error;
+ }
+
+ /* we are ready to go */
+ ssl_svr = ssl_server_new(ssl_svr_ctx, client_fd);
+
+ do
+ {
+ while ((size = ssl_read(ssl_svr, &read_buf)) == SSL_OK);
+
+ if (size < SSL_OK) /* got some alert or something nasty */
+ {
+ printf("Server ");
+ ssl_display_error(size);
+ ret = size;
+ break;
+ }
+ else /* looks more promising */
+ {
+ if (memcmp(read_buf, &basic_buf[offset], size) != 0)
+ {
+ ret = SSL_NOT_OK;
+ break;
+ }
+ }
+
+ offset += size;
+ } while (offset < sizeof(basic_buf));
+
+ printf(ret == SSL_OK && offset == sizeof(basic_buf) ?
+ "SSL basic test passed\n" :
+ "SSL basic test failed\n");
+ TTY_FLUSH();
+
+ ssl_free(ssl_svr);
+ SOCKET_CLOSE(server_fd);
+ SOCKET_CLOSE(client_fd);
+
+error:
+ ssl_ctx_free(ssl_svr_ctx);
+ return ret;
+}
+
+#if !defined(WIN32) && defined(CONFIG_SSL_CTX_MUTEXING)
+/**************************************************************************
+ * Multi-Threading Tests
+ *
+ **************************************************************************/
+#define NUM_THREADS 100
+
+typedef struct
+{
+ SSL_CTX *ssl_clnt_ctx;
+ int port;
+ int thread_id;
+} multi_t;
+
+void do_multi_clnt(multi_t *multi_data)
+{
+ int res = 1, client_fd, i;
+ SSL *ssl = NULL;
+ char tmp[5];
+
+ if ((client_fd = client_socket_init(multi_data->port)) < 0)
+ goto client_test_exit;
+
+ sleep(1);
+ ssl = ssl_client_new(multi_data->ssl_clnt_ctx, client_fd, NULL, 0);
+
+ if ((res = ssl_handshake_status(ssl)))
+ {
+ printf("Client ");
+ ssl_display_error(res);
+ goto client_test_exit;
+ }
+
+ sprintf(tmp, "%d\n", multi_data->thread_id);
+ for (i = 0; i < 10; i++)
+ ssl_write(ssl, (uint8_t *)tmp, strlen(tmp)+1);
+
+client_test_exit:
+ ssl_free(ssl);
+ SOCKET_CLOSE(client_fd);
+ free(multi_data);
+}
+
+void do_multi_svr(SSL *ssl)
+{
+ uint8_t *read_buf;
+ int *res_ptr = malloc(sizeof(int));
+ int res;
+
+ for (;;)
+ {
+ res = ssl_read(ssl, &read_buf);
+
+ /* kill the client */
+ if (res != SSL_OK)
+ {
+ if (res == SSL_ERROR_CONN_LOST)
+ {
+ SOCKET_CLOSE(ssl->client_fd);
+ ssl_free(ssl);
+ break;
+ }
+ else if (res > 0)
+ {
+ /* do nothing */
+ }
+ else /* some problem */
+ {
+ printf("Server ");
+ ssl_display_error(res);
+ goto error;
+ }
+ }
+ }
+
+ res = SSL_OK;
+error:
+ *res_ptr = res;
+ pthread_exit(res_ptr);
+}
+
+int multi_thread_test(void)
+{
+ int server_fd = -1;
+ SSL_CTX *ssl_server_ctx;
+ SSL_CTX *ssl_clnt_ctx;
+ pthread_t clnt_threads[NUM_THREADS];
+ pthread_t svr_threads[NUM_THREADS];
+ int i, res = 0;
+ struct sockaddr_in client_addr;
+ socklen_t clnt_len = sizeof(client_addr);
+
+ printf("Do multi-threading test (takes a minute)\n");
+
+ ssl_server_ctx = ssl_ctx_new(DEFAULT_SVR_OPTION, SSL_DEFAULT_SVR_SESS);
+ ssl_clnt_ctx = ssl_ctx_new(DEFAULT_CLNT_OPTION, SSL_DEFAULT_CLNT_SESS);
+
+ if (ssl_obj_load(ssl_clnt_ctx, SSL_OBJ_X509_CACERT,
+ "../ssl/test/axTLS.ca_x509.cer", NULL))
+ goto error;
+
+ if ((server_fd = server_socket_init(&g_port)) < 0)
+ goto error;
+
+ for (i = 0; i < NUM_THREADS; i++)
+ {
+ multi_t *multi_data = (multi_t *)malloc(sizeof(multi_t));
+ multi_data->ssl_clnt_ctx = ssl_clnt_ctx;
+ multi_data->port = g_port;
+ multi_data->thread_id = i+1;
+ pthread_create(&clnt_threads[i], NULL,
+ (void *(*)(void *))do_multi_clnt, (void *)multi_data);
+ pthread_detach(clnt_threads[i]);
+ }
+
+ for (i = 0; i < NUM_THREADS; i++)
+ {
+ SSL *ssl_svr;
+ int client_fd = accept(server_fd,
+ (struct sockaddr *)&client_addr, &clnt_len);
+
+ if (client_fd < 0)
+ goto error;
+
+ ssl_svr = ssl_server_new(ssl_server_ctx, client_fd);
+
+ pthread_create(&svr_threads[i], NULL,
+ (void *(*)(void *))do_multi_svr, (void *)ssl_svr);
+ }
+
+ /* make sure we've run all of the threads */
+ for (i = 0; i < NUM_THREADS; i++)
+ {
+ void *thread_res;
+ pthread_join(svr_threads[i], &thread_res);
+
+ if (*((int *)thread_res) != 0)
+ res = 1;
+
+ free(thread_res);
+ }
+
+ if (res)
+ goto error;
+
+ printf("Multi-thread test passed (%d)\n", NUM_THREADS);
+error:
+ ssl_ctx_free(ssl_server_ctx);
+ ssl_ctx_free(ssl_clnt_ctx);
+ SOCKET_CLOSE(server_fd);
+ return res;
+}
+#endif /* !defined(WIN32) && defined(CONFIG_SSL_CTX_MUTEXING) */
+
+/**************************************************************************
+ * Header issue
+ *
+ **************************************************************************/
+static void do_header_issue(void)
+{
+ char axtls_buf[2048];
+#ifndef WIN32
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+#endif
+ sprintf(axtls_buf, "./axssl s_client -connect localhost:%d", g_port);
+ system(axtls_buf);
+}
+
+static int header_issue(void)
+{
+ FILE *f = fopen("../ssl/test/header_issue.dat", "r");
+ int server_fd = -1, client_fd = -1, ret = 1;
+ uint8_t buf[2048];
+ int size = 0;
+ struct sockaddr_in client_addr;
+ socklen_t clnt_len = sizeof(client_addr);
+#ifndef WIN32
+ pthread_t thread;
+#endif
+
+ if (f == NULL || (server_fd = server_socket_init(&g_port)) < 0)
+ goto error;
+
+#ifndef WIN32
+ pthread_create(&thread, NULL,
+ (void *(*)(void *))do_header_issue, NULL);
+ pthread_detach(thread);
+#else
+ CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)do_header_issue,
+ NULL, 0, NULL);
+#endif
+ if ((client_fd = accept(server_fd,
+ (struct sockaddr *) &client_addr, &clnt_len)) < 0)
+ {
+ ret = SSL_ERROR_SOCK_SETUP_FAILURE;
+ goto error;
+ }
+
+ size = fread(buf, 1, sizeof(buf), f);
+ SOCKET_WRITE(client_fd, buf, size);
+ usleep(200000);
+
+ ret = 0;
+error:
+ fclose(f);
+ SOCKET_CLOSE(client_fd);
+ SOCKET_CLOSE(server_fd);
+ TTY_FLUSH();
+ system("killall axssl");
+ return ret;
+}
+
+/**************************************************************************
+ * main()
+ *
+ **************************************************************************/
+int main(int argc, char *argv[])
+{
+ int ret = 1;
+ BI_CTX *bi_ctx;
+ int fd;
+
+#ifdef WIN32
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(2, 2);
+ WSAStartup(wVersionRequested, &wsaData);
+ fd = _open("test_result.txt", O_WRONLY|O_TEMPORARY|O_CREAT, _S_IWRITE);
+ dup2(fd, 2); /* write stderr to this file */
+#else
+ fd = open("/dev/null", O_WRONLY); /* write stderr to /dev/null */
+ signal(SIGPIPE, SIG_IGN); /* ignore pipe errors */
+ dup2(fd, 2);
+#endif
+
+ /* can't do testing in this mode */
+#if defined CONFIG_SSL_GENERATE_X509_CERT
+ printf("Error: Must compile with default key/certificates\n");
+ exit(1);
+#endif
+
+ bi_ctx = bi_initialize();
+
+ if (AES_test(bi_ctx))
+ {
+ printf("AES tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ if (RC4_test(bi_ctx))
+ {
+ printf("RC4 tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ if (MD5_test(bi_ctx))
+ {
+ printf("MD5 tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ if (SHA1_test(bi_ctx))
+ {
+ printf("SHA1 tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ if (HMAC_test(bi_ctx))
+ {
+ printf("HMAC tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ if (BIGINT_test(bi_ctx))
+ {
+ printf("BigInt tests failed!\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ bi_terminate(bi_ctx);
+
+ if (RSA_test())
+ {
+ printf("RSA tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ if (cert_tests())
+ {
+ printf("CERT tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+#if !defined(WIN32) && defined(CONFIG_SSL_CTX_MUTEXING)
+ if (multi_thread_test())
+ goto cleanup;
+#endif
+
+ if (SSL_basic_test())
+ goto cleanup;
+
+ system("sh ../ssl/test/killopenssl.sh");
+
+ if (SSL_client_tests())
+ goto cleanup;
+
+ system("sh ../ssl/test/killopenssl.sh");
+
+ if (SSL_server_tests())
+ goto cleanup;
+
+ system("sh ../ssl/test/killopenssl.sh");
+
+ if (header_issue())
+ {
+ printf("Header tests failed\n"); TTY_FLUSH();
+ goto cleanup;
+ }
+
+ ret = 0; /* all ok */
+ printf("**** ALL TESTS PASSED ****\n"); TTY_FLUSH();
+cleanup:
+
+ if (ret)
+ printf("Error: Some tests failed!\n");
+
+ close(fd);
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The testing of the crypto and ssl stuff goes here. Keeps the individual code
+ * modules from being uncluttered with test code.
+ *
+ * This is test code - I make no apologies for the quality!
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifndef WIN32
+#include <pthread.h>
+#endif
+
+#include "ssl.h"
+
+#define DEFAULT_CERT "../ssl/test/axTLS.x509_512.cer"
+#define DEFAULT_KEY "../ssl/test/axTLS.key_512"
+//#define DEFAULT_SVR_OPTION SSL_DISPLAY_BYTES|SSL_DISPLAY_STATES
+#define DEFAULT_SVR_OPTION 0
+#define DEFAULT_CLNT_OPTION 0
+//#define DEFAULT_CLNT_OPTION SSL_DISPLAY_BYTES|SSL_DISPLAY_STATES
+
+static int g_port = 19001;
+
+/**************************************************************************
+ * AES tests
+ *
+ * Run through a couple of the RFC3602 tests to verify that AES is correct.
+ **************************************************************************/
+#define TEST1_SIZE 16
+#define TEST2_SIZE 32
+
+static int AES_test(BI_CTX *bi_ctx)
+{
+ AES_CTX aes_key;
+ int res = 1;
+ uint8_t key[TEST1_SIZE];
+ uint8_t iv[TEST1_SIZE];
+
+ {
+ /*
+ Case #1: Encrypting 16 bytes (1 block) using AES-CBC
+ Key : 0x06a9214036b8a15b512e03d534120006
+ IV : 0x3dafba429d9eb430b422da802c9fac41
+ Plaintext : "Single block msg"
+ Ciphertext: 0xe353779c1079aeb82708942dbe77181a
+
+ */
+ char *in_str = "Single block msg";
+ uint8_t ct[TEST1_SIZE];
+ uint8_t enc_data[TEST1_SIZE];
+ uint8_t dec_data[TEST1_SIZE];
+
+ bigint *key_bi = bi_str_import(
+ bi_ctx, "06A9214036B8A15B512E03D534120006");
+ bigint *iv_bi = bi_str_import(
+ bi_ctx, "3DAFBA429D9EB430B422DA802C9FAC41");
+ bigint *ct_bi = bi_str_import(
+ bi_ctx, "E353779C1079AEB82708942DBE77181A");
+ bi_export(bi_ctx, key_bi, key, TEST1_SIZE);
+ bi_export(bi_ctx, iv_bi, iv, TEST1_SIZE);
+ bi_export(bi_ctx, ct_bi, ct, TEST1_SIZE);
+
+ AES_set_key(&aes_key, key, iv, AES_MODE_128);
+ AES_cbc_encrypt(&aes_key, (const uint8_t *)in_str,
+ enc_data, sizeof(enc_data));
+ if (memcmp(enc_data, ct, sizeof(ct)))
+ {
+ printf("Error: AES ENCRYPT #1 failed\n");
+ goto end;
+ }
+
+ AES_set_key(&aes_key, key, iv, AES_MODE_128);
+ AES_convert_key(&aes_key);
+ AES_cbc_decrypt(&aes_key, enc_data, dec_data, sizeof(enc_data));
+
+ if (memcmp(dec_data, in_str, sizeof(dec_data)))
+ {
+ printf("Error: AES DECRYPT #1 failed\n");
+ goto end;
+ }
+ }
+
+ {
+ /*
+ Case #2: Encrypting 32 bytes (2 blocks) using AES-CBC
+ Key : 0xc286696d887c9aa0611bbb3e2025a45a
+ IV : 0x562e17996d093d28ddb3ba695a2e6f58
+ Plaintext : 0x000102030405060708090a0b0c0d0e0f
+ 101112131415161718191a1b1c1d1e1f
+ Ciphertext: 0xd296cd94c2cccf8a3a863028b5e1dc0a
+ 7586602d253cfff91b8266bea6d61ab1
+ */
+ uint8_t in_data[TEST2_SIZE];
+ uint8_t ct[TEST2_SIZE];
+ uint8_t enc_data[TEST2_SIZE];
+ uint8_t dec_data[TEST2_SIZE];
+
+ bigint *in_bi = bi_str_import(bi_ctx,
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+ bigint *key_bi = bi_str_import(
+ bi_ctx, "C286696D887C9AA0611BBB3E2025A45A");
+ bigint *iv_bi = bi_str_import(
+ bi_ctx, "562E17996D093D28DDB3BA695A2E6F58");
+ bigint *ct_bi = bi_str_import(bi_ctx,
+ "D296CD94C2CCCF8A3A863028B5E1DC0A7586602D253CFFF91B8266BEA6D61AB1");
+ bi_export(bi_ctx, in_bi, in_data, TEST2_SIZE);
+ bi_export(bi_ctx, key_bi, key, TEST1_SIZE);
+ bi_export(bi_ctx, iv_bi, iv, TEST1_SIZE);
+ bi_export(bi_ctx, ct_bi, ct, TEST2_SIZE);
+
+ AES_set_key(&aes_key, key, iv, AES_MODE_128);
+ AES_cbc_encrypt(&aes_key, (const uint8_t *)in_data,
+ enc_data, sizeof(enc_data));
+
+ if (memcmp(enc_data, ct, sizeof(ct)))
+ {
+ printf("Error: ENCRYPT #2 failed\n");
+ goto end;
+ }
+
+ AES_set_key(&aes_key, key, iv, AES_MODE_128);
+ AES_convert_key(&aes_key);
+ AES_cbc_decrypt(&aes_key, enc_data, dec_data, sizeof(enc_data));
+ if (memcmp(dec_data, in_data, sizeof(dec_data)))
+ {
+ printf("Error: DECRYPT #2 failed\n");
+ goto end;
+ }
+ }
+
+ res = 0;
+ printf("All AES tests passed\n");
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * RC4 tests
+ *
+ * ARC4 tests vectors from OpenSSL (crypto/rc4/rc4test.c)
+ **************************************************************************/
+static const uint8_t keys[7][30]=
+{
+ {8,0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef},
+ {8,0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef},
+ {8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {4,0xef,0x01,0x23,0x45},
+ {8,0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef},
+ {4,0xef,0x01,0x23,0x45},
+};
+
+static const uint8_t data_len[7]={8,8,8,20,28,10};
+static uint8_t data[7][30]=
+{
+ {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xff},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0xff},
+ {0x12,0x34,0x56,0x78,0x9A,0xBC,0xDE,0xF0,
+ 0x12,0x34,0x56,0x78,0x9A,0xBC,0xDE,0xF0,
+ 0x12,0x34,0x56,0x78,0x9A,0xBC,0xDE,0xF0,
+ 0x12,0x34,0x56,0x78,0xff},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff},
+ {0},
+};
+
+static const uint8_t output[7][30]=
+{
+ {0x75,0xb7,0x87,0x80,0x99,0xe0,0xc5,0x96,0x00},
+ {0x74,0x94,0xc2,0xe7,0x10,0x4b,0x08,0x79,0x00},
+ {0xde,0x18,0x89,0x41,0xa3,0x37,0x5d,0x3a,0x00},
+ {0xd6,0xa1,0x41,0xa7,0xec,0x3c,0x38,0xdf,
+ 0xbd,0x61,0x5a,0x11,0x62,0xe1,0xc7,0xba,
+ 0x36,0xb6,0x78,0x58,0x00},
+ {0x66,0xa0,0x94,0x9f,0x8a,0xf7,0xd6,0x89,
+ 0x1f,0x7f,0x83,0x2b,0xa8,0x33,0xc0,0x0c,
+ 0x89,0x2e,0xbe,0x30,0x14,0x3c,0xe2,0x87,
+ 0x40,0x01,0x1e,0xcf,0x00},
+ {0xd6,0xa1,0x41,0xa7,0xec,0x3c,0x38,0xdf,0xbd,0x61,0x00},
+ {0},
+};
+
+static int RC4_test(BI_CTX *bi_ctx)
+{
+ int i, res = 1;
+ RC4_CTX s;
+
+ for (i = 0; i < 6; i++)
+ {
+ RC4_setup(&s, &keys[i][1], keys[i][0]);
+ RC4_crypt(&s, data[i], data[i], data_len[i]);
+
+ if (memcmp(data[i], output[i], data_len[i]))
+ {
+ printf("Error: RC4 CRYPT #%d failed\n", i);
+ goto end;
+ }
+ }
+
+ res = 0;
+ printf("All RC4 tests passed\n");
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * SHA1 tests
+ *
+ * Run through a couple of the RFC3174 tests to verify that SHA1 is correct.
+ **************************************************************************/
+static int SHA1_test(BI_CTX *bi_ctx)
+{
+ SHA1_CTX ctx;
+ uint8_t ct[SHA1_SIZE];
+ uint8_t digest[SHA1_SIZE];
+ int res = 1;
+
+ {
+ const char *in_str = "abc";
+ bigint *ct_bi = bi_str_import(bi_ctx,
+ "A9993E364706816ABA3E25717850C26C9CD0D89D");
+ bi_export(bi_ctx, ct_bi, ct, SHA1_SIZE);
+
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, (const uint8_t *)in_str, strlen(in_str));
+ SHA1_Final(digest, &ctx);
+
+ if (memcmp(digest, ct, sizeof(ct)))
+ {
+ printf("Error: SHA1 #1 failed\n");
+ goto end;
+ }
+ }
+
+ {
+ const char *in_str =
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+ bigint *ct_bi = bi_str_import(bi_ctx,
+ "84983E441C3BD26EBAAE4AA1F95129E5E54670F1");
+ bi_export(bi_ctx, ct_bi, ct, SHA1_SIZE);
+
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, (const uint8_t *)in_str, strlen(in_str));
+ SHA1_Final(digest, &ctx);
+
+ if (memcmp(digest, ct, sizeof(ct)))
+ {
+ printf("Error: SHA1 #2 failed\n");
+ goto end;
+ }
+ }
+
+ res = 0;
+ printf("All SHA1 tests passed\n");
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * MD5 tests
+ *
+ * Run through a couple of the RFC1321 tests to verify that MD5 is correct.
+ **************************************************************************/
+static int MD5_test(BI_CTX *bi_ctx)
+{
+ MD5_CTX ctx;
+ uint8_t ct[MD5_SIZE];
+ uint8_t digest[MD5_SIZE];
+ int res = 1;
+
+ {
+ const char *in_str = "abc";
+ bigint *ct_bi = bi_str_import(bi_ctx,
+ "900150983CD24FB0D6963F7D28E17F72");
+ bi_export(bi_ctx, ct_bi, ct, MD5_SIZE);
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, (const uint8_t *)in_str, strlen(in_str));
+ MD5_Final(digest, &ctx);
+
+ if (memcmp(digest, ct, sizeof(ct)))
+ {
+ printf("Error: MD5 #1 failed\n");
+ goto end;
+ }
+ }
+
+ {
+ const char *in_str =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ bigint *ct_bi = bi_str_import(
+ bi_ctx, "D174AB98D277D9F5A5611C2C9F419D9F");
+ bi_export(bi_ctx, ct_bi, ct, MD5_SIZE);
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, (const uint8_t *)in_str, strlen(in_str));
+ MD5_Final(digest, &ctx);
+
+ if (memcmp(digest, ct, sizeof(ct)))
+ {
+ printf("Error: MD5 #2 failed\n");
+ goto end;
+ }
+ }
+ res = 0;
+ printf("All MD5 tests passed\n");
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * HMAC tests
+ *
+ * Run through a couple of the RFC2202 tests to verify that HMAC is correct.
+ **************************************************************************/
+static int HMAC_test(BI_CTX *bi_ctx)
+{
+ uint8_t key[SHA1_SIZE];
+ uint8_t ct[SHA1_SIZE];
+ uint8_t dgst[SHA1_SIZE];
+ int res = 1;
+ const char *key_str;
+
+ const char *data_str = "Hi There";
+ bigint *key_bi = bi_str_import(bi_ctx, "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B");
+ bigint *ct_bi = bi_str_import(bi_ctx, "9294727A3638BB1C13F48EF8158BFC9D");
+ bi_export(bi_ctx, key_bi, key, MD5_SIZE);
+ bi_export(bi_ctx, ct_bi, ct, MD5_SIZE);
+ hmac_md5((const uint8_t *)data_str, 8, key, MD5_SIZE, dgst);
+ if (memcmp(dgst, ct, MD5_SIZE))
+ {
+ printf("HMAC MD5 #1 failed\n");
+ goto end;
+ }
+
+ data_str = "what do ya want for nothing?";
+ key_str = "Jefe";
+ ct_bi = bi_str_import(bi_ctx, "750C783E6AB0B503EAA86E310A5DB738");
+ bi_export(bi_ctx, ct_bi, ct, MD5_SIZE);
+ hmac_md5((const uint8_t *)data_str, 28, (const uint8_t *)key_str, 4, dgst);
+ if (memcmp(dgst, ct, MD5_SIZE))
+ {
+ printf("HMAC MD5 #2 failed\n");
+ goto end;
+ }
+
+ data_str = "Hi There";
+ key_bi = bi_str_import(bi_ctx, "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B");
+ bi_export(bi_ctx, key_bi, key, SHA1_SIZE);
+ ct_bi = bi_str_import(bi_ctx, "B617318655057264E28BC0B6FB378C8EF146BE00");
+ bi_export(bi_ctx, ct_bi, ct, SHA1_SIZE);
+
+ hmac_sha1((const uint8_t *)data_str, 8,
+ (const uint8_t *)key, SHA1_SIZE, dgst);
+ if (memcmp(dgst, ct, SHA1_SIZE))
+ {
+ printf("HMAC SHA1 #1 failed\n");
+ goto end;
+ }
+
+ data_str = "what do ya want for nothing?";
+ key_str = "Jefe";
+ ct_bi = bi_str_import(bi_ctx, "EFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79");
+ bi_export(bi_ctx, ct_bi, ct, SHA1_SIZE);
+
+ hmac_sha1((const uint8_t *)data_str, 28, (const uint8_t *)key_str, 5, dgst);
+ if (memcmp(dgst, ct, SHA1_SIZE))
+ {
+ printf("HMAC SHA1 failed\n");
+ exit(1);
+ }
+
+ res = 0;
+ printf("All HMAC tests passed\n");
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * BIGINT tests
+ *
+ **************************************************************************/
+static int BIGINT_test(BI_CTX *ctx)
+{
+ int res = 1;
+ bigint *bi_data, *bi_exp, *bi_res;
+ const char *expnt, *plaintext, *mod;
+ uint8_t compare[MAX_KEY_BYTE_SIZE];
+
+ /**
+ * 512 bit key
+ */
+ plaintext = /* 64 byte number */
+ "01aaaaaaaaaabbbbbbbbbbbbbbbccccccccccccccdddddddddddddeeeeeeeeee";
+
+ mod = "C30773C8ABE09FCC279EE0E5343370DE"
+ "8B2FFDB6059271E3005A7CEEF0D35E0A"
+ "1F9915D95E63560836CC2EB2C289270D"
+ "BCAE8CAF6F5E907FC2759EE220071E1B";
+
+ expnt = "A1E556CD1738E10DF539E35101334E97"
+ "BE8D391C57A5C89A7AD9A2EA2ACA1B3D"
+ "F3140F5091CC535CBAA47CEC4159EE1F"
+ "B6A3661AFF1AB758426EAB158452A9B9";
+
+ bi_data = bi_import(ctx, (uint8_t *)plaintext, strlen(plaintext));
+ bi_exp = int_to_bi(ctx, 0x10001);
+ bi_set_mod(ctx, bi_str_import(ctx, mod), 0);
+ bi_res = bi_mod_power(ctx, bi_data, bi_exp);
+
+ bi_data = bi_res; /* resuse again - see if we get the original */
+
+ bi_exp = bi_str_import(ctx, expnt);
+ bi_res = bi_mod_power(ctx, bi_data, bi_exp);
+ bi_free_mod(ctx, 0);
+
+ bi_export(ctx, bi_res, compare, 64);
+ if (memcmp(plaintext, compare, 64) != 0)
+ goto end;
+
+ printf("All BIGINT tests passed\n");
+ res = 0;
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * RSA tests
+ *
+ * Use the results from openssl to verify PKCS1 etc
+ **************************************************************************/
+static int RSA_test(void)
+{
+ int res = 1;
+ const char *plaintext = /* 128 byte hex number */
+ "1aaaaaaaaaabbbbbbbbbbbbbbbccccccccccccccdddddddddddddeeeeeeeeee2"
+ "1aaaaaaaaaabbbbbbbbbbbbbbbccccccccccccccdddddddddddddeeeeeeeee2\012";
+ uint8_t enc_data[128], dec_data[128];
+ RSA_CTX *rsa_ctx = NULL;
+ BI_CTX *bi_ctx;
+ bigint *plaintext_bi;
+ bigint *enc_data_bi, *dec_data_bi;
+ uint8_t enc_data2[128], dec_data2[128];
+ int size;
+ int len;
+ uint8_t *buf;
+
+ /* extract the private key elements */
+ len = get_file("../ssl/test/axTLS.key_1024", &buf);
+ if (asn1_get_private_key(buf, len, &rsa_ctx) < 0)
+ {
+ goto end;
+ }
+
+ free(buf);
+ bi_ctx = rsa_ctx->bi_ctx;
+ plaintext_bi = bi_import(bi_ctx,
+ (const uint8_t *)plaintext, strlen(plaintext));
+
+ /* basic rsa encrypt */
+ enc_data_bi = RSA_public(rsa_ctx, plaintext_bi);
+ bi_export(bi_ctx, bi_copy(enc_data_bi), enc_data, sizeof(enc_data));
+
+ /* basic rsa decrypt */
+ dec_data_bi = RSA_private(rsa_ctx, enc_data_bi);
+ bi_export(bi_ctx, dec_data_bi, dec_data, sizeof(dec_data));
+
+ if (memcmp(dec_data, plaintext, strlen(plaintext)))
+ {
+ printf("Error: DECRYPT #1 failed\n");
+ goto end;
+ }
+
+ RSA_encrypt(rsa_ctx, (const uint8_t *)"abc", 3, enc_data2, 0);
+ size = RSA_decrypt(rsa_ctx, enc_data2, dec_data2, 1);
+ if (memcmp("abc", dec_data2, 3))
+ {
+ printf("Error: ENCRYPT/DECRYPT #2 failed\n");
+ goto end;
+ }
+
+ RSA_free(rsa_ctx);
+ res = 0;
+ printf("All RSA tests passed\n");
+
+end:
+ return res;
+}
+
+/**************************************************************************
+ * Cert Testing
+ *
+ **************************************************************************/
+static int cert_tests(void)
+{
+ int res = -1, len;
+ X509_CTX *x509_ctx;
+ SSL_CTX *ssl_ctx;
+ uint8_t *buf;
+
+ /* check a bunch of 3rd party certificates */
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/microsoft.x509_ca", &buf);
+ if ((res = add_cert_auth(ssl_ctx, buf, len)) < 0)
+ {
+ printf("Cert #1\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/thawte.x509_ca", &buf);
+ if ((res = add_cert_auth(ssl_ctx, buf, len)) < 0)
+ {
+ printf("Cert #2\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/deutsche_telecom.x509_ca", &buf);
+ if ((res = add_cert_auth(ssl_ctx, buf, len)) < 0)
+ {
+ printf("Cert #3\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/equifax.x509_ca", &buf);
+ if ((res = add_cert_auth(ssl_ctx, buf, len)) < 0)
+ {
+ printf("Cert #4\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/gnutls.cer", &buf);
+ if ((res = add_cert(ssl_ctx, buf, len)) < 0)
+ {
+ printf("Cert #5\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/socgen.cer", &buf);
+ if ((res = add_cert(ssl_ctx, buf, len)) < 0)
+ {
+ printf("Cert #6\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ len = get_file("../ssl/test/verisign.x509_ca", &buf);
+ if ((res = add_cert_auth(ssl_ctx, buf, len)) <0)
+ {
+ printf("Cert #7\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ free(buf);
+
+ if (get_file("../ssl/test/verisign.x509_my_cert", &buf) < 0 ||
+ x509_new(buf, &len, &x509_ctx))
+ {
+ printf("Cert #8\n");
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ x509_free(x509_ctx);
+ free(buf);
+
+ ssl_ctx = ssl_ctx_new(0, 0);
+ if ((res = ssl_obj_load(ssl_ctx,
+ SSL_OBJ_X509_CERT, "../ssl/test/ms_iis.cer", NULL)) != SSL_OK)
+ {
+ ssl_display_error(res);
+ goto bad_cert;
+ }
+
+ ssl_ctx_free(ssl_ctx);
+ res = 0; /* all ok */
+ printf("All Certificate tests passed\n");
+
+bad_cert:
+ if (res)
+ printf("Error: A certificate test failed\n");
+ return res;
+}
+
+/**
+ * init a server socket.
+ */
+static int server_socket_init(int *port)
+{
+ struct sockaddr_in serv_addr;
+ int server_fd;
+ char yes = 1;
+
+ /* Create socket for incoming connections */
+ if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ return -1;
+ }
+
+ setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
+
+go_again:
+ /* Construct local address structure */
+ memset(&serv_addr, 0, sizeof(serv_addr)); /* Zero out structure */
+ serv_addr.sin_family = AF_INET; /* Internet address family */
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
+ serv_addr.sin_port = htons(*port); /* Local port */
+
+ /* Bind to the local address */
+ if (bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
+ {
+ (*port)++;
+ goto go_again;
+ }
+ /* Mark the socket so it will listen for incoming connections */
+ if (listen(server_fd, 3000) < 0)
+ {
+ return -1;
+ }
+
+ return server_fd;
+}
+
+/**
+ * init a client socket.
+ */
+static int client_socket_init(uint16_t port)
+{
+ struct sockaddr_in address;
+ int client_fd;
+
+ address.sin_family = AF_INET;
+ address.sin_port = htons(port);
+ address.sin_addr.s_addr = inet_addr("127.0.0.1");
+ client_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (connect(client_fd, (struct sockaddr *)&address, sizeof(address)) < 0)
+ {
+ perror("socket");
+ SOCKET_CLOSE(client_fd);
+ client_fd = -1;
+ }
+
+ return client_fd;
+}
+
+/**************************************************************************
+ * SSL Server Testing
+ *
+ **************************************************************************/
+typedef struct
+{
+ /* not used as yet */
+ int dummy;
+} SVR_CTX;
+
+typedef struct
+{
+ const char *testname;
+ const char *openssl_option;
+} client_t;
+
+static void do_client(client_t *clnt)
+{
+ char openssl_buf[2048];
+
+ /* make sure the main thread goes first */
+ sleep(0);
+
+ /* show the session ids in the reconnect test */
+ if (strcmp(clnt->testname, "Session Reuse") == 0)
+ {
+ sprintf(openssl_buf, "echo \"hello client\" | openssl s_client "
+ "-connect localhost:%d %s 2>&1 | grep \"Session-ID:\"",
+ g_port, clnt->openssl_option);
+ }
+ else
+ {
+ sprintf(openssl_buf, "echo \"hello client\" | openssl s_client "
+#ifdef WIN32
+ "-connect localhost:%d -quiet %s",
+#else
+ "-connect localhost:%d -quiet %s > /dev/null 2>&1",
+#endif
+ g_port, clnt->openssl_option);
+ }
+
+ system(openssl_buf);
+}
+
+static int SSL_server_test(
+ const char *testname,
+ const char *openssl_option,
+ const char *device_cert,
+ const char *product_cert,
+ const char *private_key,
+ const char *ca_cert,
+ const char *password,
+ int axolotls_option)
+{
+ int server_fd, ret = 0;
+ SSL_CTX *ssl_ctx = NULL;
+ struct sockaddr_in client_addr;
+ uint8_t *read_buf;
+ socklen_t clnt_len = sizeof(client_addr);
+ client_t client_data;
+#ifndef WIN32
+ pthread_t thread;
+#endif
+ g_port++;
+
+ client_data.testname = testname;
+ client_data.openssl_option = openssl_option;
+
+ if ((server_fd = server_socket_init(&g_port)) < 0)
+ goto error;
+
+ if (private_key)
+ {
+ axolotls_option |= SSL_NO_DEFAULT_KEY;
+ }
+
+ if ((ssl_ctx = ssl_ctx_new(axolotls_option, SSL_DEFAULT_SVR_SESS)) == NULL)
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto error;
+ }
+
+ if (private_key)
+ {
+ int obj_type = SSL_OBJ_RSA_KEY;
+
+ if (strstr(private_key, ".p8"))
+ obj_type = SSL_OBJ_PKCS8;
+ else if (strstr(private_key, ".p12"))
+ obj_type = SSL_OBJ_PKCS12;
+
+ if (ssl_obj_load(ssl_ctx, obj_type, private_key, password))
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto error;
+ }
+ }
+
+ if (device_cert) /* test chaining */
+ {
+ if ((ret = ssl_obj_load(ssl_ctx,
+ SSL_OBJ_X509_CERT, device_cert, NULL)) != SSL_OK)
+ goto error;
+ }
+
+ if (product_cert) /* test chaining */
+ {
+ if ((ret = ssl_obj_load(ssl_ctx,
+ SSL_OBJ_X509_CERT, product_cert, NULL)) != SSL_OK)
+ goto error;
+ }
+
+ if (ca_cert) /* test adding certificate authorities */
+ {
+ if ((ret = ssl_obj_load(ssl_ctx,
+ SSL_OBJ_X509_CACERT, ca_cert, NULL)) != SSL_OK)
+ goto error;
+ }
+
+#ifndef WIN32
+ pthread_create(&thread, NULL,
+ (void *(*)(void *))do_client, (void *)&client_data);
+ pthread_detach(thread);
+#else
+ CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)do_client,
+ (LPVOID)&client_data, 0, NULL);
+#endif
+
+ for (;;)
+ {
+ int client_fd, size = 0;
+ SSL *ssl;
+
+ /* Wait for a client to connect */
+ if ((client_fd = accept(server_fd,
+ (struct sockaddr *)&client_addr, &clnt_len)) < 0)
+ {
+ ret = SSL_ERROR_SOCK_SETUP_FAILURE;
+ goto error;
+ }
+
+ /* we are ready to go */
+ ssl = ssl_server_new(ssl_ctx, client_fd);
+ while ((size = ssl_read(ssl, &read_buf)) == SSL_OK);
+ SOCKET_CLOSE(client_fd);
+
+ if (size < SSL_OK) /* got some alert or something nasty */
+ {
+ ret = size;
+
+ if (ret == SSL_ERROR_CONN_LOST)
+ {
+ ret = SSL_OK;
+ continue;
+ }
+
+ break; /* we've got a problem */
+ }
+ else /* looks more promising */
+ {
+ if (strstr("hello client", (char *)read_buf) == NULL)
+ {
+ printf("SSL server test \"%s\" passed\n", testname);
+ TTY_FLUSH();
+ ret = 0;
+ break;
+ }
+ }
+
+ ssl_free(ssl);
+ }
+
+ SOCKET_CLOSE(server_fd);
+
+error:
+ ssl_ctx_free(ssl_ctx);
+ return ret;
+}
+
+int SSL_server_tests(void)
+{
+ int ret = -1;
+ struct stat stat_buf;
+ SVR_CTX svr_test_ctx;
+ memset(&svr_test_ctx, 0, sizeof(SVR_CTX));
+
+ printf("### starting server tests\n"); TTY_FLUSH();
+
+ /* Go through the algorithms */
+
+ /*
+ * TLS1 client hello
+ */
+ if ((ret = SSL_server_test("TLSv1", "-cipher RC4-SHA -tls1",
+ NULL, NULL, NULL, NULL, NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * AES128-SHA
+ */
+ if ((ret = SSL_server_test("AES256-SHA", "-cipher AES128-SHA",
+ DEFAULT_CERT, NULL, DEFAULT_KEY, NULL, NULL,
+ DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * AES256-SHA
+ */
+ if ((ret = SSL_server_test("AES256-SHA", "-cipher AES128-SHA",
+ DEFAULT_CERT, NULL, DEFAULT_KEY, NULL, NULL,
+ DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * RC4-SHA
+ */
+ if ((ret = SSL_server_test("RC4-SHA", "-cipher RC4-SHA",
+ DEFAULT_CERT, NULL, DEFAULT_KEY, NULL, NULL,
+ DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * RC4-MD5
+ */
+ if ((ret = SSL_server_test("RC4-MD5", "-cipher RC4-MD5",
+ DEFAULT_CERT, NULL, DEFAULT_KEY, NULL, NULL,
+ DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * Session Reuse
+ * all the session id's should match for session resumption.
+ */
+ if ((ret = SSL_server_test("Session Reuse",
+ "-cipher RC4-SHA -reconnect",
+ DEFAULT_CERT, NULL, DEFAULT_KEY, NULL, NULL,
+ DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * 512 bit RSA key
+ */
+ if ((ret = SSL_server_test("512 bit key", "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_512.cer", NULL,
+ "../ssl/test/axTLS.key_512",
+ NULL, NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * 1024 bit RSA key (check certificate chaining)
+ */
+ if ((ret = SSL_server_test("1024 bit key",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_device.cer",
+ "../ssl/test/axTLS.x509_512.cer",
+ "../ssl/test/axTLS.device_key",
+ NULL, NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * 2048 bit RSA key
+ */
+ if ((ret = SSL_server_test("2048 bit key",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_2048.cer", NULL,
+ "../ssl/test/axTLS.key_2048",
+ NULL, NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * 4096 bit RSA key
+ */
+ if ((ret = SSL_server_test("4096 bit key",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_4096.cer", NULL,
+ "../ssl/test/axTLS.key_4096",
+ NULL, NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * Client Verification
+ */
+ if ((ret = SSL_server_test("Client Verification",
+ "-cipher RC4-SHA -tls1 "
+ "-cert ../ssl/test/axTLS.x509_2048.pem "
+ "-key ../ssl/test/axTLS.key_2048.pem ",
+ NULL, NULL, NULL,
+ "../ssl/test/axTLS.ca_x509.cer", NULL,
+ DEFAULT_SVR_OPTION|SSL_CLIENT_AUTHENTICATION)))
+ goto cleanup;
+
+ /* this test should fail */
+ if (stat("../ssl/test/axTLS.x509_bad_before.pem", &stat_buf) >= 0)
+ {
+ if ((ret = SSL_server_test("Bad Before Cert",
+ "-cipher RC4-SHA -tls1 "
+ "-cert ../ssl/test/axTLS.x509_bad_before.pem "
+ "-key ../ssl/test/axTLS.key_512.pem ",
+ NULL, NULL, NULL,
+ "../ssl/test/axTLS.ca_x509.cer", NULL,
+ DEFAULT_SVR_OPTION|SSL_CLIENT_AUTHENTICATION)) !=
+ SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID))
+ goto cleanup;
+
+ printf("SSL server test \"%s\" passed\n", "Bad Before Cert");
+ TTY_FLUSH();
+ ret = 0; /* is ok */
+ }
+
+ /* this test should fail */
+ if ((ret = SSL_server_test("Bad After Cert",
+ "-cipher RC4-SHA -tls1 "
+ "-cert ../ssl/test/axTLS.x509_bad_after.pem "
+ "-key ../ssl/test/axTLS.key_512.pem ",
+ NULL, NULL, NULL,
+ "../ssl/test/axTLS.ca_x509.cer", NULL,
+ DEFAULT_SVR_OPTION|SSL_CLIENT_AUTHENTICATION)) !=
+ SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED))
+ goto cleanup;
+
+ printf("SSL server test \"%s\" passed\n", "Bad After Cert");
+ TTY_FLUSH();
+
+ /*
+ * Key in PEM format
+ */
+ if ((ret = SSL_server_test("Key in PEM format",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_512.cer", NULL,
+ "../ssl/test/axTLS.key_512.pem", NULL,
+ NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * Cert in PEM format
+ */
+ if ((ret = SSL_server_test("Cert in PEM format",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_512.pem", NULL,
+ "../ssl/test/axTLS.key_512.pem", NULL,
+ NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * Cert chain in PEM format
+ */
+ if ((ret = SSL_server_test("Cert chain in PEM format",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_device.pem",
+ NULL, "../ssl/test/axTLS.device_key.pem",
+ "../ssl/test/axTLS.ca_x509.pem", NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * AES128 Encrypted key
+ */
+ if ((ret = SSL_server_test("AES128 encrypted key",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_aes128.pem", NULL,
+ "../ssl/test/axTLS.key_aes128.pem",
+ NULL, "abcd", DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * AES256 Encrypted key
+ */
+ if ((ret = SSL_server_test("AES256 encrypted key",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_aes256.pem", NULL,
+ "../ssl/test/axTLS.key_aes256.pem",
+ NULL, "abcd", DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * AES128 Encrypted invalid key
+ */
+ if ((ret = SSL_server_test("AES128 encrypted invalid key",
+ "-cipher RC4-SHA",
+ "../ssl/test/axTLS.x509_aes128.pem", NULL,
+ "../ssl/test/axTLS.key_aes128.pem",
+ NULL, "xyz", DEFAULT_SVR_OPTION)) != SSL_ERROR_INVALID_KEY)
+ goto cleanup;
+
+ printf("SSL server test \"%s\" passed\n", "AES128 encrypted invalid key");
+ TTY_FLUSH();
+
+ /*
+ * PKCS#8 key (encrypted)
+ */
+ if ((ret = SSL_server_test("pkcs#8 encrypted", "-cipher RC4-SHA",
+ DEFAULT_CERT, NULL, "../ssl/test/axTLS.encrypted.p8",
+ NULL, "abcd", DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * PKCS#8 key (unencrypted)
+ */
+ if ((ret = SSL_server_test("pkcs#8 unencrypted", "-cipher RC4-SHA",
+ DEFAULT_CERT, NULL, "../ssl/test/axTLS.unencrypted.p8",
+ NULL, NULL, DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ * PKCS#12 key/certificate
+ */
+ if ((ret = SSL_server_test("pkcs#12 with CA", "-cipher RC4-SHA",
+ NULL, NULL, "../ssl/test/axTLS.withCA.p12",
+ NULL, "abcd", DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ if ((ret = SSL_server_test("pkcs#12 no CA", "-cipher RC4-SHA",
+ DEFAULT_CERT, NULL, "../ssl/test/axTLS.withoutCA.p12",
+ NULL, "abcd", DEFAULT_SVR_OPTION)))
+ goto cleanup;
+
+ /*
+ *
+ */
+
+ ret = 0;
+
+cleanup:
+ if (ret)
+ {
+ printf("Error: A server test failed\n");
+ ssl_display_error(ret);
+ exit(1);
+ }
+ else
+ {
+ printf("All server tests passed\n"); TTY_FLUSH();
+ }
+
+ return ret;
+}
+
+/**************************************************************************
+ * SSL Client Testing
+ *
+ **************************************************************************/
+typedef struct
+{
+ uint8_t session_id[SSL_SESSION_ID_SIZE];
+#ifndef WIN32
+ pthread_t server_thread;
+#endif
+ int start_server;
+ int stop_server;
+ int do_reneg;
+} CLNT_SESSION_RESUME_CTX;
+
+typedef struct
+{
+ const char *testname;
+ const char *openssl_option;
+} server_t;
+
+static void do_server(server_t *svr)
+{
+ char openssl_buf[2048];
+#ifndef WIN32
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+#endif
+ sprintf(openssl_buf, "openssl s_server -tls1 "
+ "-accept %d -quiet %s ", g_port, svr->openssl_option);
+ system(openssl_buf);
+}
+
+static int SSL_client_test(
+ const char *test,
+ SSL_CTX **ssl_ctx,
+ const char *openssl_option,
+ CLNT_SESSION_RESUME_CTX *sess_resume,
+ uint32_t client_options,
+ const char *private_key,
+ const char *password,
+ const char *cert)
+{
+ server_t server_data;
+ SSL *ssl = NULL;
+ int client_fd = -1;
+ uint8_t *session_id = NULL;
+ int ret = 1;
+#ifndef WIN32
+ pthread_t thread;
+#endif
+
+ if (sess_resume == NULL || sess_resume->start_server)
+ {
+ g_port++;
+ server_data.openssl_option = openssl_option;
+
+#ifndef WIN32
+ pthread_create(&thread, NULL,
+ (void *(*)(void *))do_server, (void *)&server_data);
+ pthread_detach(thread);
+#else
+ CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)do_server,
+ (LPVOID)&server_data, 0, NULL);
+#endif
+ }
+
+ usleep(200000); /* allow server to start */
+
+ if (*ssl_ctx == NULL)
+ {
+ if (private_key)
+ {
+ client_options |= SSL_NO_DEFAULT_KEY;
+ }
+
+ if ((*ssl_ctx = ssl_ctx_new(
+ client_options, SSL_DEFAULT_CLNT_SESS)) == NULL)
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto client_test_exit;
+ }
+
+ if (private_key)
+ {
+ int obj_type = SSL_OBJ_RSA_KEY;
+
+ if (strstr(private_key, ".p8"))
+ obj_type = SSL_OBJ_PKCS8;
+ else if (strstr(private_key, ".p12"))
+ obj_type = SSL_OBJ_PKCS12;
+
+ if (ssl_obj_load(*ssl_ctx, obj_type, private_key, password))
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto client_test_exit;
+ }
+ }
+
+ if (cert)
+ {
+ if ((ret = ssl_obj_load(*ssl_ctx,
+ SSL_OBJ_X509_CERT, cert, NULL)) != SSL_OK)
+ {
+ printf("could not add cert %s (%d)\n", cert, ret);
+ TTY_FLUSH();
+ goto client_test_exit;
+ }
+ }
+
+ if (ssl_obj_load(*ssl_ctx, SSL_OBJ_X509_CACERT,
+ "../ssl/test/axTLS.ca_x509.cer", NULL))
+ {
+ printf("could not add cert auth\n"); TTY_FLUSH();
+ goto client_test_exit;
+ }
+ }
+
+ if (sess_resume && !sess_resume->start_server)
+ {
+ session_id = sess_resume->session_id;
+ }
+
+ if ((client_fd = client_socket_init(g_port)) < 0)
+ {
+ printf("could not start socket on %d\n", g_port); TTY_FLUSH();
+ goto client_test_exit;
+ }
+
+ ssl = ssl_client_new(*ssl_ctx, client_fd, session_id, sizeof(session_id));
+
+ /* check the return status */
+ if ((ret = ssl_handshake_status(ssl)))
+ goto client_test_exit;
+
+ /* renegotiate client */
+ if (sess_resume && sess_resume->do_reneg)
+ {
+ if (ssl_renegotiate(ssl) < 0)
+ goto client_test_exit;
+ }
+
+ if (sess_resume)
+ {
+ memcpy(sess_resume->session_id,
+ ssl_get_session_id(ssl), SSL_SESSION_ID_SIZE);
+ }
+
+ if (IS_SET_SSL_FLAG(SSL_SERVER_VERIFY_LATER) &&
+ (ret = ssl_verify_cert(ssl)))
+ {
+ goto client_test_exit;
+ }
+
+ ssl_write(ssl, (uint8_t *)"hello world\n", 13);
+ if (sess_resume)
+ {
+ const uint8_t *sess_id = ssl_get_session_id(ssl);
+ int i;
+
+ printf(" Session-ID: ");
+ for (i = 0; i < SSL_SESSION_ID_SIZE; i++)
+ {
+ printf("%02X", sess_id[i]);
+ }
+ printf("\n");
+ TTY_FLUSH();
+ }
+
+ ret = 0;
+
+client_test_exit:
+ ssl_free(ssl);
+ SOCKET_CLOSE(client_fd);
+ usleep(200000); /* allow openssl to say something */
+
+ if (sess_resume)
+ {
+ if (sess_resume->stop_server)
+ {
+ ssl_ctx_free(*ssl_ctx);
+ *ssl_ctx = NULL;
+#ifndef WIN32
+ pthread_cancel(sess_resume->server_thread);
+#endif
+ }
+ else if (sess_resume->start_server)
+ {
+#ifndef WIN32
+ sess_resume->server_thread = thread;
+#endif
+ }
+ }
+ else
+ {
+ ssl_ctx_free(*ssl_ctx);
+ *ssl_ctx = NULL;
+#ifndef WIN32
+ pthread_cancel(thread);
+#endif
+ }
+
+ if (ret == 0)
+ {
+ printf("SSL client test \"%s\" passed\n", test);
+ TTY_FLUSH();
+ }
+
+ return ret;
+}
+
+int SSL_client_tests(void)
+{
+ int ret = -1;
+ SSL_CTX *ssl_ctx = NULL;
+ CLNT_SESSION_RESUME_CTX sess_resume;
+ memset(&sess_resume, 0, sizeof(CLNT_SESSION_RESUME_CTX));
+
+ sess_resume.start_server = 1;
+ printf("### starting client tests\n");
+
+ if ((ret = SSL_client_test("512 bit key",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_512.pem "
+ "-key ../ssl/test/axTLS.key_512.pem", &sess_resume,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ /* all the session id's should match for session resumption */
+ sess_resume.start_server = 0;
+ if ((ret = SSL_client_test("Client session resumption #1",
+ &ssl_ctx, NULL, &sess_resume,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ sess_resume.do_reneg = 1;
+ if ((ret = SSL_client_test("Client renegotiation",
+ &ssl_ctx, NULL, &sess_resume,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+ sess_resume.do_reneg = 0;
+
+ sess_resume.stop_server = 1;
+ if ((ret = SSL_client_test("Client session resumption #2",
+ &ssl_ctx, NULL, &sess_resume,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ if ((ret = SSL_client_test("1024 bit key",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_1024.pem "
+ "-key ../ssl/test/axTLS.key_1024.pem", NULL,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ if ((ret = SSL_client_test("2048 bit key",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_2048.pem "
+ "-key ../ssl/test/axTLS.key_2048.pem", NULL,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ if ((ret = SSL_client_test("4096 bit key",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_4096.pem "
+ "-key ../ssl/test/axTLS.key_4096.pem", NULL,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ if ((ret = SSL_client_test("Server cert chaining",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_device.pem "
+ "-key ../ssl/test/axTLS.device_key.pem "
+ "-CAfile ../ssl/test/axTLS.x509_512.pem ", NULL,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)))
+ goto cleanup;
+
+ /* Check the server can verify the client */
+ if ((ret = SSL_client_test("Client peer authentication",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_2048.pem "
+ "-key ../ssl/test/axTLS.key_2048.pem "
+ "-CAfile ../ssl/test/axTLS.ca_x509.pem "
+ "-verify 1 ", NULL, DEFAULT_CLNT_OPTION,
+ "../ssl/test/axTLS.key_1024", NULL,
+ "../ssl/test/axTLS.x509_1024.cer")))
+ goto cleanup;
+
+ /* Should get an "ERROR" from openssl (as the handshake fails as soon as
+ * the certificate verification fails) */
+ if ((ret = SSL_client_test("Error: Expired cert (verify now)",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_bad_after.pem "
+ "-key ../ssl/test/axTLS.key_512.pem", NULL,
+ DEFAULT_CLNT_OPTION, NULL, NULL, NULL)) !=
+ SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED))
+ {
+ printf("*** Error: %d\n", ret);
+ goto cleanup;
+ }
+
+ printf("SSL client test \"Expired cert (verify now)\" passed\n");
+
+ /* There is no "ERROR" from openssl */
+ if ((ret = SSL_client_test("Error: Expired cert (verify later)",
+ &ssl_ctx,
+ "-cert ../ssl/test/axTLS.x509_bad_after.pem "
+ "-key ../ssl/test/axTLS.key_512.pem", NULL,
+ DEFAULT_CLNT_OPTION|SSL_SERVER_VERIFY_LATER, NULL,
+ NULL, NULL)) != SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED))
+ {
+ printf("*** Error: %d\n", ret);
+ goto cleanup;
+ }
+
+ printf("SSL client test \"Expired cert (verify later)\" passed\n");
+ ret = 0;
+
+cleanup:
+ if (ret)
+ {
+ ssl_display_error(ret);
+ printf("Error: A client test failed\n");
+ exit(1);
+ }
+ else
+ {
+ printf("All client tests passed\n"); TTY_FLUSH();
+ }
+
+ return ret;
+}
+
+/**************************************************************************
+ * SSL Basic Testing (test a big packet handshake)
+ *
+ **************************************************************************/
+static uint8_t basic_buf[256*1024];
+
+static void do_basic(void)
+{
+ int client_fd;
+ SSL *ssl_clnt;
+ SSL_CTX *ssl_clnt_ctx = ssl_ctx_new(
+ DEFAULT_CLNT_OPTION, SSL_DEFAULT_CLNT_SESS);
+ usleep(200000); /* allow server to start */
+
+ if ((client_fd = client_socket_init(g_port)) < 0)
+ goto error;
+
+ if (ssl_obj_load(ssl_clnt_ctx, SSL_OBJ_X509_CACERT,
+ "../ssl/test/axTLS.ca_x509.cer", NULL))
+ goto error;
+
+ ssl_clnt = ssl_client_new(ssl_clnt_ctx, client_fd, NULL, 0);
+
+ /* check the return status */
+ if (ssl_handshake_status(ssl_clnt) < 0)
+ {
+ printf("YA YA\n");
+ ssl_display_error(ssl_handshake_status(ssl_clnt));
+ goto error;
+ }
+
+ ssl_write(ssl_clnt, basic_buf, sizeof(basic_buf));
+ ssl_free(ssl_clnt);
+
+error:
+ ssl_ctx_free(ssl_clnt_ctx);
+ SOCKET_CLOSE(client_fd);
+
+ /* exit this thread */
+}
+
+static int SSL_basic_test(void)
+{
+ int server_fd, client_fd, ret = 0, size = 0, offset = 0;
+ SSL_CTX *ssl_svr_ctx = NULL;
+ struct sockaddr_in client_addr;
+ uint8_t *read_buf;
+ socklen_t clnt_len = sizeof(client_addr);
+ SSL *ssl_svr;
+#ifndef WIN32
+ pthread_t thread;
+#endif
+ memset(basic_buf, 0xA5, sizeof(basic_buf)/2);
+ memset(&basic_buf[sizeof(basic_buf)/2], 0x5A, sizeof(basic_buf)/2);
+
+ if ((server_fd = server_socket_init(&g_port)) < 0)
+ goto error;
+
+ ssl_svr_ctx = ssl_ctx_new(DEFAULT_SVR_OPTION, SSL_DEFAULT_SVR_SESS);
+
+#ifndef WIN32
+ pthread_create(&thread, NULL,
+ (void *(*)(void *))do_basic, NULL);
+ pthread_detach(thread);
+#else
+ CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)do_basic, NULL, 0, NULL);
+#endif
+
+ /* Wait for a client to connect */
+ if ((client_fd = accept(server_fd,
+ (struct sockaddr *) &client_addr, &clnt_len)) < 0)
+ {
+ ret = SSL_ERROR_SOCK_SETUP_FAILURE;
+ goto error;
+ }
+
+ /* we are ready to go */
+ ssl_svr = ssl_server_new(ssl_svr_ctx, client_fd);
+
+ do
+ {
+ while ((size = ssl_read(ssl_svr, &read_buf)) == SSL_OK);
+
+ if (size < SSL_OK) /* got some alert or something nasty */
+ {
+ printf("Server ");
+ ssl_display_error(size);
+ ret = size;
+ break;
+ }
+ else /* looks more promising */
+ {
+ if (memcmp(read_buf, &basic_buf[offset], size) != 0)
+ {
+ ret = SSL_NOT_OK;
+ break;
+ }
+ }
+
+ offset += size;
+ } while (offset < sizeof(basic_buf));
+
+ printf(ret == SSL_OK && offset == sizeof(basic_buf) ?
+ "SSL basic test passed\n" :
+ "SSL basic test failed\n");
+ TTY_FLUSH();
+
+ ssl_free(ssl_svr);
+ SOCKET_CLOSE(server_fd);
+ SOCKET_CLOSE(client_fd);
+
+error:
+ ssl_ctx_free(ssl_svr_ctx);
+ return ret;
+}
+
+#if !defined(WIN32) && defined(CONFIG_SSL_CTX_MUTEXING)
+/**************************************************************************
+ * Multi-Threading Tests
+ *
+ **************************************************************************/
+#define NUM_THREADS 100
+
+typedef struct
+{
+ SSL_CTX *ssl_clnt_ctx;
+ int port;
+ int thread_id;
+} multi_t;
+
+void do_multi_clnt(multi_t *multi_data)
+{
+ int res = 1, client_fd, i;
+ SSL *ssl = NULL;
+ char tmp[5];
+
+ if ((client_fd = client_socket_init(multi_data->port)) < 0)
+ goto client_test_exit;
+
+ sleep(1);
+ ssl = ssl_client_new(multi_data->ssl_clnt_ctx, client_fd, NULL, 0);
+
+ if ((res = ssl_handshake_status(ssl)))
+ {
+ printf("Client ");
+ ssl_display_error(res);
+ goto client_test_exit;
+ }
+
+ sprintf(tmp, "%d\n", multi_data->thread_id);
+ for (i = 0; i < 10; i++)
+ ssl_write(ssl, (uint8_t *)tmp, strlen(tmp)+1);
+
+client_test_exit:
+ ssl_free(ssl);
+ SOCKET_CLOSE(client_fd);
+ free(multi_data);
+}
+
+void do_multi_svr(SSL *ssl)
+{
+ uint8_t *read_buf;
+ int *res_ptr = malloc(sizeof(int));
+ int res;
+
+ for (;;)
+ {
+ res = ssl_read(ssl, &read_buf);
+
+ /* kill the client */
+ if (res != SSL_OK)
+ {
+ if (res == SSL_ERROR_CONN_LOST)
+ {
+ SOCKET_CLOSE(ssl->client_fd);
+ ssl_free(ssl);
+ break;
+ }
+ else if (res > 0)
+ {
+ /* do nothing */
+ }
+ else /* some problem */
+ {
+ printf("Server ");
+ ssl_display_error(res);
+ goto error;
+ }
+ }
+ }
+
+ res = SSL_OK;
+error:
+ *res_ptr = res;
+ pthread_exit(res_ptr);
+}
+
+int multi_thread_test(void)
+{
+ int server_fd = -1;
+ SSL_CTX *ssl_server_ctx;
+ SSL_CTX *ssl_clnt_ctx;
+ pthread_t clnt_threads[NUM_THREADS];
+ pthread_t svr_threads[NUM_THREADS];
+ int i, res = 0;
+ struct sockaddr_in client_addr;
+ socklen_t clnt_len = sizeof(client_addr);
+
+ printf("Do multi-threading test (takes a minute)\n");
+
+ ssl_server_ctx = ssl_ctx_new(DEFAULT_SVR_OPTION, SSL_DEFAULT_SVR_SESS);
+ ssl_clnt_ctx = ssl_ctx_new(DEFAULT_CLNT_OPTION, SSL_DEFAULT_CLNT_SESS);
+
+ if (ssl_obj_load(ssl_clnt_ctx, SSL_OBJ_X509_CACERT,
+ "../ssl/test/axTLS.ca_x509.cer", NULL))
+ goto error;
+
+ if ((server_fd = server_socket_init(&g_port)) < 0)
+ goto error;
+
+ for (i = 0; i < NUM_THREADS; i++)
+ {
+ multi_t *multi_data = (multi_t *)malloc(sizeof(multi_t));
+ multi_data->ssl_clnt_ctx = ssl_clnt_ctx;
+ multi_data->port = g_port;
+ multi_data->thread_id = i+1;
+ pthread_create(&clnt_threads[i], NULL,
+ (void *(*)(void *))do_multi_clnt, (void *)multi_data);
+ pthread_detach(clnt_threads[i]);
+ }
+
+ for (i = 0; i < NUM_THREADS; i++)
+ {
+ SSL *ssl_svr;
+ int client_fd = accept(server_fd,
+ (struct sockaddr *)&client_addr, &clnt_len);
+
+ if (client_fd < 0)
+ goto error;
+
+ ssl_svr = ssl_server_new(ssl_server_ctx, client_fd);
+
+ pthread_create(&svr_threads[i], NULL,
+ (void *(*)(void *))do_multi_svr, (void *)ssl_svr);
+ }
+
+ /* make sure we've run all of the threads */
+ for (i = 0; i < NUM_THREADS; i++)
+ {
+ void *thread_res;
+ pthread_join(svr_threads[i], &thread_res);
+
+ if (*((int *)thread_res) != 0)
+ res = 1;
+
+ free(thread_res);
+ }
+
+ if (res)
+ goto error;
+
+ printf("Multi-thread test passed (%d)\n", NUM_THREADS);
+error:
+ ssl_ctx_free(ssl_server_ctx);
+ ssl_ctx_free(ssl_clnt_ctx);
+ SOCKET_CLOSE(server_fd);
+ return res;
+}
+#endif /* !defined(WIN32) && defined(CONFIG_SSL_CTX_MUTEXING) */
+
+/**************************************************************************
+ * Header issue
+ *
+ **************************************************************************/
+static void do_header_issue(void)
+{
+ char axtls_buf[2048];
+#ifndef WIN32
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+#endif
+ sprintf(axtls_buf, "./axssl s_client -connect localhost:%d", g_port);
+ system(axtls_buf);
+}
+
+static int header_issue(void)
+{
+ FILE *f = fopen("../ssl/test/header_issue.dat", "r");
+ int server_fd = -1, client_fd = -1, ret = 1;
+ uint8_t buf[2048];
+ int size = 0;
+ struct sockaddr_in client_addr;
+ socklen_t clnt_len = sizeof(client_addr);
+#ifndef WIN32
+ pthread_t thread;
+#endif
+
+ if (f == NULL || (server_fd = server_socket_init(&g_port)) < 0)
+ goto error;
+
+#ifndef WIN32
+ pthread_create(&thread, NULL,
+ (void *(*)(void *))do_header_issue, NULL);
+ pthread_detach(thread);
+#else
+ CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)do_header_issue,
+ NULL, 0, NULL);
+#endif
+ if ((client_fd = accept(server_fd,
+ (struct sockaddr *) &client_addr, &clnt_len)) < 0)
+ {
+ ret = SSL_ERROR_SOCK_SETUP_FAILURE;
+ goto error;
+ }
+
+ size = fread(buf, 1, sizeof(buf), f);
+ SOCKET_WRITE(client_fd, buf, size);
+ usleep(200000);
+
+ ret = 0;
+error:
+ fclose(f);
+ SOCKET_CLOSE(client_fd);
+ SOCKET_CLOSE(server_fd);
+ TTY_FLUSH();
+ system("killall axssl");
+ return ret;
+}
+
+/**************************************************************************
+ * main()
+ *
+ **************************************************************************/
+int main(int argc, char *argv[])
+{
+ int ret = 1;
+ BI_CTX *bi_ctx;
+ int fd;
+
+#ifdef WIN32
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(2, 2);
+ WSAStartup(wVersionRequested, &wsaData);
+ fd = _open("test_result.txt", O_WRONLY|O_TEMPORARY|O_CREAT, _S_IWRITE);
+ dup2(fd, 2); /* write stderr to this file */
+#else
+ fd = open("/dev/null", O_WRONLY); /* write stderr to /dev/null */
+ signal(SIGPIPE, SIG_IGN); /* ignore pipe errors */
+ dup2(fd, 2);
+#endif
+
+ /* can't do testing in this mode */
+#if defined CONFIG_SSL_GENERATE_X509_CERT
+ printf("Error: Must compile with default key/certificates\n");
+ exit(1);
+#endif
+
+ bi_ctx = bi_initialize();
+
+ if (AES_test(bi_ctx))
+ {
+ printf("AES tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ if (RC4_test(bi_ctx))
+ {
+ printf("RC4 tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ if (MD5_test(bi_ctx))
+ {
+ printf("MD5 tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ if (SHA1_test(bi_ctx))
+ {
+ printf("SHA1 tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ if (HMAC_test(bi_ctx))
+ {
+ printf("HMAC tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ if (BIGINT_test(bi_ctx))
+ {
+ printf("BigInt tests failed!\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ bi_terminate(bi_ctx);
+
+ if (RSA_test())
+ {
+ printf("RSA tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+ if (cert_tests())
+ {
+ printf("CERT tests failed\n");
+ goto cleanup;
+ }
+ TTY_FLUSH();
+
+#if !defined(WIN32) && defined(CONFIG_SSL_CTX_MUTEXING)
+ if (multi_thread_test())
+ goto cleanup;
+#endif
+
+ if (SSL_basic_test())
+ goto cleanup;
+
+ system("sh ../ssl/test/killopenssl.sh");
+
+ if (SSL_client_tests())
+ goto cleanup;
+
+ system("sh ../ssl/test/killopenssl.sh");
+
+ if (SSL_server_tests())
+ goto cleanup;
+
+ system("sh ../ssl/test/killopenssl.sh");
+
+ if (header_issue())
+ {
+ printf("Header tests failed\n"); TTY_FLUSH();
+ goto cleanup;
+ }
+
+ ret = 0; /* all ok */
+ printf("**** ALL TESTS PASSED ****\n"); TTY_FLUSH();
+cleanup:
+
+ if (ret)
+ printf("Error: Some tests failed!\n");
+
+ close(fd);
+ return ret;
+}
--- /dev/null
+#!/bin/sh
+
+#
+# Copyright (c) 2007, Cameron Rich
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the axTLS project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# Test the various axssl bindings. To run it, got to the _install directory
+# and run this script from there.
+#
+
+if grep "CONFIG_PLATFORM_WIN32=y" "../config/.config" > /dev/null; then
+ JAVA_EXE="$JAVA_HOME/bin/java.exe"
+ PERL_BIN="/cygdrive/c/Perl/bin/perl"
+ KILL_AXSSL="kill %1"
+ KILL_CSHARP="kill %1"
+ KILL_PERL="kill %1"
+ KILL_JAVA="kill %1"
+ KILL_LUA="kill %1"
+else
+ if grep "CONFIG_PLATFORM_CYGWIN=y" "../config/.config" > /dev/null; then
+ # no .net or java on cygwin
+ PERL_BIN=/usr/bin/perl
+ KILL_AXSSL="killall axssl"
+ KILL_PERL="killall /usr/bin/perl"
+ KILL_LUA="killall /usr/local/bin/lua"
+ else # Linux
+ JAVA_EXE=/usr/java/default/bin/java
+ PERL_BIN=/usr/bin/perl
+ KILL_AXSSL="killall axssl"
+ KILL_CSHARP="killall mono"
+ KILL_PERL="killall /usr/bin/perl"
+ RUN_CSHARP="mono"
+ KILL_JAVA="killall $JAVA_EXE"
+ KILL_LUA="killall /usr/local/bin/lua"
+ fi
+fi
+
+BASE=..
+SERVER_ARGS="s_server -accept 15001 -verify -CAfile $BASE/ssl/test/axTLS.ca_x509.cer"
+CLIENT_ARGS="s_client -reconnect -connect localhost:15001 -verify -CAfile $BASE/ssl/test/axTLS.ca_x509.cer -key $BASE/ssl/test/axTLS.key_1024 -cert $BASE/ssl/test/axTLS.x509_1024.cer"
+
+# check pem arguments
+SERVER_PEM_ARGS="s_server -accept 15001 -pass abcd -key $BASE/ssl/test/axTLS.key_aes128.pem -cert $BASE/ssl/test/axTLS.x509_aes128.pem"
+CLIENT_PEM_ARGS="s_client -connect localhost:15001 -CAfile $BASE/ssl/test/axTLS.ca_x509.pem -key $BASE/ssl/test/axTLS.key_1024.pem -cert $BASE/ssl/test/axTLS.x509_1024.pem"
+
+export LD_LIBRARY_PATH=.:`perl -e 'use Config; print $Config{archlib};'`/CORE
+
+if [ -x ./axssl ]; then
+echo "############################# C SAMPLE ###########################"
+./axssl $SERVER_ARGS &
+echo "C Test passed" | ./axssl $CLIENT_ARGS
+$KILL_AXSSL
+sleep 1
+
+./axssl $SERVER_PEM_ARGS &
+echo "C Test passed" | ./axssl $CLIENT_PEM_ARGS
+$KILL_AXSSL
+sleep 1
+echo "### C tests complete"
+fi
+
+if [ -f ./axtls.jar ]; then
+echo "########################## JAVA SAMPLE ###########################"
+"$JAVA_EXE" -jar ./axtls.jar $SERVER_ARGS &
+echo "Java Test passed" | "$JAVA_EXE" -jar ./axtls.jar $CLIENT_ARGS
+$KILL_JAVA
+sleep 1
+
+"$JAVA_EXE" -jar ./axtls.jar $SERVER_PEM_ARGS &
+echo "Java Test passed" | "$JAVA_EXE" -jar ./axtls.jar $CLIENT_PEM_ARGS
+$KILL_JAVA
+sleep 1
+
+echo "### Java tests complete"
+fi
+
+if [ -x ./axssl.csharp.exe ]; then
+echo "############################ C# SAMPLE ###########################"
+$RUN_CSHARP ./axssl.csharp.exe $SERVER_ARGS &
+echo "C# Test passed" | $RUN_CSHARP ./axssl.csharp.exe $CLIENT_ARGS
+$KILL_CSHARP
+sleep 1
+
+$RUN_CSHARP ./axssl.csharp.exe $SERVER_PEM_ARGS &
+echo "C# Test passed" | $RUN_CSHARP ./axssl.csharp.exe $CLIENT_PEM_ARGS
+$KILL_CSHARP
+sleep 1
+
+echo "### C# tests complete"
+fi
+
+if [ -x ./axssl.vbnet.exe ]; then
+echo "######################## VB.NET SAMPLE ###########################"
+echo $SERVER_ARGS
+echo $CLIENT_ARGS
+./axssl.vbnet $SERVER_ARGS &
+echo "VB.NET Test passed" | ./axssl.vbnet.exe $CLIENT_ARGS
+kill %1
+sleep 1
+
+./axssl.vbnet $SERVER_PEM_ARGS &
+echo "VB.NET Test passed" | ./axssl.vbnet.exe $CLIENT_PEM_ARGS
+kill %1
+sleep 1
+echo "### VB.NET tests complete"
+fi
+
+if [ -f ./axssl.pl ]; then
+echo "########################## PERL SAMPLE ###########################"
+"$PERL_BIN" ./axssl.pl $SERVER_ARGS &
+echo "Perl Test passed" | "$PERL_BIN" ./axssl.pl $CLIENT_ARGS
+$KILL_PERL
+sleep 1
+
+"$PERL_BIN" ./axssl.pl $SERVER_PEM_ARGS &
+echo "Perl Test passed" | "$PERL_BIN" ./axssl.pl $CLIENT_PEM_ARGS
+$KILL_PERL
+sleep 1
+echo "### Perl tests complete"
+fi
+
+if [ -f ./axssl.lua ]; then
+echo "########################## LUA SAMPLE ###########################"
+./axssl.lua $SERVER_ARGS &
+echo "Lua Test passed" | ./axssl.lua $CLIENT_ARGS
+$KILL_LUA
+sleep 1
+
+./axssl.lua $SERVER_PEM_ARGS &
+echo "Lua Test passed" | ./axssl.lua $CLIENT_PEM_ARGS
+$KILL_LUA
+sleep 1
+echo "### Lua tests complete"
+fi
+
+echo "########################## ALL TESTS COMPLETE ###########################"
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIICmDCCAgECECCol67bggLewTagTia9h3MwDQYJKoZIhvcNAQECBQAwgYwxCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEwMC4GA1UECxMnRm9y
+IFRlc3QgUHVycG9zZXMgT25seS4gIE5vIGFzc3VyYW5jZXMuMTIwMAYDVQQDEylW
+ZXJpU2lnbiBUcmlhbCBTZWN1cmUgU2VydmVyIFRlc3QgUm9vdCBDQTAeFw0wNTAy
+MDkwMDAwMDBaFw0yNTAyMDgyMzU5NTlaMIGMMQswCQYDVQQGEwJVUzEXMBUGA1UE
+ChMOVmVyaVNpZ24sIEluYy4xMDAuBgNVBAsTJ0ZvciBUZXN0IFB1cnBvc2VzIE9u
+bHkuICBObyBhc3N1cmFuY2VzLjEyMDAGA1UEAxMpVmVyaVNpZ24gVHJpYWwgU2Vj
+dXJlIFNlcnZlciBUZXN0IFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ
+AoGBAJ8h98U7klaZH5cEn6CSEKmGWVBsTwHIaMAAVqGqCUn7Q9C10sEOIHBznyLy
+eSDjMs5M1nC/iAA7KCASf/yHz0AdlU+1IRSijwHTF/2dYSoTTxP2GCmtL1Ga4i7+
+zDDo086V7+NiFAGJj+CYey47ue4Xa33o/4YOA9PGL87oqFe7AgMBAAEwDQYJKoZI
+hvcNAQECBQADgYEAOq447rP5EDqFEl3vhLhgTbnyaskNYwPvxk+0grnQyDA4sF/q
+gK8nFlnvLmAOF3DmfuqW6WSr4zqTYzpwmJlsn48Om/yWirL8GuWRftit2POxTfHS
+B8VmR+PZx2k24UgWUZyojDGxJtiHd3tjCdqFgTit4NK429cWOcZrh47xeOI=
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIEQzCCA6ygAwIBAgIQR/dXCzC/x5Ta5RvL6hKEojANBgkqhkiG9w0BAQUFADCB
+jDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTAwLgYDVQQL
+EydGb3IgVGVzdCBQdXJwb3NlcyBPbmx5LiAgTm8gYXNzdXJhbmNlcy4xMjAwBgNV
+BAMTKVZlcmlTaWduIFRyaWFsIFNlY3VyZSBTZXJ2ZXIgVGVzdCBSb290IENBMB4X
+DTA2MDExNjAwMDAwMFoXDTA2MDEzMDIzNTk1OVowgbkxCzAJBgNVBAYTAkFVMQww
+CgYDVQQIEwNRbGQxETAPBgNVBAcUCEJyaXNiYW5lMRkwFwYDVQQKFBBheG9sb1RM
+UyBQcm9qZWN0MRUwEwYDVQQLFAwxMDI0IGJpdCBrZXkxOjA4BgNVBAsUMVRlcm1z
+IG9mIHVzZSBhdCB3d3cudmVyaXNpZ24uY29tL2Nwcy90ZXN0Y2EgKGMpMDUxGzAZ
+BgNVBAMUEnd3dy5heG9sb3Rscy5jby5ucjCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEAttzj5S7qfOZIrh9xg8bgjTOKbSIbLBuMnxAwfGRcUrQO2EQOHd6kMjXR
+hqY/cG2IG4G8AeqdV3nHlKbrbHbRa1lFgP6b0BQCE8TyxmP+tIAqn5L6/HTm+EEi
+Ad1Pxjeok6e7F6UXHxJltSGHmOhAf3C5kPq/FQ6QZeG4yD/uzPkCAwEAAaOCAXUw
+ggFxMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMEcGA1UdHwRAMD4wPKA6oDiGNmh0
+dHA6Ly9TVlJTZWN1cmUtY3JsLnZlcmlzaWduLmNvbS9TVlJUcmlhbFJvb3QyMDA1
+LmNybDBKBgNVHSAEQzBBMD8GCmCGSAGG+EUBBxUwMTAvBggrBgEFBQcCARYjaHR0
+cHM6Ly93d3cudmVyaXNpZ24uY29tL2Nwcy90ZXN0Y2EwHQYDVR0lBBYwFAYIKwYB
+BQUHAwEGCCsGAQUFBwMCMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0
+cDovL29jc3AudmVyaXNpZ24uY29tMG0GCCsGAQUFBwEMBGEwX6FdoFswWTBXMFUW
+CWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgsexkuMCUW
+I2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMA0GCSqGSIb3DQEB
+BQUAA4GBACtlCTJFENCcHCQLHJfiotqr2XR+oWu0MstNm8dG6WB+zYprrT+kOPDn
+1rMO7YLx76f67fC+lIXz720kQHk6LsZ8hPBQvIXnfIsKjng73DeFzBmTMFz6Qxjd
++E0FUCKplqrdwUkmR4kH6O4pdGE4AlXJNiUI2903yYdSRVMOuLuR
+-----END CERTIFICATE-----
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Common ssl/tlsv1 code to both the client and server implementations.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "ssl.h"
+
+/* The session expiry time */
+#define SSL_EXPIRY_TIME (CONFIG_SSL_EXPIRY_TIME*3600)
+
+static const uint8_t g_hello_request[] = { HS_HELLO_REQUEST, 0, 0, 0 };
+static const uint8_t g_chg_cipher_spec_pkt[] = { 1 };
+static const char * server_finished = "server finished";
+static const char * client_finished = "client finished";
+
+static int do_handshake(SSL *ssl, uint8_t *buf, int read_len);
+static void set_key_block(SSL *ssl, int is_write);
+static int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len);
+static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt);
+static int send_raw_packet(SSL *ssl, uint8_t protocol);
+
+/**
+ * The server will pick the cipher based on the order that the order that the
+ * ciphers are listed. This order is defined at compile time.
+ */
+#ifdef CONFIG_SSL_SKELETON_MODE
+const uint8_t ssl_prot_prefs[NUM_PROTOCOLS] =
+{ SSL_RC4_128_SHA };
+#else
+static void session_free(SSL_SESSION *ssl_sessions[], int sess_index);
+
+const uint8_t ssl_prot_prefs[NUM_PROTOCOLS] =
+#ifdef CONFIG_SSL_PROT_LOW /* low security, fast speed */
+{ SSL_RC4_128_SHA, SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_MD5 };
+#elif CONFIG_SSL_PROT_MEDIUM /* medium security, medium speed */
+{ SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 };
+#else /* CONFIG_SSL_PROT_HIGH */ /* high security, low speed */
+{ SSL_AES256_SHA, SSL_AES128_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 };
+#endif
+#endif /* CONFIG_SSL_SKELETON_MODE */
+
+/**
+ * The cipher map containing all the essentials for each cipher.
+ */
+#ifdef CONFIG_SSL_SKELETON_MODE
+static const cipher_info_t cipher_info[NUM_PROTOCOLS] =
+{
+ { /* RC4-SHA */
+ SSL_RC4_128_SHA, /* RC4-SHA */
+ 16, /* key size */
+ 0, /* iv size */
+ 2*(SHA1_SIZE+16), /* key block size */
+ 0, /* no padding */
+ SHA1_SIZE, /* digest size */
+ hmac_sha1, /* hmac algorithm */
+ (crypt_func)RC4_crypt, /* encrypt */
+ (crypt_func)RC4_crypt /* decrypt */
+ },
+};
+#else
+static const cipher_info_t cipher_info[NUM_PROTOCOLS] =
+{
+ { /* AES128-SHA */
+ SSL_AES128_SHA, /* AES128-SHA */
+ 16, /* key size */
+ 16, /* iv size */
+ 2*(SHA1_SIZE+16+16), /* key block size */
+ 16, /* block padding size */
+ SHA1_SIZE, /* digest size */
+ hmac_sha1, /* hmac algorithm */
+ (crypt_func)AES_cbc_encrypt, /* encrypt */
+ (crypt_func)AES_cbc_decrypt /* decrypt */
+ },
+ { /* AES256-SHA */
+ SSL_AES256_SHA, /* AES256-SHA */
+ 32, /* key size */
+ 16, /* iv size */
+ 2*(SHA1_SIZE+32+16), /* key block size */
+ 16, /* block padding size */
+ SHA1_SIZE, /* digest size */
+ hmac_sha1, /* hmac algorithm */
+ (crypt_func)AES_cbc_encrypt, /* encrypt */
+ (crypt_func)AES_cbc_decrypt /* decrypt */
+ },
+ { /* RC4-SHA */
+ SSL_RC4_128_SHA, /* RC4-SHA */
+ 16, /* key size */
+ 0, /* iv size */
+ 2*(SHA1_SIZE+16), /* key block size */
+ 0, /* no padding */
+ SHA1_SIZE, /* digest size */
+ hmac_sha1, /* hmac algorithm */
+ (crypt_func)RC4_crypt, /* encrypt */
+ (crypt_func)RC4_crypt /* decrypt */
+ },
+ /*
+ * This protocol is from SSLv2 days and is unlikely to be used - but was
+ * useful for testing different possible digest algorithms.
+ */
+ { /* RC4-MD5 */
+ SSL_RC4_128_MD5, /* RC4-MD5 */
+ 16, /* key size */
+ 0, /* iv size */
+ 2*(MD5_SIZE+16), /* key block size */
+ 0, /* no padding */
+ MD5_SIZE, /* digest size */
+ hmac_md5, /* hmac algorithm */
+ (crypt_func)RC4_crypt, /* encrypt */
+ (crypt_func)RC4_crypt /* decrypt */
+ },
+};
+#endif
+
+static void prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len,
+ uint8_t *out, int olen);
+static const cipher_info_t *get_cipher_info(uint8_t cipher);
+static void increment_read_sequence(SSL *ssl);
+static void increment_write_sequence(SSL *ssl);
+static void add_hmac_digest(SSL *ssl, int snd, uint8_t *hmac_header,
+ const uint8_t *buf, int buf_len, uint8_t *hmac_buf);
+
+/* win32 VC6.0 doesn't have variadic macros */
+#if defined(WIN32) && !defined(CONFIG_SSL_FULL_MODE)
+void DISPLAY_BYTES(SSL *ssl, const char *format,
+ const uint8_t *data, int size, ...) {}
+#endif
+
+/**
+ * Establish a new client/server context.
+ */
+EXP_FUNC SSL_CTX *STDCALL ssl_ctx_new(uint32_t options, int num_sessions)
+{
+ SSL_CTX *ssl_ctx = (SSL_CTX *)calloc(1, sizeof (SSL_CTX));
+ ssl_ctx->options = options;
+
+ if (load_key_certs(ssl_ctx) < 0)
+ {
+ free(ssl_ctx); /* can't load our key/certificate pair, so die */
+ return NULL;
+ }
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ ssl_ctx->num_sessions = num_sessions;
+#endif
+
+ SSL_CTX_MUTEX_INIT(ssl_ctx->mutex);
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ if (num_sessions)
+ {
+ ssl_ctx->ssl_sessions = (SSL_SESSION **)
+ calloc(1, num_sessions*sizeof(SSL_SESSION *));
+ }
+#endif
+
+ return ssl_ctx;
+}
+
+/*
+ * Remove a client/server context.
+ */
+EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx)
+{
+ SSL *ssl;
+ int i;
+
+ if (ssl_ctx == NULL)
+ return;
+
+ ssl = ssl_ctx->head;
+
+ /* clear out all the ssl entries */
+ while (ssl)
+ {
+ SSL *next = ssl->next;
+ ssl_free(ssl);
+ ssl = next;
+ }
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ /* clear out all the sessions */
+ for (i = 0; i < ssl_ctx->num_sessions; i++)
+ session_free(ssl_ctx->ssl_sessions, i);
+
+ free(ssl_ctx->ssl_sessions);
+#endif
+
+ i = 0;
+ while (i < CONFIG_SSL_MAX_CERTS && ssl_ctx->certs[i].buf)
+ {
+ free(ssl_ctx->certs[i].buf);
+ ssl_ctx->certs[i++].buf = NULL;
+ }
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ remove_ca_certs(ssl_ctx->ca_cert_ctx);
+#endif
+ ssl_ctx->chain_length = 0;
+ SSL_CTX_MUTEX_DESTROY(ssl_ctx->mutex);
+ RSA_free(ssl_ctx->rsa_ctx);
+ RNG_terminate();
+ free(ssl_ctx);
+}
+
+/*
+ * Free any used resources used by this connection.
+ */
+EXP_FUNC void STDCALL ssl_free(SSL *ssl)
+{
+ SSL_CTX *ssl_ctx;
+
+ if (ssl == NULL) /* just ignore null pointers */
+ return;
+
+ /* spec says we must notify when we are dying */
+ send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY);
+
+ ssl_ctx = ssl->ssl_ctx;
+
+ SSL_CTX_LOCK(ssl_ctx->mutex);
+
+ /* adjust the server SSL list */
+ if (ssl->prev)
+ ssl->prev->next = ssl->next;
+ else
+ ssl_ctx->head = ssl->next;
+
+ if (ssl->next)
+ ssl->next->prev = ssl->prev;
+ else
+ ssl_ctx->tail = ssl->prev;
+
+ SSL_CTX_UNLOCK(ssl_ctx->mutex);
+
+ /* may already be free - but be sure */
+ free(ssl->encrypt_ctx);
+ free(ssl->decrypt_ctx);
+ disposable_free(ssl);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ x509_free(ssl->x509_ctx);
+#endif
+
+ free(ssl);
+}
+
+/*
+ * Read the SSL connection and send any alerts for various errors.
+ */
+EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data)
+{
+ int ret = basic_read(ssl, in_data);
+
+ /* check for return code so we can send an alert */
+ if (ret < SSL_OK)
+ {
+ if (ret != SSL_ERROR_CONN_LOST)
+ {
+ send_alert(ssl, ret);
+#ifndef CONFIG_SSL_SKELETON_MODE
+ /* something nasty happened, so get rid of this session */
+ kill_ssl_session(ssl->ssl_ctx->ssl_sessions, ssl);
+#endif
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Write application data to the client
+ */
+EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len)
+{
+ int n = out_len, nw, i, tot = 0;
+
+ /* maximum size of a TLS packet is around 16kB, so fragment */
+ do
+ {
+ nw = n;
+
+ if (nw > RT_MAX_PLAIN_LENGTH) /* fragment if necessary */
+ nw = RT_MAX_PLAIN_LENGTH;
+
+ if ((i = send_packet(ssl, PT_APP_PROTOCOL_DATA,
+ &out_data[tot], nw)) <= 0)
+ {
+ out_len = i; /* an error */
+ break;
+ }
+
+ tot += i;
+ n -= i;
+ } while (n > 0);
+
+ return out_len;
+}
+
+/**
+ * Add a certificate to the certificate chain.
+ */
+int add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len)
+{
+ int ret = SSL_ERROR_NO_CERT_DEFINED, i = 0;
+ SSL_CERT *ssl_cert;
+ X509_CTX *cert = NULL;
+ int offset;
+
+ while (ssl_ctx->certs[i].buf && i < CONFIG_SSL_MAX_CERTS)
+ i++;
+
+ if (i == CONFIG_SSL_MAX_CERTS) /* too many certs */
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: maximum number of certs added - change of "
+ "compile-time configuration required\n");
+#endif
+ goto error;
+ }
+
+ if ((ret = x509_new(buf, &offset, &cert)))
+ goto error;
+
+#if defined (CONFIG_SSL_FULL_MODE)
+ if (ssl_ctx->options & SSL_DISPLAY_CERTS)
+ x509_print(cert, NULL);
+#endif
+
+ ssl_cert = &ssl_ctx->certs[i];
+ ssl_cert->size = len;
+ ssl_cert->buf = (uint8_t *)malloc(len);
+ memcpy(ssl_cert->buf, buf, len);
+ ssl_ctx->chain_length++;
+ len -= offset;
+ ret = SSL_OK; /* ok so far */
+
+ /* recurse? */
+ if (len > 0)
+ {
+ ret = add_cert(ssl_ctx, &buf[offset], len);
+ }
+
+error:
+ x509_free(cert); /* don't need anymore */
+ return ret;
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Add a certificate authority.
+ */
+int add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len)
+{
+ int ret = SSL_ERROR_NO_CERT_DEFINED;
+ int i = 0;
+ int offset;
+ CA_CERT_CTX *ca_cert_ctx;
+
+ if (ssl_ctx->ca_cert_ctx == NULL)
+ ssl_ctx->ca_cert_ctx = (CA_CERT_CTX *)calloc(1, sizeof(CA_CERT_CTX));
+
+ ca_cert_ctx = ssl_ctx->ca_cert_ctx;
+
+ while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
+ i++;
+
+ if (i > CONFIG_X509_MAX_CA_CERTS)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: maximum number of CA certs added - change of "
+ "compile-time configuration required\n");
+#endif
+ goto error;
+ }
+
+ if ((ret = x509_new(buf, &offset, &ca_cert_ctx->cert[i])))
+ goto error;
+
+ len -= offset;
+ ret = SSL_OK; /* ok so far */
+
+ /* recurse? */
+ if (len > 0)
+ ret = add_cert_auth(ssl_ctx, &buf[offset], len);
+
+error:
+ return ret;
+}
+
+/*
+ * Retrieve an X.509 distinguished name component
+ */
+EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component)
+{
+ if (ssl->x509_ctx == NULL)
+ return NULL;
+
+ switch (component)
+ {
+ case SSL_X509_CERT_COMMON_NAME:
+ return ssl->x509_ctx->cert_dn[X509_COMMON_NAME];
+
+ case SSL_X509_CERT_ORGANIZATION:
+ return ssl->x509_ctx->cert_dn[X509_ORGANIZATION];
+
+ case SSL_X509_CERT_ORGANIZATIONAL_NAME:
+ return ssl->x509_ctx->cert_dn[X509_ORGANIZATIONAL_UNIT];
+
+ case SSL_X509_CA_CERT_COMMON_NAME:
+ return ssl->x509_ctx->ca_cert_dn[X509_COMMON_NAME];
+
+ case SSL_X509_CA_CERT_ORGANIZATION:
+ return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATION];
+
+ case SSL_X509_CA_CERT_ORGANIZATIONAL_NAME:
+ return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATIONAL_UNIT];
+
+ default:
+ return NULL;
+ }
+}
+
+#endif
+
+/*
+ * Find an ssl object based on the client's file descriptor.
+ */
+EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd)
+{
+ SSL *ssl;
+
+ SSL_CTX_LOCK(ssl_ctx->mutex);
+ ssl = ssl_ctx->head;
+
+ /* search through all the ssl entries */
+ while (ssl)
+ {
+ if (ssl->client_fd == client_fd)
+ {
+ SSL_CTX_UNLOCK(ssl_ctx->mutex);
+ return ssl;
+ }
+
+ ssl = ssl->next;
+ }
+
+ SSL_CTX_UNLOCK(ssl_ctx->mutex);
+ return NULL;
+}
+
+/*
+ * Force the client to perform its handshake again.
+ */
+EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl)
+{
+ int ret = SSL_OK;
+
+ disposable_new(ssl);
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+ if (IS_SET_SSL_FLAG(SSL_IS_CLIENT))
+ {
+ ret = do_client_connect(ssl);
+ }
+ else
+#endif
+ {
+ send_packet(ssl, PT_HANDSHAKE_PROTOCOL,
+ g_hello_request, sizeof(g_hello_request));
+ SET_SSL_FLAG(SSL_NEED_RECORD);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Get what we need for key info.
+ * @param cipher [in] The cipher information we are after
+ * @param key_size [out] The key size for the cipher
+ * @param iv_size [out] The iv size for the cipher
+ * @return The amount of key information we need.
+ */
+static const cipher_info_t *get_cipher_info(uint8_t cipher)
+{
+ int i;
+
+ for (i = 0; i < NUM_PROTOCOLS; i++)
+ {
+ if (cipher_info[i].cipher == cipher)
+ {
+ return &cipher_info[i];
+ }
+ }
+
+ return NULL; /* error */
+}
+
+/*
+ * Get a new ssl context for a new connection.
+ */
+SSL *ssl_new(SSL_CTX *ssl_ctx, int client_fd)
+{
+ SSL *ssl = (SSL *)calloc(1, sizeof(SSL));
+ ssl->ssl_ctx = ssl_ctx;
+ ssl->need_bytes = SSL_RECORD_SIZE; /* need a record */
+ ssl->client_fd = client_fd;
+ ssl->flag = SSL_NEED_RECORD;
+ ssl->bm_data = ssl->bm_all_data+BM_RECORD_OFFSET; /* space at the start */
+ ssl->hs_status = SSL_NOT_OK; /* not connected */
+#ifdef CONFIG_ENABLE_VERIFICATION
+ ssl->ca_cert_ctx = ssl_ctx->ca_cert_ctx;
+#endif
+ disposable_new(ssl);
+
+ /* a bit hacky but saves a few bytes of memory */
+ ssl->flag |= ssl_ctx->options;
+ SSL_CTX_LOCK(ssl_ctx->mutex);
+
+ if (ssl_ctx->head == NULL)
+ {
+ ssl_ctx->head = ssl;
+ ssl_ctx->tail = ssl;
+ }
+ else
+ {
+ ssl->prev = ssl_ctx->tail;
+ ssl_ctx->tail->next = ssl;
+ ssl_ctx->tail = ssl;
+ }
+
+ SSL_CTX_UNLOCK(ssl_ctx->mutex);
+ return ssl;
+}
+
+/*
+ * Add a private key to a context.
+ */
+int add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj)
+{
+ int ret = SSL_OK;
+
+ /* get the private key details */
+ if (asn1_get_private_key(ssl_obj->buf, ssl_obj->len, &ssl_ctx->rsa_ctx))
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/**
+ * Increment the read sequence number (as a 64 bit endian indepenent #)
+ */
+static void increment_read_sequence(SSL *ssl)
+{
+ int i;
+
+ for (i = 7; i >= 0; i--)
+ {
+ if (++ssl->read_sequence[i])
+ break;
+ }
+}
+
+/**
+ * Increment the read sequence number (as a 64 bit endian indepenent #)
+ */
+static void increment_write_sequence(SSL *ssl)
+{
+ int i;
+
+ for (i = 7; i >= 0; i--)
+ {
+ if (++ssl->write_sequence[i])
+ break;
+ }
+}
+
+/**
+ * Work out the HMAC digest in a packet.
+ */
+static void add_hmac_digest(SSL *ssl, int mode, uint8_t *hmac_header,
+ const uint8_t *buf, int buf_len, uint8_t *hmac_buf)
+{
+ int hmac_len = buf_len + 8 + SSL_RECORD_SIZE;
+ uint8_t *t_buf = (uint8_t *)alloca(hmac_len+10);
+
+ memcpy(t_buf, (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE) ?
+ ssl->write_sequence : ssl->read_sequence, 8);
+ memcpy(&t_buf[8], hmac_header, SSL_RECORD_SIZE);
+ memcpy(&t_buf[8+SSL_RECORD_SIZE], buf, buf_len);
+
+ ssl->cipher_info->hmac(t_buf, hmac_len,
+ (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ) ?
+ ssl->server_mac : ssl->client_mac,
+ ssl->cipher_info->digest_size, hmac_buf);
+
+#if 0
+ print_blob("record", ssl->hmac_tx, SSL_RECORD_SIZE);
+ print_blob("buf", buf, buf_len);
+ if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE)
+ {
+ print_blob("write seq", ssl->write_sequence, 8);
+ }
+ else
+ {
+ print_blob("read seq", ssl->read_sequence, 8);
+ }
+
+ if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ)
+ {
+ print_blob("server mac",
+ ssl->server_mac, ssl->cipher_info->digest_size);
+ }
+ else
+ {
+ print_blob("client mac",
+ ssl->client_mac, ssl->cipher_info->digest_size);
+ }
+ print_blob("hmac", hmac_buf, SHA1_SIZE);
+#endif
+}
+
+/**
+ * Verify that the digest of a packet is correct.
+ */
+static int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len)
+{
+ uint8_t hmac_buf[SHA1_SIZE];
+ int hmac_offset;
+
+ if (ssl->cipher_info->padding_size)
+ {
+ hmac_offset = read_len-buf[read_len-1]-ssl->cipher_info->digest_size-1;
+ }
+ else
+ {
+ hmac_offset = read_len - ssl->cipher_info->digest_size;
+ }
+
+ /* sanity check the offset */
+ if (hmac_offset < 0)
+ {
+ return SSL_ERROR_INVALID_HMAC;
+ }
+
+ ssl->hmac_header[3] = hmac_offset >> 8; /* insert size */
+ ssl->hmac_header[4] = hmac_offset & 0xff;
+ add_hmac_digest(ssl, mode, ssl->hmac_header, buf, hmac_offset, hmac_buf);
+
+ if (memcmp(hmac_buf, &buf[hmac_offset], ssl->cipher_info->digest_size))
+ {
+ return SSL_ERROR_INVALID_HMAC;
+ }
+
+ return hmac_offset;
+}
+
+/**
+ * Add a packet to the end of our sent and received packets, so that we may use
+ * it to calculate the hash at the end.
+ */
+void add_packet(SSL *ssl, const uint8_t *pkt, int len)
+{
+ MD5_Update(&ssl->dc->md5_ctx, pkt, len);
+ SHA1_Update(&ssl->dc->sha1_ctx, pkt, len);
+}
+
+/**
+ * Work out the MD5 PRF.
+ */
+static void p_hash_md5(const uint8_t *sec, int sec_len,
+ uint8_t *seed, int seed_len, uint8_t *out, int olen)
+{
+ uint8_t a1[128];
+
+ /* A(1) */
+ hmac_md5(seed, seed_len, sec, sec_len, a1);
+ memcpy(&a1[MD5_SIZE], seed, seed_len);
+ hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out);
+
+ while (olen > MD5_SIZE)
+ {
+ uint8_t a2[MD5_SIZE];
+ out += MD5_SIZE;
+ olen -= MD5_SIZE;
+
+ /* A(N) */
+ hmac_md5(a1, MD5_SIZE, sec, sec_len, a2);
+ memcpy(a1, a2, MD5_SIZE);
+
+ /* work out the actual hash */
+ hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out);
+ }
+}
+
+/**
+ * Work out the SHA1 PRF.
+ */
+static void p_hash_sha1(const uint8_t *sec, int sec_len,
+ uint8_t *seed, int seed_len, uint8_t *out, int olen)
+{
+ uint8_t a1[128];
+
+ /* A(1) */
+ hmac_sha1(seed, seed_len, sec, sec_len, a1);
+ memcpy(&a1[SHA1_SIZE], seed, seed_len);
+ hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out);
+
+ while (olen > SHA1_SIZE)
+ {
+ uint8_t a2[SHA1_SIZE];
+ out += SHA1_SIZE;
+ olen -= SHA1_SIZE;
+
+ /* A(N) */
+ hmac_sha1(a1, SHA1_SIZE, sec, sec_len, a2);
+ memcpy(a1, a2, SHA1_SIZE);
+
+ /* work out the actual hash */
+ hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out);
+ }
+}
+
+/**
+ * Work out the PRF.
+ */
+static void prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len,
+ uint8_t *out, int olen)
+{
+ int len, i;
+ const uint8_t *S1, *S2;
+ uint8_t xbuf[256]; /* needs to be > the amount of key data */
+ uint8_t ybuf[256]; /* needs to be > the amount of key data */
+
+ len = sec_len/2;
+ S1 = sec;
+ S2 = &sec[len];
+ len += (sec_len & 1); /* add for odd, make longer */
+
+ p_hash_md5(S1, len, seed, seed_len, xbuf, olen);
+ p_hash_sha1(S2, len, seed, seed_len, ybuf, olen);
+
+ for (i = 0; i < olen; i++)
+ out[i] = xbuf[i] ^ ybuf[i];
+}
+
+/**
+ * Generate a master secret based on the client/server random data and the
+ * premaster secret.
+ */
+void generate_master_secret(SSL *ssl, const uint8_t *premaster_secret)
+{
+ uint8_t buf[128]; /* needs to be > 13+32+32 in size */
+ strcpy((char *)buf, "master secret");
+ memcpy(&buf[13], ssl->dc->client_random, SSL_RANDOM_SIZE);
+ memcpy(&buf[45], ssl->dc->server_random, SSL_RANDOM_SIZE);
+ prf(premaster_secret, SSL_SECRET_SIZE, buf, 77, ssl->dc->master_secret,
+ SSL_SECRET_SIZE);
+}
+
+/**
+ * Generate a 'random' blob of data used for the generation of keys.
+ */
+static void generate_key_block(uint8_t *client_random, uint8_t *server_random,
+ uint8_t *master_secret, uint8_t *key_block, int key_block_size)
+{
+ uint8_t buf[128];
+ strcpy((char *)buf, "key expansion");
+ memcpy(&buf[13], server_random, SSL_RANDOM_SIZE);
+ memcpy(&buf[45], client_random, SSL_RANDOM_SIZE);
+ prf(master_secret, SSL_SECRET_SIZE, buf, 77, key_block, key_block_size);
+}
+
+/**
+ * Calculate the digest used in the finished message. This function also
+ * doubles up as a certificate verify function.
+ */
+void finished_digest(SSL *ssl, const char *label, uint8_t *digest)
+{
+ uint8_t mac_buf[128];
+ uint8_t *q = mac_buf;
+ MD5_CTX md5_ctx = ssl->dc->md5_ctx;
+ SHA1_CTX sha1_ctx = ssl->dc->sha1_ctx;
+
+ if (label)
+ {
+ strcpy((char *)q, label);
+ q += strlen(label);
+ }
+
+ MD5_Final(q, &md5_ctx);
+ q += MD5_SIZE;
+
+ SHA1_Final(q, &sha1_ctx);
+ q += SHA1_SIZE;
+
+ if (label)
+ {
+ prf(ssl->dc->master_secret, SSL_SECRET_SIZE, mac_buf, (int)(q-mac_buf),
+ digest, SSL_FINISHED_HASH_SIZE);
+ }
+ else /* for use in a certificate verify */
+ {
+ memcpy(digest, mac_buf, MD5_SIZE + SHA1_SIZE);
+ }
+
+#if 0
+ printf("label: %s\n", label);
+ print_blob("master secret", ssl->dc->master_secret, 48);
+ print_blob("mac_buf", mac_buf, q-mac_buf);
+ print_blob("finished digest", digest, SSL_FINISHED_HASH_SIZE);
+#endif
+}
+
+/**
+ * Retrieve (and initialise) the context of a cipher.
+ */
+static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt)
+{
+ switch (ssl->cipher)
+ {
+#ifndef CONFIG_SSL_SKELETON_MODE
+ case SSL_AES128_SHA:
+ {
+ AES_CTX *aes_ctx = (AES_CTX *)malloc(sizeof(AES_CTX));
+ AES_set_key(aes_ctx, key, iv, AES_MODE_128);
+
+ if (is_decrypt)
+ {
+ AES_convert_key(aes_ctx);
+ }
+
+ return (void *)aes_ctx;
+ }
+
+ case SSL_AES256_SHA:
+ {
+ AES_CTX *aes_ctx = (AES_CTX *)malloc(sizeof(AES_CTX));
+ AES_set_key(aes_ctx, key, iv, AES_MODE_256);
+
+ if (is_decrypt)
+ {
+ AES_convert_key(aes_ctx);
+ }
+
+ return (void *)aes_ctx;
+ }
+ break;
+
+ case SSL_RC4_128_MD5:
+#endif
+ case SSL_RC4_128_SHA:
+ {
+ RC4_CTX *rc4_ctx = (RC4_CTX *)malloc(sizeof(RC4_CTX));
+ RC4_setup(rc4_ctx, key, 16);
+ return (void *)rc4_ctx;
+ }
+ break;
+ }
+
+ return NULL; /* its all gone wrong */
+}
+
+/**
+ * Send a packet over the socket.
+ */
+static int send_raw_packet(SSL *ssl, uint8_t protocol)
+{
+ uint8_t *rec_buf = ssl->bm_all_data;
+ int pkt_size = SSL_RECORD_SIZE+ssl->bm_index;
+ int sent = 0;
+ int ret = SSL_OK;
+
+ rec_buf[0] = protocol;
+ rec_buf[1] = 0x03; /* version = 3.1 (TLS) */
+ rec_buf[2] = 0x01;
+ rec_buf[3] = ssl->bm_index >> 8;
+ rec_buf[4] = ssl->bm_index & 0xff;
+
+ DISPLAY_BYTES(ssl, "sending %d bytes", ssl->bm_all_data,
+ pkt_size, pkt_size);
+
+ while (sent < pkt_size)
+ {
+ if ((ret = SOCKET_WRITE(ssl->client_fd,
+ &ssl->bm_all_data[sent], pkt_size)) < 0)
+ {
+ ret = SSL_ERROR_CONN_LOST;
+ break;
+ }
+
+ sent += ret;
+
+ /* keep going until the write buffer has some space */
+ if (sent != pkt_size)
+ {
+ fd_set wfds;
+ FD_ZERO(&wfds);
+ FD_SET(ssl->client_fd, &wfds);
+
+ if (select(ssl->client_fd + 1, NULL, &wfds, NULL, NULL) < 0)
+ {
+ ret = SSL_ERROR_CONN_LOST;
+ break;
+ }
+ }
+ }
+
+ SET_SSL_FLAG(SSL_NEED_RECORD); /* reset for next time */
+ ssl->bm_index = 0;
+
+ if (protocol != PT_APP_PROTOCOL_DATA)
+ {
+ /* always return SSL_OK during handshake */
+ ret = SSL_OK;
+ }
+
+ return ret;
+}
+
+/**
+ * Send an encrypted packet with padding bytes if necessary.
+ */
+int send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length)
+{
+ int msg_length = length;
+ int ret, pad_bytes = 0;
+ ssl->bm_index = msg_length;
+
+ /* if our state is bad, don't bother */
+ if (ssl->hs_status == SSL_ERROR_DEAD)
+ return SSL_ERROR_CONN_LOST;
+
+ if (in) /* has the buffer already been initialised? */
+ {
+ memcpy(ssl->bm_data, in, length);
+ }
+
+ if (IS_SET_SSL_FLAG(SSL_TX_ENCRYPTED))
+ {
+ int mode = IS_SET_SSL_FLAG(SSL_IS_CLIENT) ?
+ SSL_CLIENT_WRITE : SSL_SERVER_WRITE;
+ uint8_t hmac_header[SSL_RECORD_SIZE];
+
+ hmac_header[0] = protocol;
+ hmac_header[1] = 0x03;
+ hmac_header[2] = 0x01;
+ hmac_header[3] = length >> 8;
+ hmac_header[4] = length & 0xff;
+
+ if (protocol == PT_HANDSHAKE_PROTOCOL)
+ {
+ DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0);
+
+ if (ssl->bm_data[0] != HS_HELLO_REQUEST)
+ {
+ add_packet(ssl, ssl->bm_data, ssl->bm_index);
+ }
+ }
+
+ /* add the packet digest */
+ msg_length += ssl->cipher_info->digest_size;
+ ssl->bm_index = msg_length;
+ add_hmac_digest(ssl, mode, hmac_header, ssl->bm_data, length,
+ &ssl->bm_data[length]);
+
+ /* add padding? */
+ if (ssl->cipher_info->padding_size)
+ {
+ int last_blk_size = msg_length%ssl->cipher_info->padding_size;
+ pad_bytes = ssl->cipher_info->padding_size - last_blk_size;
+
+ /* ensure we always have at least 1 padding byte */
+ if (pad_bytes == 0)
+ pad_bytes += ssl->cipher_info->padding_size;
+
+ memset(&ssl->bm_data[msg_length], pad_bytes-1, pad_bytes);
+ msg_length += pad_bytes;
+ ssl->bm_index = msg_length;
+ }
+
+ DISPLAY_BYTES(ssl, "unencrypted write", ssl->bm_data, msg_length);
+ increment_write_sequence(ssl);
+
+ /* now encrypt the packet */
+ ssl->cipher_info->encrypt(ssl->encrypt_ctx, ssl->bm_data,
+ ssl->bm_data, msg_length);
+ }
+ else if (protocol == PT_HANDSHAKE_PROTOCOL)
+ {
+ DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0);
+
+ if (ssl->bm_data[0] != HS_HELLO_REQUEST)
+ {
+ add_packet(ssl, ssl->bm_data, ssl->bm_index);
+ }
+ }
+
+ if ((ret = send_raw_packet(ssl, protocol)) <= 0)
+ return ret;
+
+ return length; /* just return what we wanted to send */
+}
+
+/**
+ * Work out the cipher keys we are going to use for this session based on the
+ * master secret.
+ */
+static void set_key_block(SSL *ssl, int is_write)
+{
+ const cipher_info_t *ciph_info = get_cipher_info(ssl->cipher);
+ uint8_t *q;
+ uint8_t client_key[32], server_key[32]; /* big enough for AES256 */
+ uint8_t client_iv[16], server_iv[16]; /* big enough for AES128/256 */
+ int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+
+ /* only do once in a handshake */
+ if (ssl->dc->key_block == NULL)
+ {
+ ssl->dc->key_block = (uint8_t *)malloc(ciph_info->key_block_size);
+
+#if 0
+ print_blob("client", ssl->dc->client_random, 32);
+ print_blob("server", ssl->dc->server_random, 32);
+ print_blob("master", ssl->dc->master_secret, SSL_SECRET_SIZE);
+#endif
+ generate_key_block(ssl->dc->client_random, ssl->dc->server_random,
+ ssl->dc->master_secret, ssl->dc->key_block,
+ ciph_info->key_block_size);
+#if 0
+ print_blob("keyblock", ssl->key_block, ciph_info->key_block_size);
+#endif
+ }
+
+ q = ssl->dc->key_block;
+
+ if ((is_client && is_write) || (!is_client && !is_write))
+ {
+ memcpy(ssl->client_mac, q, ciph_info->digest_size);
+ }
+
+ q += ciph_info->digest_size;
+
+ if ((!is_client && is_write) || (is_client && !is_write))
+ {
+ memcpy(ssl->server_mac, q, ciph_info->digest_size);
+ }
+
+ q += ciph_info->digest_size;
+ memcpy(client_key, q, ciph_info->key_size);
+ q += ciph_info->key_size;
+ memcpy(server_key, q, ciph_info->key_size);
+ q += ciph_info->key_size;
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ if (ciph_info->iv_size) /* RC4 has no IV, AES does */
+ {
+ memcpy(client_iv, q, ciph_info->iv_size);
+ q += ciph_info->iv_size;
+ memcpy(server_iv, q, ciph_info->iv_size);
+ q += ciph_info->iv_size;
+ }
+#endif
+
+ free(is_write ? ssl->encrypt_ctx : ssl->decrypt_ctx);
+
+ /* now initialise the ciphers */
+ if (is_client)
+ {
+ finished_digest(ssl, server_finished, ssl->dc->final_finish_mac);
+
+ if (is_write)
+ ssl->encrypt_ctx = crypt_new(ssl, client_key, client_iv, 0);
+ else
+ ssl->decrypt_ctx = crypt_new(ssl, server_key, server_iv, 1);
+ }
+ else
+ {
+ finished_digest(ssl, client_finished, ssl->dc->final_finish_mac);
+
+ if (is_write)
+ ssl->encrypt_ctx = crypt_new(ssl, server_key, server_iv, 0);
+ else
+ ssl->decrypt_ctx = crypt_new(ssl, client_key, client_iv, 1);
+ }
+
+ ssl->cipher_info = ciph_info;
+}
+
+/**
+ * Read the SSL connection.
+ */
+int basic_read(SSL *ssl, uint8_t **in_data)
+{
+ int ret = SSL_OK;
+ int read_len, is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+ uint8_t *buf = ssl->bm_data;
+
+ read_len = SOCKET_READ(ssl->client_fd, &buf[ssl->bm_read_index],
+ ssl->need_bytes-ssl->got_bytes);
+
+ /* connection has gone, so die */
+ if (read_len <= 0)
+ {
+ ret = SSL_ERROR_CONN_LOST;
+ ssl->hs_status = SSL_ERROR_DEAD; /* make sure it stays dead */
+ goto error;
+ }
+
+ DISPLAY_BYTES(ssl, "received %d bytes",
+ &ssl->bm_data[ssl->bm_read_index], read_len, read_len);
+
+ ssl->got_bytes += read_len;
+ ssl->bm_read_index += read_len;
+
+ /* haven't quite got what we want, so try again later */
+ if (ssl->got_bytes < ssl->need_bytes)
+ return SSL_OK;
+
+ read_len = ssl->got_bytes;
+ ssl->got_bytes = 0;
+
+ if (IS_SET_SSL_FLAG(SSL_NEED_RECORD))
+ {
+ /* check for sslv2 "client hello" */
+ if (buf[0] & 0x80 && buf[2] == 1 && buf[3] == 0x03)
+ {
+#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE
+ DISPLAY_BYTES(ssl, "ssl2 record", buf, 5);
+ add_packet(ssl, &buf[2], 3);
+ ret = process_sslv23_client_hello(ssl);
+#else
+ printf("Error: no SSLv23 handshaking allowed\n"); TTY_FLUSH();
+ ret = SSL_ERROR_NOT_SUPPORTED;
+#endif
+ goto error; /* not an error - just get out of here */
+ }
+
+ ssl->need_bytes = (buf[3] << 8) + buf[4];
+
+ /* do we violate the spec with the message size? */
+ if (ssl->need_bytes > RT_MAX_PLAIN_LENGTH+RT_EXTRA-BM_RECORD_OFFSET)
+ {
+ ret = SSL_ERROR_INVALID_PROT_MSG;
+ goto error;
+ }
+
+ CLR_SSL_FLAG(SSL_NEED_RECORD);
+ memcpy(ssl->hmac_header, buf, 3); /* store for hmac */
+ ssl->record_type = buf[0];
+ goto error; /* no error, we're done */
+ }
+
+ /* for next time - just do it now in case of an error */
+ SET_SSL_FLAG(SSL_NEED_RECORD);
+ ssl->need_bytes = SSL_RECORD_SIZE;
+
+ /* decrypt if we need to */
+ if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED))
+ {
+ ssl->cipher_info->decrypt(ssl->decrypt_ctx, buf, buf, read_len);
+ read_len = verify_digest(ssl,
+ is_client ? SSL_CLIENT_READ : SSL_SERVER_READ, buf, read_len);
+
+ /* does the hmac work? */
+ if (read_len < 0)
+ {
+ ret = read_len;
+ goto error;
+ }
+
+ DISPLAY_BYTES(ssl, "decrypted", buf, read_len);
+ increment_read_sequence(ssl);
+ }
+
+ /* The main part of the SSL packet */
+ switch (ssl->record_type)
+ {
+ case PT_HANDSHAKE_PROTOCOL:
+ ssl->dc->bm_proc_index = 0;
+ ret = do_handshake(ssl, buf, read_len);
+ break;
+
+ case PT_CHANGE_CIPHER_SPEC:
+ if (ssl->next_state != HS_FINISHED)
+ {
+ ret = SSL_ERROR_INVALID_HANDSHAKE;
+ goto error;
+ }
+
+ /* all encrypted from now on */
+ SET_SSL_FLAG(SSL_RX_ENCRYPTED);
+ set_key_block(ssl, 0);
+ memset(ssl->read_sequence, 0, 8);
+ break;
+
+ case PT_APP_PROTOCOL_DATA:
+ if (in_data)
+ {
+ *in_data = ssl->bm_data; /* point to the work buffer */
+ (*in_data)[read_len] = 0; /* null terminate just in case */
+ }
+
+ ret = read_len;
+ break;
+
+ case PT_ALERT_PROTOCOL:
+ /* return the alert # with alert bit set */
+ ret = -buf[1];
+ DISPLAY_ALERT(ssl, buf[1]);
+ break;
+
+ default:
+ ret = SSL_ERROR_INVALID_PROT_MSG;
+ break;
+ }
+
+error:
+ ssl->bm_read_index = 0; /* reset to go again */
+
+ if (ret < SSL_OK && in_data)/* if all wrong, then clear this buffer ptr */
+ *in_data = NULL;
+
+ return ret;
+}
+
+/**
+ * Do some basic checking of data and then perform the appropriate handshaking.
+ */
+static int do_handshake(SSL *ssl, uint8_t *buf, int read_len)
+{
+ int hs_len = (buf[2]<<8) + buf[3];
+ uint8_t handshake_type = buf[0];
+ int ret = SSL_OK;
+ int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+
+ /* some integrity checking on the handshake */
+ PARANOIA_CHECK(read_len-SSL_HS_HDR_SIZE, hs_len);
+
+ if (handshake_type != ssl->next_state)
+ {
+ /* handle a special case on the client */
+ if (!is_client || handshake_type != HS_CERT_REQ ||
+ ssl->next_state != HS_SERVER_HELLO_DONE)
+ {
+ ret = SSL_ERROR_INVALID_HANDSHAKE;
+ goto error;
+ }
+ }
+
+ hs_len += SSL_HS_HDR_SIZE; /* adjust for when adding packets */
+ ssl->bm_index = hs_len; /* store the size and check later */
+ DISPLAY_STATE(ssl, 0, handshake_type, 0);
+
+ if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST)
+ add_packet(ssl, buf, hs_len);
+
+#if defined(CONFIG_SSL_ENABLE_CLIENT)
+ ret = is_client ?
+ do_clnt_handshake(ssl, handshake_type, buf, hs_len) :
+ do_svr_handshake(ssl, handshake_type, buf, hs_len);
+#else
+ ret = do_svr_handshake(ssl, handshake_type, buf, hs_len);
+#endif
+
+ /* just use recursion to get the rest */
+ if (hs_len < read_len && ret == SSL_OK)
+ ret = do_handshake(ssl, &buf[hs_len], read_len-hs_len);
+
+error:
+ return ret;
+}
+
+/**
+ * Sends the change cipher spec message. We have just read a finished message
+ * from the client.
+ */
+int send_change_cipher_spec(SSL *ssl)
+{
+ int ret = send_packet(ssl, PT_CHANGE_CIPHER_SPEC,
+ g_chg_cipher_spec_pkt, sizeof(g_chg_cipher_spec_pkt));
+ SET_SSL_FLAG(SSL_TX_ENCRYPTED);
+ set_key_block(ssl, 1);
+ memset(ssl->write_sequence, 0, 8);
+ return ret;
+}
+
+/**
+ * Send a "finished" message
+ */
+int send_finished(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+
+ buf[0] = HS_FINISHED;
+ buf[1] = 0;
+ buf[2] = 0;
+ buf[3] = SSL_FINISHED_HASH_SIZE;
+
+ /* now add the finished digest mac (12 bytes) */
+ finished_digest(ssl,
+ IS_SET_SSL_FLAG(SSL_IS_CLIENT) ?
+ client_finished : server_finished, &buf[4]);
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ /* store in the session cache */
+ if (!IS_SET_SSL_FLAG(SSL_SESSION_RESUME) && ssl->ssl_ctx->num_sessions)
+ {
+ memcpy(ssl->session->master_secret,
+ ssl->dc->master_secret, SSL_SECRET_SIZE);
+ }
+#endif
+
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL,
+ NULL, SSL_FINISHED_HASH_SIZE+4);
+}
+
+/**
+ * Send an alert message.
+ * Return 1 if the alert was an "error".
+ */
+int send_alert(SSL *ssl, int error_code)
+{
+ int alert_num = 0;
+ int is_warning = 0;
+ uint8_t buf[2];
+
+ /* Don't bother we're already dead */
+ if (ssl->hs_status == SSL_ERROR_DEAD)
+ {
+ return SSL_ERROR_CONN_LOST;
+ }
+
+#ifdef CONFIG_SSL_FULL_MODE
+ if (IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))
+ ssl_display_error(error_code);
+#endif
+
+ switch (error_code)
+ {
+ case SSL_ALERT_CLOSE_NOTIFY:
+ is_warning = 1;
+ alert_num = SSL_ALERT_CLOSE_NOTIFY;
+ break;
+
+ case SSL_ERROR_CONN_LOST: /* don't send alert just yet */
+ is_warning = 1;
+ break;
+
+ case SSL_ERROR_INVALID_HANDSHAKE:
+ case SSL_ERROR_INVALID_PROT_MSG:
+ alert_num = SSL_ALERT_HANDSHAKE_FAILURE;
+ break;
+
+ case SSL_ERROR_INVALID_HMAC:
+ case SSL_ERROR_FINISHED_INVALID:
+ alert_num = SSL_ALERT_BAD_RECORD_MAC;
+ break;
+
+ case SSL_ERROR_INVALID_VERSION:
+ alert_num = SSL_ALERT_INVALID_VERSION;
+ break;
+
+ case SSL_ERROR_INVALID_SESSION:
+ case SSL_ERROR_NO_CIPHER:
+ case SSL_ERROR_INVALID_KEY:
+ alert_num = SSL_ALERT_ILLEGAL_PARAMETER;
+ break;
+
+ case SSL_ERROR_BAD_CERTIFICATE:
+ alert_num = SSL_ALERT_BAD_CERTIFICATE;
+ break;
+
+ default:
+ /* a catch-all for any badly verified certificates */
+ alert_num = (error_code <= SSL_X509_OFFSET) ?
+ SSL_ALERT_BAD_CERTIFICATE : SSL_ALERT_UNEXPECTED_MESSAGE;
+ break;
+ }
+
+ buf[0] = is_warning ? 1 : 2;
+ buf[1] = alert_num;
+ send_packet(ssl, PT_ALERT_PROTOCOL, buf, sizeof(buf));
+ DISPLAY_ALERT(ssl, alert_num);
+ return is_warning ? 0 : 1;
+}
+
+/**
+ * Process a client finished message.
+ */
+int process_finished(SSL *ssl, int hs_len)
+{
+ uint8_t *buf = ssl->bm_data;
+ int ret = SSL_OK;
+ int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+ int resume = IS_SET_SSL_FLAG(SSL_SESSION_RESUME);
+
+ PARANOIA_CHECK(ssl->bm_index, SSL_FINISHED_HASH_SIZE+4);
+
+ /* check that we all work before we continue */
+ if (memcmp(ssl->dc->final_finish_mac, &buf[4], SSL_FINISHED_HASH_SIZE))
+ return SSL_ERROR_FINISHED_INVALID;
+
+ if ((!is_client && !resume) || (is_client && resume))
+ {
+ if ((ret = send_change_cipher_spec(ssl)) == SSL_OK)
+ ret = send_finished(ssl);
+ }
+
+ /* if we ever renegotiate */
+ ssl->next_state = is_client ? HS_HELLO_REQUEST : HS_CLIENT_HELLO;
+ ssl->hs_status = ret; /* set the final handshake status */
+
+error:
+ return ret;
+}
+
+/**
+ * Send a certificate.
+ */
+int send_certificate(SSL *ssl)
+{
+ int i = 0;
+ uint8_t *buf = ssl->bm_data;
+ int offset = 7;
+ int chain_length;
+
+ buf[0] = HS_CERTIFICATE;
+ buf[1] = 0;
+ buf[4] = 0;
+
+ while (i < ssl->ssl_ctx->chain_length)
+ {
+ SSL_CERT *cert = &ssl->ssl_ctx->certs[i];
+ buf[offset++] = 0;
+ buf[offset++] = cert->size >> 8; /* cert 1 length */
+ buf[offset++] = cert->size & 0xff;
+ memcpy(&buf[offset], cert->buf, cert->size);
+ offset += cert->size;
+ i++;
+ }
+
+ chain_length = offset - 7;
+ buf[5] = chain_length >> 8; /* cert chain length */
+ buf[6] = chain_length & 0xff;
+ chain_length += 3;
+ buf[2] = chain_length >> 8; /* handshake length */
+ buf[3] = chain_length & 0xff;
+ ssl->bm_index = offset;
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);
+}
+
+/**
+ * Create a blob of memory that we'll get rid of once the handshake is
+ * complete.
+ */
+void disposable_new(SSL *ssl)
+{
+ if (ssl->dc == NULL)
+ {
+ ssl->dc = (DISPOSABLE_CTX *)calloc(1, sizeof(DISPOSABLE_CTX));
+ MD5_Init(&ssl->dc->md5_ctx);
+ SHA1_Init(&ssl->dc->sha1_ctx);
+ }
+}
+
+/**
+ * Remove the temporary blob of memory.
+ */
+void disposable_free(SSL *ssl)
+{
+ if (ssl->dc)
+ {
+ free(ssl->dc->key_block);
+ memset(ssl->dc, 0, sizeof(DISPOSABLE_CTX));
+ free(ssl->dc);
+ ssl->dc = NULL;
+ }
+
+}
+
+#ifndef CONFIG_SSL_SKELETON_MODE /* no session resumption in this mode */
+/**
+ * Find if an existing session has the same session id. If so, use the
+ * master secret from this session for session resumption.
+ */
+SSL_SESSION *ssl_session_update(int max_sessions, SSL_SESSION *ssl_sessions[],
+ SSL *ssl, const uint8_t *session_id)
+{
+ time_t tm = time(NULL);
+ time_t oldest_sess_time = tm;
+ SSL_SESSION *oldest_sess = NULL;
+ int i;
+
+ /* no sessions? Then bail */
+ if (max_sessions == 0)
+ return NULL;
+
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+ if (session_id)
+ {
+ for (i = 0; i < max_sessions; i++)
+ {
+ if (ssl_sessions[i])
+ {
+ /* kill off any expired sessions */
+ if (tm > ssl_sessions[i]->conn_time + SSL_EXPIRY_TIME)
+ {
+ session_free(ssl_sessions, i);
+ continue;
+ }
+
+ /* if the session id matches, it must still be less than
+ the expiry time */
+ if (memcmp(ssl_sessions[i]->session_id, session_id,
+ SSL_SESSION_ID_SIZE) == 0)
+ {
+ ssl->session_index = i;
+ memcpy(ssl->dc->master_secret,
+ ssl_sessions[i]->master_secret, SSL_SECRET_SIZE);
+ SET_SSL_FLAG(SSL_SESSION_RESUME);
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+ return ssl_sessions[i]; /* a session was found */
+ }
+ }
+ }
+ }
+
+ /* If we've got here, no matching session was found - so create one */
+ for (i = 0; i < max_sessions; i++)
+ {
+ if (ssl_sessions[i] == NULL)
+ {
+ /* perfect, this will do */
+ ssl_sessions[i] = (SSL_SESSION *)calloc(1, sizeof(SSL_SESSION));
+ ssl_sessions[i]->conn_time = tm;
+ ssl->session_index = i;
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+ return ssl_sessions[i]; /* return the session object */
+ }
+ else if (ssl_sessions[i]->conn_time <= oldest_sess_time)
+ {
+ /* find the oldest session */
+ oldest_sess_time = ssl_sessions[i]->conn_time;
+ oldest_sess = ssl_sessions[i];
+ ssl->session_index = i;
+ }
+ }
+
+ /* ok, we've used up all of our sessions. So blow the oldest session away */
+ oldest_sess->conn_time = tm;
+ memset(oldest_sess->session_id, 0, sizeof(SSL_SESSION_ID_SIZE));
+ memset(oldest_sess->master_secret, 0, sizeof(SSL_SECRET_SIZE));
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+ return oldest_sess;
+}
+
+/**
+ * Free an existing session.
+ */
+static void session_free(SSL_SESSION *ssl_sessions[], int sess_index)
+{
+ if (ssl_sessions[sess_index])
+ {
+ free(ssl_sessions[sess_index]);
+ ssl_sessions[sess_index] = NULL;
+ }
+}
+
+/**
+ * This ssl object doesn't want this session anymore.
+ */
+void kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl)
+{
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+
+ if (ssl->ssl_ctx->num_sessions)
+ {
+ session_free(ssl_sessions, ssl->session_index);
+ ssl->session = NULL;
+ }
+
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+}
+#endif /* CONFIG_SSL_SKELETON_MODE */
+
+/*
+ * Get the session id for a handshake. This will be a 32 byte sequence.
+ */
+EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl)
+{
+ return ssl->session_id;
+}
+
+/*
+ * Get the session id size for a handshake.
+ */
+EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl)
+{
+ return ssl->sess_id_size;
+}
+
+/*
+ * Return the cipher id (in the SSL form).
+ */
+EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl)
+{
+ return ssl->cipher;
+}
+
+/*
+ * Return the status of the handshake.
+ */
+EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl)
+{
+ return ssl->hs_status;
+}
+
+/*
+ * Retrieve various parameters about the SSL engine.
+ */
+EXP_FUNC int STDCALL ssl_get_config(int offset)
+{
+ switch (offset)
+ {
+ /* return the appropriate build mode */
+ case SSL_BUILD_MODE:
+#if defined(CONFIG_SSL_FULL_MODE)
+ return SSL_BUILD_FULL_MODE;
+#elif defined(CONFIG_SSL_ENABLE_CLIENT)
+ return SSL_BUILD_ENABLE_CLIENT;
+#elif defined(CONFIG_ENABLE_VERIFICATION)
+ return SSL_BUILD_ENABLE_VERIFICATION;
+#elif defined(CONFIG_SSL_SERVER_ONLY )
+ return SSL_BUILD_SERVER_ONLY;
+#else
+ return SSL_BUILD_SKELETON_MODE;
+#endif
+
+ case SSL_MAX_CERT_CFG_OFFSET:
+ return CONFIG_SSL_MAX_CERTS;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ case SSL_MAX_CA_CERT_CFG_OFFSET:
+ return CONFIG_X509_MAX_CA_CERTS;
+#endif
+#ifdef CONFIG_SSL_HAS_PEM
+ case SSL_HAS_PEM:
+ return 1;
+#endif
+ default:
+ return 0;
+ }
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Authenticate a received certificate.
+ */
+EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl)
+{
+ int ret;
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+ ret = x509_verify(ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx);
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+ if (ret) /* modify into an SSL error type */
+ {
+ ret = SSL_X509_ERROR(ret);
+ }
+
+ return ret;
+}
+
+/**
+ * Process a certificate message.
+ */
+int process_certificate(SSL *ssl, X509_CTX **x509_ctx)
+{
+ int ret = SSL_OK;
+ uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
+ int pkt_size = ssl->bm_index;
+ int cert_size, offset = 5;
+ int total_cert_size = (buf[offset]<<8) + buf[offset+1];
+ int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);
+ X509_CTX **chain = x509_ctx;
+ offset += 2;
+
+ PARANOIA_CHECK(total_cert_size, offset);
+
+ while (offset < total_cert_size)
+ {
+ offset++; /* skip empty char */
+ cert_size = (buf[offset]<<8) + buf[offset+1];
+ offset += 2;
+
+ if (x509_new(&buf[offset], NULL, chain))
+ {
+ ret = SSL_ERROR_BAD_CERTIFICATE;
+ goto error;
+ }
+
+ /* DISPLAY_CERT(ssl, *chain); */
+ chain = &((*chain)->next);
+ offset += cert_size;
+ }
+
+ PARANOIA_CHECK(pkt_size, offset);
+
+ /* if we are client we can do the verify now or later */
+ if (is_client && !IS_SET_SSL_FLAG(SSL_SERVER_VERIFY_LATER))
+ {
+ ret = ssl_verify_cert(ssl);
+ }
+
+ ssl->next_state = is_client ? HS_SERVER_HELLO_DONE : HS_CLIENT_KEY_XCHG;
+ ssl->dc->bm_proc_index += offset;
+error:
+ return ret;
+}
+
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
+
+/**
+ * Debugging routine to display SSL handshaking stuff.
+ */
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * Debugging routine to display SSL states.
+ */
+void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok)
+{
+ const char *str;
+
+ if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))
+ return;
+
+ printf(not_ok ? "Error - invalid State:\t" : "State:\t");
+ printf(is_send ? "sending " : "receiving ");
+
+ switch (state)
+ {
+ case HS_HELLO_REQUEST:
+ str = "Hello Request (0)";
+ break;
+
+ case HS_CLIENT_HELLO:
+ str = "Client Hello (1)";
+ break;
+
+ case HS_SERVER_HELLO:
+ str = "Server Hello (2)";
+ break;
+
+ case HS_CERTIFICATE:
+ str = "Certificate (11)";
+ break;
+
+ case HS_SERVER_KEY_XCHG:
+ str = "Certificate Request (12)";
+ break;
+
+ case HS_CERT_REQ:
+ str = "Certificate Request (13)";
+ break;
+
+ case HS_SERVER_HELLO_DONE:
+ str = "Server Hello Done (14)";
+ break;
+
+ case HS_CERT_VERIFY:
+ str = "Certificate Verify (15)";
+ break;
+
+ case HS_CLIENT_KEY_XCHG:
+ str = "Client Key Exchange (16)";
+ break;
+
+ case HS_FINISHED:
+ str = "Finished (16)";
+ break;
+
+ default:
+ str = "Error (Unknown)";
+
+ break;
+ }
+
+ printf("%s\n", str);
+ TTY_FLUSH();
+}
+
+/**
+ * Debugging routine to display X509 certificates.
+ */
+void DISPLAY_CERT(SSL *ssl, const X509_CTX *x509_ctx)
+{
+ if (!IS_SET_SSL_FLAG(SSL_DISPLAY_CERTS))
+ return;
+
+ x509_print(x509_ctx, ssl->ssl_ctx->ca_cert_ctx);
+ TTY_FLUSH();
+}
+
+/**
+ * Debugging routine to display RSA objects
+ */
+void DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx)
+{
+ if (!IS_SET_SSL_FLAG(SSL_DISPLAY_RSA))
+ return;
+
+ RSA_print(rsa_ctx);
+ TTY_FLUSH();
+}
+
+/**
+ * Debugging routine to display SSL handshaking bytes.
+ */
+void DISPLAY_BYTES(SSL *ssl, const char *format,
+ const uint8_t *data, int size, ...)
+{
+ va_list(ap);
+
+ if (!IS_SET_SSL_FLAG(SSL_DISPLAY_BYTES))
+ return;
+
+ va_start(ap, size);
+ print_blob(format, data, size, va_arg(ap, char *));
+ va_end(ap);
+ TTY_FLUSH();
+}
+
+/**
+ * Debugging routine to display SSL handshaking errors.
+ */
+EXP_FUNC void STDCALL ssl_display_error(int error_code)
+{
+ if (error_code == SSL_OK)
+ return;
+
+ printf("Error: ");
+
+ /* X509 error? */
+ if (error_code < SSL_X509_OFFSET)
+ {
+ printf("%s\n", x509_display_error(error_code - SSL_X509_OFFSET));
+ return;
+ }
+
+ /* SSL alert error code */
+ if (error_code > SSL_ERROR_CONN_LOST)
+ {
+ printf("SSL error %d\n", -error_code);
+ return;
+ }
+
+ switch (error_code)
+ {
+ case SSL_ERROR_DEAD:
+ printf("connection dead");
+ break;
+
+ case SSL_ERROR_INVALID_HANDSHAKE:
+ printf("invalid handshake");
+ break;
+
+ case SSL_ERROR_INVALID_PROT_MSG:
+ printf("invalid protocol message");
+ break;
+
+ case SSL_ERROR_INVALID_HMAC:
+ printf("invalid mac");
+ break;
+
+ case SSL_ERROR_INVALID_VERSION:
+ printf("invalid version");
+ break;
+
+ case SSL_ERROR_INVALID_SESSION:
+ printf("invalid session");
+ break;
+
+ case SSL_ERROR_NO_CIPHER:
+ printf("no cipher");
+ break;
+
+ case SSL_ERROR_CONN_LOST:
+ printf("connection lost");
+ break;
+
+ case SSL_ERROR_BAD_CERTIFICATE:
+ printf("bad certificate");
+ break;
+
+ case SSL_ERROR_INVALID_KEY:
+ printf("invalid key");
+ break;
+
+ case SSL_ERROR_FINISHED_INVALID:
+ printf("finished invalid");
+ break;
+
+ case SSL_ERROR_NO_CERT_DEFINED:
+ printf("no certificate defined");
+ break;
+
+ case SSL_ERROR_NOT_SUPPORTED:
+ printf("Option not supported");
+ break;
+
+ default:
+ printf("undefined as yet - %d", error_code);
+ break;
+ }
+
+ printf("\n");
+ TTY_FLUSH();
+}
+
+/**
+ * Debugging routine to display alerts.
+ */
+void DISPLAY_ALERT(SSL *ssl, int alert)
+{
+ if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))
+ return;
+
+ printf("Alert: ");
+
+ switch (alert)
+ {
+ case SSL_ALERT_CLOSE_NOTIFY:
+ printf("close notify");
+ break;
+
+ case SSL_ALERT_INVALID_VERSION:
+ printf("invalid version");
+ break;
+
+ case SSL_ALERT_BAD_CERTIFICATE:
+ printf("bad certificate");
+ break;
+
+ case SSL_ALERT_UNEXPECTED_MESSAGE:
+ printf("unexpected message");
+ break;
+
+ case SSL_ALERT_BAD_RECORD_MAC:
+ printf("bad record mac");
+ break;
+
+ case SSL_ALERT_HANDSHAKE_FAILURE:
+ printf("handshake failure");
+ break;
+
+ case SSL_ALERT_ILLEGAL_PARAMETER:
+ printf("illegal parameter");
+ break;
+
+ case SSL_ALERT_DECODE_ERROR:
+ printf("decode error");
+ break;
+
+ case SSL_ALERT_DECRYPT_ERROR:
+ printf("decrypt error");
+ break;
+
+ default:
+ printf("alert - (unknown %d)", alert);
+ break;
+ }
+
+ printf("\n");
+ TTY_FLUSH();
+}
+
+#endif /* CONFIG_SSL_FULL_MODE */
+
+/**
+ * Return the version of this library.
+ */
+EXP_FUNC const char * STDCALL ssl_version()
+{
+ static const char * axtls_version = AXTLS_VERSION;
+ return axtls_version;
+}
+
+/**
+ * Enable the various language bindings to work regardless of the
+ * configuration - they just return an error statement and a bad return code.
+ */
+#if !defined(CONFIG_SSL_FULL_MODE)
+EXP_FUNC void STDCALL ssl_display_error(int error_code) {}
+#endif
+
+#ifdef CONFIG_BINDINGS
+#if !defined(CONFIG_SSL_ENABLE_CLIENT)
+EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const
+ uint8_t *session_id, uint8_t sess_id_size)
+{
+ printf(unsupported_str);
+ return NULL;
+}
+#endif
+
+#if !defined(CONFIG_SSL_CERT_VERIFICATION)
+EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl)
+{
+ printf(unsupported_str);
+ return -1;
+}
+
+EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component)
+{
+ printf(unsupported_str);
+ return NULL;
+}
+
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
+
+#endif /* CONFIG_BINDINGS */
+
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file tls1.h
+ *
+ * @brief The definitions for the TLS library.
+ */
+#ifndef HEADER_SSL_LIB_H
+#define HEADER_SSL_LIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "version.h"
+#include "crypto.h"
+#include "os_port.h"
+#include "crypto_misc.h"
+
+#define SSL_RANDOM_SIZE 32
+#define SSL_SECRET_SIZE 48
+#define SSL_FINISHED_HASH_SIZE 12
+#define SSL_RECORD_SIZE 5
+#define SSL_SERVER_READ 0
+#define SSL_SERVER_WRITE 1
+#define SSL_CLIENT_READ 2
+#define SSL_CLIENT_WRITE 3
+#define SSL_HS_HDR_SIZE 4
+
+/* the flags we use while establishing a connection */
+#define SSL_NEED_RECORD 0x0001
+#define SSL_TX_ENCRYPTED 0x0002
+#define SSL_RX_ENCRYPTED 0x0004
+#define SSL_SESSION_RESUME 0x0008
+#define SSL_IS_CLIENT 0x0010
+#define SSL_HAS_CERT_REQ 0x0020
+
+/* some macros to muck around with flag bits */
+#define SET_SSL_FLAG(A) (ssl->flag |= A)
+#define CLR_SSL_FLAG(A) (ssl->flag &= ~A)
+#define IS_SET_SSL_FLAG(A) (ssl->flag & A)
+
+#define MAX_KEY_BYTE_SIZE 512 /* for a 4096 bit key */
+#define RT_MAX_PLAIN_LENGTH 16384
+#define RT_EXTRA 1024
+#define BM_RECORD_OFFSET 5
+
+#ifdef CONFIG_SSL_SKELETON_MODE
+#define NUM_PROTOCOLS 1
+#else
+#define NUM_PROTOCOLS 4
+#endif
+
+#define PARANOIA_CHECK(A, B) if (A < B) { \
+ ret = SSL_ERROR_INVALID_HANDSHAKE; goto error; }
+
+/* protocol types */
+enum
+{
+ PT_CHANGE_CIPHER_SPEC = 20,
+ PT_ALERT_PROTOCOL,
+ PT_HANDSHAKE_PROTOCOL,
+ PT_APP_PROTOCOL_DATA
+};
+
+/* handshaking types */
+enum
+{
+ HS_HELLO_REQUEST,
+ HS_CLIENT_HELLO,
+ HS_SERVER_HELLO,
+ HS_CERTIFICATE = 11,
+ HS_SERVER_KEY_XCHG,
+ HS_CERT_REQ,
+ HS_SERVER_HELLO_DONE,
+ HS_CERT_VERIFY,
+ HS_CLIENT_KEY_XCHG,
+ HS_FINISHED = 20
+};
+
+typedef struct
+{
+ uint8_t cipher;
+ uint8_t key_size;
+ uint8_t iv_size;
+ uint8_t key_block_size;
+ uint8_t padding_size;
+ uint8_t digest_size;
+ hmac_func hmac;
+ crypt_func encrypt;
+ crypt_func decrypt;
+} cipher_info_t;
+
+struct _SSLObjLoader
+{
+ uint8_t *buf;
+ int len;
+};
+
+typedef struct _SSLObjLoader SSLObjLoader;
+
+typedef struct
+{
+ time_t conn_time;
+ uint8_t session_id[SSL_SESSION_ID_SIZE];
+ uint8_t master_secret[SSL_SECRET_SIZE];
+} SSL_SESSION;
+
+typedef struct
+{
+ uint8_t *buf;
+ int size;
+} SSL_CERT;
+
+typedef struct
+{
+ MD5_CTX md5_ctx;
+ SHA1_CTX sha1_ctx;
+ uint8_t final_finish_mac[SSL_FINISHED_HASH_SIZE];
+ uint8_t *key_block;
+ uint8_t master_secret[SSL_SECRET_SIZE];
+ uint8_t client_random[SSL_RANDOM_SIZE]; /* client's random sequence */
+ uint8_t server_random[SSL_RANDOM_SIZE]; /* server's random sequence */
+ uint16_t bm_proc_index;
+} DISPOSABLE_CTX;
+
+struct _SSL
+{
+ uint32_t flag;
+ uint16_t need_bytes;
+ uint16_t got_bytes;
+ uint8_t record_type;
+ uint8_t cipher;
+ uint8_t sess_id_size;
+ int16_t next_state;
+ int16_t hs_status;
+ DISPOSABLE_CTX *dc; /* temporary data which we'll get rid of soon */
+ int client_fd;
+ const cipher_info_t *cipher_info;
+ void *encrypt_ctx;
+ void *decrypt_ctx;
+ uint8_t bm_all_data[RT_MAX_PLAIN_LENGTH+RT_EXTRA];
+ uint8_t *bm_data;
+ uint16_t bm_index;
+ uint16_t bm_read_index;
+ struct _SSL *next; /* doubly linked list */
+ struct _SSL *prev;
+ struct _SSL_CTX *ssl_ctx; /* back reference to a clnt/svr ctx */
+#ifndef CONFIG_SSL_SKELETON_MODE
+ uint16_t session_index;
+ SSL_SESSION *session;
+#endif
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ X509_CTX *x509_ctx;
+#endif
+
+ uint8_t session_id[SSL_SESSION_ID_SIZE];
+ uint8_t client_mac[SHA1_SIZE]; /* for HMAC verification */
+ uint8_t server_mac[SHA1_SIZE]; /* for HMAC verification */
+ uint8_t read_sequence[8]; /* 64 bit sequence number */
+ uint8_t write_sequence[8]; /* 64 bit sequence number */
+ uint8_t hmac_header[SSL_RECORD_SIZE]; /* rx hmac */
+};
+
+typedef struct _SSL SSL;
+
+struct _SSL_CTX
+{
+ uint32_t options;
+ uint8_t chain_length;
+ RSA_CTX *rsa_ctx;
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ CA_CERT_CTX *ca_cert_ctx;
+#endif
+ SSL *head;
+ SSL *tail;
+ SSL_CERT certs[CONFIG_SSL_MAX_CERTS];
+#ifndef CONFIG_SSL_SKELETON_MODE
+ uint16_t num_sessions;
+ SSL_SESSION **ssl_sessions;
+#endif
+#ifdef CONFIG_SSL_CTX_MUTEXING
+ SSL_CTX_MUTEX_TYPE mutex;
+#endif
+#ifdef CONFIG_OPENSSL_COMPATIBLE
+ void *bonus_attr;
+#endif
+};
+
+typedef struct _SSL_CTX SSL_CTX;
+
+/* backwards compatibility */
+typedef struct _SSL_CTX SSLCTX;
+
+extern const uint8_t ssl_prot_prefs[NUM_PROTOCOLS];
+
+SSL *ssl_new(SSL_CTX *ssl_ctx, int client_fd);
+void disposable_new(SSL *ssl);
+void disposable_free(SSL *ssl);
+int send_packet(SSL *ssl, uint8_t protocol,
+ const uint8_t *in, int length);
+int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len);
+int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len);
+int process_finished(SSL *ssl, int hs_len);
+int process_sslv23_client_hello(SSL *ssl);
+int send_alert(SSL *ssl, int error_code);
+int send_finished(SSL *ssl);
+int send_certificate(SSL *ssl);
+int basic_read(SSL *ssl, uint8_t **in_data);
+int send_change_cipher_spec(SSL *ssl);
+void finished_digest(SSL *ssl, const char *label, uint8_t *digest);
+void generate_master_secret(SSL *ssl, const uint8_t *premaster_secret);
+void add_packet(SSL *ssl, const uint8_t *pkt, int len);
+int add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len);
+int add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj);
+void ssl_obj_free(SSLObjLoader *ssl_obj);
+int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password);
+int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password);
+int load_key_certs(SSL_CTX *ssl_ctx);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+int add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len);
+void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx);
+#endif
+#ifdef CONFIG_SSL_ENABLE_CLIENT
+int do_client_connect(SSL *ssl);
+#endif
+
+#ifdef CONFIG_SSL_FULL_MODE
+void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok);
+void DISPLAY_BYTES(SSL *ssl, const char *format,
+ const uint8_t *data, int size, ...);
+void DISPLAY_CERT(SSL *ssl, const X509_CTX *x509_ctx);
+void DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx);
+void DISPLAY_ALERT(SSL *ssl, int alert);
+#else
+#define DISPLAY_STATE(A,B,C,D)
+#define DISPLAY_CERT(A,B)
+#define DISPLAY_RSA(A,B)
+#define DISPLAY_ALERT(A, B)
+#ifdef WIN32
+void DISPLAY_BYTES(SSL *ssl, const char *format,/* win32 has no variadic macros */
+ const uint8_t *data, int size, ...);
+#else
+#define DISPLAY_BYTES(A,B,C,D,...)
+#endif
+#endif
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+int process_certificate(SSL *ssl, X509_CTX **x509_ctx);
+#endif
+
+SSL_SESSION *ssl_session_update(int max_sessions,
+ SSL_SESSION *ssl_sessions[], SSL *ssl,
+ const uint8_t *session_id);
+void kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <stdio.h>
+
+#include "ssl.h"
+
+#ifdef CONFIG_SSL_ENABLE_CLIENT /* all commented out if no client */
+
+static int send_client_hello(SSL *ssl);
+static int process_server_hello(SSL *ssl);
+static int process_server_hello_done(SSL *ssl);
+static int send_client_key_xchg(SSL *ssl);
+static int process_cert_req(SSL *ssl);
+static int send_cert_verify(SSL *ssl);
+
+/*
+ * Establish a new SSL connection to an SSL server.
+ */
+EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const
+ uint8_t *session_id, uint8_t sess_id_size)
+{
+ SSL *ssl;
+ int ret;
+
+ SOCKET_BLOCK(client_fd); /* ensure blocking mode */
+ ssl = ssl_new(ssl_ctx, client_fd);
+
+ if (session_id && ssl_ctx->num_sessions)
+ {
+ if (sess_id_size > SSL_SESSION_ID_SIZE) /* validity check */
+ {
+ ssl_free(ssl);
+ return NULL;
+ }
+
+ memcpy(ssl->session_id, session_id, sess_id_size);
+ ssl->sess_id_size = sess_id_size;
+ SET_SSL_FLAG(SSL_SESSION_RESUME); /* just flag for later */
+ }
+
+ SET_SSL_FLAG(SSL_IS_CLIENT);
+ ret = do_client_connect(ssl);
+ return ssl;
+}
+
+/*
+ * Process the handshake record.
+ */
+int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len)
+{
+ int ret = SSL_OK;
+
+ /* To get here the state must be valid */
+ switch (handshake_type)
+ {
+ case HS_SERVER_HELLO:
+ ret = process_server_hello(ssl);
+ break;
+
+ case HS_CERTIFICATE:
+ ret = process_certificate(ssl, &ssl->x509_ctx);
+ break;
+
+ case HS_SERVER_HELLO_DONE:
+ if ((ret = process_server_hello_done(ssl)) == SSL_OK)
+ {
+ if (IS_SET_SSL_FLAG(SSL_HAS_CERT_REQ))
+ {
+ if ((ret = send_certificate(ssl)) == SSL_OK &&
+ (ret = send_client_key_xchg(ssl)) == SSL_OK)
+ {
+ send_cert_verify(ssl);
+ }
+ }
+ else
+ {
+ ret = send_client_key_xchg(ssl);
+ }
+
+ if (ret == SSL_OK &&
+ (ret = send_change_cipher_spec(ssl)) == SSL_OK)
+ {
+ ret = send_finished(ssl);
+ }
+ }
+ break;
+
+ case HS_CERT_REQ:
+ ret = process_cert_req(ssl);
+ break;
+
+ case HS_FINISHED:
+ ret = process_finished(ssl, hs_len);
+ disposable_free(ssl); /* free up some memory */
+ break;
+
+ case HS_HELLO_REQUEST:
+ disposable_new(ssl);
+ ret = do_client_connect(ssl);
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Do the handshaking from the beginning.
+ */
+int do_client_connect(SSL *ssl)
+{
+ int ret = SSL_OK;
+
+ send_client_hello(ssl); /* send the client hello */
+ ssl->bm_read_index = 0;
+ ssl->next_state = HS_SERVER_HELLO;
+ ssl->hs_status = SSL_NOT_OK; /* not connected */
+ x509_free(ssl->x509_ctx);
+
+ /* sit in a loop until it all looks good */
+ while (ssl->hs_status != SSL_OK)
+ {
+ ret = basic_read(ssl, NULL);
+
+ if (ret < SSL_OK)
+ {
+ if (ret != SSL_ERROR_CONN_LOST)
+ {
+ /* let the server know we are dying and why */
+ if (send_alert(ssl, ret))
+ {
+ /* something nasty happened, so get rid of it */
+ kill_ssl_session(ssl->ssl_ctx->ssl_sessions, ssl);
+ }
+ }
+
+ break;
+ }
+ }
+
+ ssl->hs_status = ret; /* connected? */
+ return ret;
+}
+
+/*
+ * Send the initial client hello.
+ */
+static int send_client_hello(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ time_t tm = time(NULL);
+ uint8_t *tm_ptr = &buf[6]; /* time will go here */
+ int i, offset;
+
+ buf[0] = HS_CLIENT_HELLO;
+ buf[1] = 0;
+ buf[2] = 0;
+ /* byte 3 is calculated later */
+ buf[4] = 0x03;
+ buf[5] = 0x01;
+
+ /* client random value - spec says that 1st 4 bytes are big endian time */
+ *tm_ptr++ = (uint8_t)(((long)tm & 0xff000000) >> 24);
+ *tm_ptr++ = (uint8_t)(((long)tm & 0x00ff0000) >> 16);
+ *tm_ptr++ = (uint8_t)(((long)tm & 0x0000ff00) >> 8);
+ *tm_ptr++ = (uint8_t)(((long)tm & 0x000000ff));
+ get_random(SSL_RANDOM_SIZE-4, &buf[10]);
+ memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE);
+ offset = 6 + SSL_RANDOM_SIZE;
+
+ /* give session resumption a go */
+ if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) /* set initially by user */
+ {
+ buf[offset++] = ssl->sess_id_size;
+ memcpy(&buf[offset], ssl->session_id, ssl->sess_id_size);
+ offset += ssl->sess_id_size;
+ CLR_SSL_FLAG(SSL_SESSION_RESUME); /* clear so we can set later */
+ }
+ else
+ {
+ /* no session id - because no session resumption just yet */
+ buf[offset++] = 0;
+ }
+
+ buf[offset++] = 0; /* number of ciphers */
+ buf[offset++] = NUM_PROTOCOLS*2;/* number of ciphers */
+
+ /* put all our supported protocols in our request */
+ for (i = 0; i < NUM_PROTOCOLS; i++)
+ {
+ buf[offset++] = 0; /* cipher we are using */
+ buf[offset++] = ssl_prot_prefs[i];
+ }
+
+ buf[offset++] = 1; /* no compression */
+ buf[offset++] = 0;
+ buf[3] = offset - 4; /* handshake size */
+
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);
+}
+
+/*
+ * Process the server hello.
+ */
+static int process_server_hello(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ int pkt_size = ssl->bm_index;
+ int version = (buf[4] << 4) + buf[5];
+ int num_sessions = ssl->ssl_ctx->num_sessions;
+ uint8_t sess_id_size;
+ int offset, ret = SSL_OK;
+
+ /* check that we are talking to a TLSv1 server */
+ if (version != 0x31)
+ return SSL_ERROR_INVALID_VERSION;
+
+ /* get the server random value */
+ memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE);
+ offset = 6 + SSL_RANDOM_SIZE; /* skip of session id size */
+ sess_id_size = buf[offset++];
+
+ if (num_sessions)
+ {
+ ssl->session = ssl_session_update(num_sessions,
+ ssl->ssl_ctx->ssl_sessions, ssl, &buf[offset]);
+ memcpy(ssl->session->session_id, &buf[offset], sess_id_size);
+
+ /* pad the rest with 0's */
+ if (sess_id_size < SSL_SESSION_ID_SIZE)
+ {
+ memset(&ssl->session->session_id[sess_id_size], 0,
+ SSL_SESSION_ID_SIZE-sess_id_size);
+ }
+ }
+
+ memcpy(ssl->session_id, &buf[offset], sess_id_size);
+ ssl->sess_id_size = sess_id_size;
+ offset += sess_id_size;
+
+ /* get the real cipher we are using */
+ ssl->cipher = buf[++offset];
+ ssl->next_state = IS_SET_SSL_FLAG(SSL_SESSION_RESUME) ?
+ HS_FINISHED : HS_CERTIFICATE;
+
+ offset++; // skip the compr
+ PARANOIA_CHECK(pkt_size, offset);
+ ssl->dc->bm_proc_index = offset+1;
+
+error:
+ return ret;
+}
+
+/**
+ * Process the server hello done message.
+ */
+static int process_server_hello_done(SSL *ssl)
+{
+ ssl->next_state = HS_FINISHED;
+ return SSL_OK;
+}
+
+/*
+ * Send a client key exchange message.
+ */
+static int send_client_key_xchg(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ uint8_t premaster_secret[SSL_SECRET_SIZE];
+ int enc_secret_size = -1;
+
+ buf[0] = HS_CLIENT_KEY_XCHG;
+ buf[1] = 0;
+
+ premaster_secret[0] = 0x03; /* encode the version number */
+ premaster_secret[1] = 0x01;
+ get_random(SSL_SECRET_SIZE-2, &premaster_secret[2]);
+ DISPLAY_RSA(ssl, ssl->x509_ctx->rsa_ctx);
+
+ /* rsa_ctx->bi_ctx is not thread-safe */
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+ enc_secret_size = RSA_encrypt(ssl->x509_ctx->rsa_ctx, premaster_secret,
+ SSL_SECRET_SIZE, &buf[6], 0);
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+ buf[2] = (enc_secret_size + 2) >> 8;
+ buf[3] = (enc_secret_size + 2) & 0xff;
+ buf[4] = enc_secret_size >> 8;
+ buf[5] = enc_secret_size & 0xff;
+
+ generate_master_secret(ssl, premaster_secret);
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, enc_secret_size+6);
+}
+
+/*
+ * Process the certificate request.
+ */
+static int process_cert_req(SSL *ssl)
+{
+ uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
+ int ret = SSL_OK;
+ int offset = (buf[2] << 4) + buf[3];
+ int pkt_size = ssl->bm_index;
+
+ /* don't do any processing - we will send back an RSA certificate anyway */
+ ssl->next_state = HS_SERVER_HELLO_DONE;
+ SET_SSL_FLAG(SSL_HAS_CERT_REQ);
+ ssl->dc->bm_proc_index += offset;
+ PARANOIA_CHECK(pkt_size, offset);
+error:
+ return ret;
+}
+
+/*
+ * Send a certificate verify message.
+ */
+static int send_cert_verify(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ uint8_t dgst[MD5_SIZE+SHA1_SIZE];
+ RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx;
+ int n = 0, ret;
+
+ DISPLAY_RSA(ssl, rsa_ctx);
+
+ buf[0] = HS_CERT_VERIFY;
+ buf[1] = 0;
+
+ finished_digest(ssl, NULL, dgst); /* calculate the digest */
+
+ /* rsa_ctx->bi_ctx is not thread-safe */
+ if (rsa_ctx)
+ {
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+ n = RSA_encrypt(rsa_ctx, dgst, sizeof(dgst), &buf[6], 1);
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+ if (n == 0)
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto error;
+ }
+ }
+
+ buf[4] = n >> 8; /* add the RSA size (not officially documented) */
+ buf[5] = n & 0xff;
+ n += 2;
+ buf[2] = n >> 8;
+ buf[3] = n & 0xff;
+ ret = send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, n+4);
+
+error:
+ return ret;
+}
+
+#endif /* CONFIG_SSL_ENABLE_CLIENT */
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "ssl.h"
+
+static const uint8_t g_hello_done[] = { HS_SERVER_HELLO_DONE, 0, 0, 0 };
+
+static int process_client_hello(SSL *ssl);
+static int send_server_hello_sequence(SSL *ssl);
+static int send_server_hello(SSL *ssl);
+static int send_server_hello_done(SSL *ssl);
+static int process_client_key_xchg(SSL *ssl);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+static int send_certificate_request(SSL *ssl);
+static int process_cert_verify(SSL *ssl);
+#endif
+
+/*
+ * Establish a new SSL connection to an SSL client.
+ */
+EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd)
+{
+ SSL *ssl;
+
+ ssl = ssl_new(ssl_ctx, client_fd);
+ ssl->next_state = HS_CLIENT_HELLO;
+
+#ifdef CONFIG_SSL_FULL_MODE
+ if (ssl_ctx->chain_length == 0)
+ printf("Warning - no server certificate defined\n"); TTY_FLUSH();
+#endif
+
+ return ssl;
+}
+
+/*
+ * Process the handshake record.
+ */
+int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len)
+{
+ int ret = SSL_OK;
+ ssl->hs_status = SSL_NOT_OK; /* not connected */
+
+ /* To get here the state must be valid */
+ switch (handshake_type)
+ {
+ case HS_CLIENT_HELLO:
+ if ((ret = process_client_hello(ssl)) == SSL_OK)
+ ret = send_server_hello_sequence(ssl);
+ break;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ case HS_CERTIFICATE:/* the client sends its cert */
+ ret = process_certificate(ssl, &ssl->x509_ctx);
+
+ if (ret == SSL_OK) /* verify the cert */
+ {
+ int cert_res;
+ cert_res = x509_verify(
+ ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx);
+ ret = (cert_res == 0) ? SSL_OK : SSL_X509_ERROR(cert_res);
+ }
+ break;
+
+ case HS_CERT_VERIFY:
+ ret = process_cert_verify(ssl);
+ add_packet(ssl, buf, hs_len); /* needs to be done after */
+ break;
+#endif
+ case HS_CLIENT_KEY_XCHG:
+ ret = process_client_key_xchg(ssl);
+ break;
+
+ case HS_FINISHED:
+ ret = process_finished(ssl, hs_len);
+ disposable_free(ssl); /* free up some memory */
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Process a client hello message.
+ */
+static int process_client_hello(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ uint8_t *record_buf = ssl->hmac_header;
+ int pkt_size = ssl->bm_index;
+ int i, j, cs_len, id_len, offset = 6 + SSL_RANDOM_SIZE;
+ int version = (record_buf[1] << 4) + record_buf[2];
+ int ret = SSL_OK;
+
+ /* should be v3.1 (TLSv1) or better - we'll send in v3.1 mode anyway */
+ if (version < 0x31)
+ {
+ ret = SSL_ERROR_INVALID_VERSION;
+ ssl_display_error(ret);
+ goto error;
+ }
+
+ memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE);
+
+ /* process the session id */
+ id_len = buf[offset++];
+ if (id_len > SSL_SESSION_ID_SIZE)
+ {
+ return SSL_ERROR_INVALID_SESSION;
+ }
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions,
+ ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL);
+#endif
+
+ offset += id_len;
+ cs_len = (buf[offset]<<8) + buf[offset+1];
+ offset += 3; /* add 1 due to all cipher suites being 8 bit */
+
+ PARANOIA_CHECK(pkt_size, offset);
+
+ /* work out what cipher suite we are going to use */
+ for (j = 0; j < NUM_PROTOCOLS; j++)
+ {
+ for (i = 0; i < cs_len; i += 2)
+ {
+ if (ssl_prot_prefs[j] == buf[offset+i]) /* got a match? */
+ {
+ ssl->cipher = ssl_prot_prefs[j];
+ goto do_state;
+ }
+ }
+ }
+
+ /* ouch! protocol is not supported */
+ ret = SSL_ERROR_NO_CIPHER;
+
+do_state:
+error:
+ return ret;
+}
+
+#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE
+/*
+ * Some browsers use a hybrid SSLv2 "client hello"
+ */
+int process_sslv23_client_hello(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ int bytes_needed = ((buf[0] & 0x7f) << 8) + buf[1];
+ int version = (buf[3] << 4) + buf[4];
+ int ret = SSL_OK;
+
+ /* we have already read 3 extra bytes so far */
+ int read_len = SOCKET_READ(ssl->client_fd, buf, bytes_needed-3);
+ int cs_len = buf[1];
+ int id_len = buf[3];
+ int ch_len = buf[5];
+ int i, j, offset = 8; /* start at first cipher */
+ int random_offset = 0;
+
+ DISPLAY_BYTES(ssl, "received %d bytes", buf, read_len, read_len);
+
+ /* should be v3.1 (TLSv1) or better - we'll send in v3.1 mode anyway */
+ if (version < 0x31)
+ {
+ return SSL_ERROR_INVALID_VERSION;
+ }
+
+ add_packet(ssl, buf, read_len);
+
+ /* connection has gone, so die */
+ if (bytes_needed < 0)
+ {
+ return SSL_ERROR_CONN_LOST;
+ }
+
+ /* now work out what cipher suite we are going to use */
+ for (j = 0; j < NUM_PROTOCOLS; j++)
+ {
+ for (i = 0; i < cs_len; i += 3)
+ {
+ if (ssl_prot_prefs[j] == buf[offset+i])
+ {
+ ssl->cipher = ssl_prot_prefs[j];
+ goto server_hello;
+ }
+ }
+ }
+
+ /* ouch! protocol is not supported */
+ ret = SSL_ERROR_NO_CIPHER;
+ goto error;
+
+server_hello:
+ /* get the session id */
+ offset += cs_len - 2; /* we've gone 2 bytes past the end */
+#ifndef CONFIG_SSL_SKELETON_MODE
+ ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions,
+ ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL);
+#endif
+
+ /* get the client random data */
+ offset += id_len;
+
+ /* random can be anywhere between 16 and 32 bytes long - so it is padded
+ * with 0's to the left */
+ if (ch_len == 0x10)
+ {
+ random_offset += 0x10;
+ }
+
+ memcpy(&ssl->dc->client_random[random_offset], &buf[offset], ch_len);
+ ret = send_server_hello_sequence(ssl);
+
+error:
+ return ret;
+}
+#endif
+
+/*
+ * Send the entire server hello sequence
+ */
+static int send_server_hello_sequence(SSL *ssl)
+{
+ int ret;
+
+ if ((ret = send_server_hello(ssl)) == SSL_OK)
+ {
+#ifndef CONFIG_SSL_SKELETON_MODE
+ /* resume handshake? */
+ if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))
+ {
+ if ((ret = send_change_cipher_spec(ssl)) == SSL_OK)
+ {
+ ret = send_finished(ssl);
+ ssl->next_state = HS_FINISHED;
+ }
+ }
+ else
+#endif
+ if ((ret = send_certificate(ssl)) == SSL_OK)
+ {
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ /* ask the client for its certificate */
+ if (IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION))
+ {
+ if ((ret = send_certificate_request(ssl)) == SSL_OK)
+ {
+ ret = send_server_hello_done(ssl);
+ ssl->next_state = HS_CERTIFICATE;
+ }
+ }
+ else
+#endif
+ {
+ ret = send_server_hello_done(ssl);
+ ssl->next_state = HS_CLIENT_KEY_XCHG;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Send a server hello message.
+ */
+static int send_server_hello(SSL *ssl)
+{
+ uint8_t *buf = ssl->bm_data;
+ int offset = 0;
+
+ buf[0] = HS_SERVER_HELLO;
+ buf[1] = 0;
+ buf[2] = 0;
+ /* byte 3 is calculated later */
+ buf[4] = 0x03;
+ buf[5] = 0x01;
+
+ /* server random value */
+ get_random(SSL_RANDOM_SIZE, &buf[6]);
+ memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE);
+ offset = 6 + SSL_RANDOM_SIZE;
+
+#ifndef CONFIG_SSL_SKELETON_MODE
+ if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))
+ {
+ /* retrieve id from session cache */
+ buf[offset++] = SSL_SESSION_ID_SIZE;
+ memcpy(&buf[offset], ssl->session->session_id, SSL_SESSION_ID_SIZE);
+ memcpy(ssl->session_id, ssl->session->session_id, SSL_SESSION_ID_SIZE);
+ ssl->sess_id_size = SSL_SESSION_ID_SIZE;
+ offset += SSL_SESSION_ID_SIZE;
+ }
+ else /* generate our own session id */
+#endif
+ {
+#ifndef CONFIG_SSL_SKELETON_MODE
+ buf[offset++] = SSL_SESSION_ID_SIZE;
+ get_random(SSL_SESSION_ID_SIZE, &buf[offset]);
+ memcpy(ssl->session_id, &buf[offset], SSL_SESSION_ID_SIZE);
+ ssl->sess_id_size = SSL_SESSION_ID_SIZE;
+
+ /* store id in session cache */
+ if (ssl->ssl_ctx->num_sessions)
+ {
+ memcpy(ssl->session->session_id,
+ ssl->session_id, SSL_SESSION_ID_SIZE);
+ }
+
+ offset += SSL_SESSION_ID_SIZE;
+#else
+ buf[offset++] = 0; /* don't bother with session id in skelton mode */
+#endif
+ }
+
+ buf[offset++] = 0; /* cipher we are using */
+ buf[offset++] = ssl->cipher;
+ buf[offset++] = 0; /* no compression */
+ buf[3] = offset - 4; /* handshake size */
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);
+}
+
+/*
+ * Send the server hello done message.
+ */
+static int send_server_hello_done(SSL *ssl)
+{
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL,
+ g_hello_done, sizeof(g_hello_done));
+}
+
+/*
+ * Pull apart a client key exchange message. Decrypt the pre-master key (using
+ * our RSA private key) and then work out the master key. Initialise the
+ * ciphers.
+ */
+static int process_client_key_xchg(SSL *ssl)
+{
+ uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
+ int pkt_size = ssl->bm_index;
+ int premaster_size, secret_length = (buf[2] << 8) + buf[3];
+ uint8_t premaster_secret[MAX_KEY_BYTE_SIZE];
+ RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx;
+ int offset = 4;
+ int ret = SSL_OK;
+
+ if (rsa_ctx == NULL)
+ {
+ ret = SSL_ERROR_NO_CERT_DEFINED;
+ goto error;
+ }
+
+ /* is there an extra size field? */
+ if ((secret_length - 2) == rsa_ctx->num_octets)
+ offset += 2;
+
+ PARANOIA_CHECK(pkt_size, rsa_ctx->num_octets+offset);
+
+ /* rsa_ctx->bi_ctx is not thread-safe */
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+ premaster_size = RSA_decrypt(rsa_ctx, &buf[offset], premaster_secret, 1);
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+ if (premaster_size != SSL_SECRET_SIZE ||
+ premaster_secret[0] != 0x03 || /* check version is 3.1 (TLS) */
+ premaster_secret[1] != 0x01)
+ {
+ /* guard against a Bleichenbacher attack */
+ memset(premaster_secret, 0, SSL_SECRET_SIZE);
+ /* and continue - will die eventually when checking the mac */
+ }
+
+#if 0
+ print_blob("pre-master", premaster_secret, SSL_SECRET_SIZE);
+#endif
+
+ generate_master_secret(ssl, premaster_secret);
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ ssl->next_state = IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION) ?
+ HS_CERT_VERIFY : HS_FINISHED;
+#else
+ ssl->next_state = HS_FINISHED;
+#endif
+error:
+ ssl->dc->bm_proc_index += rsa_ctx->num_octets+offset;
+ return ret;
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+static const uint8_t g_cert_request[] = { HS_CERT_REQ, 0, 0, 4, 1, 0, 0, 0 };
+
+/*
+ * Send the certificate request message.
+ */
+static int send_certificate_request(SSL *ssl)
+{
+ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL,
+ g_cert_request, sizeof(g_cert_request));
+}
+
+/*
+ * Ensure the client has the private key by first decrypting the packet and
+ * then checking the packet digests.
+ */
+static int process_cert_verify(SSL *ssl)
+{
+ uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
+ int pkt_size = ssl->bm_index;
+ uint8_t dgst_buf[MAX_KEY_BYTE_SIZE];
+ uint8_t dgst[MD5_SIZE+SHA1_SIZE];
+ X509_CTX *x509_ctx = ssl->x509_ctx;
+ int ret = SSL_OK;
+ int n;
+
+ PARANOIA_CHECK(pkt_size, x509_ctx->rsa_ctx->num_octets+6);
+ DISPLAY_RSA(ssl, x509_ctx->rsa_ctx);
+
+ /* rsa_ctx->bi_ctx is not thread-safe */
+ SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
+ n = RSA_decrypt(x509_ctx->rsa_ctx, &buf[6], dgst_buf, 0);
+ SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
+
+ if (n != SHA1_SIZE + MD5_SIZE)
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ goto end_cert_vfy;
+ }
+
+ finished_digest(ssl, NULL, dgst); /* calculate the digest */
+ if (memcmp(dgst_buf, dgst, MD5_SIZE + SHA1_SIZE))
+ {
+ ret = SSL_ERROR_INVALID_KEY;
+ }
+
+end_cert_vfy:
+ ssl->next_state = HS_FINISHED;
+error:
+ return ret;
+}
+
+#endif
--- /dev/null
+#define AXTLS_VERSION "1.2.1"
--- /dev/null
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file x509.c
+ *
+ * Certificate processing.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "os_port.h"
+#include "crypto_misc.h"
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Retrieve the signature from a certificate.
+ */
+static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len)
+{
+ int offset = 0;
+ const uint8_t *ptr = NULL;
+
+ if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
+ goto end_get_sig;
+
+ if (asn1_sig[offset++] != ASN1_OCTET_STRING)
+ goto end_get_sig;
+ *len = get_asn1_length(asn1_sig, &offset);
+ ptr = &asn1_sig[offset]; /* all ok */
+
+end_get_sig:
+ return ptr;
+}
+
+#endif
+
+/**
+ * Construct a new x509 object.
+ * @return 0 if ok. < 0 if there was a problem.
+ */
+int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
+{
+ int begin_tbs, end_tbs;
+ int ret = X509_NOT_OK, offset = 0, cert_size = 0;
+ X509_CTX *x509_ctx;
+ BI_CTX *bi_ctx;
+
+ *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX));
+ x509_ctx = *ctx;
+
+ /* get the certificate size */
+ asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE);
+
+ if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
+ goto end_cert;
+
+ begin_tbs = offset; /* start of the tbs */
+ end_tbs = begin_tbs; /* work out the end of the tbs */
+ asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);
+
+ if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
+ goto end_cert;
+
+ if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */
+ {
+ if (asn1_version(cert, &offset, x509_ctx))
+ goto end_cert;
+ }
+
+ if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */
+ asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
+ goto end_cert;
+
+ /* make sure the signature is ok */
+ if (asn1_signature_type(cert, &offset, x509_ctx))
+ {
+ ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST;
+ goto end_cert;
+ }
+
+ if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) ||
+ asn1_validity(cert, &offset, x509_ctx) ||
+ asn1_name(cert, &offset, x509_ctx->cert_dn) ||
+ asn1_public_key(cert, &offset, x509_ctx))
+ goto end_cert;
+
+ bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
+ /* use the appropriate signature algorithm (SHA1/MD5/MD2) */
+ if (x509_ctx->sig_type == SIG_TYPE_MD5)
+ {
+ MD5_CTX md5_ctx;
+ uint8_t md5_dgst[MD5_SIZE];
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
+ MD5_Final(md5_dgst, &md5_ctx);
+ x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);
+ }
+ else if (x509_ctx->sig_type == SIG_TYPE_SHA1)
+ {
+ SHA1_CTX sha_ctx;
+ uint8_t sha_dgst[SHA1_SIZE];
+ SHA1_Init(&sha_ctx);
+ SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
+ SHA1_Final(sha_dgst, &sha_ctx);
+ x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);
+ }
+ else if (x509_ctx->sig_type == SIG_TYPE_MD2)
+ {
+ MD2_CTX md2_ctx;
+ uint8_t md2_dgst[MD2_SIZE];
+ MD2_Init(&md2_ctx);
+ MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
+ MD2_Final(md2_dgst, &md2_ctx);
+ x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE);
+ }
+
+ offset = end_tbs; /* skip the v3 data */
+ if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
+ asn1_signature(cert, &offset, x509_ctx))
+ goto end_cert;
+#endif
+
+ if (len)
+ {
+ *len = cert_size;
+ }
+
+ ret = X509_OK;
+end_cert:
+
+#ifdef CONFIG_SSL_FULL_MODE
+ if (ret)
+ {
+ printf("Error: Invalid X509 ASN.1 file\n");
+ }
+#endif
+
+ return ret;
+}
+
+/**
+ * Free an X.509 object's resources.
+ */
+void x509_free(X509_CTX *x509_ctx)
+{
+ X509_CTX *next;
+ int i;
+
+ if (x509_ctx == NULL) /* if already null, then don't bother */
+ return;
+
+ for (i = 0; i < X509_NUM_DN_TYPES; i++)
+ {
+ free(x509_ctx->ca_cert_dn[i]);
+ free(x509_ctx->cert_dn[i]);
+ }
+
+ free(x509_ctx->signature);
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ if (x509_ctx->digest)
+ {
+ bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
+ }
+#endif
+
+ RSA_free(x509_ctx->rsa_ctx);
+
+ next = x509_ctx->next;
+ free(x509_ctx);
+ x509_free(next); /* clear the chain */
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Take a signature and decrypt it.
+ */
+static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
+ bigint *modulus, bigint *pub_exp)
+{
+ int i, size;
+ bigint *decrypted_bi, *dat_bi;
+ bigint *bir = NULL;
+ uint8_t *block = (uint8_t *)alloca(sig_len);
+
+ /* decrypt */
+ dat_bi = bi_import(ctx, sig, sig_len);
+ ctx->mod_offset = BIGINT_M_OFFSET;
+
+ /* convert to a normal block */
+ decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
+
+ bi_export(ctx, decrypted_bi, block, sig_len);
+ ctx->mod_offset = BIGINT_M_OFFSET;
+
+ i = 10; /* start at the first possible non-padded byte */
+ while (block[i++] && i < sig_len);
+ size = sig_len - i;
+
+ /* get only the bit we want */
+ if (size > 0)
+ {
+ int len;
+ const uint8_t *sig_ptr = get_signature(&block[i], &len);
+
+ if (sig_ptr)
+ {
+ bir = bi_import(ctx, sig_ptr, len);
+ }
+ }
+
+ /* save a few bytes of memory */
+ bi_clear_cache(ctx);
+ return bir;
+}
+
+/**
+ * Do some basic checks on the certificate chain.
+ *
+ * Certificate verification consists of a number of checks:
+ * - The date of the certificate is after the start date.
+ * - The date of the certificate is before the finish date.
+ * - A root certificate exists in the certificate store.
+ * - That the certificate(s) are not self-signed.
+ * - The certificate chain is valid.
+ * - The signature of the certificate is valid.
+ */
+int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
+{
+ int ret = X509_OK, i = 0;
+ bigint *cert_sig;
+ X509_CTX *next_cert = NULL;
+ BI_CTX *ctx = NULL;
+ bigint *mod = NULL, *expn = NULL;
+ int match_ca_cert = 0;
+ struct timeval tv;
+ uint8_t is_self_signed = 0;
+
+ if (cert == NULL)
+ {
+ ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
+ goto end_verify;
+ }
+
+ /* a self-signed certificate that is not in the CA store - use this
+ to check the signature */
+ if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)
+ {
+ is_self_signed = 1;
+ ctx = cert->rsa_ctx->bi_ctx;
+ mod = cert->rsa_ctx->m;
+ expn = cert->rsa_ctx->e;
+ }
+
+ gettimeofday(&tv, NULL);
+
+ /* check the not before date */
+ if (tv.tv_sec < cert->not_before)
+ {
+ ret = X509_VFY_ERROR_NOT_YET_VALID;
+ goto end_verify;
+ }
+
+ /* check the not after date */
+ if (tv.tv_sec > cert->not_after)
+ {
+ ret = X509_VFY_ERROR_EXPIRED;
+ goto end_verify;
+ }
+
+ next_cert = cert->next;
+
+ /* last cert in the chain - look for a trusted cert */
+ if (next_cert == NULL)
+ {
+ if (ca_cert_ctx != NULL)
+ {
+ /* go thu the CA store */
+ while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
+ {
+ if (asn1_compare_dn(cert->ca_cert_dn,
+ ca_cert_ctx->cert[i]->cert_dn) == 0)
+ {
+ /* use this CA certificate for signature verification */
+ match_ca_cert = 1;
+ ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx;
+ mod = ca_cert_ctx->cert[i]->rsa_ctx->m;
+ expn = ca_cert_ctx->cert[i]->rsa_ctx->e;
+ break;
+ }
+
+ i++;
+ }
+ }
+
+ /* couldn't find a trusted cert (& let self-signed errors be returned) */
+ if (!match_ca_cert && !is_self_signed)
+ {
+ ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
+ goto end_verify;
+ }
+ }
+ else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0)
+ {
+ /* check the chain */
+ ret = X509_VFY_ERROR_INVALID_CHAIN;
+ goto end_verify;
+ }
+ else /* use the next certificate in the chain for signature verify */
+ {
+ ctx = next_cert->rsa_ctx->bi_ctx;
+ mod = next_cert->rsa_ctx->m;
+ expn = next_cert->rsa_ctx->e;
+ }
+
+ /* cert is self signed */
+ if (!match_ca_cert && is_self_signed)
+ {
+ ret = X509_VFY_ERROR_SELF_SIGNED;
+ goto end_verify;
+ }
+
+ /* check the signature */
+ cert_sig = sig_verify(ctx, cert->signature, cert->sig_len,
+ bi_clone(ctx, mod), bi_clone(ctx, expn));
+
+ if (cert_sig && cert->digest)
+ {
+ if (bi_compare(cert_sig, cert->digest) != 0)
+ ret = X509_VFY_ERROR_BAD_SIGNATURE;
+
+
+ bi_free(ctx, cert_sig);
+ }
+ else
+ {
+ ret = X509_VFY_ERROR_BAD_SIGNATURE;
+ }
+
+ if (ret)
+ goto end_verify;
+
+ /* go down the certificate chain using recursion. */
+ if (next_cert != NULL)
+ {
+ ret = x509_verify(ca_cert_ctx, next_cert);
+ }
+
+end_verify:
+ return ret;
+}
+#endif
+
+#if defined (CONFIG_SSL_FULL_MODE)
+/**
+ * Used for diagnostics.
+ */
+static const char *not_part_of_cert = "<Not Part Of Certificate>";
+void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx)
+{
+ if (cert == NULL)
+ return;
+
+ printf("=== CERTIFICATE ISSUED TO ===\n");
+ printf("Common Name (CN):\t\t");
+ printf("%s\n", cert->cert_dn[X509_COMMON_NAME] ?
+ cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert);
+
+ printf("Organization (O):\t\t");
+ printf("%s\n", cert->cert_dn[X509_ORGANIZATION] ?
+ cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert);
+
+ printf("Organizational Unit (OU):\t");
+ printf("%s\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ?
+ cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
+
+ printf("=== CERTIFICATE ISSUED BY ===\n");
+ printf("Common Name (CN):\t\t");
+ printf("%s\n", cert->ca_cert_dn[X509_COMMON_NAME] ?
+ cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert);
+
+ printf("Organization (O):\t\t");
+ printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATION] ?
+ cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert);
+
+ printf("Organizational Unit (OU):\t");
+ printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ?
+ cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);
+
+ printf("Not Before:\t\t\t%s", ctime(&cert->not_before));
+ printf("Not After:\t\t\t%s", ctime(&cert->not_after));
+ printf("RSA bitsize:\t\t\t%d\n", cert->rsa_ctx->num_octets*8);
+ printf("Sig Type:\t\t\t");
+ switch (cert->sig_type)
+ {
+ case SIG_TYPE_MD5:
+ printf("MD5\n");
+ break;
+ case SIG_TYPE_SHA1:
+ printf("SHA1\n");
+ break;
+ case SIG_TYPE_MD2:
+ printf("MD2\n");
+ break;
+ default:
+ printf("Unrecognized: %d\n", cert->sig_type);
+ break;
+ }
+
+ if (ca_cert_ctx)
+ {
+ printf("Verify:\t\t\t\t%s\n",
+ x509_display_error(x509_verify(ca_cert_ctx, cert)));
+ }
+
+#if 0
+ print_blob("Signature", cert->signature, cert->sig_len);
+ bi_print("Modulus", cert->rsa_ctx->m);
+ bi_print("Pub Exp", cert->rsa_ctx->e);
+#endif
+
+ if (ca_cert_ctx)
+ {
+ x509_print(cert->next, ca_cert_ctx);
+ }
+
+ TTY_FLUSH();
+}
+
+const char * x509_display_error(int error)
+{
+ switch (error)
+ {
+ case X509_OK:
+ return "Certificate verify successful";
+
+ case X509_NOT_OK:
+ return "X509 not ok";
+
+ case X509_VFY_ERROR_NO_TRUSTED_CERT:
+ return "No trusted cert is available";
+
+ case X509_VFY_ERROR_BAD_SIGNATURE:
+ return "Bad signature";
+
+ case X509_VFY_ERROR_NOT_YET_VALID:
+ return "Cert is not yet valid";
+
+ case X509_VFY_ERROR_EXPIRED:
+ return "Cert has expired";
+
+ case X509_VFY_ERROR_SELF_SIGNED:
+ return "Cert is self-signed";
+
+ case X509_VFY_ERROR_INVALID_CHAIN:
+ return "Chain is invalid (check order of certs)";
+
+ case X509_VFY_ERROR_UNSUPPORTED_DIGEST:
+ return "Unsupported digest";
+
+ case X509_INVALID_PRIV_KEY:
+ return "Invalid private key";
+
+ default:
+ return "Unknown";
+ }
+}
+#endif /* CONFIG_SSL_FULL_MODE */
+
--- /dev/null
+Deny all
+
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<script type="text/javascript">
+//<![CDATA[
+var version = {major: 2, minor: 1, revision: 3, date: new Date("Nov 3, 2006"), extensions: {}};
+//]]>
+</script>
+<!--
+TiddlyWiki 2.1.3 by Jeremy Ruston, (jeremy [at] osmosoft [dot] com)
+
+Copyright (c) Osmosoft Limited 2004-2006
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+Neither the name of the Osmosoft Limited nor the names of its contributors may be
+used to endorse or promote products derived from this software without specific
+prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+-->
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
+<!--PRE-HEAD-START-->
+<!--{{{-->
+<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>
+<!--}}}-->
+<!--PRE-HEAD-END-->
+<title> axTLS Embedded SSL - changes, notes and errata </title>
+<script type="text/javascript">
+//<![CDATA[
+// ---------------------------------------------------------------------------------
+// Configuration repository
+// ---------------------------------------------------------------------------------
+
+// Miscellaneous options
+var config = {
+ numRssItems: 20, // Number of items in the RSS feed
+ animFast: 0.12, // Speed for animations (lower == slower)
+ animSlow: 0.01, // Speed for EasterEgg animations
+ cascadeFast: 20, // Speed for cascade animations (higher == slower)
+ cascadeSlow: 60, // Speed for EasterEgg cascade animations
+ cascadeDepth: 5, // Depth of cascade animation
+ displayStartupTime: false // Whether to display startup time
+ };
+
+// Messages
+config.messages = {
+ messageClose: {},
+ dates: {}
+};
+
+// Options that can be set in the options panel and/or cookies
+config.options = {
+ chkRegExpSearch: false,
+ chkCaseSensitiveSearch: false,
+ chkAnimate: true,
+ chkSaveBackups: true,
+ chkAutoSave: false,
+ chkGenerateAnRssFeed: false,
+ chkSaveEmptyTemplate: false,
+ chkOpenInNewWindow: true,
+ chkToggleLinks: false,
+ chkHttpReadOnly: true,
+ chkForceMinorUpdate: false,
+ chkConfirmDelete: true,
+ chkInsertTabs: false,
+ txtBackupFolder: "",
+ txtMainTab: "tabTimeline",
+ txtMoreTab: "moreTabAll",
+ txtMaxEditRows: "30"
+ };
+
+// List of notification functions to be called when certain tiddlers are changed or deleted
+config.notifyTiddlers = [
+ {name: "StyleSheetLayout", notify: refreshStyles},
+ {name: "StyleSheetColors", notify: refreshStyles},
+ {name: "StyleSheet", notify: refreshStyles},
+ {name: "StyleSheetPrint", notify: refreshStyles},
+ {name: "PageTemplate", notify: refreshPageTemplate},
+ {name: "SiteTitle", notify: refreshPageTitle},
+ {name: "SiteSubtitle", notify: refreshPageTitle},
+ {name: "ColorPalette", notify: refreshColorPalette},
+ {name: null, notify: refreshDisplay}
+ ];
+
+// Default tiddler templates
+var DEFAULT_VIEW_TEMPLATE = 1;
+var DEFAULT_EDIT_TEMPLATE = 2;
+config.tiddlerTemplates = {
+ 1: "ViewTemplate",
+ 2: "EditTemplate"
+ };
+
+// More messages (rather a legacy layout that shouldn't really be like this)
+config.views = {
+ wikified: {
+ tag: {}
+ },
+ editor: {
+ tagChooser: {}
+ }
+ };
+
+// Macros; each has a 'handler' member that is inserted later
+config.macros = {
+ today: {},
+ version: {},
+ search: {sizeTextbox: 15},
+ tiddler: {},
+ tag: {},
+ tags: {},
+ tagging: {},
+ timeline: {},
+ allTags: {},
+ list: {
+ all: {},
+ missing: {},
+ orphans: {},
+ shadowed: {}
+ },
+ closeAll: {},
+ permaview: {},
+ saveChanges: {},
+ slider: {},
+ option: {},
+ newTiddler: {},
+ newJournal: {},
+ sparkline: {},
+ tabs: {},
+ gradient: {},
+ message: {},
+ view: {},
+ edit: {},
+ tagChooser: {},
+ toolbar: {},
+ br: {},
+ plugins: {},
+ refreshDisplay: {},
+ importTiddlers: {}
+ };
+
+// Commands supported by the toolbar macro
+config.commands = {
+ closeTiddler: {},
+ closeOthers: {},
+ editTiddler: {},
+ saveTiddler: {hideReadOnly: true},
+ cancelTiddler: {},
+ deleteTiddler: {hideReadOnly: true},
+ permalink: {},
+ references: {},
+ jump: {}
+ };
+
+// Browser detection... In a very few places, there's nothing else for it but to
+// know what browser we're using.
+config.userAgent = navigator.userAgent.toLowerCase();
+config.browser = {
+ isIE: config.userAgent.indexOf("msie") != -1 && config.userAgent.indexOf("opera") == -1,
+ ieVersion: /MSIE (\d.\d)/i.exec(config.userAgent), // config.browser.ieVersion[1], if it exists, will be the IE version string, eg "6.0"
+ isSafari: config.userAgent.indexOf("applewebkit") != -1,
+ isBadSafari: !((new RegExp("[\u0150\u0170]","g")).test("\u0150")),
+ firefoxDate: /Gecko\/(\d{8})/i.exec(config.userAgent), // config.browser.firefoxDate[1], if it exists, will be Firefox release date as "YYYYMMDD"
+ isOpera: config.userAgent.indexOf("opera") != -1,
+ isLinux: config.userAgent.indexOf("linux") != -1,
+ isUnix: config.userAgent.indexOf("x11") != -1,
+ isMac: config.userAgent.indexOf("mac") != -1,
+ isWindows: config.userAgent.indexOf("win") != -1
+ };
+
+// Basic regular expressions
+config.textPrimitives = {
+ upperLetter: "[A-Z\u00c0-\u00de\u0150\u0170]",
+ lowerLetter: "[a-z0-9_\\-\u00df-\u00ff\u0151\u0171]",
+ anyLetter: "[A-Za-z0-9_\\-\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]",
+ anyLetterStrict: "[A-Za-z0-9\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]"
+ };
+if(config.browser.isBadSafari)
+ config.textPrimitives = {
+ upperLetter: "[A-Z\u00c0-\u00de]",
+ lowerLetter: "[a-z0-9_\\-\u00df-\u00ff]",
+ anyLetter: "[A-Za-z0-9_\\-\u00c0-\u00de\u00df-\u00ff]",
+ anyLetterStrict: "[A-Za-z0-9\u00c0-\u00de\u00df-\u00ff]"
+ }
+config.textPrimitives.sliceSeparator = "::";
+config.textPrimitives.urlPattern = "[a-z]{3,8}:[^\\s:'\"][^\\s'\"]*(?:/|\\b)";
+config.textPrimitives.unWikiLink = "~";
+config.textPrimitives.wikiLink = "(?:(?:" + config.textPrimitives.upperLetter + "+" +
+ config.textPrimitives.lowerLetter + "+" +
+ config.textPrimitives.upperLetter +
+ config.textPrimitives.anyLetter + "*)|(?:" +
+ config.textPrimitives.upperLetter + "{2,}" +
+ config.textPrimitives.lowerLetter + "+))";
+
+config.textPrimitives.cssLookahead = "(?:(" + config.textPrimitives.anyLetter + "+)\\(([^\\)\\|\\n]+)(?:\\):))|(?:(" + config.textPrimitives.anyLetter + "+):([^;\\|\\n]+);)";
+config.textPrimitives.cssLookaheadRegExp = new RegExp(config.textPrimitives.cssLookahead,"mg");
+
+config.textPrimitives.brackettedLink = "\\[\\[([^\\]]+)\\]\\]";
+config.textPrimitives.titledBrackettedLink = "\\[\\[([^\\[\\]\\|]+)\\|([^\\[\\]\\|]+)\\]\\]";
+config.textPrimitives.tiddlerForcedLinkRegExp = new RegExp("(?:" + config.textPrimitives.titledBrackettedLink + ")|(?:" +
+ config.textPrimitives.brackettedLink + ")|(?:" +
+ config.textPrimitives.urlPattern + ")","mg");
+config.textPrimitives.tiddlerAnyLinkRegExp = new RegExp("("+ config.textPrimitives.wikiLink + ")|(?:" +
+ config.textPrimitives.titledBrackettedLink + ")|(?:" +
+ config.textPrimitives.brackettedLink + ")|(?:" +
+ config.textPrimitives.urlPattern + ")","mg");
+
+// ---------------------------------------------------------------------------------
+// Shadow tiddlers
+// ---------------------------------------------------------------------------------
+
+config.shadowTiddlers = {
+ ColorPalette: "Background: #fff\n" +
+ "Foreground: #000\n" +
+ "PrimaryPale: #8cf\n" +
+ "PrimaryLight: #18f\n" +
+ "PrimaryMid: #04b\n" +
+ "PrimaryDark: #014\n" +
+ "SecondaryPale: #ffc\n" +
+ "SecondaryLight: #fe8\n" +
+ "SecondaryMid: #db4\n" +
+ "SecondaryDark: #841\n" +
+ "TertiaryPale: #eee\n" +
+ "TertiaryLight: #ccc\n" +
+ "TertiaryMid: #999\n" +
+ "TertiaryDark: #666\n" +
+ "Error: #f88\n",
+ StyleSheet: "",
+ StyleSheetColors: "/*{{{*/\nbody {\n background: [[ColorPalette::Background]];\n color: [[ColorPalette::Foreground]];\n}\n\na{\n color: [[ColorPalette::PrimaryMid]];\n}\n\na:hover{\n background: [[ColorPalette::PrimaryMid]];\n color: [[ColorPalette::Background]];\n}\n\na img{\n border: 0;\n}\n\nh1,h2,h3,h4,h5 {\n color: [[ColorPalette::SecondaryDark]];\n background: [[ColorPalette::PrimaryPale]];\n}\n\n.button {\n color: [[ColorPalette::PrimaryDark]];\n border: 1px solid [[ColorPalette::Background]];\n}\n\n.button:hover {\n color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::SecondaryLight]];\n border-color: [[ColorPalette::SecondaryMid]];\n}\n\n.button:active {\n color: [[ColorPalette::Background]];\n background: [[ColorPalette::SecondaryMid]];\n border: 1px solid [[ColorPalette::SecondaryDark]];\n}\n\n.header {\n background: [[ColorPalette::PrimaryMid]];\n}\n\n.headerShadow {\n color: [[ColorPalette::Foreground]];\n}\n\n.headerShadow a {\n font-weight: normal;\n color: [[ColorPalette::Foreground]];\n}\n\n.headerForeground {\n color: [[ColorPalette::Background]];\n}\n\n.headerForeground a {\n font-weight: normal;\n color: [[ColorPalette::PrimaryPale]];\n}\n\n.tabSelected{\n color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::TertiaryPale]];\n border-left: 1px solid [[ColorPalette::TertiaryLight]];\n border-top: 1px solid [[ColorPalette::TertiaryLight]];\n border-right: 1px solid [[ColorPalette::TertiaryLight]];\n}\n\n.tabUnselected {\n color: [[ColorPalette::Background]];\n background: [[ColorPalette::TertiaryMid]];\n}\n\n.tabContents {\n color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::TertiaryPale]];\n border: 1px solid [[ColorPalette::TertiaryLight]];\n}\n\n.tabContents .button {\n border: 0;}\n\n#sidebar {\n}\n\n#sidebarOptions input {\n border: 1px solid [[ColorPalette::PrimaryMid]];\n}\n\n#sidebarOptions .sliderPanel {\n background: [[ColorPalette::PrimaryPale]];\n}\n\n#sidebarOptions .sliderPanel a {\n border: none;\n color: [[ColorPalette::PrimaryMid]];\n}\n\n#sidebarOptions .sliderPanel a:hover {\n color: [[ColorPalette::Background]];\n background: [[ColorPalette::PrimaryMid]];\n}\n\n#sidebarOptions .sliderPanel a:active {\n color: [[ColorPalette::PrimaryMid]];\n background: [[ColorPalette::Background]];\n}\n\n.wizard {\n background: [[ColorPalette::SecondaryLight]];\n border-top: 1px solid [[ColorPalette::SecondaryMid]];\n border-left: 1px solid [[ColorPalette::SecondaryMid]];\n}\n\n.wizard h1 {\n color: [[ColorPalette::SecondaryDark]];\n}\n\n.wizard h2 {\n color: [[ColorPalette::Foreground]];\n}\n\n.wizardStep {\n background: [[ColorPalette::Background]];\n border-top: 1px solid [[ColorPalette::SecondaryMid]];\n border-bottom: 1px solid [[ColorPalette::SecondaryMid]];\n border-left: 1px solid [[ColorPalette::SecondaryMid]];\n}\n\n.wizard .button {\n color: [[ColorPalette::Background]];\n background: [[ColorPalette::PrimaryMid]];\n border-top: 1px solid [[ColorPalette::PrimaryLight]];\n border-right: 1px solid [[ColorPalette::PrimaryDark]];\n border-bottom: 1px solid [[ColorPalette::PrimaryDark]];\n border-left: 1px solid [[ColorPalette::PrimaryLight]];\n}\n\n.wizard .button:hover {\n color: [[ColorPalette::PrimaryLight]];\n background: [[ColorPalette::PrimaryDark]];\n border-color: [[ColorPalette::PrimaryLight]];\n}\n\n.wizard .button:active {\n color: [[ColorPalette::Background]];\n background: [[ColorPalette::PrimaryMid]];\n border-top: 1px solid [[ColorPalette::PrimaryLight]];\n border-right: 1px solid [[ColorPalette::PrimaryDark]];\n border-bottom: 1px solid [[ColorPalette::PrimaryDark]];\n border-left: 1px solid [[ColorPalette::PrimaryLight]];\n}\n\n#messageArea {\n border: 1px solid [[ColorPalette::SecondaryDark]];\n background: [[ColorPalette::SecondaryMid]];\n color: [[ColorPalette::PrimaryDark]];\n}\n\n#messageArea .button {\n padding: 0.2em 0.2em 0.2em 0.2em;\n color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::Background]];\n}\n\n.popup {\n background: [[ColorPalette::PrimaryLight]];\n border: 1px solid [[ColorPalette::PrimaryMid]];\n}\n\n.popup hr {\n color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::PrimaryDark]];\n border-bottom: 1px;\n}\n\n.listBreak div{\n border-bottom: 1px solid [[ColorPalette::PrimaryDark]];\n}\n\n.popup li.disabled {\n color: [[ColorPalette::PrimaryMid]];\n}\n\n.popup li a, .popup li a:visited {\n color: [[ColorPalette::TertiaryPale]];\n border: none;\n}\n\n.popup li a:hover {\n background: [[ColorPalette::PrimaryDark]];\n color: [[ColorPalette::Background]];\n border: none;\n}\n\n.tiddler .defaultCommand {\n font-weight: bold;\n}\n\n.shadow .title {\n color: [[ColorPalette::TertiaryDark]];\n}\n\n.title {\n color: [[ColorPalette::SecondaryDark]];\n}\n\n.subtitle {\n color: [[ColorPalette::TertiaryDark]];\n}\n\n.toolbar {\n color: [[ColorPalette::PrimaryMid]];\n}\n\n.tagging, .tagged {\n border: 1px solid [[ColorPalette::TertiaryPale]];\n background-color: [[ColorPalette::TertiaryPale]];\n}\n\n.selected .tagging, .selected .tagged {\n background-color: [[ColorPalette::TertiaryLight]];\n border: 1px solid [[ColorPalette::TertiaryMid]];\n}\n\n.tagging .listTitle, .tagged .listTitle {\n color: [[ColorPalette::PrimaryDark]];\n}\n\n.tagging .button, .tagged .button {\n border: none;\n}\n\n.footer {\n color: [[ColorPalette::TertiaryLight]];\n}\n\n.selected .footer {\n color: [[ColorPalette::TertiaryMid]];\n}\n\n.sparkline {\n background: [[ColorPalette::PrimaryPale]];\n border: 0;\n}\n\n.sparktick {\n background: [[ColorPalette::PrimaryDark]];\n}\n\n.error, .errorButton {\n color: [[ColorPalette::Foreground]];\n background: [[ColorPalette::Error]];\n}\n\n.warning {\n color: [[ColorPalette::Foreground]];\n background: [[ColorPalette::SecondaryPale]];\n}\n\n.cascade {\n background: [[ColorPalette::TertiaryPale]];\n color: [[ColorPalette::TertiaryMid]];\n border: 1px solid [[ColorPalette::TertiaryMid]];\n}\n\n.imageLink, #displayArea .imageLink {\n background: transparent;\n}\n\n.viewer .listTitle {list-style-type: none; margin-left: -2em;}\n\n.viewer .button {\n border: 1px solid [[ColorPalette::SecondaryMid]];\n}\n\n.viewer blockquote {\n border-left: 3px solid [[ColorPalette::TertiaryDark]];\n}\n\n.viewer table {\n border: 2px solid [[ColorPalette::TertiaryDark]];\n}\n\n.viewer th, thead td {\n background: [[ColorPalette::SecondaryMid]];\n border: 1px solid [[ColorPalette::TertiaryDark]];\n color: [[ColorPalette::Background]];\n}\n\n.viewer td, .viewer tr {\n border: 1px solid [[ColorPalette::TertiaryDark]];\n}\n\n.viewer pre {\n border: 1px solid [[ColorPalette::SecondaryLight]];\n background: [[ColorPalette::SecondaryPale]];\n}\n\n.viewer code {\n color: [[ColorPalette::SecondaryDark]];\n}\n\n.viewer hr {\n border: 0;\n border-top: dashed 1px [[ColorPalette::TertiaryDark]];\n color: [[ColorPalette::TertiaryDark]];\n}\n\n.highlight, .marked {\n background: [[ColorPalette::SecondaryLight]];\n}\n\n.editor input {\n border: 1px solid [[ColorPalette::PrimaryMid]];\n}\n\n.editor textarea {\n border: 1px solid [[ColorPalette::PrimaryMid]];\n width: 100%;\n}\n\n.editorFooter {\n color: [[ColorPalette::TertiaryMid]];\n}\n\n/*}}}*/",
+ StyleSheetLayout: "/*{{{*/\n* html .tiddler {\n height: 1%;\n}\n\nbody {\n font-size: .75em;\n font-family: arial,helvetica;\n margin: 0;\n padding: 0;\n}\n\nh1,h2,h3,h4,h5 {\n font-weight: bold;\n text-decoration: none;\n padding-left: 0.4em;\n}\n\nh1 {font-size: 1.35em;}\nh2 {font-size: 1.25em;}\nh3 {font-size: 1.1em;}\nh4 {font-size: 1em;}\nh5 {font-size: .9em;}\n\nhr {\n height: 1px;\n}\n\na{\n text-decoration: none;\n}\n\ndt {font-weight: bold;}\n\nol { list-style-type: decimal }\nol ol { list-style-type: lower-alpha }\nol ol ol { list-style-type: lower-roman }\nol ol ol ol { list-style-type: decimal }\nol ol ol ol ol { list-style-type: lower-alpha }\nol ol ol ol ol ol { list-style-type: lower-roman }\nol ol ol ol ol ol ol { list-style-type: decimal }\n\n.txtOptionInput {\n width: 11em;\n}\n\n#contentWrapper .chkOptionInput {\n border: 0;\n}\n\n.externalLink {\n text-decoration: underline;\n}\n\n.indent {margin-left:3em;}\n.outdent {margin-left:3em; text-indent:-3em;}\ncode.escaped {white-space:nowrap;}\n\n.tiddlyLinkExisting {\n font-weight: bold;\n}\n\n.tiddlyLinkNonExisting {\n font-style: italic;\n}\n\n/* the 'a' is required for IE, otherwise it renders the whole tiddler a bold */\na.tiddlyLinkNonExisting.shadow {\n font-weight: bold;\n}\n\n#mainMenu .tiddlyLinkExisting, \n#mainMenu .tiddlyLinkNonExisting,\n#sidebarTabs .tiddlyLinkNonExisting{\n font-weight: normal;\n font-style: normal;\n}\n\n#sidebarTabs .tiddlyLinkExisting {\n font-weight: bold;\n font-style: normal;\n}\n\n.header {\n position: relative;\n}\n\n.header a:hover {\n background: transparent;\n}\n\n.headerShadow {\n position: relative;\n padding: 4.5em 0em 1em 1em;\n left: -1px;\n top: -1px;\n}\n\n.headerForeground {\n position: absolute;\n padding: 4.5em 0em 1em 1em;\n left: 0px;\n top: 0px;\n}\n\n.siteTitle {\n font-size: 3em;\n}\n\n.siteSubtitle {\n font-size: 1.2em;\n}\n\n#mainMenu {\n position: absolute;\n left: 0;\n width: 10em;\n text-align: right;\n line-height: 1.6em;\n padding: 1.5em 0.5em 0.5em 0.5em;\n font-size: 1.1em;\n}\n\n#sidebar {\n position: absolute;\n right: 3px;\n width: 16em;\n font-size: .9em;\n}\n\n#sidebarOptions {\n padding-top: 0.3em;\n}\n\n#sidebarOptions a {\n margin: 0em 0.2em;\n padding: 0.2em 0.3em;\n display: block;\n}\n\n#sidebarOptions input {\n margin: 0.4em 0.5em;\n}\n\n#sidebarOptions .sliderPanel {\n margin-left: 1em;\n padding: 0.5em;\n font-size: .85em;\n}\n\n#sidebarOptions .sliderPanel a {\n font-weight: bold;\n display: inline;\n padding: 0;\n}\n\n#sidebarOptions .sliderPanel input {\n margin: 0 0 .3em 0;\n}\n\n#sidebarTabs .tabContents {\n width: 15em;\n overflow: hidden;\n}\n\n.wizard {\n padding: 0.1em 0em 0em 2em;\n}\n\n.wizard h1 {\n font-size: 2em;\n font-weight: bold;\n background: none;\n padding: 0em 0em 0em 0em;\n margin: 0.4em 0em 0.2em 0em;\n}\n\n.wizard h2 {\n font-size: 1.2em;\n font-weight: bold;\n background: none;\n padding: 0em 0em 0em 0em;\n margin: 0.2em 0em 0.2em 0em;\n}\n\n.wizardStep {\n padding: 1em 1em 1em 1em;\n}\n\n.wizard .button {\n margin: 0.5em 0em 0em 0em;\n font-size: 1.2em;\n}\n\n#messageArea {\nposition:absolute; top:0; right:0; margin: 0.5em; padding: 0.5em;\n}\n\n*[id='messageArea'] {\nposition:fixed !important; z-index:99;}\n\n.messageToolbar {\ndisplay: block;\ntext-align: right;\n}\n\n#messageArea a{\n text-decoration: underline;\n}\n\n.popup {\n font-size: .9em;\n padding: 0.2em;\n list-style: none;\n margin: 0;\n}\n\n.popup hr {\n display: block;\n height: 1px;\n width: auto;\n padding: 0;\n margin: 0.2em 0em;\n}\n\n.listBreak {\n font-size: 1px;\n line-height: 1px;\n}\n\n.listBreak div {\n margin: 2px 0;\n}\n\n.popup li.disabled {\n padding: 0.2em;\n}\n\n.popup li a{\n display: block;\n padding: 0.2em;\n}\n\n.tabset {\n padding: 1em 0em 0em 0.5em;\n}\n\n.tab {\n margin: 0em 0em 0em 0.25em;\n padding: 2px;\n}\n\n.tabContents {\n padding: 0.5em;\n}\n\n.tabContents ul, .tabContents ol {\n margin: 0;\n padding: 0;\n}\n\n.txtMainTab .tabContents li {\n list-style: none;\n}\n\n.tabContents li.listLink {\n margin-left: .75em;\n}\n\n#displayArea {\n margin: 1em 17em 0em 14em;\n}\n\n\n.toolbar {\n text-align: right;\n font-size: .9em;\n visibility: hidden;\n}\n\n.selected .toolbar {\n visibility: visible;\n}\n\n.tiddler {\n padding: 1em 1em 0em 1em;\n}\n\n.missing .viewer,.missing .title {\n font-style: italic;\n}\n\n.title {\n font-size: 1.6em;\n font-weight: bold;\n}\n\n.missing .subtitle {\n display: none;\n}\n\n.subtitle {\n font-size: 1.1em;\n}\n\n.tiddler .button {\n padding: 0.2em 0.4em;\n}\n\n.tagging {\nmargin: 0.5em 0.5em 0.5em 0;\nfloat: left;\ndisplay: none;\n}\n\n.isTag .tagging {\ndisplay: block;\n}\n\n.tagged {\nmargin: 0.5em;\nfloat: right;\n}\n\n.tagging, .tagged {\nfont-size: 0.9em;\npadding: 0.25em;\n}\n\n.tagging ul, .tagged ul {\nlist-style: none;margin: 0.25em;\npadding: 0;\n}\n\n.tagClear {\nclear: both;\n}\n\n.footer {\n font-size: .9em;\n}\n\n.footer li {\ndisplay: inline;\n}\n\n* html .viewer pre {\n width: 99%;\n padding: 0 0 1em 0;\n}\n\n.viewer {\n line-height: 1.4em;\n padding-top: 0.5em;\n}\n\n.viewer .button {\n margin: 0em 0.25em;\n padding: 0em 0.25em;\n}\n\n.viewer blockquote {\n line-height: 1.5em;\n padding-left: 0.8em;\n margin-left: 2.5em;\n}\n\n.viewer ul, .viewer ol{\n margin-left: 0.5em;\n padding-left: 1.5em;\n}\n\n.viewer table {\n border-collapse: collapse;\n margin: 0.8em 1.0em;\n}\n\n.viewer th, .viewer td, .viewer tr,.viewer caption{\n padding: 3px;\n}\n\n.viewer table.listView {\n font-size: 0.85em;\n margin: 0.8em 1.0em;\n}\n\n.viewer table.listView th, .viewer table.listView td, .viewer table.listView tr {\n padding: 0px 3px 0px 3px;\n}\n\n.viewer pre {\n padding: 0.5em;\n margin-left: 0.5em;\n font-size: 1.2em;\n line-height: 1.4em;\n overflow: auto;\n}\n\n.viewer code {\n font-size: 1.2em;\n line-height: 1.4em;\n}\n\n.editor {\nfont-size: 1.1em;\n}\n\n.editor input, .editor textarea {\n display: block;\n width: 100%;\n font: inherit;\n}\n\n.editorFooter {\n padding: 0.25em 0em;\n font-size: .9em;\n}\n\n.editorFooter .button {\npadding-top: 0px; padding-bottom: 0px;}\n\n.fieldsetFix {border: 0;\npadding: 0;\nmargin: 1px 0px 1px 0px;\n}\n\n.sparkline {\n line-height: 1em;\n}\n\n.sparktick {\n outline: 0;\n}\n\n.zoomer {\n font-size: 1.1em;\n position: absolute;\n padding: 1em;\n}\n\n.cascade {\n font-size: 1.1em;\n position: absolute;\n overflow: hidden;\n}\n/*}}}*/",
+ StyleSheetPrint: "/*{{{*/\n@media print {\n#mainMenu, #sidebar, #messageArea, .toolbar {display: none ! important;}\n#displayArea {margin: 1em 1em 0em 1em;}\n/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */\nnoscript {display:none;}\n}\n/*}}}*/",
+ PageTemplate: "<!--{{{-->\n<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>\n<div class='headerShadow'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span> \n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n<div class='headerForeground'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span> \n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n</div>\n<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>\n<div id='sidebar'>\n<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>\n<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>\n</div>\n<div id='displayArea'>\n<div id='messageArea'></div>\n<div id='tiddlerDisplay'></div>\n</div>\n<!--}}}-->",
+ ViewTemplate: "<!--{{{-->\n<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler permalink references jump'></div>\n<div class='title' macro='view title'></div>\n<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date [[DD MMM YYYY]]'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date [[DD MMM YYYY]]'></span>)</div>\n<div class='tagging' macro='tagging'></div>\n<div class='tagged' macro='tags'></div>\n<div class='viewer' macro='view text wikified'></div>\n<div class='tagClear'></div>\n<!--}}}-->",
+ EditTemplate: "<!--{{{-->\n<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'></div>\n<div class='title' macro='view title'></div>\n<div class='editor' macro='edit title'></div>\n<div class='editor' macro='edit text'></div>\n<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>\n<!--}}}-->",
+ MarkupPreHead: "<!--{{{-->\n<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>\n<!--}}}-->",
+ MarkupPostHead: "",
+ MarkupPreBody: "",
+ MarkupPostBody: ""
+ };
+
+// ---------------------------------------------------------------------------------
+// Translateable strings
+// ---------------------------------------------------------------------------------
+
+// Strings in "double quotes" should be translated; strings in 'single quotes' should be left alone
+
+merge(config.options,{
+ txtUserName: "YourName"});
+
+merge(config.messages,{
+ customConfigError: "Problems were encountered loading plugins. See PluginManager for details",
+ pluginError: "Error: %0",
+ pluginDisabled: "Not executed because disabled via 'systemConfigDisable' tag",
+ pluginForced: "Executed because forced via 'systemConfigForce' tag",
+ pluginVersionError: "Not executed because this plugin needs a newer version of TiddlyWiki",
+ nothingSelected: "Nothing is selected. You must select one or more items first",
+ savedSnapshotError: "It appears that this TiddlyWiki has been incorrectly saved. Please see http://www.tiddlywiki.com/#DownloadSoftware for details",
+ subtitleUnknown: "(unknown)",
+ undefinedTiddlerToolTip: "The tiddler '%0' doesn't yet exist",
+ shadowedTiddlerToolTip: "The tiddler '%0' doesn't yet exist, but has a pre-defined shadow value",
+ tiddlerLinkTooltip: "%0 - %1, %2",
+ externalLinkTooltip: "External link to %0",
+ noTags: "There are no tagged tiddlers",
+ notFileUrlError: "You need to save this TiddlyWiki to a file before you can save changes",
+ cantSaveError: "It's not possible to save changes. This could be because your browser doesn't support saving (instead, use FireFox if you can), or because the pathname to your TiddlyWiki file contains illegal characters",
+ invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
+ backupSaved: "Backup saved",
+ backupFailed: "Failed to save backup file",
+ rssSaved: "RSS feed saved",
+ rssFailed: "Failed to save RSS feed file",
+ emptySaved: "Empty template saved",
+ emptyFailed: "Failed to save empty template file",
+ mainSaved: "Main TiddlyWiki file saved",
+ mainFailed: "Failed to save main TiddlyWiki file. Your changes have not been saved",
+ macroError: "Error in macro <<%0>>",
+ macroErrorDetails: "Error while executing macro <<%0>>:\n%1",
+ missingMacro: "No such macro",
+ overwriteWarning: "A tiddler named '%0' already exists. Choose OK to overwrite it",
+ unsavedChangesWarning: "WARNING! There are unsaved changes in TiddlyWiki\n\nChoose OK to save\nChoose CANCEL to discard",
+ confirmExit: "--------------------------------\n\nThere are unsaved changes in TiddlyWiki. If you continue you will lose those changes\n\n--------------------------------",
+ saveInstructions: "SaveChanges",
+ unsupportedTWFormat: "Unsupported TiddlyWiki format '%0'",
+ tiddlerSaveError: "Error when saving tiddler '%0'",
+ tiddlerLoadError: "Error when loading tiddler '%0'",
+ wrongSaveFormat: "Cannot save with storage format '%0'. Using standard format for save.",
+ invalidFieldName: "Invalid field name %0",
+ fieldCannotBeChanged: "Field '%0' cannot be changed"});
+
+merge(config.messages.messageClose,{
+ text: "close",
+ tooltip: "close this message area"});
+
+config.messages.dates.months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November","December"];
+config.messages.dates.days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
+config.messages.dates.shortMonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
+config.messages.dates.shortDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
+
+merge(config.views.wikified.tag,{
+ labelNoTags: "no tags",
+ labelTags: "tags: ",
+ openTag: "Open tag '%0'",
+ tooltip: "Show tiddlers tagged with '%0'",
+ openAllText: "Open all",
+ openAllTooltip: "Open all of these tiddlers",
+ popupNone: "No other tiddlers tagged with '%0'"});
+
+merge(config.views.wikified,{
+ defaultText: "The tiddler '%0' doesn't yet exist. Double-click to create it",
+ defaultModifier: "(missing)",
+ shadowModifier: "(built-in shadow tiddler)",
+ createdPrompt: "created"});
+
+merge(config.views.editor,{
+ tagPrompt: "Type tags separated with spaces, [[use double square brackets]] if necessary, or add existing",
+ defaultText: "Type the text for '%0'"});
+
+merge(config.views.editor.tagChooser,{
+ text: "tags",
+ tooltip: "Choose existing tags to add to this tiddler",
+ popupNone: "There are no tags defined",
+ tagTooltip: "Add the tag '%0'"});
+
+merge(config.macros.search,{
+ label: "search",
+ prompt: "Search this TiddlyWiki",
+ accessKey: "F",
+ successMsg: "%0 tiddlers found matching %1",
+ failureMsg: "No tiddlers found matching %0"});
+
+merge(config.macros.tagging,{
+ label: "tagging: ",
+ labelNotTag: "not tagging",
+ tooltip: "List of tiddlers tagged with '%0'"});
+
+merge(config.macros.timeline,{
+ dateFormat: "DD MMM YYYY"});
+
+merge(config.macros.allTags,{
+ tooltip: "Show tiddlers tagged with '%0'",
+ noTags: "There are no tagged tiddlers"});
+
+config.macros.list.all.prompt = "All tiddlers in alphabetical order";
+config.macros.list.missing.prompt = "Tiddlers that have links to them but are not defined";
+config.macros.list.orphans.prompt = "Tiddlers that are not linked to from any other tiddlers";
+config.macros.list.shadowed.prompt = "Tiddlers shadowed with default contents";
+
+merge(config.macros.closeAll,{
+ label: "close all",
+ prompt: "Close all displayed tiddlers (except any that are being edited)"});
+
+merge(config.macros.permaview,{
+ label: "permaview",
+ prompt: "Link to an URL that retrieves all the currently displayed tiddlers"});
+
+merge(config.macros.saveChanges,{
+ label: "save changes",
+ prompt: "Save all tiddlers to create a new TiddlyWiki",
+ accessKey: "S"});
+
+merge(config.macros.newTiddler,{
+ label: "new tiddler",
+ prompt: "Create a new tiddler",
+ title: "New Tiddler",
+ accessKey: "N"});
+
+merge(config.macros.newJournal,{
+ label: "new journal",
+ prompt: "Create a new tiddler from the current date and time",
+ accessKey: "J"});
+
+merge(config.macros.plugins,{
+ skippedText: "(This plugin has not been executed because it was added since startup)",
+ noPluginText: "There are no plugins installed",
+ confirmDeleteText: "Are you sure you want to delete these tiddlers:\n\n%0",
+ listViewTemplate : {
+ columns: [
+ {name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
+ {name: 'Title', field: 'title', tiddlerLink: 'title', title: "Title", type: 'TiddlerLink'},
+ {name: 'Forced', field: 'forced', title: "Forced", tag: 'systemConfigForce', type: 'TagCheckbox'},
+ {name: 'Disabled', field: 'disabled', title: "Disabled", tag: 'systemConfigDisable', type: 'TagCheckbox'},
+ {name: 'Executed', field: 'executed', title: "Loaded", type: 'Boolean', trueText: "Yes", falseText: "No"},
+ {name: 'Error', field: 'error', title: "Status", type: 'Boolean', trueText: "Error", falseText: "OK"},
+ {name: 'Log', field: 'log', title: "Log", type: 'StringList'}
+ ],
+ rowClasses: [
+ {className: 'error', field: 'error'},
+ {className: 'warning', field: 'warning'}
+ ],
+ actions: [
+ {caption: "More actions...", name: ''},
+ {caption: "Remove systemConfig tag", name: 'remove'},
+ {caption: "Delete these tiddlers forever", name: 'delete'}
+ ]}
+ });
+
+merge(config.macros.refreshDisplay,{
+ label: "refresh",
+ prompt: "Redraw the entire TiddlyWiki display"
+ });
+
+merge(config.macros.importTiddlers,{
+ readOnlyWarning: "You cannot import tiddlers into a read-only TiddlyWiki. Try opening the TiddlyWiki file from a file:// URL",
+ defaultPath: "http://www.tiddlywiki.com/index.html",
+ fetchLabel: "fetch",
+ fetchPrompt: "Fetch the tiddlywiki file",
+ fetchError: "There were problems fetching the tiddlywiki file",
+ confirmOverwriteText: "Are you sure you want to overwrite these tiddlers:\n\n%0",
+ wizardTitle: "Import tiddlers from another TiddlyWiki file",
+ step1: "Step 1: Locate the TiddlyWiki file",
+ step1prompt: "Enter the URL or pathname here: ",
+ step1promptFile: "...or browse for a file: ",
+ step1promptFeeds: "...or select a pre-defined feed: ",
+ step1feedPrompt: "Choose...",
+ step2: "Step 2: Loading TiddlyWiki file",
+ step2Text: "Please wait while the file is loaded from: %0",
+ step3: "Step 3: Choose the tiddlers to import",
+ step4: "%0 tiddler(s) imported",
+ step5: "Done",
+ listViewTemplate: {
+ columns: [
+ {name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
+ {name: 'Title', field: 'title', title: "Title", type: 'String'},
+ {name: 'Snippet', field: 'text', title: "Snippet", type: 'String'},
+ {name: 'Tags', field: 'tags', title: "Tags", type: 'Tags'}
+ ],
+ rowClasses: [
+ ],
+ actions: [
+ {caption: "More actions...", name: ''},
+ {caption: "Import these tiddlers", name: 'import'}
+ ]}
+ });
+
+merge(config.commands.closeTiddler,{
+ text: "close",
+ tooltip: "Close this tiddler"});
+
+merge(config.commands.closeOthers,{
+ text: "close others",
+ tooltip: "Close all other tiddlers"});
+
+merge(config.commands.editTiddler,{
+ text: "edit",
+ tooltip: "Edit this tiddler",
+ readOnlyText: "view",
+ readOnlyTooltip: "View the source of this tiddler"});
+
+merge(config.commands.saveTiddler,{
+ text: "done",
+ tooltip: "Save changes to this tiddler"});
+
+merge(config.commands.cancelTiddler,{
+ text: "cancel",
+ tooltip: "Undo changes to this tiddler",
+ warning: "Are you sure you want to abandon your changes to '%0'?",
+ readOnlyText: "done",
+ readOnlyTooltip: "View this tiddler normally"});
+
+merge(config.commands.deleteTiddler,{
+ text: "delete",
+ tooltip: "Delete this tiddler",
+ warning: "Are you sure you want to delete '%0'?"});
+
+merge(config.commands.permalink,{
+ text: "permalink",
+ tooltip: "Permalink for this tiddler"});
+
+merge(config.commands.references,{
+ text: "references",
+ tooltip: "Show tiddlers that link to this one",
+ popupNone: "No references"});
+
+merge(config.commands.jump,{
+ text: "jump",
+ tooltip: "Jump to another open tiddler"});
+
+merge(config.shadowTiddlers,{
+ DefaultTiddlers: "GettingStarted",
+ MainMenu: "GettingStarted",
+ SiteTitle: "My TiddlyWiki",
+ SiteSubtitle: "a reusable non-linear personal web notebook",
+ SiteUrl: "http://www.tiddlywiki.com/",
+ GettingStarted: "To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:\n* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)\n* MainMenu: The menu (usually on the left)\n* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened\nYou'll also need to enter your username for signing your edits: <<option txtUserName>>",
+ SideBarOptions: "<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal 'DD MMM YYYY'>><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel 'options »' 'Change TiddlyWiki advanced options'>>",
+ OptionsPanel: "These InterfaceOptions for customising TiddlyWiki are saved in your browser\n\nYour username for signing your edits. Write it as a WikiWord (eg JoeBloggs)\n\n<<option txtUserName>>\n<<option chkSaveBackups>> SaveBackups\n<<option chkAutoSave>> AutoSave\n<<option chkRegExpSearch>> RegExpSearch\n<<option chkCaseSensitiveSearch>> CaseSensitiveSearch\n<<option chkAnimate>> EnableAnimations\n\n----\nAdvancedOptions\nPluginManager\nImportTiddlers",
+ AdvancedOptions: "<<option chkGenerateAnRssFeed>> GenerateAnRssFeed\n<<option chkOpenInNewWindow>> OpenLinksInNewWindow\n<<option chkSaveEmptyTemplate>> SaveEmptyTemplate\n<<option chkToggleLinks>> Clicking on links to tiddlers that are already open causes them to close\n^^(override with Control or other modifier key)^^\n<<option chkHttpReadOnly>> HideEditingFeatures when viewed over HTTP\n<<option chkForceMinorUpdate>> Treat edits as MinorChanges by preserving date and time\n^^(override with Shift key when clicking 'done' or by pressing Ctrl-Shift-Enter^^\n<<option chkConfirmDelete>> ConfirmBeforeDeleting\nMaximum number of lines in a tiddler edit box: <<option txtMaxEditRows>>\nFolder name for backup files: <<option txtBackupFolder>>\n<<option chkInsertTabs>> Use tab key to insert tab characters instead of jumping to next field",
+ SideBarTabs: "<<tabs txtMainTab Timeline Timeline TabTimeline All 'All tiddlers' TabAll Tags 'All tags' TabTags More 'More lists' TabMore>>",
+ TabTimeline: "<<timeline>>",
+ TabAll: "<<list all>>",
+ TabTags: "<<allTags>>",
+ TabMore: "<<tabs txtMoreTab Missing 'Missing tiddlers' TabMoreMissing Orphans 'Orphaned tiddlers' TabMoreOrphans Shadowed 'Shadowed tiddlers' TabMoreShadowed>>",
+ TabMoreMissing: "<<list missing>>",
+ TabMoreOrphans: "<<list orphans>>",
+ TabMoreShadowed: "<<list shadowed>>",
+ PluginManager: "<<plugins>>",
+ ImportTiddlers: "<<importTiddlers>>"});
+
+// ---------------------------------------------------------------------------------
+// Main
+// ---------------------------------------------------------------------------------
+
+var params = null; // Command line parameters
+var store = null; // TiddlyWiki storage
+var story = null; // Main story
+var formatter = null; // Default formatters for the wikifier
+config.parsers = {}; // Hashmap of alternative parsers for the wikifier
+var anim = new Animator(); // Animation engine
+var readOnly = false; // Whether we're in readonly mode
+var highlightHack = null; // Embarrassing hack department...
+var hadConfirmExit = false; // Don't warn more than once
+var safeMode = false; // Disable all plugins and cookies
+var installedPlugins = []; // Information filled in when plugins are executed
+var startingUp = false; // Whether we're in the process of starting up
+var pluginInfo,tiddler; // Used to pass information to plugins in loadPlugins()
+
+// Whether to use the JavaSaver applet
+var useJavaSaver = config.browser.isSafari || config.browser.isOpera;
+
+// Starting up
+function main()
+{
+ var now, then = new Date();
+ startingUp = true;
+ window.onbeforeunload = function(e) {if(window.confirmExit) return confirmExit();};
+ params = getParameters();
+ if(params)
+ params = params.parseParams("open",null,false);
+ store = new TiddlyWiki();
+ invokeParamifier(params,"oninit");
+ story = new Story("tiddlerDisplay","tiddler");
+ addEvent(document,"click",Popup.onDocumentClick);
+ saveTest();
+ loadOptionsCookie();
+ for(var s=0; s<config.notifyTiddlers.length; s++)
+ store.addNotification(config.notifyTiddlers[s].name,config.notifyTiddlers[s].notify);
+ store.loadFromDiv("storeArea","store",true);
+ invokeParamifier(params,"onload");
+ var pluginProblem = loadPlugins();
+ formatter = new Formatter(config.formatters);
+ readOnly = (window.location.protocol == "file:") ? false : config.options.chkHttpReadOnly;
+ invokeParamifier(params,"onconfig");
+ store.notifyAll();
+ restart();
+ if(pluginProblem)
+ {
+ story.displayTiddler(null,"PluginManager");
+ displayMessage(config.messages.customConfigError);
+ }
+ now = new Date();
+ if(config.displayStartupTime)
+ displayMessage("TiddlyWiki startup in " + (now-then)/1000 + " seconds");
+ startingUp = false;
+}
+
+// Restarting
+function restart()
+{
+ invokeParamifier(params,"onstart");
+ if(story.isEmpty())
+ {
+ var defaultParams = store.getTiddlerText("DefaultTiddlers").parseParams("open",null,false);
+ invokeParamifier(defaultParams,"onstart");
+ }
+ window.scrollTo(0,0);
+}
+
+function saveTest()
+{
+ var saveTest = document.getElementById("saveTest");
+ if(saveTest.hasChildNodes())
+ alert(config.messages.savedSnapshotError);
+ saveTest.appendChild(document.createTextNode("savetest"));
+}
+
+function loadPlugins()
+{
+ if(safeMode)
+ return false;
+ var configTiddlers = store.getTaggedTiddlers("systemConfig");
+ installedPlugins = [];
+ var hadProblem = false;
+ for(var t=0; t<configTiddlers.length; t++)
+ {
+ tiddler = configTiddlers[t];
+ pluginInfo = getPluginInfo(tiddler);
+ if(isPluginExecutable(pluginInfo))
+ {
+ pluginInfo.executed = true;
+ pluginInfo.error = false;
+ try
+ {
+ if(tiddler.text && tiddler.text != "")
+ window.eval(tiddler.text);
+ }
+ catch(e)
+ {
+ pluginInfo.log.push(config.messages.pluginError.format([exceptionText(e)]));
+ pluginInfo.error = true;
+ hadProblem = true;
+ }
+ }
+ else
+ pluginInfo.warning = true;
+ installedPlugins.push(pluginInfo);
+ }
+ return hadProblem;
+}
+
+function getPluginInfo(tiddler)
+{
+ var p = store.getTiddlerSlices(tiddler.title,["Name","Description","Version","CoreVersion","Date","Source","Author","License","Browsers"]);
+ p.tiddler = tiddler;
+ p.title = tiddler.title;
+ p.log = [];
+ return p;
+}
+
+// Check that a particular plugin is valid for execution
+function isPluginExecutable(plugin)
+{
+ if(plugin.tiddler.isTagged("systemConfigDisable"))
+ return verifyTail(plugin,false,config.messages.pluginDisabled);
+ if(plugin.tiddler.isTagged("systemConfigForce"))
+ return verifyTail(plugin,true,config.messages.pluginForced);
+ if(plugin["CoreVersion"])
+ {
+ var coreVersion = plugin["CoreVersion"].split(".");
+ var w = parseInt(coreVersion[0]) - version.major;
+ if(w == 0 && coreVersion[1])
+ w = parseInt(coreVersion[1]) - version.minor;
+ if(w == 0 && coreVersion[2])
+ w = parseInt(coreVersion[2]) - version.revision;
+ if(w > 0)
+ return verifyTail(plugin,false,config.messages.pluginVersionError);
+ }
+ return true;
+}
+
+function verifyTail(plugin,result,message)
+{
+ plugin.log.push(message);
+ return result;
+}
+
+function invokeMacro(place,macro,params,wikifier,tiddler)
+{
+ try
+ {
+ var m = config.macros[macro];
+ if(m && m.handler)
+ m.handler(place,macro,params.readMacroParams(),wikifier,params,tiddler);
+ else
+ createTiddlyError(place,config.messages.macroError.format([macro]),config.messages.macroErrorDetails.format([macro,config.messages.missingMacro]));
+ }
+ catch(ex)
+ {
+ createTiddlyError(place,config.messages.macroError.format([macro]),config.messages.macroErrorDetails.format([macro,ex.toString()]));
+ }
+}
+
+// ---------------------------------------------------------------------------------
+// Paramifiers
+// ---------------------------------------------------------------------------------
+
+function getParameters()
+{
+ var p = null;
+ if(window.location.hash)
+ {
+ p = decodeURI(window.location.hash.substr(1));
+ if(config.browser.firefoxDate != null && config.browser.firefoxDate[1] < "20051111")
+ p = convertUTF8ToUnicode(p);
+ }
+ return p;
+}
+
+function invokeParamifier(params,handler)
+{
+ if(!params || params.length == undefined || params.length <= 1)
+ return;
+ for(var t=1; t<params.length; t++)
+ {
+ var p = config.paramifiers[params[t].name];
+ if(p && p[handler] instanceof Function)
+ p[handler](params[t].value);
+ }
+}
+
+config.paramifiers = {};
+
+config.paramifiers.start = {
+ oninit: function(v) {
+ safeMode = v.toLowerCase() == "safe";
+ }
+};
+
+config.paramifiers.open = {
+ onstart: function(v) {
+ story.displayTiddler("bottom",v,null,false,false);
+ }
+};
+
+config.paramifiers.story = {
+ onstart: function(v) {
+ var list = store.getTiddlerText(v,"").parseParams("open",null,false);
+ invokeParamifier(list,"onstart");
+ }
+};
+
+config.paramifiers.search = {
+ onstart: function(v) {
+ story.search(v,false,false);
+ }
+};
+
+config.paramifiers.searchRegExp = {
+ onstart: function(v) {
+ story.prototype.search(v,false,true);
+ }
+};
+
+config.paramifiers.tag = {
+ onstart: function(v) {
+ var tagged = store.getTaggedTiddlers(v,"title");
+ for(var t=0; t<tagged.length; t++)
+ story.displayTiddler("bottom",tagged[t].title,null,false,false);
+ }
+};
+
+config.paramifiers.newTiddler = {
+ onstart: function(v) {
+ if(!readOnly)
+ {
+ story.displayTiddler(null,v,DEFAULT_EDIT_TEMPLATE);
+ story.focusTiddler(v,"text");
+ }
+ }
+};
+
+config.paramifiers.newJournal = {
+ onstart: function(v) {
+ if(!readOnly)
+ {
+ var now = new Date();
+ var title = now.formatString(v.trim());
+ story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE);
+ story.focusTiddler(title,"text");
+ }
+ }
+};
+
+// ---------------------------------------------------------------------------------
+// Formatter helpers
+// ---------------------------------------------------------------------------------
+
+function Formatter(formatters)
+{
+ this.formatters = [];
+ var pattern = [];
+ for(var n=0; n<formatters.length; n++)
+ {
+ pattern.push("(" + formatters[n].match + ")");
+ this.formatters.push(formatters[n]);
+ }
+ this.formatterRegExp = new RegExp(pattern.join("|"),"mg");
+}
+
+config.formatterHelpers = {
+
+ createElementAndWikify: function(w)
+ {
+ w.subWikifyTerm(createTiddlyElement(w.output,this.element),this.termRegExp);
+ },
+
+ inlineCssHelper: function(w)
+ {
+ var styles = [];
+ config.textPrimitives.cssLookaheadRegExp.lastIndex = w.nextMatch;
+ var lookaheadMatch = config.textPrimitives.cssLookaheadRegExp.exec(w.source);
+ while(lookaheadMatch && lookaheadMatch.index == w.nextMatch)
+ {
+ var s,v;
+ if(lookaheadMatch[1])
+ {
+ s = lookaheadMatch[1].unDash();
+ v = lookaheadMatch[2];
+ }
+ else
+ {
+ s = lookaheadMatch[3].unDash();
+ v = lookaheadMatch[4];
+ }
+ if (s=="bgcolor")
+ s = "backgroundColor";
+ styles.push({style: s, value: v});
+ w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
+ config.textPrimitives.cssLookaheadRegExp.lastIndex = w.nextMatch;
+ lookaheadMatch = config.textPrimitives.cssLookaheadRegExp.exec(w.source);
+ }
+ return styles;
+ },
+
+ applyCssHelper: function(e,styles)
+ {
+ for(var t=0; t< styles.length; t++)
+ {
+ try
+ {
+ e.style[styles[t].style] = styles[t].value;
+ }
+ catch (ex)
+ {
+ }
+ }
+ },
+
+ enclosedTextHelper: function(w)
+ {
+ this.lookaheadRegExp.lastIndex = w.matchStart;
+ var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
+ if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
+ {
+ var text = lookaheadMatch[1];
+ if(config.browser.isIE)
+ text = text.replace(/\n/g,"\r");
+ createTiddlyElement(w.output,this.element,null,null,text);
+ w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
+ }
+ },
+
+ isExternalLink: function(link)
+ {
+ if(store.tiddlerExists(link) || store.isShadowTiddler(link))
+ {
+ //# Definitely not an external link
+ return false;
+ }
+ var urlRegExp = new RegExp(config.textPrimitives.urlPattern,"mg");
+ if(urlRegExp.exec(link))
+ {
+ // Definitely an external link
+ return true;
+ }
+ if (link.indexOf(".")!=-1 || link.indexOf("\\")!=-1 || link.indexOf("/")!=-1)
+ {
+ //# Link contains . / or \ so is probably an external link
+ return true;
+ }
+ //# Otherwise assume it is not an external link
+ return false;
+ }
+
+};
+
+// ---------------------------------------------------------------------------------
+// Standard formatters
+// ---------------------------------------------------------------------------------
+
+config.formatters = [
+{
+ name: "table",
+ match: "^\\|(?:[^\\n]*)\\|(?:[fhck]?)$",
+ lookaheadRegExp: /^\|([^\n]*)\|([fhck]?)$/mg,
+ rowTermRegExp: /(\|(?:[fhck]?)$\n?)/mg,
+ cellRegExp: /(?:\|([^\n\|]*)\|)|(\|[fhck]?$\n?)/mg,
+ cellTermRegExp: /((?:\x20*)\|)/mg,
+ rowTypes: {"c":"caption", "h":"thead", "":"tbody", "f":"tfoot"},
+
+ handler: function(w)
+ {
+ var table = createTiddlyElement(w.output,"table");
+ var prevColumns = [];
+ var currRowType = null;
+ var rowContainer;
+ var rowCount = 0;
+ w.nextMatch = w.matchStart;
+ this.lookaheadRegExp.lastIndex = w.nextMatch;
+ var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
+ while(lookaheadMatch && lookaheadMatch.index == w.nextMatch)
+ {
+ var nextRowType = lookaheadMatch[2];
+ if(nextRowType == "k")
+ {
+ table.className = lookaheadMatch[1];
+ w.nextMatch += lookaheadMatch[0].length+1;
+ }
+ else
+ {
+ if(nextRowType != currRowType)
+ {
+ rowContainer = createTiddlyElement(table,this.rowTypes[nextRowType]);
+ currRowType = nextRowType;
+ }
+ if(currRowType == "c")
+ {
+ // Caption
+ w.nextMatch++;
+ if(rowContainer != table.firstChild)
+ table.insertBefore(rowContainer,table.firstChild);
+ rowContainer.setAttribute("align",rowCount == 0?"top":"bottom");
+ w.subWikifyTerm(rowContainer,this.rowTermRegExp);
+ }
+ else
+ {
+ this.rowHandler(w,createTiddlyElement(rowContainer,"tr",null,(rowCount&1)?"oddRow":"evenRow"),prevColumns);
+ rowCount++;
+ }
+ }
+ this.lookaheadRegExp.lastIndex = w.nextMatch;
+ lookaheadMatch = this.lookaheadRegExp.exec(w.source);
+ }
+ },
+ rowHandler: function(w,e,prevColumns)
+ {
+ var col = 0;
+ var colSpanCount = 1;
+ var prevCell = null;
+ this.cellRegExp.lastIndex = w.nextMatch;
+ var cellMatch = this.cellRegExp.exec(w.source);
+ while(cellMatch && cellMatch.index == w.nextMatch)
+ {
+ if(cellMatch[1] == "~")
+ {
+ // Rowspan
+ var last = prevColumns[col];
+ if(last)
+ {
+ last.rowSpanCount++;
+ last.element.setAttribute("rowspan",last.rowSpanCount);
+ last.element.setAttribute("rowSpan",last.rowSpanCount); // Needed for IE
+ last.element.valign = "center";
+ }
+ w.nextMatch = this.cellRegExp.lastIndex-1;
+ }
+ else if(cellMatch[1] == ">")
+ {
+ // Colspan
+ colSpanCount++;
+ w.nextMatch = this.cellRegExp.lastIndex-1;
+ }
+ else if(cellMatch[2])
+ {
+ // End of row
+ if(prevCell && colSpanCount > 1)
+ {
+ prevCell.setAttribute("colspan",colSpanCount);
+ prevCell.setAttribute("colSpan",colSpanCount); // Needed for IE
+ }
+ w.nextMatch = this.cellRegExp.lastIndex;
+ break;
+ }
+ else
+ {
+ // Cell
+ w.nextMatch++;
+ var styles = config.formatterHelpers.inlineCssHelper(w);
+ var spaceLeft = false;
+ var chr = w.source.substr(w.nextMatch,1);
+ while(chr == " ")
+ {
+ spaceLeft = true;
+ w.nextMatch++;
+ chr = w.source.substr(w.nextMatch,1);
+ }
+ var cell;
+ if(chr == "!")
+ {
+ cell = createTiddlyElement(e,"th");
+ w.nextMatch++;
+ }
+ else
+ cell = createTiddlyElement(e,"td");
+ prevCell = cell;
+ prevColumns[col] = {rowSpanCount:1, element:cell};
+ if(colSpanCount > 1)
+ {
+ cell.setAttribute("colspan",colSpanCount);
+ cell.setAttribute("colSpan",colSpanCount); // Needed for IE
+ colSpanCount = 1;
+ }
+ config.formatterHelpers.applyCssHelper(cell,styles);
+ w.subWikifyTerm(cell,this.cellTermRegExp);
+ if(w.matchText.substr(w.matchText.length-2,1) == " ") // spaceRight
+ cell.align = spaceLeft ? "center" : "left";
+ else if(spaceLeft)
+ cell.align = "right";
+ w.nextMatch--;
+ }
+ col++;
+ this.cellRegExp.lastIndex = w.nextMatch;
+ cellMatch = this.cellRegExp.exec(w.source);
+ }
+ }
+},
+
+{
+ name: "heading",
+ match: "^!{1,5}",
+ termRegExp: /(\n)/mg,
+ handler: function(w)
+ {
+ w.subWikifyTerm(createTiddlyElement(w.output,"h" + w.matchLength),this.termRegExp);
+ }
+},
+
+{
+ name: "list",
+ match: "^(?:(?:(?:\\*)|(?:#)|(?:;)|(?::))+)",
+ lookaheadRegExp: /^(?:(?:(\*)|(#)|(;)|(:))+)/mg,
+ termRegExp: /(\n)/mg,
+ handler: function(w)
+ {
+ var placeStack = [w.output];
+ var currLevel = 0, currType = null;
+ var listLevel, listType, itemType;
+ w.nextMatch = w.matchStart;
+ this.lookaheadRegExp.lastIndex = w.nextMatch;
+ var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
+ while(lookaheadMatch && lookaheadMatch.index == w.nextMatch)
+ {
+ if(lookaheadMatch[1])
+ {
+ listType = "ul";
+ itemType = "li";
+ }
+ else if(lookaheadMatch[2])
+ {
+ listType = "ol";
+ itemType = "li";
+ }
+ else if(lookaheadMatch[3])
+ {
+ listType = "dl";
+ itemType = "dt";
+ }
+ else if(lookaheadMatch[4])
+ {
+ listType = "dl";
+ itemType = "dd";
+ }
+ listLevel = lookaheadMatch[0].length;
+ w.nextMatch += lookaheadMatch[0].length;
+ if(listLevel > currLevel)
+ {
+ for(var t=currLevel; t<listLevel; t++)
+ placeStack.push(createTiddlyElement(placeStack[placeStack.length-1],listType));
+ }
+ else if(listLevel < currLevel)
+ {
+ for(var t=currLevel; t>listLevel; t--)
+ placeStack.pop();
+ }
+ else if(listLevel == currLevel && listType != currType)
+ {
+ placeStack.pop();
+ placeStack.push(createTiddlyElement(placeStack[placeStack.length-1],listType));
+ }
+ currLevel = listLevel;
+ currType = listType;
+ var e = createTiddlyElement(placeStack[placeStack.length-1],itemType);
+ w.subWikifyTerm(e,this.termRegExp);
+ this.lookaheadRegExp.lastIndex = w.nextMatch;
+ lookaheadMatch = this.lookaheadRegExp.exec(w.source);
+ }
+ }
+},
+
+{
+ name: "quoteByBlock",
+ match: "^<<<\\n",
+ termRegExp: /(^<<<(\n|$))/mg,
+ element: "blockquote",
+ handler: config.formatterHelpers.createElementAndWikify
+},
+
+{
+ name: "quoteByLine",
+ match: "^>+",
+ lookaheadRegExp: /^>+/mg,
+ termRegExp: /(\n)/mg,
+ element: "blockquote",
+ handler: function(w)
+ {
+ var placeStack = [w.output];
+ var currLevel = 0;
+ var newLevel = w.matchLength;
+ var t;
+ do {
+ if(newLevel > currLevel)
+ {
+ for(t=currLevel; t<newLevel; t++)
+ placeStack.push(createTiddlyElement(placeStack[placeStack.length-1],this.element));
+ }
+ else if(newLevel < currLevel)
+ {
+ for(t=currLevel; t>newLevel; t--)
+ placeStack.pop();
+ }
+ currLevel = newLevel;
+ w.subWikifyTerm(placeStack[placeStack.length-1],this.termRegExp);
+ createTiddlyElement(placeStack[placeStack.length-1],"br");
+ this.lookaheadRegExp.lastIndex = w.nextMatch;
+ var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
+ var matched = lookaheadMatch && lookaheadMatch.index == w.nextMatch;
+ if(matched)
+ {
+ newLevel = lookaheadMatch[0].length;
+ w.nextMatch += lookaheadMatch[0].length;
+ }
+ } while(matched);
+ }
+},
+
+{
+ name: "rule",
+ match: "^----+$\\n?",
+ handler: function(w)
+ {
+ createTiddlyElement(w.output,"hr");
+ }
+},
+
+{
+ name: "monospacedByLine",
+ match: "^\\{\\{\\{\\n",
+ lookaheadRegExp: /^\{\{\{\n((?:^[^\n]*\n)+?)(^\}\}\}$\n?)/mg,
+ element: "pre",
+ handler: config.formatterHelpers.enclosedTextHelper
+},
+
+{
+ name: "monospacedByLineForCSS",
+ match: "^/\\*[\\{]{3}\\*/\\n",
+ lookaheadRegExp: /\/\*[\{]{3}\*\/\n*((?:^[^\n]*\n)+?)(\n*^\/\*[\}]{3}\*\/$\n?)/mg,
+ element: "pre",
+ handler: config.formatterHelpers.enclosedTextHelper
+},
+
+{
+ name: "monospacedByLineForPlugin",
+ match: "^//\\{\\{\\{\\n",
+ lookaheadRegExp: /^\/\/\{\{\{\n\n*((?:^[^\n]*\n)+?)(\n*^\/\/\}\}\}$\n?)/mg,
+ element: "pre",
+ handler: config.formatterHelpers.enclosedTextHelper
+},
+
+{
+ name: "monospacedByLineForTemplate",
+ match: "^<!--[\\{]{3}-->\\n",
+ lookaheadRegExp: /<!--[\{]{3}-->\n*((?:^[^\n]*\n)+?)(\n*^<!--[\}]{3}-->$\n?)/mg,
+ element: "pre",
+ handler: config.formatterHelpers.enclosedTextHelper
+},
+
+{
+ name: "wikifyCommentForPlugin",
+ match: "^/\\*\\*\\*\\n",
+ termRegExp: /(^\*\*\*\/\n)/mg,
+ handler: function(w)
+ {
+ w.subWikifyTerm(w.output,this.termRegExp);
+ }
+},
+
+{
+ name: "wikifyCommentForTemplate",
+ match: "^<!---\\n",
+ termRegExp: /(^--->\n)/mg,
+ handler: function(w)
+ {
+ w.subWikifyTerm(w.output,this.termRegExp);
+ }
+},
+
+{
+ name: "macro",
+ match: "<<",
+ lookaheadRegExp: /<<([^>\s]+)(?:\s*)((?:[^>]|(?:>(?!>)))*)>>/mg,
+ handler: function(w)
+ {
+ this.lookaheadRegExp.lastIndex = w.matchStart;
+ var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
+ if(lookaheadMatch && lookaheadMatch.index == w.matchStart && lookaheadMatch[1])
+ {
+ w.nextMatch = this.lookaheadRegExp.lastIndex;
+ invokeMacro(w.output,lookaheadMatch[1],lookaheadMatch[2],w,w.tiddler);
+ }
+ }
+},
+
+{
+ name: "prettyLink",
+ match: "\\[\\[",
+ lookaheadRegExp: /\[\[(.*?)(?:\|(~)?(.*?))?\]\]/mg,
+ handler: function(w)
+ {
+ this.lookaheadRegExp.lastIndex = w.matchStart;
+ var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
+ if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
+ {
+ var e;
+ var text = lookaheadMatch[1];
+ if(lookaheadMatch[3])
+ {
+ // Pretty bracketted link
+ var link = lookaheadMatch[3];
+ e = (!lookaheadMatch[2] && config.formatterHelpers.isExternalLink(link))
+ ? createExternalLink(w.output,link)
+ : createTiddlyLink(w.output,link,false,null,w.isStatic);
+ }
+ else
+ {
+ // Simple bracketted link
+ e = createTiddlyLink(w.output,text,false,null,w.isStatic);
+ }
+ createTiddlyText(e,text);
+ w.nextMatch = this.lookaheadRegExp.lastIndex;
+ }
+ }
+},
+
+{
+ name: "unWikiLink",
+ match: config.textPrimitives.unWikiLink+config.textPrimitives.wikiLink,
+ handler: function(w)
+ {
+ w.outputText(w.output,w.matchStart+1,w.nextMatch);
+ }
+},
+
+{
+ name: "wikiLink",
+ match: config.textPrimitives.wikiLink,
+ handler: function(w)
+ {
+ if(w.matchStart > 0)
+ {
+ var preRegExp = new RegExp(config.textPrimitives.anyLetterStrict,"mg");
+ preRegExp.lastIndex = w.matchStart-1;
+ var preMatch = preRegExp.exec(w.source);
+ if(preMatch.index == w.matchStart-1)
+ {
+ w.outputText(w.output,w.matchStart,w.nextMatch);
+ return;
+ }
+ }
+ if(w.autoLinkWikiWords == true || store.isShadowTiddler(w.matchText))
+ {
+ var link = createTiddlyLink(w.output,w.matchText,false,null,w.isStatic);
+ w.outputText(link,w.matchStart,w.nextMatch);
+ }
+ else
+ {
+ w.outputText(w.output,w.matchStart,w.nextMatch);
+ }
+ }
+},
+
+{
+ name: "urlLink",
+ match: config.textPrimitives.urlPattern,
+ handler: function(w)
+ {
+ w.outputText(createExternalLink(w.output,w.matchText),w.matchStart,w.nextMatch);
+ }
+},
+
+{
+ name: "image",
+ match: "\\[[<>]?[Ii][Mm][Gg]\\[",
+ lookaheadRegExp: /\[(<?)(>?)[Ii][Mm][Gg]\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg,
+ handler: function(w)
+ {
+ this.lookaheadRegExp.lastIndex = w.matchStart;
+ var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
+ if(lookaheadMatch && lookaheadMatch.index == w.matchStart) // Simple bracketted link
+ {
+ var e = w.output;
+ if(lookaheadMatch[5])
+ {
+ var link = lookaheadMatch[5];
+ e = config.formatterHelpers.isExternalLink(link) ? createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic);
+ addClass(e,"imageLink");
+ }
+ var img = createTiddlyElement(e,"img");
+ if(lookaheadMatch[1])
+ img.align = "left";
+ else if(lookaheadMatch[2])
+ img.align = "right";
+ if(lookaheadMatch[3])
+ img.title = lookaheadMatch[3];
+ img.src = lookaheadMatch[4];
+ w.nextMatch = this.lookaheadRegExp.lastIndex;
+ }
+ }
+},
+
+{
+ name: "html",
+ match: "<[Hh][Tt][Mm][Ll]>",
+ lookaheadRegExp: /<[Hh][Tt][Mm][Ll]>((?:.|\n)*?)<\/[Hh][Tt][Mm][Ll]>/mg,
+ handler: function(w)
+ {
+ this.lookaheadRegExp.lastIndex = w.matchStart;
+ var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
+ if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
+ {
+ createTiddlyElement(w.output,"span").innerHTML = lookaheadMatch[1];
+ w.nextMatch = this.lookaheadRegExp.lastIndex;
+ }
+ }
+},
+
+{
+ name: "commentByBlock",
+ match: "/%",
+ lookaheadRegExp: /\/%((?:.|\n)*?)%\//mg,
+ handler: function(w)
+ {
+ this.lookaheadRegExp.lastIndex = w.matchStart;
+ var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
+ if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
+ w.nextMatch = this.lookaheadRegExp.lastIndex;
+ }
+},
+
+{
+ name: "boldByChar",
+ match: "''",
+ termRegExp: /('')/mg,
+ element: "strong",
+ handler: config.formatterHelpers.createElementAndWikify
+},
+
+{
+ name: "italicByChar",
+ match: "//",
+ termRegExp: /(\/\/)/mg,
+ element: "em",
+ handler: config.formatterHelpers.createElementAndWikify
+},
+
+{
+ name: "underlineByChar",
+ match: "__",
+ termRegExp: /(__)/mg,
+ element: "u",
+ handler: config.formatterHelpers.createElementAndWikify
+},
+
+{
+ name: "strikeByChar",
+ match: "--(?!\\s|$)",
+ termRegExp: /((?!\s)--|(?=\n\n))/mg,
+ element: "strike",
+ handler: config.formatterHelpers.createElementAndWikify
+},
+
+{
+ name: "superscriptByChar",
+ match: "\\^\\^",
+ termRegExp: /(\^\^)/mg,
+ element: "sup",
+ handler: config.formatterHelpers.createElementAndWikify
+},
+
+{
+ name: "subscriptByChar",
+ match: "~~",
+ termRegExp: /(~~)/mg,
+ element: "sub",
+ handler: config.formatterHelpers.createElementAndWikify
+},
+
+{
+ name: "monospacedByChar",
+ match: "\\{\\{\\{",
+ lookaheadRegExp: /\{\{\{((?:.|\n)*?)\}\}\}/mg,
+ handler: function(w)
+ {
+ this.lookaheadRegExp.lastIndex = w.matchStart;
+ var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
+ if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
+ {
+ createTiddlyElement(w.output,"code",null,null,lookaheadMatch[1]);
+ w.nextMatch = this.lookaheadRegExp.lastIndex;
+ }
+ }
+},
+
+{
+ name: "styleByChar",
+ match: "@@",
+ termRegExp: /(@@)/mg,
+ handler: function(w)
+ {
+ var e = createTiddlyElement(w.output,"span");
+ var styles = config.formatterHelpers.inlineCssHelper(w);
+ if(styles.length == 0)
+ e.className = "marked";
+ else
+ config.formatterHelpers.applyCssHelper(e,styles);
+ w.subWikifyTerm(e,this.termRegExp);
+ }
+},
+
+{
+ name: "lineBreak",
+ match: "\\n|<br ?/?>",
+ handler: function(w)
+ {
+ createTiddlyElement(w.output,"br");
+ }
+},
+
+{
+ name: "rawText",
+ match: "\\\"{3}|<nowiki>",
+ lookaheadRegExp: /(?:\"{3}|<nowiki>)((?:.|\n)*?)(?:\"{3}|<\/nowiki>)/mg,
+ handler: function(w)
+ {
+ this.lookaheadRegExp.lastIndex = w.matchStart;
+ var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
+ if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
+ {
+ createTiddlyElement(w.output,"span",null,null,lookaheadMatch[1]);
+ w.nextMatch = this.lookaheadRegExp.lastIndex;
+ }
+ }
+},
+
+{
+ name: "mdash",
+ match: "--",
+ handler: function(w)
+ {
+ createTiddlyElement(w.output,"span").innerHTML = "—";
+ }
+},
+
+{
+ name: "htmlEntitiesEncoding",
+ match: "(?:(?:&#?[a-zA-Z0-9]{2,8};|.)(?:&#?(?:x0*(?:3[0-6][0-9a-fA-F]|1D[c-fC-F][0-9a-fA-F]|20[d-fD-F][0-9a-fA-F]|FE2[0-9a-fA-F])|0*(?:76[89]|7[7-9][0-9]|8[0-7][0-9]|761[6-9]|76[2-7][0-9]|84[0-3][0-9]|844[0-7]|6505[6-9]|6506[0-9]|6507[0-1]));)+|&#?[a-zA-Z0-9]{2,8};)",
+ handler: function(w)
+ {
+ createTiddlyElement(w.output,"span").innerHTML = w.matchText;
+ }
+},
+
+{
+ name: "customClasses",
+ match: "\\{\\{",
+ termRegExp: /(\}\}\})/mg,
+ lookaheadRegExp: /\{\{[\s]*([\w]+[\s\w]*)[\s]*\{(\n?)/mg,
+ handler: function(w)
+ {
+ this.lookaheadRegExp.lastIndex = w.matchStart;
+ var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
+ if(lookaheadMatch)
+ {
+ var e = createTiddlyElement(w.output,lookaheadMatch[2] == "\n" ? "div" : "span",null,lookaheadMatch[1]);
+ w.nextMatch = this.lookaheadRegExp.lastIndex;
+ w.subWikifyTerm(e,this.termRegExp);
+ }
+ }
+}
+
+];
+
+// ---------------------------------------------------------------------------------
+// Wikifier
+// ---------------------------------------------------------------------------------
+
+function getParser(tiddler)
+{
+ var f = formatter;
+ if(tiddler!=null)
+ {
+ for(var i in config.parsers)
+ {
+ if(tiddler.isTagged(config.parsers[i].formatTag))
+ {
+ f = config.parsers[i];
+ break;
+ }
+ }
+ }
+ return f;
+}
+
+function wikify(source,output,highlightRegExp,tiddler)
+{
+ if(source && source != "")
+ {
+ var wikifier = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler);
+ wikifier.subWikifyUnterm(output);
+ }
+}
+
+function wikifyStatic(source,highlightRegExp,tiddler)
+{
+ var e = createTiddlyElement(document.body,"div");
+ e.style.display = "none";
+ var html = "";
+ if(source && source != "")
+ {
+ var wikifier = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler);
+ wikifier.isStatic = true;
+ wikifier.subWikifyUnterm(e);
+ html = e.innerHTML;
+ e.parentNode.removeChild(e);
+ }
+ return html;
+}
+
+// Wikify a named tiddler to plain text
+function wikifyPlain(title)
+{
+ if(store.tiddlerExists(title) || store.isShadowTiddler(title))
+ {
+ var wikifier = new Wikifier(store.getTiddlerText(title),formatter,null,store.getTiddler(title));
+ return wikifier.wikifyPlain();
+ }
+ else
+ return "";
+}
+
+// Highlight plain text into an element
+function highlightify(source,output,highlightRegExp)
+{
+ if(source && source != "")
+ {
+ var wikifier = new Wikifier(source,formatter,highlightRegExp);
+ wikifier.outputText(output,0,source.length);
+ }
+}
+
+// Construct a wikifier object
+// source - source string that's going to be wikified
+// formatter - Formatter() object containing the list of formatters to be used
+// highlightRegExp - regular expression of the text string to highlight
+// tiddler - reference to the tiddler that's taken to be the container for this wikification
+function Wikifier(source,formatter,highlightRegExp,tiddler)
+{
+ this.source = source;
+ this.output = null;
+ this.formatter = formatter;
+ this.nextMatch = 0;
+ this.autoLinkWikiWords = tiddler && tiddler.autoLinkWikiWords() == false ? false : true;
+ this.highlightRegExp = highlightRegExp;
+ this.highlightMatch = null;
+ this.isStatic = false;
+ if(highlightRegExp)
+ {
+ highlightRegExp.lastIndex = 0;
+ this.highlightMatch = highlightRegExp.exec(source);
+ }
+ this.tiddler = tiddler;
+}
+
+Wikifier.prototype.wikifyPlain = function()
+{
+ var e = createTiddlyElement(document.body,"div");
+ e.style.display = "none";
+ this.subWikify(e);
+ var text = getPlainText(e);
+ e.parentNode.removeChild(e);
+ return text;
+}
+
+Wikifier.prototype.subWikify = function(output,terminator)
+{
+ // Handle the terminated and unterminated cases separately
+ if (terminator)
+ this.subWikifyTerm(output,new RegExp("(" + terminator + ")","mg"));
+ else
+ this.subWikifyUnterm(output);
+}
+
+Wikifier.prototype.subWikifyUnterm = function(output)
+{
+ // subWikify() can be indirectly recursive, so we need to save the old output pointer
+ var oldOutput = this.output;
+ this.output = output;
+ // Get the first match
+ this.formatter.formatterRegExp.lastIndex = this.nextMatch;
+ var formatterMatch = this.formatter.formatterRegExp.exec(this.source);
+ while(formatterMatch)
+ {
+ // Output any text before the match
+ if(formatterMatch.index > this.nextMatch)
+ this.outputText(this.output,this.nextMatch,formatterMatch.index);
+ // Set the match parameters for the handler
+ this.matchStart = formatterMatch.index;
+ this.matchLength = formatterMatch[0].length;
+ this.matchText = formatterMatch[0];
+ this.nextMatch = this.formatter.formatterRegExp.lastIndex;
+ // Figure out which formatter matched and call its handler
+ for(var t=1; t<formatterMatch.length; t++)
+ {
+ if(formatterMatch[t])
+ {
+ this.formatter.formatters[t-1].handler(this);
+ this.formatter.formatterRegExp.lastIndex = this.nextMatch;
+ break;
+ }
+ }
+ // Get the next match
+ formatterMatch = this.formatter.formatterRegExp.exec(this.source);
+ }
+ // Output any text after the last match
+ if(this.nextMatch < this.source.length)
+ {
+ this.outputText(this.output,this.nextMatch,this.source.length);
+ this.nextMatch = this.source.length;
+ }
+ // Restore the output pointer
+ this.output = oldOutput;
+}
+
+Wikifier.prototype.subWikifyTerm = function(output,terminatorRegExp)
+{
+ // subWikify() can be indirectly recursive, so we need to save the old output pointer
+ var oldOutput = this.output;
+ this.output = output;
+ // Get the first matches for the formatter and terminator RegExps
+ terminatorRegExp.lastIndex = this.nextMatch;
+ var terminatorMatch = terminatorRegExp.exec(this.source);
+ this.formatter.formatterRegExp.lastIndex = this.nextMatch;
+ var formatterMatch = this.formatter.formatterRegExp.exec(terminatorMatch ? this.source.substr(0,terminatorMatch.index) : this.source);
+ while(terminatorMatch || formatterMatch)
+ {
+ // Check for a terminator match before the next formatter match
+ if(terminatorMatch && (!formatterMatch || terminatorMatch.index <= formatterMatch.index))
+ {
+ // Output any text before the match
+ if(terminatorMatch.index > this.nextMatch)
+ this.outputText(this.output,this.nextMatch,terminatorMatch.index);
+ // Set the match parameters
+ this.matchText = terminatorMatch[1];
+ this.matchLength = terminatorMatch[1].length;
+ this.matchStart = terminatorMatch.index;
+ this.nextMatch = this.matchStart + this.matchLength;
+ // Restore the output pointer
+ this.output = oldOutput;
+ return;
+ }
+ // It must be a formatter match; output any text before the match
+ if(formatterMatch.index > this.nextMatch)
+ this.outputText(this.output,this.nextMatch,formatterMatch.index);
+ // Set the match parameters
+ this.matchStart = formatterMatch.index;
+ this.matchLength = formatterMatch[0].length;
+ this.matchText = formatterMatch[0];
+ this.nextMatch = this.formatter.formatterRegExp.lastIndex;
+ // Figure out which formatter matched and call its handler
+ for(var t=1; t<formatterMatch.length; t++)
+ {
+ if(formatterMatch[t])
+ {
+ this.formatter.formatters[t-1].handler(this);
+ this.formatter.formatterRegExp.lastIndex = this.nextMatch;
+ break;
+ }
+ }
+ // Get the next match
+ terminatorRegExp.lastIndex = this.nextMatch;
+ terminatorMatch = terminatorRegExp.exec(this.source);
+ formatterMatch = this.formatter.formatterRegExp.exec(terminatorMatch ? this.source.substr(0,terminatorMatch.index) : this.source);
+ }
+ // Output any text after the last match
+ if(this.nextMatch < this.source.length)
+ {
+ this.outputText(this.output,this.nextMatch,this.source.length);
+ this.nextMatch = this.source.length;
+ }
+ // Restore the output pointer
+ this.output = oldOutput;
+}
+
+Wikifier.prototype.outputText = function(place,startPos,endPos)
+{
+ // Check for highlights
+ while(this.highlightMatch && (this.highlightRegExp.lastIndex > startPos) && (this.highlightMatch.index < endPos) && (startPos < endPos))
+ {
+ // Deal with any plain text before the highlight
+ if(this.highlightMatch.index > startPos)
+ {
+ createTiddlyText(place,this.source.substring(startPos,this.highlightMatch.index));
+ startPos = this.highlightMatch.index;
+ }
+ // Deal with the highlight
+ var highlightEnd = Math.min(this.highlightRegExp.lastIndex,endPos);
+ var theHighlight = createTiddlyElement(place,"span",null,"highlight",this.source.substring(startPos,highlightEnd));
+ startPos = highlightEnd;
+ // Nudge along to the next highlight if we're done with this one
+ if(startPos >= this.highlightRegExp.lastIndex)
+ this.highlightMatch = this.highlightRegExp.exec(this.source);
+ }
+ // Do the unhighlighted text left over
+ if(startPos < endPos)
+ {
+ createTiddlyText(place,this.source.substring(startPos,endPos));
+ }
+}
+
+// ---------------------------------------------------------------------------------
+// Macro definitions
+// ---------------------------------------------------------------------------------
+
+config.macros.today.handler = function(place,macroName,params)
+{
+ var now = new Date();
+ var text;
+ if(params[0])
+ text = now.formatString(params[0].trim());
+ else
+ text = now.toLocaleString();
+ createTiddlyElement(place,"span",null,null,text);
+}
+
+config.macros.version.handler = function(place)
+{
+ createTiddlyElement(place,"span",null,null,version.major + "." + version.minor + "." + version.revision + (version.beta ? " (beta " + version.beta + ")" : ""));
+}
+
+config.macros.list.handler = function(place,macroName,params)
+{
+ var type = params[0] ? params[0] : "all";
+ var theList = document.createElement("ul");
+ place.appendChild(theList);
+ if(this[type].prompt)
+ createTiddlyElement(theList,"li",null,"listTitle",this[type].prompt);
+ var results;
+ if(this[type].handler)
+ results = this[type].handler(params);
+ for(var t = 0; t < results.length; t++)
+ {
+ var theListItem = document.createElement("li")
+ theList.appendChild(theListItem);
+ if(typeof results[t] == "string")
+ createTiddlyLink(theListItem,results[t],true);
+ else
+ createTiddlyLink(theListItem,results[t].title,true);
+ }
+}
+
+config.macros.list.all.handler = function(params)
+{
+ return store.reverseLookup("tags","excludeLists",false,"title");
+}
+
+config.macros.list.missing.handler = function(params)
+{
+ return store.getMissingLinks();
+}
+
+config.macros.list.orphans.handler = function(params)
+{
+ return store.getOrphans();
+}
+
+config.macros.list.shadowed.handler = function(params)
+{
+ return store.getShadowed();
+}
+
+config.macros.allTags.handler = function(place,macroName,params)
+{
+ var tags = store.getTags();
+ var theDateList = createTiddlyElement(place,"ul");
+ if(tags.length == 0)
+ createTiddlyElement(theDateList,"li",null,"listTitle",this.noTags);
+ for(var t=0; t<tags.length; t++)
+ {
+ var theListItem =createTiddlyElement(theDateList,"li");
+ var theTag = createTiddlyButton(theListItem,tags[t][0] + " (" + tags[t][1] + ")",this.tooltip.format([tags[t][0]]),onClickTag);
+ theTag.setAttribute("tag",tags[t][0]);
+ }
+}
+
+config.macros.timeline.handler = function(place,macroName,params)
+{
+ var field = params[0] ? params[0] : "modified";
+ var tiddlers = store.reverseLookup("tags","excludeLists",false,field);
+ var lastDay = "";
+ var last = params[1] ? tiddlers.length-Math.min(tiddlers.length,parseInt(params[1])) : 0;
+ for(var t=tiddlers.length-1; t>=last; t--)
+ {
+ var tiddler = tiddlers[t];
+ var theDay = tiddler[field].convertToLocalYYYYMMDDHHMM().substr(0,8);
+ if(theDay != lastDay)
+ {
+ var theDateList = document.createElement("ul");
+ place.appendChild(theDateList);
+ createTiddlyElement(theDateList,"li",null,"listTitle",tiddler[field].formatString(this.dateFormat));
+ lastDay = theDay;
+ }
+ var theDateListItem = createTiddlyElement(theDateList,"li",null,"listLink");
+ theDateListItem.appendChild(createTiddlyLink(place,tiddler.title,true));
+ }
+}
+
+config.macros.search.handler = function(place,macroName,params)
+{
+ var searchTimeout = null;
+ var btn = createTiddlyButton(place,this.label,this.prompt,this.onClick);
+ var txt = createTiddlyElement(place,"input",null,"txtOptionInput");
+ if(params[0])
+ txt.value = params[0];
+ txt.onkeyup = this.onKeyPress;
+ txt.onfocus = this.onFocus;
+ txt.setAttribute("size",this.sizeTextbox);
+ txt.setAttribute("accessKey",this.accessKey);
+ txt.setAttribute("autocomplete","off");
+ txt.setAttribute("lastSearchText","");
+ if(config.browser.isSafari)
+ {
+ txt.setAttribute("type","search");
+ txt.setAttribute("results","5");
+ }
+ else
+ txt.setAttribute("type","text");
+}
+
+// Global because there's only ever one outstanding incremental search timer
+config.macros.search.timeout = null;
+
+config.macros.search.doSearch = function(txt)
+{
+ if(txt.value.length > 0)
+ {
+ story.search(txt.value,config.options.chkCaseSensitiveSearch,config.options.chkRegExpSearch);
+ txt.setAttribute("lastSearchText",txt.value);
+ }
+}
+
+config.macros.search.onClick = function(e)
+{
+ config.macros.search.doSearch(this.nextSibling);
+ return false;
+}
+
+config.macros.search.onKeyPress = function(e)
+{
+ if(!e) var e = window.event;
+ switch(e.keyCode)
+ {
+ case 13: // Ctrl-Enter
+ case 10: // Ctrl-Enter on IE PC
+ config.macros.search.doSearch(this);
+ break;
+ case 27: // Escape
+ this.value = "";
+ clearMessage();
+ break;
+ }
+ if(this.value.length > 2)
+ {
+ if(this.value != this.getAttribute("lastSearchText"))
+ {
+ if(config.macros.search.timeout)
+ clearTimeout(config.macros.search.timeout);
+ var txt = this;
+ config.macros.search.timeout = setTimeout(function() {config.macros.search.doSearch(txt);},500);
+ }
+ }
+ else
+ {
+ if(config.macros.search.timeout)
+ clearTimeout(config.macros.search.timeout);
+ }
+}
+
+config.macros.search.onFocus = function(e)
+{
+ this.select();
+}
+
+config.macros.tiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler)
+{
+ params = paramString.parseParams("name",null,true,false,true);
+ var names = params[0]["name"];
+ var tiddlerName = names[0];
+ var className = names[1] ? names[1] : null;
+ var args = params[0]["with"];
+ var wrapper = createTiddlyElement(place,"span",null,className);
+ if(!args)
+ {
+ wrapper.setAttribute("refresh","content");
+ wrapper.setAttribute("tiddler",tiddlerName);
+ }
+ var text = store.getTiddlerText(tiddlerName);
+ if(text)
+ {
+ var stack = config.macros.tiddler.tiddlerStack;
+ if(stack.indexOf(tiddlerName) !== -1)
+ return;
+ stack.push(tiddlerName);
+ try
+ {
+ var n = args ? Math.min(args.length,9) : 0;
+ for(var i=0; i<n; i++)
+ {
+ var placeholderRE = new RegExp("\\$" + (i + 1),"mg");
+ text = text.replace(placeholderRE,args[i]);
+ }
+ config.macros.tiddler.renderText(wrapper,text,tiddlerName,params);
+ }
+ finally
+ {
+ stack.pop();
+ }
+ }
+}
+
+config.macros.tiddler.renderText = function(place,text,tiddlerName,params)
+{
+ wikify(text,place,null,store.getTiddler(tiddlerName));
+}
+
+config.macros.tiddler.tiddlerStack = [];
+
+config.macros.tag.handler = function(place,macroName,params)
+{
+ createTagButton(place,params[0]);
+}
+
+config.macros.tags.handler = function(place,macroName,params,wikifier,paramString,tiddler)
+{
+ params = paramString.parseParams("anon",null,true,false,false);
+ var theList = createTiddlyElement(place,"ul");
+ var title = getParam(params,"anon","");
+ if(title && store.tiddlerExists(title))
+ tiddler = store.getTiddler(title);
+ var sep = getParam(params,"sep"," ");
+ var lingo = config.views.wikified.tag;
+ var prompt = tiddler.tags.length == 0 ? lingo.labelNoTags : lingo.labelTags;
+ createTiddlyElement(theList,"li",null,"listTitle",prompt.format([tiddler.title]));
+ for(var t=0; t<tiddler.tags.length; t++)
+ {
+ createTagButton(createTiddlyElement(theList,"li"),tiddler.tags[t],tiddler.title);
+ if(t<tiddler.tags.length-1)
+ createTiddlyText(theList,sep);
+ }
+}
+
+config.macros.tagging.handler = function(place,macroName,params,wikifier,paramString,tiddler)
+{
+ params = paramString.parseParams("anon",null,true,false,false);
+ var theList = createTiddlyElement(place,"ul");
+ var title = getParam(params,"anon","");
+ if(title == "" && tiddler instanceof Tiddler)
+ title = tiddler.title;
+ var sep = getParam(params,"sep"," ");
+ theList.setAttribute("title",this.tooltip.format([title]));
+ var tagged = store.getTaggedTiddlers(title);
+ var prompt = tagged.length == 0 ? this.labelNotTag : this.label;
+ createTiddlyElement(theList,"li",null,"listTitle",prompt.format([title,tagged.length]));
+ for(var t=0; t<tagged.length; t++)
+ {
+ createTiddlyLink(createTiddlyElement(theList,"li"),tagged[t].title,true);
+ if(t<tagged.length-1)
+ createTiddlyText(theList,sep);
+ }
+}
+
+config.macros.closeAll.handler = function(place)
+{
+ createTiddlyButton(place,this.label,this.prompt,this.onClick);
+}
+
+config.macros.closeAll.onClick = function(e)
+{
+ story.closeAllTiddlers();
+ return false;
+}
+
+config.macros.permaview.handler = function(place)
+{
+ createTiddlyButton(place,this.label,this.prompt,this.onClick);
+}
+
+config.macros.permaview.onClick = function(e)
+{
+ story.permaView();
+ return false;
+}
+
+config.macros.saveChanges.handler = function(place)
+{
+ if(!readOnly)
+ createTiddlyButton(place,this.label,this.prompt,this.onClick,null,null,this.accessKey);
+}
+
+config.macros.saveChanges.onClick = function(e)
+{
+ saveChanges();
+ return false;
+}
+
+config.macros.slider.onClickSlider = function(e)
+{
+ if(!e) var e = window.event;
+ var n = this.nextSibling;
+ var cookie = n.getAttribute("cookie");
+ var isOpen = n.style.display != "none";
+ if(anim && config.options.chkAnimate)
+ anim.startAnimating(new Slider(n,!isOpen,e.shiftKey || e.altKey,"none"));
+ else
+ n.style.display = isOpen ? "none" : "block";
+ config.options[cookie] = !isOpen;
+ saveOptionCookie(cookie);
+ return false;
+}
+
+config.macros.slider.createSlider = function(place,cookie,title,tooltip)
+{
+ var cookie = cookie ? cookie : "";
+ var btn = createTiddlyButton(place,title,tooltip,this.onClickSlider);
+ var panel = createTiddlyElement(null,"div",null,"sliderPanel");
+ panel.setAttribute("cookie",cookie);
+ panel.style.display = config.options[cookie] ? "block" : "none";
+ place.appendChild(panel);
+ return panel;
+}
+
+config.macros.slider.handler = function(place,macroName,params)
+{
+ var panel = this.createSlider(place,params[0],params[2],params[3]);
+ var text = store.getTiddlerText(params[1]);
+ panel.setAttribute("refresh", "content");
+ panel.setAttribute("tiddler", params[1]);
+ if(text)
+ wikify(text,panel,null,store.getTiddler(params[1]));
+}
+
+config.macros.option.onChangeOption = function(e)
+{
+ var opt = this.getAttribute("option");
+ var elementType,valueField;
+ if(opt)
+ {
+ switch(opt.substr(0,3))
+ {
+ case "txt":
+ elementType = "input";
+ valueField = "value";
+ break;
+ case "chk":
+ elementType = "input";
+ valueField = "checked";
+ break;
+ }
+ config.options[opt] = this[valueField];
+ saveOptionCookie(opt);
+ var nodes = document.getElementsByTagName(elementType);
+ for(var t=0; t<nodes.length; t++)
+ {
+ var optNode = nodes[t].getAttribute("option");
+ if(opt == optNode)
+ nodes[t][valueField] = this[valueField];
+ }
+ }
+ return(true);
+}
+
+config.macros.option.handler = function(place,macroName,params)
+{
+ var opt = params[0];
+ if(config.options[opt] == undefined)
+ return;
+ var c;
+ switch(opt.substr(0,3))
+ {
+ case "txt":
+ c = document.createElement("input");
+ c.onkeyup = this.onChangeOption;
+ c.setAttribute("option",opt);
+ c.className = "txtOptionInput";
+ place.appendChild(c);
+ c.value = config.options[opt];
+ break;
+ case "chk":
+ c = document.createElement("input");
+ c.setAttribute("type","checkbox");
+ c.onclick = this.onChangeOption;
+ c.setAttribute("option",opt);
+ c.className = "chkOptionInput";
+ place.appendChild(c);
+ c.checked = config.options[opt];
+ break;
+ }
+}
+
+
+
+config.macros.newTiddler.createNewTiddlerButton = function(place,title,params,label,prompt,accessKey,newFocus,isJournal)
+{
+ var tags = [];
+ for(var t=1; t<params.length; t++)
+ if((params[t].name == "anon" && t != 1) || (params[t].name == "tag"))
+ tags.push(params[t].value);
+ label = getParam(params,"label",label);
+ prompt = getParam(params,"prompt",prompt);
+ accessKey = getParam(params,"accessKey",accessKey);
+ newFocus = getParam(params,"focus",newFocus);
+ var btn = createTiddlyButton(place,label,prompt,this.onClickNewTiddler,null,null,accessKey);
+ btn.setAttribute("newTitle",title);
+ btn.setAttribute("isJournal",isJournal);
+ btn.setAttribute("params",tags.join("|"));
+ btn.setAttribute("newFocus",newFocus);
+ btn.setAttribute("newTemplate",getParam(params,"template",DEFAULT_EDIT_TEMPLATE));
+ var text = getParam(params,"text");
+ if(text !== undefined)
+ btn.setAttribute("newText",text);
+ return btn;
+}
+
+config.macros.newTiddler.onClickNewTiddler = function()
+{
+ var title = this.getAttribute("newTitle");
+ if(this.getAttribute("isJournal"))
+ {
+ var now = new Date();
+ title = now.formatString(title.trim());
+ }
+ var params = this.getAttribute("params").split("|");
+ var focus = this.getAttribute("newFocus");
+ var template = this.getAttribute("newTemplate");
+ story.displayTiddler(null,title,template);
+ var text = this.getAttribute("newText");
+ if(typeof text == "string")
+ story.getTiddlerField(title,"text").value = text.format([title]);
+ for(var t=0;t<params.length;t++)
+ story.setTiddlerTag(title,params[t],+1);
+ story.focusTiddler(title,focus);
+ return false;
+}
+
+config.macros.newTiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler)
+{
+ if(!readOnly)
+ {
+ params = paramString.parseParams("anon",null,true,false,false);
+ var title = params[1] && params[1].name == "anon" ? params[1].value : this.title;
+ title = getParam(params,"title",title);
+ this.createNewTiddlerButton(place,title,params,this.label,this.prompt,this.accessKey,"title",false);
+ }
+}
+
+config.macros.newJournal.handler = function(place,macroName,params,wikifier,paramString,tiddler)
+{
+ if(!readOnly)
+ {
+ params = paramString.parseParams("anon",null,true,false,false);
+ var title = params[1] && params[1].name == "anon" ? params[1].value : "";
+ title = getParam(params,"title",title);
+ config.macros.newTiddler.createNewTiddlerButton(place,title,params,this.label,this.prompt,this.accessKey,"text",true);
+ }
+}
+
+config.macros.sparkline.handler = function(place,macroName,params)
+{
+ var data = [];
+ var min = 0;
+ var max = 0;
+ for(var t=0; t<params.length; t++)
+ {
+ var v = parseInt(params[t]);
+ if(v < min)
+ min = v;
+ if(v > max)
+ max = v;
+ data.push(v);
+ }
+ if(data.length < 1)
+ return;
+ var box = createTiddlyElement(place,"span",null,"sparkline",String.fromCharCode(160));
+ box.title = data.join(",");
+ var w = box.offsetWidth;
+ var h = box.offsetHeight;
+ box.style.paddingRight = (data.length * 2 - w) + "px";
+ box.style.position = "relative";
+ for(var d=0; d<data.length; d++)
+ {
+ var tick = document.createElement("img");
+ tick.border = 0;
+ tick.className = "sparktick";
+ tick.style.position = "absolute";
+ tick.src = "data:image/gif,GIF89a%01%00%01%00%91%FF%00%FF%FF%FF%00%00%00%C0%C0%C0%00%00%00!%F9%04%01%00%00%02%00%2C%00%00%00%00%01%00%01%00%40%02%02T%01%00%3B";
+ tick.style.left = d*2 + "px";
+ tick.style.width = "2px";
+ var v = Math.floor(((data[d] - min)/(max-min)) * h);
+ tick.style.top = (h-v) + "px";
+ tick.style.height = v + "px";
+ box.appendChild(tick);
+ }
+}
+
+config.macros.tabs.handler = function(place,macroName,params)
+{
+ var cookie = params[0];
+ var numTabs = (params.length-1)/3;
+ var wrapper = createTiddlyElement(null,"div",null,cookie);
+ var tabset = createTiddlyElement(wrapper,"div",null,"tabset");
+ tabset.setAttribute("cookie",cookie);
+ var validTab = false;
+ for(var t=0; t<numTabs; t++)
+ {
+ var label = params[t*3+1];
+ var prompt = params[t*3+2];
+ var content = params[t*3+3];
+ var tab = createTiddlyButton(tabset,label,prompt,this.onClickTab,"tab tabUnselected");
+ tab.setAttribute("tab",label);
+ tab.setAttribute("content",content);
+ tab.title = prompt;
+ if(config.options[cookie] == label)
+ validTab = true;
+ }
+ if(!validTab)
+ config.options[cookie] = params[1];
+ place.appendChild(wrapper);
+ this.switchTab(tabset,config.options[cookie]);
+}
+
+config.macros.tabs.onClickTab = function(e)
+{
+ config.macros.tabs.switchTab(this.parentNode,this.getAttribute("tab"));
+ return false;
+}
+
+config.macros.tabs.switchTab = function(tabset,tab)
+{
+ var cookie = tabset.getAttribute("cookie");
+ var theTab = null
+ var nodes = tabset.childNodes;
+ for(var t=0; t<nodes.length; t++)
+ if(nodes[t].getAttribute && nodes[t].getAttribute("tab") == tab)
+ {
+ theTab = nodes[t];
+ theTab.className = "tab tabSelected";
+ }
+ else
+ nodes[t].className = "tab tabUnselected"
+ if(theTab)
+ {
+ if(tabset.nextSibling && tabset.nextSibling.className == "tabContents")
+ tabset.parentNode.removeChild(tabset.nextSibling);
+ var tabContent = createTiddlyElement(null,"div",null,"tabContents");
+ tabset.parentNode.insertBefore(tabContent,tabset.nextSibling);
+ var contentTitle = theTab.getAttribute("content");
+ wikify(store.getTiddlerText(contentTitle),tabContent,null,store.getTiddler(contentTitle));
+ if(cookie)
+ {
+ config.options[cookie] = tab;
+ saveOptionCookie(cookie);
+ }
+ }
+}
+
+// <<gradient [[tiddler name]] vert|horiz rgb rgb rgb rgb... >>
+config.macros.gradient.handler = function(place,macroName,params,wikifier)
+{
+ var terminator = ">>";
+ var panel;
+ if(wikifier)
+ panel = createTiddlyElement(place,"div",null,"gradient");
+ else
+ panel = place;
+ panel.style.position = "relative";
+ panel.style.overflow = "hidden";
+ panel.style.zIndex = "0";
+ var t;
+ if(wikifier)
+ {
+ var styles = config.formatterHelpers.inlineCssHelper(wikifier);
+ config.formatterHelpers.applyCssHelper(panel,styles);
+ }
+ var colours = [];
+ for(t=1; t<params.length; t++)
+ {
+ var c = new RGB(params[t]);
+ if(c)
+ colours.push(c);
+ }
+ drawGradient(panel,params[0] != "vert",colours);
+ if(wikifier)
+ wikifier.subWikify(panel,terminator);
+ if(document.all)
+ {
+ panel.style.height = "100%";
+ panel.style.width = "100%";
+ }
+}
+
+config.macros.message.handler = function(place,macroName,params)
+{
+ if(params[0])
+ {
+ var m = config;
+ var p = params[0].split(".");
+ for(var t=0; t<p.length; t++)
+ {
+ if(p[t] in m)
+ m = m[p[t]];
+ else
+ break;
+ }
+ createTiddlyText(place,m.toString().format(params.splice(1)));
+ }
+}
+
+config.macros.view.handler = function(place,macroName,params,wikifier,paramString,tiddler)
+{
+ if((tiddler instanceof Tiddler) && params[0])
+ {
+ var value = store.getValue(tiddler,params[0]);
+ if(value != undefined)
+ switch(params[1])
+ {
+ case undefined:
+ highlightify(value,place,highlightHack);
+ break;
+ case "link":
+ createTiddlyLink(place,value,true);
+ break;
+ case "wikified":
+ wikify(value,place,highlightHack,tiddler);
+ break;
+ case "date":
+ value = Date.convertFromYYYYMMDDHHMM(value);
+ if(params[2])
+ createTiddlyText(place,value.formatString(params[2]));
+ else
+ createTiddlyText(place,value);
+ break;
+ }
+ }
+}
+
+config.macros.edit.handler = function(place,macroName,params,wikifier,paramString,tiddler)
+{
+ var field = params[0];
+ if((tiddler instanceof Tiddler) && field)
+ {
+ story.setDirty(tiddler.title,true);
+ if(field != "text")
+ {
+ var e = createTiddlyElement(null,"input");
+ if(tiddler.isReadOnly())
+ e.setAttribute("readOnly","readOnly");
+ e.setAttribute("edit",field);
+ e.setAttribute("type","text");
+ var v = store.getValue(tiddler,field);
+ if(!v)
+ v = "";
+ e.value = v;
+ e.setAttribute("size","40");
+ e.setAttribute("autocomplete","off");
+ place.appendChild(e);
+ }
+ else
+ {
+ var wrapper1 = createTiddlyElement(null,"fieldset",null,"fieldsetFix");
+ var wrapper2 = createTiddlyElement(wrapper1,"div");
+ var e = createTiddlyElement(wrapper2,"textarea");
+ if(tiddler.isReadOnly())
+ e.setAttribute("readOnly","readOnly");
+ var v = store.getValue(tiddler,field);
+ if(!v)
+ v = "";
+ e.value = v;
+ var rows = 10;
+ var lines = v.match(/\n/mg);
+ var maxLines = Math.max(parseInt(config.options.txtMaxEditRows),5);
+ if(lines != null && lines.length > rows)
+ rows = lines.length + 5;
+ rows = Math.min(rows,maxLines);
+ e.setAttribute("rows",rows);
+ e.setAttribute("edit",field);
+ place.appendChild(wrapper1);
+ }
+ }
+}
+
+config.macros.tagChooser.onClick = function(e)
+{
+ if(!e) var e = window.event;
+ var lingo = config.views.editor.tagChooser;
+ var popup = Popup.create(this);
+ var tags = store.getTags();
+ if(tags.length == 0)
+ createTiddlyText(createTiddlyElement(popup,"li"),lingo.popupNone);
+ for(var t=0; t<tags.length; t++)
+ {
+ var theTag = createTiddlyButton(createTiddlyElement(popup,"li"),tags[t][0],lingo.tagTooltip.format([tags[t][0]]),config.macros.tagChooser.onTagClick);
+ theTag.setAttribute("tag",tags[t][0]);
+ theTag.setAttribute("tiddler", this.getAttribute("tiddler"));
+ }
+ Popup.show(popup,false);
+ e.cancelBubble = true;
+ if(e.stopPropagation) e.stopPropagation();
+ return(false);
+}
+
+config.macros.tagChooser.onTagClick = function(e)
+{
+ if(!e) var e = window.event;
+ var tag = this.getAttribute("tag");
+ var title = this.getAttribute("tiddler");
+ if(!readOnly)
+ story.setTiddlerTag(title,tag,0);
+ return(false);
+}
+
+config.macros.tagChooser.handler = function(place,macroName,params,wikifier,paramString,tiddler)
+{
+ if(tiddler instanceof Tiddler)
+ {
+ var title = tiddler.title;
+ var lingo = config.views.editor.tagChooser;
+ var btn = createTiddlyButton(place,lingo.text,lingo.tooltip,this.onClick);
+ btn.setAttribute("tiddler", title);
+ }
+}
+
+// Create a toolbar command button
+// place - parent DOM element
+// command - reference to config.commands[] member -or- name of member
+// tiddler - reference to tiddler that toolbar applies to
+// theClass - the class to give the button
+config.macros.toolbar.createCommand = function(place,commandName,tiddler,theClass)
+{
+ if(typeof commandName != "string")
+ {
+ var c = null;
+ for(var t in config.commands)
+ if(config.commands[t] == commandName)
+ c = t;
+ commandName = c;
+ }
+ if((tiddler instanceof Tiddler) && (typeof commandName == "string"))
+ {
+ var title = tiddler.title;
+ var command = config.commands[commandName];
+ var ro = tiddler.isReadOnly();
+ var shadow = store.isShadowTiddler(title) && !store.tiddlerExists(title);
+ var text = ro && command.readOnlyText ? command.readOnlyText : command.text;
+ var tooltip = ro && command.readOnlyTooltip ? command.readOnlyTooltip : command.tooltip;
+ if((!ro || (ro && !command.hideReadOnly)) && !(shadow && command.hideShadow))
+
+ {
+ var btn = createTiddlyButton(null,text,tooltip,this.onClickCommand);
+ btn.setAttribute("commandName", commandName);
+ btn.setAttribute("tiddler", title);
+ if(theClass)
+ addClass(btn,theClass);
+ place.appendChild(btn);
+ }
+ }
+}
+
+config.macros.toolbar.onClickCommand = function(e)
+{
+ if(!e) var e = window.event;
+ var command = config.commands[this.getAttribute("commandName")];
+ return command.handler(e,this,this.getAttribute("tiddler"));
+}
+
+// Invoke the first command encountered from a given place that is tagged with a specified class
+config.macros.toolbar.invokeCommand = function(place,theClass,event)
+{
+ var children = place.getElementsByTagName("a")
+ for(var t=0; t<children.length; t++)
+ {
+ var c = children[t];
+ if(hasClass(c,theClass) && c.getAttribute && c.getAttribute("commandName"))
+ {
+ if(c.onclick instanceof Function)
+ c.onclick.call(c,event);
+ break;
+ }
+ }
+}
+
+config.macros.toolbar.handler = function(place,macroName,params,wikifier,paramString,tiddler)
+{
+ for(var t=0; t<params.length; t++)
+ {
+ var c = params[t];
+ var theClass = "";
+ switch(c.substr(0,1))
+ {
+ case "+":
+ theClass = "defaultCommand";
+ c = c.substr(1);
+ break;
+ case "-":
+ theClass = "cancelCommand";
+ c = c.substr(1);
+ break;
+ }
+ if(c in config.commands)
+ this.createCommand(place,c,tiddler,theClass);
+ }
+}
+
+config.macros.plugins.handler = function(place,macroName,params,wikifier,paramString,tiddler)
+{
+ var e = createTiddlyElement(place,"div");
+ e.setAttribute("refresh","macro");
+ e.setAttribute("macroName","plugins");
+ e.setAttribute("params",paramString);
+ this.refresh(e,paramString);
+}
+
+config.macros.plugins.refresh = function(place,params)
+{
+ var selectedRows = [];
+ ListView.forEachSelector(place,function(e,rowName) {
+ if(e.checked)
+ selectedRows.push(e.getAttribute("rowName"));
+ });
+ removeChildren(place);
+ params = params.parseParams("anon");
+ var plugins = installedPlugins.slice(0);
+ var t,tiddler,p;
+ var configTiddlers = store.getTaggedTiddlers("systemConfig");
+ for(t=0; t<configTiddlers.length; t++)
+ {
+ tiddler = configTiddlers[t];
+ if(plugins.findByField("title",tiddler.title) == null)
+ {
+ p = getPluginInfo(tiddler);
+ p.executed = false;
+ p.log.splice(0,0,this.skippedText);
+ plugins.push(p);
+ }
+ }
+ for(t=0; t<plugins.length; t++)
+ {
+ var p = plugins[t];
+ p.forced = p.tiddler.isTagged("systemConfigForce");
+ p.disabled = p.tiddler.isTagged("systemConfigDisable");
+ p.Selected = selectedRows.indexOf(plugins[t].title) != -1;
+ }
+ if(plugins.length == 0)
+ createTiddlyElement(place,"em",null,null,this.noPluginText);
+ else
+ ListView.create(place,plugins,this.listViewTemplate,this.onSelectCommand);
+}
+
+config.macros.plugins.onSelectCommand = function(command,rowNames)
+{
+ var t;
+ switch(command)
+ {
+ case "remove":
+ for(t=0; t<rowNames.length; t++)
+ store.setTiddlerTag(rowNames[t],false,"systemConfig");
+ break;
+ case "delete":
+ if(rowNames.length > 0 && confirm(config.macros.plugins.confirmDeleteText.format([rowNames.join(", ")])))
+ {
+ for(t=0; t<rowNames.length; t++)
+ {
+ store.removeTiddler(rowNames[t]);
+ story.closeTiddler(rowNames[t],true,false);
+ }
+ }
+ break;
+ }
+ if(config.options.chkAutoSave)
+ saveChanges(true);
+}
+
+config.macros.refreshDisplay.handler = function(place)
+{
+ createTiddlyButton(place,this.label,this.prompt,this.onClick);
+}
+
+config.macros.refreshDisplay.onClick = function(e)
+{
+ refreshAll();
+ return false;
+}
+
+config.macros.importTiddlers.handler = function(place,macroName,params,wikifier,paramString,tiddler)
+{
+ if(readOnly)
+ {
+ createTiddlyElement(place,"div",null,"marked",this.readOnlyWarning);
+ return;
+ }
+ var importer = createTiddlyElement(null,"div",null,"importTiddler wizard");
+ createTiddlyElement(importer,"h1",null,null,this.wizardTitle);
+ createTiddlyElement(importer,"h2",null,"step1",this.step1);
+ var step = createTiddlyElement(importer,"div",null,"wizardStep");
+ createTiddlyText(step,this.step1prompt);
+ var input = createTiddlyElement(null,"input",null,"txtOptionInput");
+ input.type = "text";
+ input.size = 50;
+ step.appendChild(input);
+ importer.inputBox = input;
+ createTiddlyElement(step,"br");
+ createTiddlyText(step,this.step1promptFile);
+ var fileInput = createTiddlyElement(null,"input",null,"txtOptionInput");
+ fileInput.type = "file";
+ fileInput.size = 50;
+ fileInput.onchange = this.onBrowseChange;
+ fileInput.onkeyup = this.onBrowseChange;
+ step.appendChild(fileInput);
+ createTiddlyElement(step,"br");
+ createTiddlyText(step,this.step1promptFeeds);
+ var feeds = this.getFeeds([{caption: this.step1feedPrompt, name: ""}]);
+ createTiddlyDropDown(step,this.onFeedChange,feeds);
+ createTiddlyElement(step,"br");
+ createTiddlyButton(step,this.fetchLabel,this.fetchPrompt,this.onFetch,null,null,null);
+ place.appendChild(importer);
+}
+
+config.macros.importTiddlers.getFeeds = function(feeds)
+{
+ var tagged = store.getTaggedTiddlers("contentPublisher","title");
+ for(var t=0; t<tagged.length; t++)
+ feeds.push({caption: tagged[t].title, name: store.getTiddlerSlice(tagged[t].title,"URL")});
+ return feeds;
+}
+
+config.macros.importTiddlers.onFeedChange = function(e)
+{
+ var importer = findRelated(this,"importTiddler","className","parentNode");
+ importer.inputBox.value = this.value;
+ this.selectedIndex = 0;
+}
+
+config.macros.importTiddlers.onBrowseChange = function(e)
+{
+ var importer = findRelated(this,"importTiddler","className","parentNode");
+ importer.inputBox.value = "file://" + this.value;
+}
+
+config.macros.importTiddlers.onFetch = function(e)
+{
+ var importer = findRelated(this,"importTiddler","className","parentNode");
+ var url = importer.inputBox.value;
+ var cutoff = findRelated(importer.firstChild,"step2","className","nextSibling");
+ while(cutoff)
+ {
+ var temp = cutoff.nextSibling;
+ cutoff.parentNode.removeChild(cutoff);
+ cutoff = temp;
+ }
+ createTiddlyElement(importer,"h2",null,"step2",config.macros.importTiddlers.step2);
+ var step = createTiddlyElement(importer,"div",null,"wizardStep",config.macros.importTiddlers.step2Text.format([url]));
+ loadRemoteFile(url,config.macros.importTiddlers.onLoad,importer);
+}
+
+config.macros.importTiddlers.onLoad = function(status,params,responseText,url,xhr)
+{
+ if(!status)
+ {
+ displayMessage(this.fetchError);
+ return;
+ }
+ var importer = params;
+ // Check that the tiddler we're in hasn't been closed - doesn't work on IE
+// var p = importer;
+// while(p.parentNode)
+// p = p.parentNode;
+// if(!(p instanceof HTMLDocument))
+// return;
+ // Crack out the content - (should be refactored)
+ var posOpeningDiv = responseText.indexOf(startSaveArea);
+ var limitClosingDiv = responseText.indexOf("<!--POST-BODY-START--"+">");
+ var posClosingDiv = responseText.lastIndexOf(endSaveArea,limitClosingDiv == -1 ? responseText.length : limitClosingDiv);
+ if((posOpeningDiv == -1) || (posClosingDiv == -1))
+ {
+ alert(config.messages.invalidFileError.format([url]));
+ return;
+ }
+ var content = "<html><body>" + responseText.substring(posOpeningDiv,posClosingDiv + endSaveArea.length) + "</body></html>";
+ // Create the iframe
+ var iframe = document.createElement("iframe");
+ iframe.style.display = "none";
+ importer.insertBefore(iframe,importer.firstChild);
+ var doc = iframe.document;
+ if(iframe.contentDocument)
+ doc = iframe.contentDocument; // For NS6
+ else if(iframe.contentWindow)
+ doc = iframe.contentWindow.document; // For IE5.5 and IE6
+ // Put the content in the iframe
+ doc.open();
+ doc.writeln(content);
+ doc.close();
+ // Load the content into a TiddlyWiki() object
+ var storeArea = doc.getElementById("storeArea");
+ var importStore = new TiddlyWiki();
+ importStore.loadFromDiv(storeArea,"store");
+ // Get rid of the iframe
+ iframe.parentNode.removeChild(iframe);
+ // Extract data for the listview
+ var tiddlers = [];
+ importStore.forEachTiddler(function(title,tiddler)
+ {
+ var t = {};
+ t.title = title;
+ t.modified = tiddler.modified;
+ t.modifier = tiddler.modifier;
+ t.text = tiddler.text.substr(0,50);
+ t.tags = tiddler.tags;
+ tiddlers.push(t);
+ });
+ // Display the listview
+ createTiddlyElement(importer,"h2",null,"step3",config.macros.importTiddlers.step3);
+ var step = createTiddlyElement(importer,"div",null,"wizardStep");
+ ListView.create(step,tiddlers,config.macros.importTiddlers.listViewTemplate,config.macros.importTiddlers.onSelectCommand);
+ // Save the importer
+ importer.store = importStore;
+}
+
+config.macros.importTiddlers.onSelectCommand = function(listView,command,rowNames)
+{
+ var importer = findRelated(listView,"importTiddler","className","parentNode");
+ switch(command)
+ {
+ case "import":
+ config.macros.importTiddlers.doImport(importer,rowNames);
+ break;
+ }
+ if(config.options.chkAutoSave)
+ saveChanges(true);
+}
+
+config.macros.importTiddlers.doImport = function(importer,rowNames)
+{
+ var theStore = importer.store;
+ var overwrite = new Array();
+ var t;
+ for(t=0; t<rowNames.length; t++)
+ {
+ if(store.tiddlerExists(rowNames[t]))
+ overwrite.push(rowNames[t]);
+ }
+ if(overwrite.length > 0)
+ if(!confirm(this.confirmOverwriteText.format([overwrite.join(", ")])))
+ return;
+ for(t=0; t<rowNames.length; t++)
+ {
+ var inbound = theStore.fetchTiddler(rowNames[t]);
+ store.saveTiddler(inbound.title, inbound.title, inbound.text, inbound.modifier, inbound.modified, inbound.tags);
+ store.fetchTiddler(inbound.title).created = inbound.created;
+ store.notify(rowNames[t],false);
+ }
+ store.notifyAll();
+ store.setDirty(true);
+ createTiddlyElement(importer,"h2",null,"step4",this.step4.format([rowNames.length]));
+ var step = createTiddlyElement(importer,"div",null,"wizardStep");
+ for(t=0; t<rowNames.length; t++)
+ {
+ createTiddlyLink(step,rowNames[t],true);
+ createTiddlyElement(step,"br");
+ }
+ createTiddlyElement(importer,"h2",null,"step5",this.step5);
+}
+// ---------------------------------------------------------------------------------
+// Menu and toolbar commands
+// ---------------------------------------------------------------------------------
+
+config.commands.closeTiddler.handler = function(event,src,title)
+{
+ story.closeTiddler(title,true,event.shiftKey || event.altKey);
+ return false;
+}
+
+config.commands.closeOthers.handler = function(event,src,title)
+{
+ story.closeAllTiddlers(title);
+ return false;
+}
+
+config.commands.editTiddler.handler = function(event,src,title)
+{
+ clearMessage();
+ story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE);
+ story.focusTiddler(title,"text");
+ return false;
+}
+
+config.commands.saveTiddler.handler = function(event,src,title)
+{
+ var newTitle = story.saveTiddler(title,event.shiftKey);
+ if(newTitle)
+ story.displayTiddler(null,newTitle);
+ return false;
+}
+
+config.commands.cancelTiddler.handler = function(event,src,title)
+{
+ if(story.hasChanges(title) && !readOnly)
+ if(!confirm(this.warning.format([title])))
+ return false;
+ story.setDirty(title,false);
+ story.displayTiddler(null,title);
+ return false;
+}
+
+config.commands.deleteTiddler.handler = function(event,src,title)
+{
+ var deleteIt = true;
+ if (config.options.chkConfirmDelete)
+ deleteIt = confirm(this.warning.format([title]));
+ if (deleteIt)
+ {
+ store.removeTiddler(title);
+ story.closeTiddler(title,true,event.shiftKey || event.altKey);
+ if(config.options.chkAutoSave)
+ saveChanges();
+ }
+ return false;
+}
+
+config.commands.permalink.handler = function(event,src,title)
+{
+ var t = encodeURIComponent(String.encodeTiddlyLink(title));
+ if(window.location.hash != t)
+ window.location.hash = t;
+ return false;
+}
+
+config.commands.references.handler = function(event,src,title)
+{
+ var popup = Popup.create(src);
+ if(popup)
+ {
+ var references = store.getReferringTiddlers(title);
+ var c = false;
+ for(var r=0; r<references.length; r++)
+ if(references[r].title != title && !references[r].isTagged("excludeLists"))
+ {
+ createTiddlyLink(createTiddlyElement(popup,"li"),references[r].title,true);
+ c = true;
+ }
+ if(!c)
+ createTiddlyText(createTiddlyElement(popup,"li",null,"disabled"),this.popupNone);
+ }
+ Popup.show(popup,false);
+ event.cancelBubble = true;
+ if (event.stopPropagation) event.stopPropagation();
+ return false;
+}
+
+config.commands.jump.handler = function(event,src,title)
+{
+ var popup = Popup.create(src);
+ if(popup)
+ {
+ story.forEachTiddler(function(title,element) {
+ createTiddlyLink(createTiddlyElement(popup,"li"),title,true);
+ });
+ }
+ Popup.show(popup,false);
+ event.cancelBubble = true;
+ if (event.stopPropagation) event.stopPropagation();
+ return false;
+}
+
+// ---------------------------------------------------------------------------------
+// Tiddler() object
+// ---------------------------------------------------------------------------------
+
+function Tiddler()
+{
+ this.title = null;
+ this.text = null;
+ this.modifier = null;
+ this.modified = new Date();
+ this.created = new Date();
+ this.links = [];
+ this.linksUpdated = false;
+ this.tags = [];
+ return this;
+}
+
+Tiddler.prototype.getLinks = function()
+{
+ if(this.linksUpdated==false)
+ this.changed();
+ return this.links;
+}
+
+// Format the text for storage in an RSS item
+Tiddler.prototype.saveToRss = function(url)
+{
+ var s = [];
+ s.push("<item>");
+ s.push("<title" + ">" + this.title.htmlEncode() + "</title" + ">");
+ s.push("<description>" + wikifyStatic(this.text,null,this).htmlEncode() + "</description>");
+ for(var t=0; t<this.tags.length; t++)
+ s.push("<category>" + this.tags[t] + "</category>");
+ s.push("<link>" + url + "#" + encodeURIComponent(String.encodeTiddlyLink(this.title)) + "</link>");
+ s.push("<pubDate>" + this.modified.toGMTString() + "</pubDate>");
+ s.push("</item>");
+ return(s.join("\n"));
+}
+
+// Change the text and other attributes of a tiddler
+Tiddler.prototype.set = function(title,text,modifier,modified,tags,created,fields)
+{
+ this.assign(title,text,modifier,modified,tags,created,fields);
+ this.changed();
+ return this;
+}
+
+// Change the text and other attributes of a tiddler without triggered a tiddler.changed() call
+Tiddler.prototype.assign = function(title,text,modifier,modified,tags,created,fields)
+{
+ if(title != undefined)
+ this.title = title;
+ if(text != undefined)
+ this.text = text;
+ if(modifier != undefined)
+ this.modifier = modifier;
+ if(modified != undefined)
+ this.modified = modified;
+ if(created != undefined)
+ this.created = created;
+ if(fields != undefined)
+ this.fields = fields;
+ if(tags != undefined)
+ this.tags = (typeof tags == "string") ? tags.readBracketedList() : tags;
+ else if(this.tags == undefined)
+ this.tags = [];
+ return this;
+}
+
+// Get the tags for a tiddler as a string (space delimited, using [[brackets]] for tags containing spaces)
+Tiddler.prototype.getTags = function()
+{
+ return String.encodeTiddlyLinkList(this.tags);
+}
+
+// Test if a tiddler carries a tag
+Tiddler.prototype.isTagged = function(tag)
+{
+ return this.tags.indexOf(tag) != -1;
+}
+
+// Static method to convert "\n" to newlines, "\s" to "\"
+Tiddler.unescapeLineBreaks = function(text)
+{
+ return text ? text.unescapeLineBreaks() : "";
+}
+
+// Convert newlines to "\n", "\" to "\s"
+Tiddler.prototype.escapeLineBreaks = function()
+{
+ return this.text.escapeLineBreaks();
+}
+
+// Updates the secondary information (like links[] array) after a change to a tiddler
+Tiddler.prototype.changed = function()
+{
+ this.links = [];
+ var t = this.autoLinkWikiWords() ? 0 : 1;
+ var tiddlerLinkRegExp = t==0 ? config.textPrimitives.tiddlerAnyLinkRegExp : config.textPrimitives.tiddlerForcedLinkRegExp;
+ tiddlerLinkRegExp.lastIndex = 0;
+ var formatMatch = tiddlerLinkRegExp.exec(this.text);
+ while(formatMatch)
+ {
+ if(t==0 && formatMatch[1] && formatMatch[1] != this.title) // wikiWordLink
+ {
+ if(formatMatch.index > 0)
+ {
+ var preRegExp = new RegExp(config.textPrimitives.unWikiLink+"|"+config.textPrimitives.anyLetter,"mg");
+ preRegExp.lastIndex = formatMatch.index-1;
+ var preMatch = preRegExp.exec(this.text);
+ if(preMatch.index != formatMatch.index-1)
+ this.links.pushUnique(formatMatch[1]);
+ }
+ else
+ this.links.pushUnique(formatMatch[1]);
+ }
+ else if(formatMatch[2-t] && (store.tiddlerExists(formatMatch[3-t]) || store.isShadowTiddler(formatMatch[3-t]))) // titledBrackettedLink
+ this.links.pushUnique(formatMatch[3-t]);
+ else if(formatMatch[4-t] && formatMatch[4-t] != this.title) // brackettedLink
+ this.links.pushUnique(formatMatch[4-t]);
+ // Do not add link if match urlPattern (formatMatch[5-t])
+ formatMatch = tiddlerLinkRegExp.exec(this.text);
+ }
+ this.linksUpdated = true;
+ return;
+}
+
+Tiddler.prototype.getSubtitle = function()
+{
+ var theModifier = this.modifier;
+ if(!theModifier)
+ theModifier = config.messages.subtitleUnknown;
+ var theModified = this.modified;
+ if(theModified)
+ theModified = theModified.toLocaleString();
+ else
+ theModified = config.messages.subtitleUnknown;
+ return(config.messages.tiddlerLinkTooltip.format([this.title,theModifier,theModified]));
+}
+
+Tiddler.prototype.isReadOnly = function()
+{
+ return readOnly;
+}
+
+Tiddler.prototype.autoLinkWikiWords = function()
+{
+ return !(this.isTagged("systemConfig") || this.isTagged("excludeMissing"));
+}
+
+Tiddler.prototype.generateFingerprint = function()
+{
+ return "0x" + Crypto.hexSha1Str(this.text);
+}
+
+// ---------------------------------------------------------------------------------
+// TiddlyWiki() object contains Tiddler()s
+// ---------------------------------------------------------------------------------
+
+function TiddlyWiki()
+{
+ var tiddlers = {}; // Hashmap by name of tiddlers
+ this.tiddlersUpdated = false;
+ this.namedNotifications = []; // Array of {name:,notify:} of notification functions
+ this.notificationLevel = 0;
+ this.slices = {}; // map tiddlerName->(map sliceName->sliceValue). Lazy.
+ this.clear = function() {
+ tiddlers = {};
+ this.setDirty(false);
+ };
+ this.fetchTiddler = function(title) {
+ return tiddlers[title];
+ };
+ this.deleteTiddler = function(title) {
+ delete this.slices[title];
+ delete tiddlers[title];
+ };
+ this.addTiddler = function(tiddler) {
+ delete this.slices[tiddler.title];
+ tiddlers[tiddler.title] = tiddler;
+ };
+ this.forEachTiddler = function(callback) {
+ for(var t in tiddlers)
+ {
+ var tiddler = tiddlers[t];
+ if(tiddler instanceof Tiddler)
+ callback.call(this,t,tiddler);
+ }
+ };
+}
+
+// Set the dirty flag
+TiddlyWiki.prototype.setDirty = function(dirty)
+{
+ this.dirty = dirty;
+}
+
+TiddlyWiki.prototype.isDirty = function()
+{
+ return this.dirty;
+}
+
+TiddlyWiki.prototype.suspendNotifications = function()
+{
+ this.notificationLevel--;
+}
+
+TiddlyWiki.prototype.resumeNotifications = function()
+{
+ this.notificationLevel++;
+}
+
+// Invoke the notification handlers for a particular tiddler
+TiddlyWiki.prototype.notify = function(title,doBlanket)
+{
+ if(!this.notificationLevel)
+ for(var t=0; t<this.namedNotifications.length; t++)
+ {
+ var n = this.namedNotifications[t];
+ if((n.name == null && doBlanket) || (n.name == title))
+ n.notify(title);
+ }
+}
+
+// Invoke the notification handlers for all tiddlers
+TiddlyWiki.prototype.notifyAll = function()
+{
+ if(!this.notificationLevel)
+ for(var t=0; t<this.namedNotifications.length; t++)
+ {
+ var n = this.namedNotifications[t];
+ if(n.name)
+ n.notify(n.name);
+ }
+}
+
+// Add a notification handler to a tiddler
+TiddlyWiki.prototype.addNotification = function(title,fn)
+{
+ for (var i=0; i<this.namedNotifications.length; i++)
+ if((this.namedNotifications[i].name == title) && (this.namedNotifications[i].notify == fn))
+ return this;
+ this.namedNotifications.push({name: title, notify: fn});
+ return this;
+}
+
+TiddlyWiki.prototype.removeTiddler = function(title)
+{
+ var tiddler = this.fetchTiddler(title);
+ if(tiddler)
+ {
+ this.deleteTiddler(title);
+ this.notify(title,true);
+ this.setDirty(true);
+ }
+}
+
+TiddlyWiki.prototype.tiddlerExists = function(title)
+{
+ var t = this.fetchTiddler(title);
+ return (t != undefined);
+}
+
+TiddlyWiki.prototype.isShadowTiddler = function(title)
+{
+ return typeof config.shadowTiddlers[title] == "string";
+}
+
+TiddlyWiki.prototype.getTiddler = function(title)
+{
+ var t = this.fetchTiddler(title);
+ if(t != undefined)
+ return t;
+ else
+ return null;
+}
+
+TiddlyWiki.prototype.getTiddlerText = function(title,defaultText)
+{
+ var tiddler = this.fetchTiddler(title);
+ if(tiddler)
+ return tiddler.text;
+ if(!title)
+ return defaultText;
+ var pos = title.indexOf(config.textPrimitives.sliceSeparator);
+ if(pos != -1)
+ {
+ var slice = this.getTiddlerSlice(title.substr(0,pos),title.substr(pos + config.textPrimitives.sliceSeparator.length));
+ if(slice)
+ return slice;
+ }
+ if(this.isShadowTiddler(title))
+ return config.shadowTiddlers[title];
+ if(defaultText != undefined)
+ return defaultText;
+ return null;
+}
+
+TiddlyWiki.prototype.slicesRE = /(?:[\'\/]*~?(\w+)[\'\/]*\:[\'\/]*\s*(.*?)\s*$)|(?:\|[\'\/]*~?(\w+)\:?[\'\/]*\|\s*(.*?)\s*\|)/gm
+
+// @internal
+TiddlyWiki.prototype.calcAllSlices = function(title)
+{
+ var slices = {};
+ var text = this.getTiddlerText(title,"");
+ this.slicesRE.lastIndex = 0;
+ do
+ {
+ var m = this.slicesRE.exec(text);
+ if (m)
+ {
+ if (m[1])
+ slices[m[1]] = m[2];
+ else
+ slices[m[3]] = m[4];
+ }
+ }
+ while(m);
+ return slices;
+}
+
+// Returns the slice of text of the given name
+//#
+//# A text slice is a substring in the tiddler's text that is defined
+//# either like this
+//# aName: textSlice
+//# or
+//# |aName:| textSlice |
+//# or
+//# |aName| textSlice |
+//#
+//# In the text the name (or name:) may be decorated with '' or //. I.e.
+//# this would also a possible text slice:
+//#
+//# |''aName:''| textSlice |
+//#
+//# @param name should only contain "word characters" (i.e. "a-ZA-Z_0-9")
+//# @return [may be undefined] the (trimmed) text of the specified slice.
+TiddlyWiki.prototype.getTiddlerSlice = function(title,sliceName)
+{
+ var slices = this.slices[title];
+ if (!slices) {
+ slices = this.calcAllSlices(title);
+ this.slices[title] = slices;
+ }
+ return slices[sliceName];
+}
+
+// Build an hashmap of the specified named slices of a tiddler
+TiddlyWiki.prototype.getTiddlerSlices = function(title,sliceNames)
+{
+ var r = {};
+ for(var t=0; t<sliceNames.length; t++)
+ {
+ var slice = this.getTiddlerSlice(title,sliceNames[t]);
+ if(slice)
+ r[sliceNames[t]] = slice;
+ }
+ return r;
+}
+
+TiddlyWiki.prototype.getRecursiveTiddlerText = function(title,defaultText,depth)
+{
+ var bracketRegExp = new RegExp("(?:\\[\\[([^\\]]+)\\]\\])","mg");
+ var text = this.getTiddlerText(title,null);
+ if(text == null)
+ return defaultText;
+ var textOut = [];
+ var lastPos = 0;
+ do {
+ var match = bracketRegExp.exec(text);
+ if(match)
+ {
+ textOut.push(text.substr(lastPos,match.index-lastPos));
+ if(match[1])
+ {
+ if(depth <= 0)
+ textOut.push(match[1]);
+ else
+ textOut.push(this.getRecursiveTiddlerText(match[1],"[[" + match[1] + "]]",depth-1));
+ }
+ lastPos = match.index + match[0].length;
+ }
+ else
+ textOut.push(text.substr(lastPos));
+ } while(match);
+ return(textOut.join(""));
+}
+
+TiddlyWiki.prototype.setTiddlerTag = function(title,status,tag)
+{
+ var tiddler = this.fetchTiddler(title);
+ if(tiddler)
+ {
+ var t = tiddler.tags.indexOf(tag);
+ if(t != -1)
+ tiddler.tags.splice(t,1);
+ if(status)
+ tiddler.tags.push(tag);
+ tiddler.changed();
+ this.notify(title,true);
+ this.setDirty(true);
+ }
+}
+
+TiddlyWiki.prototype.saveTiddler = function(title,newTitle,newBody,modifier,modified,tags,fields)
+{
+ var tiddler = this.fetchTiddler(title);
+ var created;
+ if(tiddler)
+ {
+ created = tiddler.created; // Preserve created date
+ this.deleteTiddler(title);
+ }
+ else
+ {
+ tiddler = new Tiddler();
+ created = modified;
+ }
+ tiddler.set(newTitle,newBody,modifier,modified,tags,created,fields);
+ this.addTiddler(tiddler);
+ if(title != newTitle)
+ this.notify(title,true);
+ this.notify(newTitle,true);
+ this.setDirty(true);
+ return tiddler;
+}
+
+TiddlyWiki.prototype.createTiddler = function(title)
+{
+ var tiddler = this.fetchTiddler(title);
+ if(!tiddler)
+ {
+ tiddler = new Tiddler();
+ tiddler.title = title;
+ this.addTiddler(tiddler);
+ this.setDirty(true);
+ }
+ return tiddler;
+}
+
+// Load contents of a tiddlywiki from an HTML DIV
+TiddlyWiki.prototype.loadFromDiv = function(src,idPrefix,noUpdate)
+{
+ this.idPrefix = idPrefix;
+ var storeElem = (typeof src == "string") ? document.getElementById(src) : src;
+ var tiddlers = this.getLoader().loadTiddlers(this,storeElem.childNodes);
+ this.setDirty(false);
+ if(!noUpdate)
+ {
+ for(var i = 0;i<tiddlers.length; i++)
+ tiddlers[i].changed();
+ }
+}
+
+TiddlyWiki.prototype.updateTiddlers = function()
+{
+ this.tiddlersUpdated = true;
+ this.forEachTiddler(function(title,tiddler) {
+ tiddler.changed();
+ });
+}
+
+// Return all tiddlers formatted as an HTML string
+TiddlyWiki.prototype.allTiddlersAsHtml = function()
+{
+ return store.getSaver().externalize(store);
+}
+
+// Return an array of tiddlers matching a search regular expression
+TiddlyWiki.prototype.search = function(searchRegExp,sortField,excludeTag)
+{
+ var candidates = this.reverseLookup("tags",excludeTag,false);
+ var results = [];
+ for(var t=0; t<candidates.length; t++)
+ {
+ if((candidates[t].title.search(searchRegExp) != -1) || (candidates[t].text.search(searchRegExp) != -1))
+ results.push(candidates[t]);
+ }
+ if(!sortField)
+ sortField = "title";
+ results.sort(function(a,b) {return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);});
+ return results;
+}
+
+// Return an array of all the tags in use. Each member of the array is another array where [0] is the name of the tag and [1] is the number of occurances
+TiddlyWiki.prototype.getTags = function()
+{
+ var results = [];
+ this.forEachTiddler(function(title,tiddler) {
+ for(var g=0; g<tiddler.tags.length; g++)
+ {
+ var tag = tiddler.tags[g];
+ var f = false;
+ for(var c=0; c<results.length; c++)
+ if(results[c][0] == tag)
+ {
+ f = true;
+ results[c][1]++;
+ }
+ if(!f)
+ results.push([tag,1]);
+ }
+ });
+ results.sort(function(a,b) {return a[0].toLowerCase() < b[0].toLowerCase() ? -1 : (a[0].toLowerCase() == b[0].toLowerCase() ? 0 : +1);});
+ return results;
+}
+
+// Return an array of the tiddlers that are tagged with a given tag
+TiddlyWiki.prototype.getTaggedTiddlers = function(tag,sortField)
+{
+ return this.reverseLookup("tags",tag,true,sortField);
+}
+
+// Return an array of the tiddlers that link to a given tiddler
+TiddlyWiki.prototype.getReferringTiddlers = function(title,unusedParameter,sortField)
+{
+ if(!this.tiddlersUpdated)
+ this.updateTiddlers();
+ return this.reverseLookup("links",title,true,sortField);
+}
+
+// Return an array of the tiddlers that do or do not have a specified entry in the specified storage array (ie, "links" or "tags")
+// lookupMatch == true to match tiddlers, false to exclude tiddlers
+TiddlyWiki.prototype.reverseLookup = function(lookupField,lookupValue,lookupMatch,sortField)
+{
+ var results = [];
+ this.forEachTiddler(function(title,tiddler) {
+ var f = !lookupMatch;
+ for(var lookup=0; lookup<tiddler[lookupField].length; lookup++)
+ if(tiddler[lookupField][lookup] == lookupValue)
+ f = lookupMatch;
+ if(f)
+ results.push(tiddler);
+ });
+ if(!sortField)
+ sortField = "title";
+ results.sort(function(a,b) {return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);});
+ return results;
+}
+
+// Return the tiddlers as a sorted array
+TiddlyWiki.prototype.getTiddlers = function(field,excludeTag)
+{
+ var results = [];
+ this.forEachTiddler(function(title,tiddler) {
+ if(excludeTag == undefined || !tiddler.isTagged(excludeTag))
+ results.push(tiddler);
+ });
+ if(field)
+ results.sort(function(a,b) {return a[field] < b[field] ? -1 : (a[field] == b[field] ? 0 : +1);});
+ return results;
+}
+
+// Return array of names of tiddlers that are referred to but not defined
+TiddlyWiki.prototype.getMissingLinks = function(sortField)
+{
+ if(!this.tiddlersUpdated)
+ this.updateTiddlers();
+ var results = [];
+ this.forEachTiddler(function (title,tiddler) {
+ for(var n=0; n<tiddler.links.length;n++)
+ {
+ var link = tiddler.links[n];
+ if(this.fetchTiddler(link) == null && !this.isShadowTiddler(link))
+ results.pushUnique(link);
+ }
+ });
+ results.sort();
+ return results;
+}
+
+// Return an array of names of tiddlers that are defined but not referred to
+TiddlyWiki.prototype.getOrphans = function()
+{
+ var results = [];
+ this.forEachTiddler(function (title,tiddler) {
+ if(this.getReferringTiddlers(title).length == 0 && !tiddler.isTagged("excludeLists"))
+ results.push(title);
+ });
+ results.sort();
+ return results;
+}
+
+// Return an array of names of all the shadow tiddlers
+TiddlyWiki.prototype.getShadowed = function()
+{
+ var results = [];
+ for(var t in config.shadowTiddlers)
+ if(typeof config.shadowTiddlers[t] == "string")
+ results.push(t);
+ results.sort();
+ return results;
+}
+
+// Resolves a Tiddler reference or tiddler title into a Tiddler object, or null if it doesn't exist
+TiddlyWiki.prototype.resolveTiddler = function(tiddler)
+{
+ var t = (typeof tiddler == 'string') ? this.getTiddler(tiddler) : tiddler;
+ return t instanceof Tiddler ? t : null;
+}
+
+TiddlyWiki.prototype.getLoader = function()
+{
+ if (!this.loader)
+ this.loader = new TW21Loader();
+ return this.loader;
+}
+
+TiddlyWiki.prototype.getSaver = function()
+{
+ if (!this.saver)
+ this.saver = new TW21Saver();
+ return this.saver;
+}
+
+// Returns true if path is a valid field name (path),
+// i.e. a sequence of identifiers, separated by '.'
+TiddlyWiki.isValidFieldName = function (name) {
+ var match = /[a-zA-Z_]\w*(\.[a-zA-Z_]\w*)*/.exec(name);
+ return match && (match[0] == name);
+}
+
+// Throws an exception when name is not a valid field name.
+TiddlyWiki.checkFieldName = function(name) {
+ if (!TiddlyWiki.isValidFieldName(name))
+ throw config.messages.invalidFieldName.format([name]);
+}
+
+function StringFieldAccess(n, readOnly) {
+ this.set = readOnly
+ ? function(t,v) {if (v != t[n]) throw config.messages.fieldCannotBeChanged.format([n]);}
+ : function(t,v) {if (v != t[n]) {t[n] = v; return true;}};
+ this.get = function(t) {return t[n];};
+}
+
+function DateFieldAccess(n) {
+ this.set = function(t,v) {
+ var d = v instanceof Date ? v : Date.convertFromYYYYMMDDHHMM(v);
+ if (d != t[n]) {
+ t[n] = d; return true;
+ }
+ };
+ this.get = function(t) {return t[n].convertToYYYYMMDDHHMM();}
+}
+
+function LinksFieldAccess(n) {
+ this.set = function(t,v) {
+ var s = (typeof v == "string") ? v.readBracketedList() : v;
+ if (s.toString() != t[n].toString()) {
+ t[n] = s; return true;
+ }
+ };
+ this.get = function(t) {return String.encodeTiddlyLinkList(t[n]);}
+}
+
+TiddlyWiki.standardFieldAccess = {
+ // The set functions return true when setting the data has changed the value.
+
+ "title": new StringFieldAccess("title", true),
+ // Handle the "tiddler" field name as the title
+ "tiddler": new StringFieldAccess("title", true),
+
+ "text": new StringFieldAccess("text"),
+ "modifier": new StringFieldAccess("modifier"),
+ "modified": new DateFieldAccess("modified"),
+ "created": new DateFieldAccess("created"),
+ "tags": new LinksFieldAccess("tags")
+};
+
+TiddlyWiki.isStandardField = function(name) {
+ return TiddlyWiki.standardFieldAccess[name] != undefined;
+}
+
+// Sets the value of the given field of the tiddler to the value.
+// Setting an ExtendedField's value to null or undefined removes the field.
+// Setting a namespace to undefined removes all fields of that namespace.
+// The fieldName is case-insensitive.
+// All values will be converted to a string value.
+TiddlyWiki.prototype.setValue = function(tiddler, fieldName, value) {
+ TiddlyWiki.checkFieldName(fieldName);
+ var t = this.resolveTiddler(tiddler);
+ if (!t)
+ return;
+
+ fieldName = fieldName.toLowerCase();
+
+ var isRemove = (value === undefined) || (value === null);
+
+ if (!t.fields)
+ t.fields = {};
+
+ var accessor = TiddlyWiki.standardFieldAccess[fieldName];
+ if (accessor) {
+ if (isRemove)
+ // don't remove StandardFields
+ return;
+ var h = TiddlyWiki.standardFieldAccess[fieldName];
+ if (!h.set(t, value))
+ return;
+
+ } else {
+ var oldValue = t.fields[fieldName];
+
+ if (isRemove) {
+ if (oldValue !== undefined) {
+ // deletes a single field
+ delete t.fields[fieldName];
+ } else {
+ // no concrete value is defined for the fieldName
+ // so we guess this is a namespace path.
+
+ // delete all fields in a namespace
+ var re = new RegExp('^'+fieldName+'\\.');
+ var dirty = false;
+ for (var n in t.fields) {
+ if (n.match(re)) {
+ delete t.fields[n];
+ dirty = true;
+ }
+ }
+ if (!dirty)
+ return
+ }
+
+ } else {
+ // the "normal" set case. value is defined (not null/undefined)
+ // For convenience provide a nicer conversion Date->String
+ value = value instanceof Date
+ ? value.convertToYYYYMMDDHHMMSSMMM()
+ : String(value);
+ if (oldValue == value)
+ return;
+ t.fields[fieldName] = value;
+ }
+ }
+
+ // When we are here the tiddler/store really was changed.
+ this.notify(t.title,true);
+ if (!fieldName.match(/^temp\./))
+ this.setDirty(true);
+}
+
+// Returns the value of the given field of the tiddler.
+// The fieldName is case-insensitive.
+// Will only return String values (or undefined).
+TiddlyWiki.prototype.getValue = function(tiddler, fieldName) {
+ var t = this.resolveTiddler(tiddler);
+ if (!t)
+ return undefined;
+
+ fieldName = fieldName.toLowerCase();
+
+ var accessor = TiddlyWiki.standardFieldAccess[fieldName];
+ if (accessor) {
+ return accessor.get(t);
+ }
+
+ return t.fields ? t.fields[fieldName] : undefined;
+}
+
+// Calls the callback function for every field in the tiddler.
+//
+// When callback function returns a non-false value the iteration stops
+// and that value is returned.
+//
+// The order of the fields is not defined.
+//
+// @param callback a function(tiddler, fieldName, value).
+//
+TiddlyWiki.prototype.forEachField = function(tiddler, callback, onlyExtendedFields) {
+ var t = this.resolveTiddler(tiddler);
+ if (!t)
+ return undefined;
+
+ if (t.fields) {
+ for (var n in t.fields) {
+ var result = callback(t, n, t.fields[n]);
+ if (result)
+ return result;
+ }
+ }
+
+ if (onlyExtendedFields)
+ return undefined;
+
+ for (var n in TiddlyWiki.standardFieldAccess) {
+ if (n == "tiddler")
+ // even though the "title" field can also be referenced through the name "tiddler"
+ // we only visit this field once.
+ continue;
+
+ var result = callback(t, n, TiddlyWiki.standardFieldAccess[n].get(t));
+ if (result)
+ return result;
+ }
+
+ return undefined;
+};
+// ---------------------------------------------------------------------------------
+// Story functions
+// ---------------------------------------------------------------------------------
+
+// A story is a HTML div containing a sequence of tiddlers that can be manipulated
+// container - id of containing element
+// idPrefix - string prefix prepended to title to make ids for tiddlers in this story
+function Story(container,idPrefix)
+{
+ this.container = container;
+ this.idPrefix = idPrefix;
+ this.highlightRegExp = null;
+}
+
+// Iterate through all the tiddlers in a story
+// fn - callback function to be called for each tiddler. Arguments are:
+// tiddler - reference to Tiddler object
+// element - reference to tiddler display element
+Story.prototype.forEachTiddler = function(fn)
+{
+ var place = document.getElementById(this.container);
+ if(!place)
+ return;
+ var e = place.firstChild;
+ while(e)
+ {
+ var n = e.nextSibling;
+ var title = e.getAttribute("tiddler");
+ fn.call(this,title,e);
+ e = n;
+ }
+}
+
+// Display several tiddlers given their titles in an array. Parameters same as displayTiddler(), except:
+// titles - array of string titles
+Story.prototype.displayTiddlers = function(srcElement,titles,template,animate,slowly)
+{
+ for(var t = titles.length-1;t>=0;t--)
+ this.displayTiddler(srcElement,titles[t],template,animate,slowly);
+}
+
+// Display a given tiddler with a given template. If the tiddler is already displayed but with a different
+// template, it is switched to the specified template
+// srcElement - reference to element from which this one is being opened -or-
+// special positions "top", "bottom"
+// title - title of tiddler to display
+// template - the name of the tiddler containing the template -or-
+// one of the constants DEFAULT_VIEW_TEMPLATE and DEFAULT_EDIT_TEMPLATE -or-
+// null or undefined to indicate the current template if there is one, DEFAULT_VIEW_TEMPLATE if not
+// animate - whether to perform animations
+// slowly - whether to perform animations in slomo
+Story.prototype.displayTiddler = function(srcElement,title,template,animate,slowly)
+{
+ var place = document.getElementById(this.container);
+ var tiddlerElem = document.getElementById(this.idPrefix + title);
+ if(tiddlerElem)
+ this.refreshTiddler(title,template);
+ else
+ {
+ var before = this.positionTiddler(srcElement);
+ tiddlerElem = this.createTiddler(place,before,title,template);
+ }
+ if(srcElement && typeof srcElement !== "string")
+ {
+ if(anim && config.options.chkAnimate && (animate == undefined || animate == true))
+ anim.startAnimating(new Cascade(title,srcElement,tiddlerElem,slowly),new Scroller(tiddlerElem,slowly));
+ else
+ window.scrollTo(0,ensureVisible(tiddlerElem));
+ }
+}
+
+// Figure out the appropriate position for a newly opened tiddler
+// srcElement - reference to the element containing the link to the tiddler -or-
+// special positions "top", "bottom"
+// returns - reference to the tiddler that the new one should appear before (null for the bottom of the story)
+Story.prototype.positionTiddler = function(srcElement)
+{
+ var place = document.getElementById(this.container);
+ var before;
+ if(typeof srcElement == "string")
+ {
+ switch(srcElement)
+ {
+ case "top":
+ before = place.firstChild;
+ break;
+ case "bottom":
+ before = null;
+ break;
+ }
+ }
+ else
+ {
+ var after = this.findContainingTiddler(srcElement);
+ if(after == null)
+ before = place.firstChild;
+ else if(after.nextSibling)
+ before = after.nextSibling;
+ else
+ before = null;
+ }
+ return before;
+}
+
+// Create a tiddler frame at the appropriate place in a story column
+// place - reference to parent element
+// before - null, or reference to element before which to insert new tiddler
+// title - title of new tiddler
+// template - the name of the tiddler containing the template or one of the constants DEFAULT_VIEW_TEMPLATE and DEFAULT_EDIT_TEMPLATE
+Story.prototype.createTiddler = function(place,before,title,template)
+{
+ var tiddlerElem = createTiddlyElement(null,"div",this.idPrefix + title,"tiddler");
+ tiddlerElem.setAttribute("refresh","tiddler");
+ place.insertBefore(tiddlerElem,before);
+ this.refreshTiddler(title,template);
+ return tiddlerElem;
+}
+
+// Overridable for choosing the name of the template to apply for a tiddler
+Story.prototype.chooseTemplateForTiddler = function(title,template)
+{
+ if(!template)
+ template = DEFAULT_VIEW_TEMPLATE;
+ if(template == DEFAULT_VIEW_TEMPLATE || template == DEFAULT_EDIT_TEMPLATE)
+ template = config.tiddlerTemplates[template];
+ return template;
+}
+
+// Overridable for extracting the text of a template from a tiddler
+Story.prototype.getTemplateForTiddler = function(title,template,tiddler)
+{
+ return store.getRecursiveTiddlerText(template,null,10);
+}
+
+// Apply a template to an existing tiddler if it is not already displayed using that template
+// title - title of tiddler to update
+// template - the name of the tiddler containing the template or one of the constants DEFAULT_VIEW_TEMPLATE and DEFAULT_EDIT_TEMPLATE
+// force - if true, forces the refresh even if the template hasn't changedd
+Story.prototype.refreshTiddler = function(title,template,force)
+{
+ var tiddlerElem = document.getElementById(this.idPrefix + title);
+ if(tiddlerElem)
+ {
+ if(tiddlerElem.getAttribute("dirty") == "true" && !force)
+ return tiddlerElem;
+ template = this.chooseTemplateForTiddler(title,template);
+ var currTemplate = tiddlerElem.getAttribute("template");
+ if((template != currTemplate) || force)
+ {
+ var tiddler = store.getTiddler(title);
+ if(!tiddler)
+ {
+ tiddler = new Tiddler();
+ if(store.isShadowTiddler(title))
+ tiddler.set(title,store.getTiddlerText(title),config.views.wikified.shadowModifier,version.date,[],version.date);
+ else
+ {
+ var text = template=="EditTemplate"
+ ? config.views.editor.defaultText.format([title])
+ : config.views.wikified.defaultText.format([title]);
+ tiddler.set(title,text,config.views.wikified.defaultModifier,version.date,[],version.date);
+ }
+ }
+ tiddlerElem.setAttribute("tags",tiddler.tags.join(" "));
+ tiddlerElem.setAttribute("tiddler",title);
+ tiddlerElem.setAttribute("template",template);
+ var me = this;
+ tiddlerElem.onmouseover = this.onTiddlerMouseOver;
+ tiddlerElem.onmouseout = this.onTiddlerMouseOut;
+ tiddlerElem.ondblclick = this.onTiddlerDblClick;
+ tiddlerElem[window.event?"onkeydown":"onkeypress"] = this.onTiddlerKeyPress;
+ var html = this.getTemplateForTiddler(title,template,tiddler);
+ tiddlerElem.innerHTML = html;
+ applyHtmlMacros(tiddlerElem,tiddler);
+ if(store.getTaggedTiddlers(title).length > 0)
+ addClass(tiddlerElem,"isTag");
+ else
+ removeClass(tiddlerElem,"isTag");
+ if(!store.tiddlerExists(title))
+ {
+ if(store.isShadowTiddler(title))
+ addClass(tiddlerElem,"shadow");
+ else
+ addClass(tiddlerElem,"missing");
+ }
+ else
+ {
+ removeClass(tiddlerElem,"shadow");
+ removeClass(tiddlerElem,"missing");
+ }
+ }
+ }
+ return tiddlerElem;
+}
+
+// Refresh all tiddlers in the Story
+Story.prototype.refreshAllTiddlers = function()
+{
+ var place = document.getElementById(this.container);
+ var e = place.firstChild;
+ if(!e)
+ return;
+ this.refreshTiddler(e.getAttribute("tiddler"),e.getAttribute("template"),true);
+ while((e = e.nextSibling) != null)
+ this.refreshTiddler(e.getAttribute("tiddler"),e.getAttribute("template"),true);
+}
+
+// Default tiddler onmouseover/out event handlers
+Story.prototype.onTiddlerMouseOver = function(e)
+{
+ if(window.addClass instanceof Function)
+ addClass(this,"selected");
+}
+
+Story.prototype.onTiddlerMouseOut = function(e)
+{
+ if(window.removeClass instanceof Function)
+ removeClass(this,"selected");
+}
+
+// Default tiddler ondblclick event handler
+Story.prototype.onTiddlerDblClick = function(e)
+{
+ if(!e) var e = window.event;
+ var theTarget = resolveTarget(e);
+ if(theTarget && theTarget.nodeName.toLowerCase() != "input" && theTarget.nodeName.toLowerCase() != "textarea")
+ {
+ if(document.selection && document.selection.empty)
+ document.selection.empty();
+ config.macros.toolbar.invokeCommand(this,"defaultCommand",e);
+ e.cancelBubble = true;
+ if (e.stopPropagation) e.stopPropagation();
+ return true;
+ }
+ else
+ return false;
+}
+
+Story.prototype.onTiddlerKeyPress = function(e)
+{
+ if(!e) var e = window.event;
+ clearMessage();
+ var consume = false;
+ var title = this.getAttribute("tiddler");
+ var target = resolveTarget(e);
+ switch(e.keyCode)
+ {
+ case 9: // Tab
+ if(config.options.chkInsertTabs && target.tagName.toLowerCase() == "textarea")
+ {
+ replaceSelection(target,String.fromCharCode(9));
+ consume = true;
+ }
+ if(config.isOpera)
+ {
+ target.onblur = function()
+ {
+ this.focus();
+ this.onblur = null;
+ }
+ }
+ break;
+ case 13: // Ctrl-Enter
+ case 10: // Ctrl-Enter on IE PC
+ case 77: // Ctrl-Enter is "M" on some platforms
+ if(e.ctrlKey)
+ {
+ blurElement(this);
+ config.macros.toolbar.invokeCommand(this,"defaultCommand",e);
+ consume = true;
+ }
+ break;
+ case 27: // Escape
+ blurElement(this);
+ config.macros.toolbar.invokeCommand(this,"cancelCommand",e);
+ consume = true;
+ break;
+ }
+ e.cancelBubble = consume;
+ if(consume)
+ {
+ if(e.stopPropagation) e.stopPropagation(); // Stop Propagation
+ e.returnValue = true; // Cancel The Event in IE
+ if(e.preventDefault ) e.preventDefault(); // Cancel The Event in Moz
+ }
+ return(!consume);
+};
+
+// Returns the specified field (input or textarea element) in a tiddler, otherwise the first edit field it finds
+// or null if it found no edit field at all
+Story.prototype.getTiddlerField = function(title,field)
+{
+ var tiddlerElem = document.getElementById(this.idPrefix + title);
+ var e = null;
+ if(tiddlerElem != null)
+ {
+ var children = tiddlerElem.getElementsByTagName("*");
+ for (var t=0; t<children.length; t++)
+ {
+ var c = children[t];
+ if(c.tagName.toLowerCase() == "input" || c.tagName.toLowerCase() == "textarea")
+ {
+ if(!e)
+ e = c;
+ if(c.getAttribute("edit") == field)
+ e = c;
+ }
+ }
+ }
+ return e;
+}
+
+// Focus a specified tiddler. Attempts to focus the specified field, otherwise the first edit field it finds
+Story.prototype.focusTiddler = function(title,field)
+{
+ var e = this.getTiddlerField(title,field);
+ if(e)
+ {
+ e.focus();
+ e.select();
+ }
+}
+
+// Ensures that a specified tiddler does not have the focus
+Story.prototype.blurTiddler = function(title)
+{
+ var tiddlerElem = document.getElementById(this.idPrefix + title);
+ if(tiddlerElem != null && tiddlerElem.focus && tiddlerElem.blur)
+ {
+ tiddlerElem.focus();
+ tiddlerElem.blur();
+ }
+}
+
+// Adds a specified value to the edit controls (if any) of a particular
+// array-formatted field of a particular tiddler (eg "tags")
+// title - name of tiddler
+// tag - value of field, without any [[brackets]]
+// mode - +1 to add the tag, -1 to remove it, 0 to toggle it
+// field - name of field (eg "tags")
+Story.prototype.setTiddlerField = function(title,tag,mode,field)
+{
+ var c = story.getTiddlerField(title,field);
+
+ var tags = c.value.readBracketedList();
+ tags.setItem(tag,mode);
+ c.value = String.encodeTiddlyLinkList(tags);
+}
+
+// The same as setTiddlerField but preset to the "tags" field
+Story.prototype.setTiddlerTag = function(title,tag,mode)
+{
+ Story.prototype.setTiddlerField(title,tag,mode,"tags");
+}
+
+// Close a specified tiddler
+// title - name of tiddler to close
+// animate - whether to perform animations
+// slowly - whether to perform animations in slomo
+Story.prototype.closeTiddler = function(title,animate,slowly)
+{
+ var tiddlerElem = document.getElementById(this.idPrefix + title);
+ if(tiddlerElem != null)
+ {
+ clearMessage();
+ this.scrubTiddler(tiddlerElem);
+ if(anim && config.options.chkAnimate && animate)
+ anim.startAnimating(new Slider(tiddlerElem,false,slowly,"all"));
+ else
+ tiddlerElem.parentNode.removeChild(tiddlerElem);
+ }
+}
+
+// Scrub IDs from a tiddler. This is so that the 'ghost' of a tiddler while it is being closed
+// does not interfere with things
+// tiddler - reference to the tiddler element
+Story.prototype.scrubTiddler = function(tiddlerElem)
+{
+ tiddlerElem.id = null;
+}
+
+// Set the 'dirty' flag of a tiddler
+// title - title of tiddler to change
+// dirty - new boolean status of flag
+Story.prototype.setDirty = function(title,dirty)
+{
+ var tiddlerElem = document.getElementById(this.idPrefix + title);
+ if(tiddlerElem != null)
+ tiddlerElem.setAttribute("dirty",dirty ? "true" : "false");
+}
+
+// Is a particular tiddler dirty (with unsaved changes)?
+Story.prototype.isDirty = function(title)
+{
+ var tiddlerElem = document.getElementById(this.idPrefix + title);
+ if(tiddlerElem != null)
+ return tiddlerElem.getAttribute("dirty") == "true";
+ return null;
+}
+
+// Determine whether any open tiddler are dirty
+Story.prototype.areAnyDirty = function()
+{
+ var r = false;
+ this.forEachTiddler(function(title,element) {
+ if(this.isDirty(title))
+ r = true;
+ });
+ return r;
+}
+
+// Close all tiddlers in the story
+Story.prototype.closeAllTiddlers = function(exclude)
+{
+ clearMessage();
+ this.forEachTiddler(function(title,element) {
+ if((title != exclude) && element.getAttribute("dirty") != "true")
+ this.closeTiddler(title);
+ });
+ window.scrollTo(0,0);
+}
+
+// Check if there are any tiddlers in the story
+Story.prototype.isEmpty = function()
+{
+ var place = document.getElementById(this.container);
+ return(place && place.firstChild == null);
+}
+
+// Perform a search and display the result
+// text - text to search for
+// useCaseSensitive - true for case sensitive matching
+// useRegExp - true to interpret text as a RegExp
+Story.prototype.search = function(text,useCaseSensitive,useRegExp)
+{
+ this.closeAllTiddlers();
+ highlightHack = new RegExp(useRegExp ? text : text.escapeRegExp(),useCaseSensitive ? "mg" : "img");
+ var matches = store.search(highlightHack,"title","excludeSearch");
+ var titles = [];
+ for(var t=matches.length-1; t>=0; t--)
+ titles.push(matches[t].title);
+ this.displayTiddlers(null,titles);
+ highlightHack = null;
+ var q = useRegExp ? "/" : "'";
+ if(matches.length > 0)
+ displayMessage(config.macros.search.successMsg.format([titles.length.toString(),q + text + q]));
+ else
+ displayMessage(config.macros.search.failureMsg.format([q + text + q]));
+}
+
+// Determine if the specified element is within a tiddler in this story
+// e - reference to an element
+// returns: reference to a tiddler element or null if none
+Story.prototype.findContainingTiddler = function(e)
+{
+ while(e && !hasClass(e,"tiddler"))
+ e = e.parentNode;
+ return(e);
+}
+
+// Gather any saveable fields from a tiddler element
+// e - reference to an element to scan recursively
+// fields - object to contain gathered field values
+Story.prototype.gatherSaveFields = function(e,fields)
+{
+ if(e && e.getAttribute)
+ {
+ var f = e.getAttribute("edit");
+ if(f)
+ fields[f] = e.value.replace(/\r/mg,"");;
+ if(e.hasChildNodes())
+ {
+ var c = e.childNodes;
+ for(var t=0; t<c.length; t++)
+ this.gatherSaveFields(c[t],fields)
+ }
+ }
+}
+
+// Determine whether a tiddler has any edit fields, and if so if their values have been changed
+// title - name of tiddler
+Story.prototype.hasChanges = function(title)
+{
+ var e = document.getElementById(this.idPrefix + title);
+ if(e != null)
+ {
+ var fields = {};
+ this.gatherSaveFields(e,fields);
+ var tiddler = store.fetchTiddler(title);
+ if (!tiddler)
+ return false;
+ for(var n in fields)
+ if (store.getValue(title,n) != fields[n])
+ return true;
+ }
+ return false;
+}
+
+// Save any open edit fields of a tiddler and updates the display as necessary
+// title - name of tiddler
+// minorUpdate - true if the modified date shouldn't be updated
+// returns: title of saved tiddler, or null if not saved
+Story.prototype.saveTiddler = function(title,minorUpdate)
+{
+ var tiddlerElem = document.getElementById(this.idPrefix + title);
+ if(tiddlerElem != null)
+ {
+ var fields = {};
+ this.gatherSaveFields(tiddlerElem,fields);
+ var newTitle = fields.title ? fields.title : title;
+ if(store.tiddlerExists(newTitle) && newTitle != title)
+ {
+ if(confirm(config.messages.overwriteWarning.format([newTitle.toString()])))
+ this.closeTiddler(newTitle,false,false);
+ else
+ return null;
+ }
+ tiddlerElem.id = this.idPrefix + newTitle;
+ tiddlerElem.setAttribute("tiddler",newTitle);
+ tiddlerElem.setAttribute("template",DEFAULT_VIEW_TEMPLATE);
+ tiddlerElem.setAttribute("dirty","false");
+ if(config.options.chkForceMinorUpdate)
+ minorUpdate = !minorUpdate;
+ var newDate = new Date();
+ store.saveTiddler(title,newTitle,fields.text,config.options.txtUserName,minorUpdate ? undefined : newDate,fields.tags);
+ for (var n in fields)
+ if (!TiddlyWiki.isStandardField(n))
+ store.setValue(newTitle,n,fields[n]);
+ if(config.options.chkAutoSave)
+ saveChanges();
+ return newTitle;
+ }
+ return null;
+}
+
+Story.prototype.permaView = function()
+{
+ var links = [];
+ this.forEachTiddler(function(title,element) {
+ links.push(String.encodeTiddlyLink(title));
+ });
+ var t = encodeURIComponent(links.join(" "));
+ if(t == "")
+ t = "#";
+ if(window.location.hash != t)
+ window.location.hash = t;
+}
+
+// ---------------------------------------------------------------------------------
+// Message area
+// ---------------------------------------------------------------------------------
+
+function getMessageDiv()
+{
+ var msgArea = document.getElementById("messageArea");
+ if(!msgArea)
+ return null;
+ if(!msgArea.hasChildNodes())
+ createTiddlyButton(createTiddlyElement(msgArea,"div",null,"messageToolbar"),
+ config.messages.messageClose.text,
+ config.messages.messageClose.tooltip,
+ clearMessage);
+ msgArea.style.display = "block";
+ return createTiddlyElement(msgArea,"div");
+}
+
+function displayMessage(text,linkText)
+{
+ var e = getMessageDiv();
+ if(!e)
+ {
+ alert(text);
+ return;
+ }
+ if(linkText)
+ {
+ var link = createTiddlyElement(e,"a",null,null,text);
+ link.href = linkText;
+ link.target = "_blank";
+ }
+ else
+ e.appendChild(document.createTextNode(text));
+}
+
+function clearMessage()
+{
+ var msgArea = document.getElementById("messageArea");
+ if(msgArea)
+ {
+ removeChildren(msgArea);
+ msgArea.style.display = "none";
+ }
+ return false;
+}
+
+// ---------------------------------------------------------------------------------
+// Refresh mechanism
+// ---------------------------------------------------------------------------------
+
+config.refreshers = {
+ link: function(e,changeList)
+ {
+ var title = e.getAttribute("tiddlyLink");
+ refreshTiddlyLink(e,title);
+ return true;
+ },
+
+ tiddler: function(e,changeList)
+ {
+ var title = e.getAttribute("tiddler");
+ var template = e.getAttribute("template");
+ if(changeList && changeList.indexOf(title) != -1 && !story.isDirty(title))
+ story.refreshTiddler(title,template,true);
+ else
+ refreshElements(e,changeList);
+ return true;
+ },
+
+ content: function(e,changeList)
+ {
+ var title = e.getAttribute("tiddler");
+ var force = e.getAttribute("force");
+ if(force != null || changeList == null || changeList.indexOf(title) != -1)
+ {
+ removeChildren(e);
+ wikify(store.getTiddlerText(title,title),e);
+ return true;
+ }
+ else
+ return false;
+ },
+
+ macro: function(e,changeList)
+ {
+ var macro = e.getAttribute("macroName");
+ var params = e.getAttribute("params");
+ if(macro)
+ macro = config.macros[macro];
+ if(macro && macro.refresh)
+ macro.refresh(e,params);
+ return true;
+ }
+};
+
+function refreshElements(root,changeList)
+{
+ var nodes = root.childNodes;
+ for(var c=0; c<nodes.length; c++)
+ {
+ var e = nodes[c],type;
+ if(e.getAttribute)
+ type = e.getAttribute("refresh");
+ else
+ type = null;
+ var refresher = config.refreshers[type];
+ var refreshed = false;
+ if(refresher != undefined)
+ refreshed = refresher(e,changeList);
+ if(e.hasChildNodes() && !refreshed)
+ refreshElements(e,changeList);
+ }
+}
+
+function applyHtmlMacros(root,tiddler)
+{
+ var e = root.firstChild;
+ while(e)
+ {
+ var nextChild = e.nextSibling;
+ if(e.getAttribute)
+ {
+ var macro = e.getAttribute("macro");
+ if(macro)
+ {
+ var params = "";
+ var p = macro.indexOf(" ");
+ if(p != -1)
+ {
+ params = macro.substr(p+1);
+ macro = macro.substr(0,p);
+ }
+ invokeMacro(e,macro,params,null,tiddler);
+ }
+ }
+ if(e.hasChildNodes())
+ applyHtmlMacros(e,tiddler);
+ e = nextChild;
+ }
+}
+
+function refreshPageTemplate(title)
+{
+ var stash = createTiddlyElement(document.body,"div");
+ stash.style.display = "none";
+ var display = document.getElementById("tiddlerDisplay");
+ var nodes,t;
+ if(display)
+ {
+ nodes = display.childNodes;
+ for(t=nodes.length-1; t>=0; t--)
+ stash.appendChild(nodes[t]);
+ }
+ var wrapper = document.getElementById("contentWrapper");
+ if(!title)
+ title = "PageTemplate";
+ var html = store.getRecursiveTiddlerText(title,null,10);
+ wrapper.innerHTML = html;
+ applyHtmlMacros(wrapper);
+ refreshElements(wrapper);
+ display = document.getElementById("tiddlerDisplay");
+ removeChildren(display);
+ if(!display)
+ display = createTiddlyElement(wrapper,"div","tiddlerDisplay");
+ nodes = stash.childNodes;
+ for(t=nodes.length-1; t>=0; t--)
+ display.appendChild(nodes[t]);
+ stash.parentNode.removeChild(stash);
+}
+
+function refreshDisplay(hint)
+{
+ var e = document.getElementById("contentWrapper");
+ if(typeof hint == "string")
+ hint = [hint];
+ refreshElements(e,hint);
+}
+
+function refreshPageTitle()
+{
+ document.title = wikifyPlain("SiteTitle") + " - " + wikifyPlain("SiteSubtitle");
+}
+
+function refreshStyles(title)
+{
+ setStylesheet(title == null ? "" : store.getRecursiveTiddlerText(title,"",10),title);
+}
+
+function refreshColorPalette(title)
+{
+ if(!startingUp)
+ refreshAll();
+}
+
+function refreshAll()
+{
+ refreshPageTemplate();
+ refreshDisplay();
+ refreshStyles("StyleSheetLayout");
+ refreshStyles("StyleSheetColors");
+ refreshStyles("StyleSheet");
+ refreshStyles("StyleSheetPrint");
+}
+
+// ---------------------------------------------------------------------------------
+// Options cookie stuff
+// ---------------------------------------------------------------------------------
+
+function loadOptionsCookie()
+{
+ if(safeMode)
+ return;
+ var cookies = document.cookie.split(";");
+ for(var c=0; c<cookies.length; c++)
+ {
+ var p = cookies[c].indexOf("=");
+ if(p != -1)
+ {
+ var name = cookies[c].substr(0,p).trim();
+ var value = cookies[c].substr(p+1).trim();
+ switch(name.substr(0,3))
+ {
+ case "txt":
+ config.options[name] = unescape(value);
+ break;
+ case "chk":
+ config.options[name] = value == "true";
+ break;
+ }
+ }
+ }
+}
+
+function saveOptionCookie(name)
+{
+ if(safeMode)
+ return;
+ var c = name + "=";
+ switch(name.substr(0,3))
+ {
+ case "txt":
+ c += escape(config.options[name].toString());
+ break;
+ case "chk":
+ c += config.options[name] ? "true" : "false";
+ break;
+ }
+ c += "; expires=Fri, 1 Jan 2038 12:00:00 UTC; path=/";
+ document.cookie = c;
+}
+
+// ---------------------------------------------------------------------------------
+// Saving
+// ---------------------------------------------------------------------------------
+
+var saveUsingSafari = false;
+
+var startSaveArea = '<div id="' + 'storeArea">'; // Split up into two so that indexOf() of this source doesn't find it
+var endSaveArea = '</d' + 'iv>';
+
+// If there are unsaved changes, force the user to confirm before exitting
+function confirmExit()
+{
+ hadConfirmExit = true;
+ if((store && store.isDirty && store.isDirty()) || (story && story.areAnyDirty && story.areAnyDirty()))
+ return config.messages.confirmExit;
+}
+
+// Give the user a chance to save changes before exitting
+function checkUnsavedChanges()
+{
+ if(store && store.isDirty && store.isDirty() && window.hadConfirmExit === false)
+ {
+ if(confirm(config.messages.unsavedChangesWarning))
+ saveChanges();
+ }
+}
+
+function updateMarkupBlock(s,blockName,tiddlerName)
+{
+ return s.replaceChunk(
+ "<!--%0-START-->".format([blockName]),
+ "<!--%0-END-->".format([blockName]),
+ "\n" + store.getRecursiveTiddlerText(tiddlerName,"") + "\n");
+}
+
+// Save this tiddlywiki with the pending changes
+function saveChanges(onlyIfDirty)
+{
+ if(onlyIfDirty && !store.isDirty())
+ return;
+ clearMessage();
+ // Get the URL of the document
+ var originalPath = document.location.toString();
+ // Check we were loaded from a file URL
+ if(originalPath.substr(0,5) != "file:")
+ {
+ alert(config.messages.notFileUrlError);
+ if(store.tiddlerExists(config.messages.saveInstructions))
+ story.displayTiddler(null,config.messages.saveInstructions);
+ return;
+ }
+ var localPath = getLocalPath(originalPath);
+ // Load the original file
+ var original = loadFile(localPath);
+ if(original == null)
+ {
+ alert(config.messages.cantSaveError);
+ if(store.tiddlerExists(config.messages.saveInstructions))
+ story.displayTiddler(null,config.messages.saveInstructions);
+ return;
+ }
+ // Locate the storeArea div's
+ var posOpeningDiv = original.indexOf(startSaveArea);
+ var limitClosingDiv = original.indexOf("<!--POST-BODY-START--"+">");
+ var posClosingDiv = original.lastIndexOf(endSaveArea,limitClosingDiv == -1 ? original.length : limitClosingDiv);
+ if((posOpeningDiv == -1) || (posClosingDiv == -1))
+ {
+ alert(config.messages.invalidFileError.format([localPath]));
+ return;
+ }
+ // Save the backup
+ if(config.options.chkSaveBackups)
+ {
+ var backupPath = getBackupPath(localPath);
+ var backup = saveFile(backupPath,original);
+ if(backup)
+ displayMessage(config.messages.backupSaved,"file://" + backupPath);
+ else
+ alert(config.messages.backupFailed);
+ }
+ // Save Rss
+ if(config.options.chkGenerateAnRssFeed)
+ {
+ var rssPath = localPath.substr(0,localPath.lastIndexOf(".")) + ".xml";
+ var rssSave = saveFile(rssPath,convertUnicodeToUTF8(generateRss()));
+ if(rssSave)
+ displayMessage(config.messages.rssSaved,"file://" + rssPath);
+ else
+ alert(config.messages.rssFailed);
+ }
+ // Save empty template
+ if(config.options.chkSaveEmptyTemplate)
+ {
+ var emptyPath,p;
+ if((p = localPath.lastIndexOf("/")) != -1)
+ emptyPath = localPath.substr(0,p) + "/empty.html";
+ else if((p = localPath.lastIndexOf("\\")) != -1)
+ emptyPath = localPath.substr(0,p) + "\\empty.html";
+ else
+ emptyPath = localPath + ".empty.html";
+ var empty = original.substr(0,posOpeningDiv + startSaveArea.length) + original.substr(posClosingDiv);
+ var emptySave = saveFile(emptyPath,empty);
+ if(emptySave)
+ displayMessage(config.messages.emptySaved,"file://" + emptyPath);
+ else
+ alert(config.messages.emptyFailed);
+ }
+ var save;
+ try
+ {
+ // Save new file
+ var revised = original.substr(0,posOpeningDiv + startSaveArea.length) + "\n" +
+ convertUnicodeToUTF8(store.allTiddlersAsHtml()) + "\n" +
+ original.substr(posClosingDiv);
+ var newSiteTitle = convertUnicodeToUTF8((wikifyPlain("SiteTitle") + " - " + wikifyPlain("SiteSubtitle")).htmlEncode());
+ revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
+ revised = updateMarkupBlock(revised,"PRE-HEAD","MarkupPreHead");
+ revised = updateMarkupBlock(revised,"POST-HEAD","MarkupPostHead");
+ revised = updateMarkupBlock(revised,"PRE-BODY","MarkupPreBody");
+ revised = updateMarkupBlock(revised,"POST-BODY","MarkupPostBody");
+ save = saveFile(localPath,revised);
+ }
+ catch (e)
+ {
+ showException(e);
+ }
+ if(save)
+ {
+ displayMessage(config.messages.mainSaved,"file://" + localPath);
+ store.setDirty(false);
+ }
+ else
+ alert(config.messages.mainFailed);
+}
+
+function getLocalPath(originalPath)
+{
+ // Remove any location or query part of the URL
+ var argPos = originalPath.indexOf("?");
+ if(argPos != -1)
+ originalPath = originalPath.substr(0,argPos);
+ var hashPos = originalPath.indexOf("#");
+ if(hashPos != -1)
+ originalPath = originalPath.substr(0,hashPos);
+ // Convert file://localhost/ to file:///
+ if(originalPath.indexOf("file://localhost/") == 0)
+ originalPath = "file://" + originalPath.substr(16);
+ // Convert to a native file format assuming
+ // "file:///x:/path/path/path..." - pc local file --> "x:\path\path\path..."
+ // "file://///server/share/path/path/path..." - FireFox pc network file --> "\\server\share\path\path\path..."
+ // "file:///path/path/path..." - mac/unix local file --> "/path/path/path..."
+ // "file://server/share/path/path/path..." - pc network file --> "\\server\share\path\path\path..."
+ var localPath;
+ if(originalPath.charAt(9) == ":") // pc local file
+ localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\\");
+ else if(originalPath.indexOf("file://///") == 0) // FireFox pc network file
+ localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\\");
+ else if(originalPath.indexOf("file:///") == 0) // mac/unix local file
+ localPath = unescape(originalPath.substr(7));
+ else if(originalPath.indexOf("file:/") == 0) // mac/unix local file
+ localPath = unescape(originalPath.substr(5));
+ else // pc network file
+ localPath = "\\\\" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\\");
+ return localPath;
+}
+
+function getBackupPath(localPath)
+{
+ var backSlash = true;
+ var dirPathPos = localPath.lastIndexOf("\\");
+ if(dirPathPos == -1)
+ {
+ dirPathPos = localPath.lastIndexOf("/");
+ backSlash = false;
+ }
+ var backupFolder = config.options.txtBackupFolder;
+ if(!backupFolder || backupFolder == "")
+ backupFolder = ".";
+ var backupPath = localPath.substr(0,dirPathPos) + (backSlash ? "\\" : "/") + backupFolder + localPath.substr(dirPathPos);
+ backupPath = backupPath.substr(0,backupPath.lastIndexOf(".")) + "." + (new Date()).convertToYYYYMMDDHHMMSSMMM() + ".html";
+ return backupPath;
+}
+
+function generateRss()
+{
+ var s = [];
+ var d = new Date();
+ var u = store.getTiddlerText("SiteUrl");
+ // Assemble the header
+ s.push("<" + "?xml version=\"1.0\"?" + ">");
+ s.push("<rss version=\"2.0\">");
+ s.push("<channel>");
+ s.push("<title" + ">" + wikifyPlain("SiteTitle").htmlEncode() + "</title" + ">");
+ if(u)
+ s.push("<link>" + u.htmlEncode() + "</link>");
+ s.push("<description>" + wikifyPlain("SiteSubtitle").htmlEncode() + "</description>");
+ s.push("<language>en-us</language>");
+ s.push("<copyright>Copyright " + d.getFullYear() + " " + config.options.txtUserName.htmlEncode() + "</copyright>");
+ s.push("<pubDate>" + d.toGMTString() + "</pubDate>");
+ s.push("<lastBuildDate>" + d.toGMTString() + "</lastBuildDate>");
+ s.push("<docs>http://blogs.law.harvard.edu/tech/rss</docs>");
+ s.push("<generator>TiddlyWiki " + version.major + "." + version.minor + "." + version.revision + "</generator>");
+ // The body
+ var tiddlers = store.getTiddlers("modified","excludeLists");
+ var n = config.numRssItems > tiddlers.length ? 0 : tiddlers.length-config.numRssItems;
+ for (var t=tiddlers.length-1; t>=n; t--)
+ s.push(tiddlers[t].saveToRss(u));
+ // And footer
+ s.push("</channel>");
+ s.push("</rss>");
+ // Save it all
+ return s.join("\n");
+}
+
+
+// UTF-8 encoding rules:
+// 0x0000 - 0x007F: 0xxxxxxx
+// 0x0080 - 0x07FF: 110xxxxx 10xxxxxx
+// 0x0800 - 0xFFFF: 1110xxxx 10xxxxxx 10xxxxxx
+
+function convertUTF8ToUnicode(u)
+{
+ if(window.netscape == undefined)
+ return manualConvertUTF8ToUnicode(u);
+ else
+ return mozConvertUTF8ToUnicode(u);
+}
+
+function manualConvertUTF8ToUnicode(utf)
+{
+ var uni = utf;
+ var src = 0;
+ var dst = 0;
+ var b1, b2, b3;
+ var c;
+ while(src < utf.length)
+ {
+ b1 = utf.charCodeAt(src++);
+ if(b1 < 0x80)
+ dst++;
+ else if(b1 < 0xE0)
+ {
+ b2 = utf.charCodeAt(src++);
+ c = String.fromCharCode(((b1 & 0x1F) << 6) | (b2 & 0x3F));
+ uni = uni.substring(0,dst++).concat(c,utf.substr(src));
+ }
+ else
+ {
+ b2 = utf.charCodeAt(src++);
+ b3 = utf.charCodeAt(src++);
+ c = String.fromCharCode(((b1 & 0xF) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F));
+ uni = uni.substring(0,dst++).concat(c,utf.substr(src));
+ }
+ }
+ return(uni);
+}
+
+function mozConvertUTF8ToUnicode(u)
+{
+ try
+ {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
+ converter.charset = "UTF-8";
+ }
+ catch(e)
+ {
+ return manualConvertUTF8ToUnicode(u);
+ } // fallback
+ var s = converter.ConvertToUnicode(u);
+ var fin = converter.Finish();
+ return (fin.length > 0) ? s+fin : s;
+}
+
+function convertUnicodeToUTF8(s)
+{
+ if(window.netscape == undefined)
+ return manualConvertUnicodeToUTF8(s);
+ else
+ return mozConvertUnicodeToUTF8(s);
+}
+
+function manualConvertUnicodeToUTF8(s)
+{
+ var re = /[^\u0000-\u007F]/g ;
+ return s.replace(re, function($0) {return("&#" + $0.charCodeAt(0).toString() + ";");})
+}
+
+function mozConvertUnicodeToUTF8(s)
+{
+ try
+ {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
+ converter.charset = "UTF-8";
+ }
+ catch(e)
+ {
+ return manualConvertUnicodeToUTF8(s);
+ } // fallback
+ var u = converter.ConvertFromUnicode(s);
+ var fin = converter.Finish();
+ if(fin.length > 0)
+ return u + fin;
+ else
+ return u;
+}
+
+function saveFile(fileUrl, content)
+{
+ var r = null;
+ if((r == null) || (r == false))
+ r = mozillaSaveFile(fileUrl, content);
+ if((r == null) || (r == false))
+ r = ieSaveFile(fileUrl, content);
+ if((r == null) || (r == false))
+ r = javaSaveFile(fileUrl, content);
+ return(r);
+}
+
+function loadFile(fileUrl)
+{
+ var r = null;
+ if((r == null) || (r == false))
+ r = mozillaLoadFile(fileUrl);
+ if((r == null) || (r == false))
+ r = ieLoadFile(fileUrl);
+ if((r == null) || (r == false))
+ r = javaLoadFile(fileUrl);
+ return(r);
+}
+
+// Returns null if it can't do it, false if there's an error, true if it saved OK
+function ieSaveFile(filePath, content)
+{
+ try
+ {
+ var fso = new ActiveXObject("Scripting.FileSystemObject");
+ }
+ catch(e)
+ {
+ //alert("Exception while attempting to save\n\n" + e.toString());
+ return(null);
+ }
+ var file = fso.OpenTextFile(filePath,2,-1,0);
+ file.Write(content);
+ file.Close();
+ return(true);
+}
+
+// Returns null if it can't do it, false if there's an error, or a string of the content if successful
+function ieLoadFile(filePath)
+{
+ try
+ {
+ var fso = new ActiveXObject("Scripting.FileSystemObject");
+ var file = fso.OpenTextFile(filePath,1);
+ var content = file.ReadAll();
+ file.Close();
+ }
+ catch(e)
+ {
+ //alert("Exception while attempting to load\n\n" + e.toString());
+ return(null);
+ }
+ return(content);
+}
+
+// Returns null if it can't do it, false if there's an error, true if it saved OK
+function mozillaSaveFile(filePath, content)
+{
+ if(window.Components)
+ try
+ {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
+ file.initWithPath(filePath);
+ if (!file.exists())
+ file.create(0, 0664);
+ var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
+ out.init(file, 0x20 | 0x02, 00004,null);
+ out.write(content, content.length);
+ out.flush();
+ out.close();
+ return(true);
+ }
+ catch(e)
+ {
+ //alert("Exception while attempting to save\n\n" + e);
+ return(false);
+ }
+ return(null);
+}
+
+// Returns null if it can't do it, false if there's an error, or a string of the content if successful
+function mozillaLoadFile(filePath)
+{
+ if(window.Components)
+ try
+ {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
+ file.initWithPath(filePath);
+ if (!file.exists())
+ return(null);
+ var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
+ inputStream.init(file, 0x01, 00004, null);
+ var sInputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
+ sInputStream.init(inputStream);
+ return(sInputStream.read(sInputStream.available()));
+ }
+ catch(e)
+ {
+ //alert("Exception while attempting to load\n\n" + e);
+ return(false);
+ }
+ return(null);
+}
+
+function javaUrlToFilename(url)
+{
+ var f = "//localhost";
+ if(url.indexOf(f) == 0)
+ return url.substring(f.length);
+ var i = url.indexOf(":");
+ if(i > 0)
+ return url.substring(i-1);
+ return url;
+}
+
+function javaSaveFile(filePath, content)
+{
+ try
+ {
+ if(document.applets["TiddlySaver"])
+ return document.applets["TiddlySaver"].saveFile(javaUrlToFilename(filePath),"UTF-8",content);
+ }
+ catch(e)
+ {
+ }
+ try
+ {
+ var s = new java.io.PrintStream(new java.io.FileOutputStream(javaUrlToFilename(filePath)));
+ s.print(content);
+ s.close();
+ }
+ catch(e)
+ {
+ return null;
+ }
+ return true;
+}
+
+function javaLoadFile(filePath)
+{
+ try
+ {
+ if(document.applets["TiddlySaver"])
+ return String(document.applets["TiddlySaver"].loadFile(javaUrlToFilename(filePath),"UTF-8"));
+ }
+ catch(e)
+ {
+ }
+ var content = [];
+ try
+ {
+ var r = new java.io.BufferedReader(new java.io.FileReader(javaUrlToFilename(filePath)));
+ var line;
+ while ((line = r.readLine()) != null)
+ content.push(new String(line));
+ r.close();
+ }
+ catch(e)
+ {
+ return null;
+ }
+ return content.join("\n");
+}
+
+
+// ---------------------------------------------------------------------------------
+// Remote HTTP requests
+// ---------------------------------------------------------------------------------
+
+// Load a file over http
+// url - the source url
+// callback - function to call when there's a response
+// params - parameter object that gets passed to the callback for storing it's state
+// Return value is the underlying XMLHttpRequest object, or 'null' if there was an error
+// Callback function is called like this:
+// callback(status,params,responseText,xhr)
+// status - true if OK, false if error
+// params - the parameter object provided to loadRemoteFile()
+// responseText - the text of the file
+// xhr - the underlying XMLHttpRequest object
+function loadRemoteFile(url,callback,params)
+{
+ // Get an xhr object
+ var x;
+ try
+ {
+ x = new XMLHttpRequest(); // Modern
+ }
+ catch(e)
+ {
+ try
+ {
+ x = new ActiveXObject("Msxml2.XMLHTTP"); // IE 6
+ }
+ catch (e)
+ {
+ return null;
+ }
+ }
+ // Install callback
+ x.onreadystatechange = function()
+ {
+ if (x.readyState == 4)
+ {
+ if ((x.status == 0 || x.status == 200) && callback)
+ {
+ callback(true,params,x.responseText,url,x);
+ }
+ else
+ callback(false,params,null,url,x);
+ }
+ }
+ // Send request
+ if(window.netscape && window.netscape.security && document.location.protocol.indexOf("http") == -1)
+ window.netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
+ try
+ {
+ url = url + (url.indexOf("?") < 0 ? "?" : "&") + "nocache=" + Math.random();
+ x.open("GET",url,true);
+ if (x.overrideMimeType)
+ x.overrideMimeType("text/html");
+ x.send(null);
+ }
+ catch (e)
+ {
+ alert("Error in send " + e);
+ return null;
+ }
+ return x;
+}
+// ---------------------------------------------------------------------------------
+// TiddlyWiki-specific utility functions
+// ---------------------------------------------------------------------------------
+
+function createTiddlyButton(theParent,theText,theTooltip,theAction,theClass,theId,theAccessKey)
+{
+ var theButton = document.createElement("a");
+ if(theAction)
+ {
+ theButton.onclick = theAction;
+ theButton.setAttribute("href","javascript:;");
+ }
+ if(theTooltip)
+ theButton.setAttribute("title",theTooltip);
+ if(theText)
+ theButton.appendChild(document.createTextNode(theText));
+ if(theClass)
+ theButton.className = theClass;
+ else
+ theButton.className = "button";
+ if(theId)
+ theButton.id = theId;
+ if(theParent)
+ theParent.appendChild(theButton);
+ if(theAccessKey)
+ theButton.setAttribute("accessKey",theAccessKey);
+ return(theButton);
+}
+
+function createTiddlyLink(place,title,includeText,theClass,isStatic)
+{
+ var text = includeText ? title : null;
+ var i = getTiddlyLinkInfo(title,theClass)
+ var btn;
+ if(isStatic)
+ btn = createExternalLink(place,"#" + title);
+ else
+ btn = createTiddlyButton(place,text,i.subTitle,onClickTiddlerLink,i.classes);
+ btn.setAttribute("refresh","link");
+ btn.setAttribute("tiddlyLink",title);
+ return(btn);
+}
+
+function refreshTiddlyLink(e,title)
+{
+ var i = getTiddlyLinkInfo(title,e.className);
+ e.className = i.classes;
+ e.title = i.subTitle;
+}
+
+function getTiddlyLinkInfo(title,currClasses)
+{
+ var classes = currClasses ? currClasses.split(" ") : [];
+ classes.pushUnique("tiddlyLink");
+ var tiddler = store.fetchTiddler(title);
+ var subTitle;
+ if(tiddler)
+ {
+ subTitle = tiddler.getSubtitle();
+ classes.pushUnique("tiddlyLinkExisting");
+ classes.remove("tiddlyLinkNonExisting");
+ classes.remove("shadow");
+ }
+ else
+ {
+ classes.remove("tiddlyLinkExisting");
+ classes.pushUnique("tiddlyLinkNonExisting");
+ if(store.isShadowTiddler(title))
+ {
+ subTitle = config.messages.shadowedTiddlerToolTip.format([title]);
+ classes.pushUnique("shadow");
+ }
+ else
+ {
+ subTitle = config.messages.undefinedTiddlerToolTip.format([title]);
+ classes.remove("shadow");
+ }
+ }
+ return {classes: classes.join(" "), subTitle: subTitle};
+}
+
+function createExternalLink(place,url)
+{
+ var theLink = document.createElement("a");
+ theLink.className = "externalLink";
+ theLink.href = url;
+ theLink.title = config.messages.externalLinkTooltip.format([url]);
+ if(config.options.chkOpenInNewWindow)
+ theLink.target = "_blank";
+ place.appendChild(theLink);
+ return(theLink);
+}
+
+// Event handler for clicking on a tiddly link
+function onClickTiddlerLink(e)
+{
+ if (!e) var e = window.event;
+ var theTarget = resolveTarget(e);
+ var theLink = theTarget;
+ var title = null;
+ do {
+ title = theLink.getAttribute("tiddlyLink");
+ theLink = theLink.parentNode;
+ } while(title == null && theLink != null);
+ if(title)
+ {
+ var toggling = e.metaKey || e.ctrlKey;
+ if(config.options.chkToggleLinks)
+ toggling = !toggling;
+ var opening;
+ if(toggling && document.getElementById("tiddler" + title))
+ story.closeTiddler(title,true,e.shiftKey || e.altKey);
+ else
+ story.displayTiddler(theTarget,title,null,true,e.shiftKey || e.altKey);
+ }
+ clearMessage();
+ return(false);
+}
+
+// Create a button for a tag with a popup listing all the tiddlers that it tags
+function createTagButton(place,tag,excludeTiddler)
+{
+ var theTag = createTiddlyButton(place,tag,config.views.wikified.tag.tooltip.format([tag]),onClickTag);
+ theTag.setAttribute("tag",tag);
+ if(excludeTiddler)
+ theTag.setAttribute("tiddler",excludeTiddler);
+ return(theTag);
+}
+
+// Event handler for clicking on a tiddler tag
+function onClickTag(e)
+{
+ if (!e) var e = window.event;
+ var theTarget = resolveTarget(e);
+ var popup = Popup.create(this);
+ var tag = this.getAttribute("tag");
+ var title = this.getAttribute("tiddler");
+ if(popup && tag)
+ {
+ var tagged = store.getTaggedTiddlers(tag);
+ var titles = [];
+ var li,r;
+ for(r=0;r<tagged.length;r++)
+ if(tagged[r].title != title)
+ titles.push(tagged[r].title);
+ var lingo = config.views.wikified.tag;
+ if(titles.length > 0)
+ {
+ var openAll = createTiddlyButton(createTiddlyElement(popup,"li"),lingo.openAllText.format([tag]),lingo.openAllTooltip,onClickTagOpenAll);
+ openAll.setAttribute("tag",tag);
+ createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
+ for(r=0; r<titles.length; r++)
+ {
+ createTiddlyLink(createTiddlyElement(popup,"li"),titles[r],true);
+ }
+ }
+ else
+ createTiddlyText(createTiddlyElement(popup,"li",null,"disabled"),lingo.popupNone.format([tag]));
+ createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
+ var h = createTiddlyLink(createTiddlyElement(popup,"li"),tag,false);
+ createTiddlyText(h,lingo.openTag.format([tag]));
+ }
+ Popup.show(popup,false);
+ e.cancelBubble = true;
+ if (e.stopPropagation) e.stopPropagation();
+ return(false);
+}
+
+// Event handler for 'open all' on a tiddler popup
+function onClickTagOpenAll(e)
+{
+ if (!e) var e = window.event;
+ var tag = this.getAttribute("tag");
+ var tagged = store.getTaggedTiddlers(tag);
+ var titles = [];
+ for(var t=0; t<tagged.length; t++)
+ titles.push(tagged[t].title);
+ story.displayTiddlers(this,titles);
+ return(false);
+}
+
+function onClickError(e)
+{
+ if (!e) var e = window.event;
+ var popup = Popup.create(this);
+ var lines = this.getAttribute("errorText").split("\n");
+ for(var t=0; t<lines.length; t++)
+ createTiddlyElement(popup,"li",null,null,lines[t]);
+ Popup.show(popup,false);
+ e.cancelBubble = true;
+ if (e.stopPropagation) e.stopPropagation();
+ return false;
+}
+
+function createTiddlyDropDown(place,onchange,options)
+{
+ var sel = createTiddlyElement(place,"select");
+ sel.onchange = onchange;
+ for(var t=0; t<options.length; t++)
+ {
+ var e = createTiddlyElement(sel,"option",null,null,options[t].caption);
+ e.value = options[t].name;
+ }
+}
+
+function createTiddlyError(place,title,text)
+{
+ var btn = createTiddlyButton(place,title,null,onClickError,"errorButton");
+ if (text) btn.setAttribute("errorText",text);
+}
+
+function merge(dst,src,preserveExisting)
+{
+ for (p in src)
+ if (!preserveExisting || dst[p] === undefined)
+ dst[p] = src[p];
+ return dst;
+}
+
+// Returns a string containing the description of an exception, optionally prepended by a message
+function exceptionText(e, message)
+{
+ var s = e.description ? e.description : e.toString();
+ return message ? "%0:\n%1".format([message, s]) : s;
+}
+
+// Displays an alert of an exception description with optional message
+function showException(e, message)
+{
+ alert(exceptionText(e, message));
+}
+
+// ---------------------------------------------------------------------------------
+// Animation engine
+// ---------------------------------------------------------------------------------
+
+function Animator()
+{
+ this.running = 0; // Incremented at start of each animation, decremented afterwards. If zero, the interval timer is disabled
+ this.timerID = 0; // ID of the timer used for animating
+ this.animations = []; // List of animations in progress
+ return this;
+}
+
+// Start animation engine
+Animator.prototype.startAnimating = function() // Variable number of arguments
+{
+ for(var t=0; t<arguments.length; t++)
+ this.animations.push(arguments[t]);
+ if(this.running == 0)
+ {
+ var me = this;
+ this.timerID = window.setInterval(function() {me.doAnimate(me);},5);
+ }
+ this.running += arguments.length;
+}
+
+// Perform an animation engine tick, calling each of the known animation modules
+Animator.prototype.doAnimate = function(me)
+{
+ var a = 0;
+ while(a < me.animations.length)
+ {
+ var animation = me.animations[a];
+ if(animation.tick())
+ a++;
+ else
+ {
+ me.animations.splice(a,1);
+ if(--me.running == 0)
+ window.clearInterval(me.timerID);
+ }
+ }
+}
+
+// Map a 0..1 value to 0..1, but slow down at the start and end
+Animator.slowInSlowOut = function(progress)
+{
+ return(1-((Math.cos(progress * Math.PI)+1)/2));
+}
+
+// ---------------------------------------------------------------------------------
+// Cascade animation
+// ---------------------------------------------------------------------------------
+
+function Cascade(text,startElement,targetElement,slowly)
+{
+ var winWidth = findWindowWidth();
+ var winHeight = findWindowHeight();
+ this.elements = [];
+ this.startElement = startElement;
+ this.startLeft = findPosX(this.startElement);
+ this.startTop = findPosY(this.startElement);
+ this.startWidth = Math.min(this.startElement.offsetWidth,winWidth);
+ this.startHeight = Math.min(this.startElement.offsetHeight,winHeight);
+ this.targetElement = targetElement;
+ targetElement.style.position = "relative";
+ targetElement.style.zIndex = 2;
+ this.targetLeft = findPosX(this.targetElement);
+ this.targetTop = findPosY(this.targetElement);
+ this.targetWidth = Math.min(this.targetElement.offsetWidth,winWidth);
+ this.targetHeight = Math.min(this.targetElement.offsetHeight,winHeight);
+ this.progress = -1;
+ this.steps = slowly ? config.cascadeSlow : config.cascadeFast;
+ this.text = text;
+ this.tick();
+ return this;
+}
+
+Cascade.prototype.tick = function()
+{
+ this.progress++;
+ if(this.progress >= this.steps)
+ {
+ while(this.elements.length > 0)
+ this.removeTail();
+ this.targetElement.style.position = "static";
+ this.targetElement.style.zIndex = "";
+ return false;
+ }
+ else
+ {
+ if(this.elements.length > 0 && this.progress > config.cascadeDepth)
+ this.removeTail();
+ if(this.progress < (this.steps - config.cascadeDepth))
+ {
+ var f = Animator.slowInSlowOut(this.progress/(this.steps - config.cascadeDepth - 1));
+ var e = createTiddlyElement(document.body,"div",null,"cascade",this.text);
+ e.style.zIndex = 1;
+ e.style.left = this.startLeft + (this.targetLeft-this.startLeft) * f + "px";
+ e.style.top = this.startTop + (this.targetTop-this.startTop) * f + "px";
+ e.style.width = this.startWidth + (this.targetWidth-this.startWidth) * f + "px";
+ e.style.height = this.startHeight + (this.targetHeight-this.startHeight) * f + "px";
+ e.style.display = "block";
+ this.elements.push(e);
+ }
+ return true;
+ }
+}
+
+Cascade.prototype.removeTail = function()
+{
+ var e = this.elements[0];
+ e.parentNode.removeChild(e);
+ this.elements.shift();
+}
+
+// ---------------------------------------------------------------------------------
+// Scroller animation
+// ---------------------------------------------------------------------------------
+
+function Scroller(targetElement,slowly)
+{
+ this.targetElement = targetElement;
+ this.startScroll = findScrollY();
+ this.targetScroll = ensureVisible(targetElement);
+ this.progress = 0;
+ this.step = slowly ? config.animSlow : config.animFast;
+ return this;
+}
+
+Scroller.prototype.tick = function()
+{
+ this.progress += this.step;
+ if(this.progress > 1)
+ {
+ window.scrollTo(0,this.targetScroll);
+ return false;
+ }
+ else
+ {
+ var f = Animator.slowInSlowOut(this.progress);
+ window.scrollTo(0,this.startScroll + (this.targetScroll-this.startScroll) * f);
+ return true;
+ }
+}
+
+// ---------------------------------------------------------------------------------
+// Slider animation
+// ---------------------------------------------------------------------------------
+
+// deleteMode - "none", "all" [delete target element and it's children], [only] "children" [but not the target element]
+function Slider(element,opening,slowly,deleteMode)
+{
+ this.element = element;
+ element.style.display = "block";
+ this.deleteMode = deleteMode;
+ this.element.style.height = "auto";
+ this.realHeight = element.offsetHeight;
+ this.opening = opening;
+ this.step = slowly ? config.animSlow : config.animFast;
+ if(opening)
+ {
+ this.progress = 0;
+ element.style.height = "0px";
+ element.style.display = "block";
+ }
+ else
+ {
+ this.progress = 1;
+ this.step = -this.step;
+ }
+ element.style.overflow = "hidden";
+ return this;
+}
+
+Slider.prototype.stop = function()
+{
+ if(this.opening)
+ {
+ this.element.style.height = "auto";
+ this.element.style.opacity = 1;
+ this.element.style.filter = "alpha(opacity:100)";
+ }
+ else
+ {
+ switch(this.deleteMode)
+ {
+ case "none":
+ this.element.style.display = "none";
+ break;
+ case "all":
+ this.element.parentNode.removeChild(this.element);
+ break;
+ case "children":
+ removeChildren(this.element);
+ break;
+ }
+ }
+}
+
+Slider.prototype.tick = function()
+{
+ this.progress += this.step;
+ if(this.progress < 0 || this.progress > 1)
+ {
+ this.stop();
+ return false;
+ }
+ else
+ {
+ var f = Animator.slowInSlowOut(this.progress);
+ var h = this.realHeight * f;
+ this.element.style.height = h + "px";
+ this.element.style.opacity = f;
+ this.element.style.filter = "alpha(opacity:" + f * 100 +")";
+ return true;
+ }
+}
+
+// ---------------------------------------------------------------------------------
+// Popup menu
+// ---------------------------------------------------------------------------------
+
+var Popup = {
+ stack: [] // Array of objects with members root: and popup:
+ };
+
+Popup.create = function(root)
+{
+ Popup.remove();
+ var popup = createTiddlyElement(document.body,"ol","popup","popup");
+ Popup.stack.push({root: root, popup: popup});
+ return popup;
+}
+
+Popup.onDocumentClick = function(e)
+{
+ if (!e) var e = window.event;
+ var target = resolveTarget(e);
+ if(e.eventPhase == undefined)
+ Popup.remove();
+ else if(e.eventPhase == Event.BUBBLING_PHASE || e.eventPhase == Event.AT_TARGET)
+ Popup.remove();
+ return true;
+}
+
+Popup.show = function(unused,slowly)
+{
+ var curr = Popup.stack[Popup.stack.length-1];
+ var rootLeft = findPosX(curr.root);
+ var rootTop = findPosY(curr.root);
+ var rootHeight = curr.root.offsetHeight;
+ var popupLeft = rootLeft;
+ var popupTop = rootTop + rootHeight;
+ var popupWidth = curr.popup.offsetWidth;
+ var winWidth = findWindowWidth();
+ if(popupLeft + popupWidth > winWidth)
+ popupLeft = winWidth - popupWidth;
+ curr.popup.style.left = popupLeft + "px";
+ curr.popup.style.top = popupTop + "px";
+ curr.popup.style.display = "block";
+ addClass(curr.root,"highlight");
+ if(anim && config.options.chkAnimate)
+ anim.startAnimating(new Scroller(curr.popup,slowly));
+ else
+ window.scrollTo(0,ensureVisible(curr.popup));
+}
+
+Popup.remove = function()
+{
+ if(Popup.stack.length > 0)
+ {
+ Popup.removeFrom(0);
+ }
+}
+
+Popup.removeFrom = function(from)
+{
+ for(var t=Popup.stack.length-1; t>=from; t--)
+ {
+ var p = Popup.stack[t];
+ removeClass(p.root,"highlight");
+ p.popup.parentNode.removeChild(p.popup);
+ }
+ Popup.stack = Popup.stack.slice(0,from);
+}
+
+// ---------------------------------------------------------------------------------
+// ListView gadget
+// ---------------------------------------------------------------------------------
+
+var ListView = {};
+
+// Create a listview
+// place - where in the DOM tree to insert the listview
+// listObject - array of objects to be included in the listview
+// listTemplate - template for the listview
+// callback - callback for a command being selected
+// className - optional classname for the <table> element
+ListView.create = function(place,listObject,listTemplate,callback,className)
+{
+ var table = createTiddlyElement(place,"table",null,className ? className : "listView");
+ var thead = createTiddlyElement(table,"thead");
+ var r = createTiddlyElement(thead,"tr");
+ for(var t=0; t<listTemplate.columns.length; t++)
+ {
+ var columnTemplate = listTemplate.columns[t];
+ var c = createTiddlyElement(r,"th");
+ var colType = ListView.columnTypes[columnTemplate.type];
+ if(colType && colType.createHeader)
+ colType.createHeader(c,columnTemplate,t);
+ }
+ var tbody = createTiddlyElement(table,"tbody");
+ for(var rc=0; rc<listObject.length; rc++)
+ {
+ rowObject = listObject[rc];
+ r = createTiddlyElement(tbody,"tr");
+ for(var c=0; c<listTemplate.rowClasses.length; c++)
+ {
+ if(rowObject[listTemplate.rowClasses[c].field])
+ addClass(r,listTemplate.rowClasses[c].className);
+ }
+ rowObject.rowElement = rowObject;
+ rowObject.colElements = {};
+ for(var cc=0; cc<listTemplate.columns.length; cc++)
+ {
+ var c = createTiddlyElement(r,"td");
+ var columnTemplate = listTemplate.columns[cc];
+ var field = columnTemplate.field;
+ var colType = ListView.columnTypes[columnTemplate.type];
+ if(colType && colType.createItem)
+ colType.createItem(c,rowObject,field,columnTemplate,cc,rc);
+ rowObject.colElements[field] = c;
+ }
+ }
+ if(callback && listTemplate.actions)
+ createTiddlyDropDown(place,ListView.getCommandHandler(callback),listTemplate.actions);
+ if(callback && listTemplate.buttons)
+ {
+ for(t=0; t<listTemplate.buttons.length; t++)
+ {
+ var a = listTemplate.buttons[t];
+ if(a && a.name != "")
+ createTiddlyButton(place,a.caption,null,ListView.getCommandHandler(callback,a.name,a.allowEmptySelection));
+ }
+ }
+ return table;
+}
+
+ListView.getCommandHandler = function(callback,name,allowEmptySelection)
+{
+ return function(e)
+ {
+ var view = findRelated(this,"TABLE",null,"previousSibling");
+ var tiddlers = [];
+ ListView.forEachSelector(view,function(e,rowName) {
+ if(e.checked)
+ tiddlers.push(rowName);
+ });
+ if(tiddlers.length == 0 && !allowEmptySelection)
+ alert(config.messages.nothingSelected);
+ else
+ {
+ if(this.nodeName.toLowerCase() == "select")
+ {
+ callback(view,this.value,tiddlers);
+ this.selectedIndex = 0;
+ }
+ else
+ callback(view,name,tiddlers);
+ }
+ };
+}
+
+// Invoke a callback for each selector checkbox in the listview
+// view - <table> element of listView
+// callback(checkboxElement,rowName)
+// where
+// checkboxElement - DOM element of checkbox
+// rowName - name of this row as assigned by the column template
+// result: true if at least one selector was checked
+ListView.forEachSelector = function(view,callback)
+{
+ var checkboxes = view.getElementsByTagName("input");
+ var hadOne = false;
+ for(var t=0; t<checkboxes.length; t++)
+ {
+ var cb = checkboxes[t];
+ if(cb.getAttribute("type") == "checkbox")
+ {
+ var rn = cb.getAttribute("rowName");
+ if(rn)
+ {
+ callback(cb,rn);
+ hadOne = true;
+ }
+ }
+ }
+ return hadOne;
+}
+
+ListView.columnTypes = {};
+
+ListView.columnTypes.String = {
+ createHeader: function(place,columnTemplate,col)
+ {
+ createTiddlyText(place,columnTemplate.title);
+ },
+ createItem: function(place,listObject,field,columnTemplate,col,row)
+ {
+ var v = listObject[field];
+ if(v != undefined)
+ createTiddlyText(place,v);
+ }
+};
+
+ListView.columnTypes.Date = {
+ createHeader: ListView.columnTypes.String.createHeader,
+ createItem: function(place,listObject,field,columnTemplate,col,row)
+ {
+ var v = listObject[field];
+ if(v != undefined)
+ createTiddlyText(place,v.formatString(columnTemplate.dateFormat));
+ }
+};
+
+ListView.columnTypes.StringList = {
+ createHeader: ListView.columnTypes.String.createHeader,
+ createItem: function(place,listObject,field,columnTemplate,col,row)
+ {
+ var v = listObject[field];
+ if(v != undefined)
+ {
+ for(var t=0; t<v.length; t++)
+ {
+ createTiddlyText(place,v[t]);
+ createTiddlyElement(place,"br");
+ }
+ }
+ }
+};
+
+ListView.columnTypes.Selector = {
+ createHeader: function(place,columnTemplate,col)
+ {
+ createTiddlyCheckbox(place,null,false,this.onHeaderChange);
+ },
+ createItem: function(place,listObject,field,columnTemplate,col,row)
+ {
+ var e = createTiddlyCheckbox(place,null,listObject[field],null);
+ e.setAttribute("rowName",listObject[columnTemplate.rowName]);
+ },
+ onHeaderChange: function(e)
+ {
+ var state = this.checked;
+ var view = findRelated(this,"TABLE");
+ if(!view)
+ return;
+ ListView.forEachSelector(view,function(e,rowName) {
+ e.checked = state;
+ });
+ }
+};
+
+ListView.columnTypes.Tags = {
+ createHeader: ListView.columnTypes.String.createHeader,
+ createItem: function(place,listObject,field,columnTemplate,col,row)
+ {
+ var tags = listObject[field];
+ createTiddlyText(place,String.encodeTiddlyLinkList(tags));
+ }
+};
+
+ListView.columnTypes.Boolean = {
+ createHeader: ListView.columnTypes.String.createHeader,
+ createItem: function(place,listObject,field,columnTemplate,col,row)
+ {
+ if(listObject[field] == true)
+ createTiddlyText(place,columnTemplate.trueText);
+ if(listObject[field] == false)
+ createTiddlyText(place,columnTemplate.falseText);
+ }
+};
+
+ListView.columnTypes.TagCheckbox = {
+ createHeader: ListView.columnTypes.String.createHeader,
+ createItem: function(place,listObject,field,columnTemplate,col,row)
+ {
+ var e = createTiddlyCheckbox(place,null,listObject[field],this.onChange);
+ e.setAttribute("tiddler",listObject.title);
+ e.setAttribute("tag",columnTemplate.tag);
+ },
+ onChange : function(e)
+ {
+ var tag = this.getAttribute("tag");
+ var tiddler = this.getAttribute("tiddler");
+ store.setTiddlerTag(tiddler,this.checked,tag);
+ }
+};
+
+ListView.columnTypes.TiddlerLink = {
+ createHeader: ListView.columnTypes.String.createHeader,
+ createItem: function(place,listObject,field,columnTemplate,col,row)
+ {
+ var v = listObject[field];
+ if(v != undefined)
+ {
+ var link = createTiddlyLink(place,listObject[columnTemplate.tiddlerLink],false,null);
+ createTiddlyText(link,listObject[field]);
+ }
+ }
+};
+// ---------------------------------------------------------------------------------
+// Augmented methods for the JavaScript Number(), Array(), String() and Date() objects
+// ---------------------------------------------------------------------------------
+
+// Clamp a number to a range
+Number.prototype.clamp = function(min,max)
+{
+ var c = this;
+ if(c < min)
+ c = min;
+ if(c > max)
+ c = max;
+ return c;
+}
+
+// Add indexOf function if browser does not support it
+if(!Array.indexOf) {
+Array.prototype.indexOf = function(item,from)
+{
+ if(!from)
+ from = 0;
+ for(var i=from; i<this.length; i++)
+ if(this[i] === item)
+ return i;
+ return -1;
+}}
+
+// Find an entry in a given field of the members of an array
+Array.prototype.findByField = function(field,value)
+{
+ for(var t=0; t<this.length; t++)
+ if(this[t][field] == value)
+ return t;
+ return null;
+}
+
+// Return whether an entry exists in an array
+Array.prototype.contains = function(item)
+{
+ return this.indexOf(item) != -1;
+};
+
+// Adds, removes or toggles a particular value within an array
+// value - value to add
+// mode - +1 to add value, -1 to remove value, 0 to toggle it
+Array.prototype.setItem = function(value,mode)
+{
+ var p = this.indexOf(value);
+ if(mode == 0)
+ mode = (p == -1) ? +1 : -1;
+ if(mode == +1)
+ {
+ if(p == -1)
+ this.push(value);
+ }
+ else if(mode == -1)
+ {
+ if(p != -1)
+ this.splice(p,1);
+ }
+}
+
+// Return whether one of a list of values exists in an array
+Array.prototype.containsAny = function(items)
+{
+ for(var i=0; i<items.length; i++)
+ if (this.indexOf(items[i]) != -1)
+ return true;
+ return false;
+};
+
+// Return whether all of a list of values exists in an array
+Array.prototype.containsAll = function(items)
+{
+ for (var i = 0; i<items.length; i++)
+ if (this.indexOf(items[i]) == -1)
+ return false;
+ return true;
+};
+
+// Push a new value into an array only if it is not already present in the array. If the optional unique parameter is false, it reverts to a normal push
+Array.prototype.pushUnique = function(item,unique)
+{
+ if(unique != undefined && unique == false)
+ this.push(item);
+ else
+ {
+ if(this.indexOf(item) == -1)
+ this.push(item);
+ }
+}
+
+Array.prototype.remove = function(item)
+{
+ var p = this.indexOf(item);
+ if(p != -1)
+ this.splice(p,1);
+}
+
+// Get characters from the right end of a string
+String.prototype.right = function(n)
+{
+ if(n < this.length)
+ return this.slice(this.length-n);
+ else
+ return this;
+}
+
+// Trim whitespace from both ends of a string
+String.prototype.trim = function()
+{
+ return this.replace(/^\s*|\s*$/g,"");
+}
+
+// Convert a string from a CSS style property name to a JavaScript style name ("background-color" -> "backgroundColor")
+String.prototype.unDash = function()
+{
+ var s = this.split("-");
+ if(s.length > 1)
+ for(var t=1; t<s.length; t++)
+ s[t] = s[t].substr(0,1).toUpperCase() + s[t].substr(1);
+ return s.join("");
+}
+
+// Substitute substrings from an array into a format string that includes '%1'-type specifiers
+String.prototype.format = function(substrings)
+{
+ var subRegExp = /(?:%(\d+))/mg;
+ var currPos = 0;
+ var r = [];
+ do {
+ var match = subRegExp.exec(this);
+ if(match && match[1])
+ {
+ if(match.index > currPos)
+ r.push(this.substring(currPos,match.index));
+ r.push(substrings[parseInt(match[1])]);
+ currPos = subRegExp.lastIndex;
+ }
+ } while(match);
+ if(currPos < this.length)
+ r.push(this.substring(currPos,this.length));
+ return r.join("");
+}
+
+// Escape any special RegExp characters with that character preceded by a backslash
+String.prototype.escapeRegExp = function()
+{
+ var s = "\\^$*+?()=!|,{}[].";
+ var c = this;
+ for(var t=0; t<s.length; t++)
+ c = c.replace(new RegExp("\\" + s.substr(t,1),"g"),"\\" + s.substr(t,1));
+ return c;
+}
+
+// Convert "\" to "\s", newlines to "\n" (and remove carriage returns)
+String.prototype.escapeLineBreaks = function()
+{
+ return this.replace(/\\/mg,"\\s").replace(/\n/mg,"\\n").replace(/\r/mg,"");
+}
+
+// Convert "\n" to newlines, "\b" to " ", "\s" to "\" (and remove carriage returns)
+String.prototype.unescapeLineBreaks = function()
+{
+ return this.replace(/\\n/mg,"\n").replace(/\\b/mg," ").replace(/\\s/mg,"\\").replace(/\r/mg,"");
+}
+
+// Convert & to "&", < to "<", > to ">" and " to """
+String.prototype.htmlEncode = function()
+{
+ return(this.replace(/&/mg,"&").replace(/</mg,"<").replace(/>/mg,">").replace(/\"/mg,"""));
+}
+
+// Convert "&" to &, "<" to <, ">" to > and """ to "
+String.prototype.htmlDecode = function()
+{
+ return(this.replace(/&/mg,"&").replace(/</mg,"<").replace(/>/mg,">").replace(/"/mg,"\""));
+}
+
+// Parse a space-separated string of name:value parameters where:
+// - the name or the value can be optional (in which case separate defaults are used instead)
+// - in case of ambiguity, a lone word is taken to be a value
+// - if 'cascadeDefaults' is set to true, then the defaults are modified by updated by each specified name or value
+// - name prefixes are not allowed if the 'noNames' parameter is true
+// - if both the name and value are present they must be separated by a colon
+// - the name and the value may both be quoted with single- or double-quotes, double-square brackets
+// - names or values quoted with {{double-curly braces}} are evaluated as a JavaScript expression
+// - as long as the 'allowEval' parameter is true
+// The result is an array of objects:
+// result[0] = object with a member for each parameter name, value of that member being an array of values
+// result[1..n] = one object for each parameter, with 'name' and 'value' members
+String.prototype.parseParams = function(defaultName,defaultValue,allowEval,noNames,cascadeDefaults)
+{
+ var parseToken = function(match,p)
+ {
+ var n;
+ if(match[p]) // Double quoted
+ n = match[p];
+ else if(match[p+1]) // Single quoted
+ n = match[p+1];
+ else if(match[p+2]) // Double-square-bracket quoted
+ n = match[p+2];
+ else if(match[p+3]) // Double-brace quoted
+ try
+ {
+ n = match[p+3];
+ if(allowEval)
+ n = window.eval(n);
+ }
+ catch(e)
+ {
+ throw "Unable to evaluate {{" + match[p+3] + "}}: " + exceptionText(e);
+ }
+ else if(match[p+4]) // Unquoted
+ n = match[p+4];
+ else if(match[p+5]) // empty quote
+ n = "";
+ return n;
+ };
+ var r = [{}];
+ var dblQuote = "(?:\"((?:(?:\\\\\")|[^\"])+)\")";
+ var sngQuote = "(?:'((?:(?:\\\\\')|[^'])+)')";
+ var dblSquare = "(?:\\[\\[((?:\\s|\\S)*?)\\]\\])";
+ var dblBrace = "(?:\\{\\{((?:\\s|\\S)*?)\\}\\})";
+ var unQuoted = noNames ? "([^\"'\\s]\\S*)" : "([^\"':\\s][^\\s:]*)";
+ var emptyQuote = "((?:\"\")|(?:''))";
+ var skipSpace = "(?:\\s*)";
+ var token = "(?:" + dblQuote + "|" + sngQuote + "|" + dblSquare + "|" + dblBrace + "|" + unQuoted + "|" + emptyQuote + ")";
+ var re = noNames
+ ? new RegExp(token,"mg")
+ : new RegExp(skipSpace + token + skipSpace + "(?:(\\:)" + skipSpace + token + ")?","mg");
+ var params = [];
+ do {
+ var match = re.exec(this);
+ if(match)
+ {
+ var n = parseToken(match,1);
+ if(noNames)
+ r.push({name: "", value: n});
+ else
+ {
+ var v = parseToken(match,8);
+ if(v == null && defaultName)
+ {
+ v = n;
+ n = defaultName;
+ }
+ else if(v == null && defaultValue)
+ v = defaultValue;
+ r.push({name: n, value: v});
+ if(cascadeDefaults)
+ {
+ defaultName = n;
+ defaultValue = v;
+ }
+ }
+ }
+ } while(match);
+ // Summarise parameters into first element
+ for(var t=1; t<r.length; t++)
+ {
+ if(r[0][r[t].name])
+ r[0][r[t].name].push(r[t].value);
+ else
+ r[0][r[t].name] = [r[t].value];
+ }
+ return r;
+}
+
+// Process a string list of macro parameters into an array. Parameters can be quoted with "", '',
+// [[]], {{ }} or left unquoted (and therefore space-separated). Double-braces {{}} results in
+// an *evaluated* parameter: e.g. {{config.options.txtUserName}} results in the current user's name.
+String.prototype.readMacroParams = function()
+{
+ var p = this.parseParams("list",null,true,true);
+ var n = [];
+ for(var t=1; t<p.length; t++)
+ n.push(p[t].value);
+ return n;
+}
+
+// Process a string list of unique tiddler names into an array. Tiddler names that have spaces in them must be [[bracketed]]
+String.prototype.readBracketedList = function(unique)
+{
+ var p = this.parseParams("list",null,false,true);
+ var n = [];
+ for(var t=1; t<p.length; t++)
+ n.pushUnique(p[t].value,unique);
+ return n;
+}
+
+// Returns array with start and end index of chunk between given start and end marker, or undefined.
+String.prototype.getChunkRange = function(start,end)
+{
+ var s = this.indexOf(start);
+ if(s != -1)
+ {
+ s += start.length;
+ var e = this.indexOf(end,s);
+ if(e != -1)
+ return [s, e];
+ }
+}
+
+// Replace a chunk of a string given start and end markers
+String.prototype.replaceChunk = function(start,end,sub)
+{
+ var r = this.getChunkRange(start,end);
+ return r
+ ? this.substring(0,r[0]) + sub + this.substring(r[1])
+ : this;
+}
+
+// Returns a chunk of a string between start and end markers, or undefined
+String.prototype.getChunk = function(start,end)
+{
+ var r = this.getChunkRange(start,end);
+ if (r)
+ return this.substring(r[0],r[1]);
+}
+
+
+// Static method to bracket a string with double square brackets if it contains a space
+String.encodeTiddlyLink = function(title)
+{
+ if(title.indexOf(" ") == -1)
+ return(title);
+ else
+ return("[[" + title + "]]");
+}
+
+// Static method to encodeTiddlyLink for every item in an array and join them with spaces
+String.encodeTiddlyLinkList = function(list)
+{
+ if(list)
+ {
+ var results = [];
+ for(var t=0; t<list.length; t++)
+ results.push(String.encodeTiddlyLink(list[t]));
+ return results.join(" ");
+ }
+ else
+ return "";
+}
+
+// Static method to left-pad a string with 0s to a certain width
+String.zeroPad = function(n,d)
+{
+ var s = n.toString();
+ if(s.length < d)
+ s = "000000000000000000000000000".substr(0,d-s.length) + s;
+ return(s);
+}
+
+String.prototype.startsWith = function(prefix)
+{
+ return !prefix || this.substring(0,prefix.length) == prefix;
+}
+
+// Returns the first value of the given named parameter.
+//#
+//# @param params
+//# as returned by parseParams or null/undefined
+//# @return [may be null/undefined]
+//#
+function getParam(params, name, defaultValue) {
+ if (!params)
+ return defaultValue;
+ var p = params[0][name];
+ return p ? p[0] : defaultValue;
+}
+
+// Returns the first value of the given boolean named parameter.
+//#
+//# @param params
+//# as returned by parseParams or null/undefined
+//#
+function getFlag(params, name, defaultValue) {
+ return !!getParam(params, name, defaultValue);
+}
+
+// Substitute date components into a string
+Date.prototype.formatString = function(template)
+{
+ var t = template.replace(/0hh12/g,String.zeroPad(this.getHours12(),2));
+ t = t.replace(/hh12/g,this.getHours12());
+ t = t.replace(/0hh/g,String.zeroPad(this.getHours(),2));
+ t = t.replace(/hh/g,this.getHours());
+ t = t.replace(/0mm/g,String.zeroPad(this.getMinutes(),2));
+ t = t.replace(/mm/g,this.getMinutes());
+ t = t.replace(/0ss/g,String.zeroPad(this.getSeconds(),2));
+ t = t.replace(/ss/g,this.getSeconds());
+ t = t.replace(/[ap]m/g,this.getAmPm().toLowerCase());
+ t = t.replace(/[AP]M/g,this.getAmPm().toUpperCase());
+ t = t.replace(/wYYYY/g,this.getYearForWeekNo());
+ t = t.replace(/wYY/g,String.zeroPad(this.getYearForWeekNo()-2000,2));
+ t = t.replace(/YYYY/g,this.getFullYear());
+ t = t.replace(/YY/g,String.zeroPad(this.getFullYear()-2000,2));
+ t = t.replace(/MMM/g,config.messages.dates.months[this.getMonth()]);
+ t = t.replace(/mmm/g,config.messages.dates.shortMonths[this.getMonth()]);
+ t = t.replace(/0MM/g,String.zeroPad(this.getMonth()+1,2));
+ t = t.replace(/MM/g,this.getMonth()+1);
+ t = t.replace(/0WW/g,String.zeroPad(this.getWeek(),2));
+ t = t.replace(/WW/g,this.getWeek());
+ t = t.replace(/DDD/g,config.messages.dates.days[this.getDay()]);
+ t = t.replace(/ddd/g,config.messages.dates.shortDays[this.getDay()]);
+ t = t.replace(/0DD/g,String.zeroPad(this.getDate(),2));
+ t = t.replace(/DDth/g,this.getDate()+this.daySuffix());
+ t = t.replace(/DD/g,this.getDate());
+ return t;
+}
+
+Date.prototype.getWeek = function()
+{
+ var dt = new Date(this.getTime());
+ var d = dt.getDay();
+ if (d==0) d=7;// JavaScript Sun=0, ISO Sun=7
+ dt.setTime(dt.getTime()+(4-d)*86400000);// shift day to Thurs of same week to calculate weekNo
+ var n = Math.floor((dt.getTime()-new Date(dt.getFullYear(),0,1)+3600000)/86400000);
+ return Math.floor(n/7)+1;
+}
+
+Date.prototype.getYearForWeekNo = function()
+{
+ var dt = new Date(this.getTime());
+ var d = dt.getDay();
+ if (d==0) d=7;// JavaScript Sun=0, ISO Sun=7
+ dt.setTime(dt.getTime()+(4-d)*86400000);// shift day to Thurs of same week
+ return dt.getFullYear();
+}
+
+Date.prototype.getHours12 = function()
+{
+ var h = this.getHours();
+ return h > 12 ? h-12 : ( h > 0 ? h : 12 );
+}
+
+Date.prototype.getAmPm = function()
+{
+ return this.getHours() >= 12 ? "pm" : "am";
+}
+
+Date.prototype.daySuffix = function()
+{
+ var num = this.getDate();
+ if (num >= 11 && num <= 13) return "th";
+ else if (num.toString().substr(-1)=="1") return "st";
+ else if (num.toString().substr(-1)=="2") return "nd";
+ else if (num.toString().substr(-1)=="3") return "rd";
+ return "th";
+}
+
+// Convert a date to local YYYYMMDDHHMM string format
+Date.prototype.convertToLocalYYYYMMDDHHMM = function()
+{
+ return(String.zeroPad(this.getFullYear(),4) + String.zeroPad(this.getMonth()+1,2) + String.zeroPad(this.getDate(),2) + String.zeroPad(this.getHours(),2) + String.zeroPad(this.getMinutes(),2));
+}
+
+// Convert a date to UTC YYYYMMDDHHMM string format
+Date.prototype.convertToYYYYMMDDHHMM = function()
+{
+ return(String.zeroPad(this.getUTCFullYear(),4) + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2));
+}
+
+// Convert a date to UTC YYYYMMDD.HHMMSSMMM string format
+Date.prototype.convertToYYYYMMDDHHMMSSMMM = function()
+{
+ return(String.zeroPad(this.getUTCFullYear(),4) + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + "." + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2) + String.zeroPad(this.getUTCSeconds(),2) + String.zeroPad(this.getUTCMilliseconds(),4));
+}
+
+// Static method to create a date from a UTC YYYYMMDDHHMM format string
+Date.convertFromYYYYMMDDHHMM = function(d)
+{
+ var theDate = new Date(Date.UTC(parseInt(d.substr(0,4),10),
+ parseInt(d.substr(4,2),10)-1,
+ parseInt(d.substr(6,2),10),
+ parseInt(d.substr(8,2),10),
+ parseInt(d.substr(10,2),10),0,0));
+ return(theDate);
+}
+
+// ---------------------------------------------------------------------------------
+// Crypto functions and associated conversion routines
+// ---------------------------------------------------------------------------------
+
+// Crypto "namespace"
+function Crypto() {}
+
+// Convert a string to an array of big-endian 32-bit words
+Crypto.strToBe32s = function(str)
+{
+ var be = Array();
+ var len = Math.floor(str.length/4);
+ var i, j;
+ for(i=0, j=0; i<len; i++, j+=4)
+ {
+ be[i] = ((str.charCodeAt(j)&0xff) << 24)|((str.charCodeAt(j+1)&0xff) << 16)|((str.charCodeAt(j+2)&0xff) << 8)|(str.charCodeAt(j+3)&0xff);
+ }
+ while (j<str.length)
+ {
+ be[j>>2] |= (str.charCodeAt(j)&0xff)<<(24-(j*8)%32);
+ j++;
+ }
+ return be;
+}
+
+// Convert an array of big-endian 32-bit words to a string
+Crypto.be32sToStr = function(be)
+{
+ var str = "";
+ for(var i=0;i<be.length*32;i+=8)
+ str += String.fromCharCode((be[i>>5]>>>(24-i%32)) & 0xff);
+ return str;
+}
+
+// Convert an array of big-endian 32-bit words to a hex string
+Crypto.be32sToHex = function(be)
+{
+ var hex = "0123456789ABCDEF";
+ var str = "";
+ for(var i=0;i<be.length*4;i++)
+ str += hex.charAt((be[i>>2]>>((3-i%4)*8+4))&0xF) + hex.charAt((be[i>>2]>>((3-i%4)*8))&0xF);
+ return str;
+}
+
+// Return, in hex, the SHA-1 hash of a string
+Crypto.hexSha1Str = function(str)
+{
+ return Crypto.be32sToHex(Crypto.sha1Str(str));
+}
+
+// Return the SHA-1 hash of a string
+Crypto.sha1Str = function(str)
+{
+ return Crypto.sha1(Crypto.strToBe32s(str),str.length);
+}
+
+// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
+Crypto.sha1 = function(x,blen)
+{
+ // Add 32-bit integers, wrapping at 32 bits
+ //# Uses 16-bit operations internally to work around bugs in some JavaScript interpreters.
+ add32 = function(a,b)
+ {
+ var lsw = (a&0xFFFF)+(b&0xFFFF);
+ var msw = (a>>16)+(b>>16)+(lsw>>16);
+ return (msw<<16)|(lsw&0xFFFF);
+ };
+ // Add five 32-bit integers, wrapping at 32 bits
+ //# Uses 16-bit operations internally to work around bugs in some JavaScript interpreters.
+ add32x5 = function(a,b,c,d,e)
+ {
+ var lsw = (a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF);
+ var msw = (a>>16)+(b>>16)+(c>>16)+(d>>16)+(e>>16)+(lsw>>16);
+ return (msw<<16)|(lsw&0xFFFF);
+ };
+ // Bitwise rotate left a 32-bit integer by 1 bit
+ rol32 = function(n)
+ {
+ return (n>>>31)|(n<<1);
+ };
+
+ var len = blen*8;
+ // Append padding so length in bits is 448 mod 512
+ x[len>>5] |= 0x80 << (24-len%32);
+ // Append length
+ x[((len+64>>9)<<4)+15] = len;
+ var w = Array(80);
+
+ var k1 = 0x5A827999;
+ var k2 = 0x6ED9EBA1;
+ var k3 = 0x8F1BBCDC;
+ var k4 = 0xCA62C1D6;
+
+ var h0 = 0x67452301;
+ var h1 = 0xEFCDAB89;
+ var h2 = 0x98BADCFE;
+ var h3 = 0x10325476;
+ var h4 = 0xC3D2E1F0;
+
+ for(var i=0;i<x.length;i+=16)
+ {
+ var j,t;
+ var a = h0;
+ var b = h1;
+ var c = h2;
+ var d = h3;
+ var e = h4;
+ for(j = 0;j<16;j++)
+ {
+ w[j] = x[i+j];
+ t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
+ e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
+ }
+ for(j=16;j<20;j++)
+ {
+ w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
+ t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
+ e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
+ }
+ for(j=20;j<40;j++)
+ {
+ w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
+ t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k2);
+ e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
+ }
+ for(j=40;j<60;j++)
+ {
+ w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
+ t = add32x5(e,(a>>>27)|(a<<5),(b&c)|(d&(b|c)),w[j],k3);
+ e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
+ }
+ for(j=60;j<80;j++)
+ {
+ w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
+ t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k4);
+ e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
+ }
+
+ h0 = add32(h0,a);
+ h1 = add32(h1,b);
+ h2 = add32(h2,c);
+ h3 = add32(h3,d);
+ h4 = add32(h4,e);
+ }
+ return Array(h0,h1,h2,h3,h4);
+}
+
+// ---------------------------------------------------------------------------------
+// RGB colour object
+// ---------------------------------------------------------------------------------
+
+// Construct an RGB colour object from a '#rrggbb', '#rgb' or 'rgb(n,n,n)' string or from separate r,g,b values
+function RGB(r,g,b)
+{
+ this.r = 0;
+ this.g = 0;
+ this.b = 0;
+ if(typeof r == "string")
+ {
+ if(r.substr(0,1) == "#")
+ {
+ if(r.length == 7)
+ {
+ this.r = parseInt(r.substr(1,2),16)/255;
+ this.g = parseInt(r.substr(3,2),16)/255;
+ this.b = parseInt(r.substr(5,2),16)/255;
+ }
+ else
+ {
+ this.r = parseInt(r.substr(1,1),16)/15;
+ this.g = parseInt(r.substr(2,1),16)/15;
+ this.b = parseInt(r.substr(3,1),16)/15;
+ }
+ }
+ else
+ {
+ var rgbPattern = /rgb\s*\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/ ;
+ var c = r.match(rgbPattern);
+ if (c)
+ {
+ this.r = parseInt(c[1],10)/255;
+ this.g = parseInt(c[2],10)/255;
+ this.b = parseInt(c[3],10)/255;
+ }
+ }
+ }
+ else
+ {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ }
+ return this;
+}
+
+// Mixes this colour with another in a specified proportion
+// c = other colour to mix
+// f = 0..1 where 0 is this colour and 1 is the new colour
+// Returns an RGB object
+RGB.prototype.mix = function(c,f)
+{
+ return new RGB(this.r + (c.r-this.r) * f,this.g + (c.g-this.g) * f,this.b + (c.b-this.b) * f);
+}
+
+// Return an rgb colour as a #rrggbb format hex string
+RGB.prototype.toString = function()
+{
+ var r = this.r.clamp(0,1);
+ var g = this.g.clamp(0,1);
+ var b = this.b.clamp(0,1);
+ return("#" + ("0" + Math.floor(r * 255).toString(16)).right(2) +
+ ("0" + Math.floor(g * 255).toString(16)).right(2) +
+ ("0" + Math.floor(b * 255).toString(16)).right(2));
+}
+
+// ---------------------------------------------------------------------------------
+// DOM utilities - many derived from www.quirksmode.org
+// ---------------------------------------------------------------------------------
+
+function drawGradient(place,horiz,colours)
+{
+ for(var t=0; t<= 100; t+=2)
+ {
+ var bar = document.createElement("div");
+ place.appendChild(bar);
+ bar.style.position = "absolute";
+ bar.style.left = horiz ? t + "%" : 0;
+ bar.style.top = horiz ? 0 : t + "%";
+ bar.style.width = horiz ? (101-t) + "%" : "100%";
+ bar.style.height = horiz ? "100%" : (101-t) + "%";
+ bar.style.zIndex = -1;
+ var f = t/100;
+ var p = f*(colours.length-1);
+ bar.style.backgroundColor = colours[Math.floor(p)].mix(colours[Math.ceil(p)],p-Math.floor(p)).toString();
+ }
+}
+
+function createTiddlyText(theParent,theText)
+{
+ return theParent.appendChild(document.createTextNode(theText));
+}
+
+function createTiddlyCheckbox(theParent,caption,checked,onChange)
+{
+ var cb = document.createElement("input");
+ cb.setAttribute("type","checkbox");
+ cb.onclick = onChange;
+ theParent.appendChild(cb);
+ cb.checked = checked;
+ cb.className = "chkOptionInput";
+ if(caption)
+ wikify(caption,theParent);
+ return cb;
+}
+
+function createTiddlyElement(theParent,theElement,theID,theClass,theText)
+{
+ var e = document.createElement(theElement);
+ if(theClass != null)
+ e.className = theClass;
+ if(theID != null)
+ e.setAttribute("id",theID);
+ if(theText != null)
+ e.appendChild(document.createTextNode(theText));
+ if(theParent != null)
+ theParent.appendChild(e);
+ return(e);
+}
+
+// Add an event handler
+// Thanks to John Resig, via QuirksMode
+function addEvent(obj,type,fn)
+{
+ if(obj.attachEvent)
+ {
+ obj['e'+type+fn] = fn;
+ obj[type+fn] = function(){obj['e'+type+fn](window.event);}
+ obj.attachEvent('on'+type,obj[type+fn]);
+ }
+ else
+ obj.addEventListener(type,fn,false);
+}
+
+// Remove an event handler
+// Thanks to John Resig, via QuirksMode
+function removeEvent(obj,type,fn)
+{
+ if(obj.detachEvent)
+ {
+ obj.detachEvent('on'+type,obj[type+fn]);
+ obj[type+fn] = null;
+ }
+ else
+ obj.removeEventListener(type,fn,false);
+}
+
+function addClass(e,theClass)
+{
+ var currClass = e.className.split(" ");
+ if(currClass.indexOf(theClass) == -1)
+ e.className += " " + theClass;
+}
+
+function removeClass(e,theClass)
+{
+ var currClass = e.className.split(" ");
+ var i = currClass.indexOf(theClass);
+ while(i != -1)
+ {
+ currClass.splice(i,1);
+ i = currClass.indexOf(theClass);
+ }
+ e.className = currClass.join(" ");
+}
+
+function hasClass(e,theClass)
+{
+ if(e.className)
+ {
+ if(e.className.split(" ").indexOf(theClass) != -1)
+ return true;
+ }
+ return false;
+}
+
+// Find the closest relative with a given property value (property defaults to tagName, relative defaults to parentNode)
+function findRelated(e,value,name,relative)
+{
+ name = name ? name : "tagName";
+ relative = relative ? relative : "parentNode";
+ if(name == "className")
+ {
+ while(e && !hasClass(e,value))
+ {
+ e = e[relative];
+ }
+ }
+ else
+ {
+ while(e && e[name] != value)
+ {
+ e = e[relative];
+ }
+ }
+ return e;
+}
+
+// Resolve the target object of an event
+function resolveTarget(e)
+{
+ var obj;
+ if (e.target)
+ obj = e.target;
+ else if (e.srcElement)
+ obj = e.srcElement;
+ if (obj.nodeType == 3) // defeat Safari bug
+ obj = obj.parentNode;
+ return(obj);
+}
+
+// Return the content of an element as plain text with no formatting
+function getPlainText(e)
+{
+ var text = "";
+ if(e.innerText)
+ text = e.innerText;
+ else if(e.textContent)
+ text = e.textContent;
+ return text;
+}
+
+// Get the scroll position for window.scrollTo necessary to scroll a given element into view
+function ensureVisible(e)
+{
+ var posTop = findPosY(e);
+ var posBot = posTop + e.offsetHeight;
+ var winTop = findScrollY();
+ var winHeight = findWindowHeight();
+ var winBot = winTop + winHeight;
+ if(posTop < winTop)
+ return(posTop);
+ else if(posBot > winBot)
+ {
+ if(e.offsetHeight < winHeight)
+ return(posTop - (winHeight - e.offsetHeight));
+ else
+ return(posTop);
+ }
+ else
+ return(winTop);
+}
+
+// Get the current width of the display window
+function findWindowWidth()
+{
+ return(window.innerWidth ? window.innerWidth : document.documentElement.clientWidth);
+}
+
+// Get the current height of the display window
+function findWindowHeight()
+{
+ return(window.innerHeight ? window.innerHeight : document.documentElement.clientHeight);
+}
+
+// Get the current horizontal page scroll position
+function findScrollX()
+{
+ return(window.scrollX ? window.scrollX : document.documentElement.scrollLeft);
+}
+
+// Get the current vertical page scroll position
+function findScrollY()
+{
+ return(window.scrollY ? window.scrollY : document.documentElement.scrollTop);
+}
+
+function findPosX(obj)
+{
+ var curleft = 0;
+ while (obj.offsetParent)
+ {
+ curleft += obj.offsetLeft;
+ obj = obj.offsetParent;
+ }
+ return curleft;
+}
+
+function findPosY(obj)
+{
+ var curtop = 0;
+ while (obj.offsetParent)
+ {
+ curtop += obj.offsetTop;
+ obj = obj.offsetParent;
+ }
+ return curtop;
+}
+
+// Blur a particular element
+function blurElement(e)
+{
+ if(e != null && e.focus && e.blur)
+ {
+ e.focus();
+ e.blur();
+ }
+}
+
+// Create a non-breaking space
+function insertSpacer(place)
+{
+ var e = document.createTextNode(String.fromCharCode(160));
+ if(place)
+ place.appendChild(e);
+ return e;
+}
+
+// Remove all children of a node
+function removeChildren(e)
+{
+ while(e.hasChildNodes())
+ e.removeChild(e.firstChild);
+}
+
+// Add a stylesheet, replacing any previous custom stylesheet
+function setStylesheet(s,id)
+{
+ if(!id)
+ id = "customStyleSheet";
+ var n = document.getElementById(id);
+ if(document.createStyleSheet) // Test for IE's non-standard createStyleSheet method
+ {
+ if(n)
+ n.parentNode.removeChild(n);
+ // This failed without the
+ document.getElementsByTagName("head")[0].insertAdjacentHTML("beforeEnd"," <style id='" + id + "'>" + s + "</style>");
+ }
+ else
+ {
+ if(n)
+ n.replaceChild(document.createTextNode(s),n.firstChild);
+ else
+ {
+ var n = document.createElement("style");
+ n.type = "text/css";
+ n.id = id;
+ n.appendChild(document.createTextNode(s));
+ document.getElementsByTagName("head")[0].appendChild(n);
+ }
+ }
+}
+
+// Replace the current selection of a textarea or text input and scroll it into view
+
+function replaceSelection(e,text)
+{
+ if (e.setSelectionRange)
+ {
+ var oldpos = e.selectionStart + 1;
+ e.value = e.value.substr(0,e.selectionStart) + text + e.value.substr(e.selectionStart);
+ e.setSelectionRange( oldpos, oldpos);
+ var linecount = e.value.split('\n').length;
+ var thisline = e.value.substr(0,e.selectionStart).split('\n').length-1;
+ e.scrollTop = Math.floor((thisline-e.rows/2)*e.scrollHeight/linecount);
+ }
+ else if (document.selection)
+ {
+ var range = document.selection.createRange();
+ if (range.parentElement() == e)
+ {
+ var isCollapsed = range.text == "";
+ range.text = text;
+ if (!isCollapsed)
+ {
+ range.moveStart('character', -text.length);
+ range.select();
+ }
+ }
+ }
+}
+
+// Returns the text of the given (text) node, possibly merging subsequent text nodes
+function getNodeText(e)
+{
+ var t = "";
+ while (e && e.nodeName == "#text")
+ {
+ t += e.nodeValue;
+ e = e.nextSibling;
+ }
+ return t;
+}
+//# -------------------------
+//# LoaderBase: A (abstract) storage loader that loads the tiddlers from a list of HTML elements.
+//# The format of the elements is defined by subclasses of this loader through the internalizeTiddler implementation.
+//# Subclasses must implement:
+//# function getTitle(store, e)
+//#
+//# store must implement:
+//# function createTiddler(title).
+//#
+
+function LoaderBase()
+{
+}
+
+LoaderBase.prototype.loadTiddler = function(store,e,tiddlers)
+{
+ var title = this.getTitle(store, e);
+ if (title)
+ {
+ var tiddler = store.createTiddler(title);
+ this.internalizeTiddler(store, tiddler, title, e);
+ tiddlers.push(tiddler);
+ }
+}
+
+LoaderBase.prototype.loadTiddlers = function(store,nodes)
+{
+ var tiddlers = [];
+ for (var t = 0; t < nodes.length; t++)
+ {
+ try
+ {
+ this.loadTiddler(store, nodes[t], tiddlers);
+ }
+ catch(e)
+ {
+ showException(e, config.messages.tiddlerLoadError.format([this.getTitle(store, nodes[t])]));
+ }
+ }
+ return tiddlers;
+}
+
+//# -------------------------
+//# SaverBase: a (abstract) storage saver that externalizes all tiddlers into a string,
+//# with every tiddler individually externalized (using this.externalizeTiddler) and joined with newlines
+//# Subclasses must implement:
+//# function externalizeTiddler(store, tiddler)
+//#
+//# store must implement:
+//# function getTiddlers(sortByFieldName)
+//#
+
+function SaverBase()
+{
+}
+
+SaverBase.prototype.externalize = function(store)
+{
+ var results = [];
+ var tiddlers = store.getTiddlers("title");
+ for (var t = 0; t < tiddlers.length; t++)
+ results.push(this.externalizeTiddler(store, tiddlers[t]));
+ return results.join("\n");
+}
+//--------------------------------
+// TW21Loader (inherits from LoaderBase)
+
+function TW21Loader() {};
+
+TW21Loader.prototype = new LoaderBase();
+
+TW21Loader.prototype.getTitle = function(store, e) {
+ var title = null;
+ if(e.getAttribute)
+ title = e.getAttribute("tiddler");
+ if(!title && e.id) {
+ var lenPrefix = store.idPrefix.length;
+ if (e.id.substr(0,lenPrefix) == store.idPrefix)
+ title = e.id.substr(lenPrefix);
+ }
+ return title;
+}
+
+TW21Loader.prototype.internalizeTiddler = function(store, tiddler, title, data) {
+ var text = getNodeText(data.firstChild).unescapeLineBreaks();
+ var modifier = data.getAttribute("modifier");
+ var modified = Date.convertFromYYYYMMDDHHMM(data.getAttribute("modified"));
+ var c = data.getAttribute("created");
+ var created = c ? Date.convertFromYYYYMMDDHHMM(c) : modified;
+ var tags = data.getAttribute("tags");
+ var fields = {};
+ var attrs = data.attributes;
+ for(var i = attrs.length-1; i >= 0; i--) {
+ var name = attrs[i].name;
+ if (attrs[i].specified && !TiddlyWiki.isStandardField(name)) {
+ fields[name] = attrs[i].value.unescapeLineBreaks();
+ }
+ }
+ tiddler.assign(title,text,modifier,modified,tags,created, fields);
+ return tiddler;
+};
+
+//--------------------------------
+// TW21Saver (inherits from SaverBase)
+
+function TW21Saver() {};
+
+TW21Saver.prototype = new SaverBase();
+
+TW21Saver.prototype.externalizeTiddler = function(store, tiddler)
+{
+ try {
+ var extendedFieldAttributes = "";
+ store.forEachField(tiddler,
+ function(tiddler, fieldName, value) {
+ // don't store stuff from the temp namespace
+ if (!fieldName.match(/^temp\./))
+ extendedFieldAttributes += ' %0="%1"'.format([fieldName, value.escapeLineBreaks().htmlEncode()]);
+ }, true);
+ return '<div tiddler="%0" modifier="%1" modified="%2" created="%3" tags="%4"%6>%5</div>'.format([
+ tiddler.title.htmlEncode(),
+ tiddler.modifier.htmlEncode(),
+ tiddler.modified.convertToYYYYMMDDHHMM(),
+ tiddler.created.convertToYYYYMMDDHHMM(),
+ tiddler.getTags().htmlEncode(),
+ tiddler.escapeLineBreaks().htmlEncode(),
+ extendedFieldAttributes
+ ]);
+ } catch (e) {
+ throw exceptionText(e, config.messages.tiddlerSaveError.format([tiddler.title]));
+ }
+}
+
+// ---------------------------------------------------------------------------------
+// Deprecated code
+// ---------------------------------------------------------------------------------
+
+// @Deprecated: Use createElementAndWikify and this.termRegExp instead
+config.formatterHelpers.charFormatHelper = function(w)
+{
+ w.subWikify(createTiddlyElement(w.output,this.element),this.terminator);
+}
+
+// @Deprecated: Use enclosedTextHelper and this.lookaheadRegExp instead
+config.formatterHelpers.monospacedByLineHelper = function(w)
+{
+ var lookaheadRegExp = new RegExp(this.lookahead,"mg");
+ lookaheadRegExp.lastIndex = w.matchStart;
+ var lookaheadMatch = lookaheadRegExp.exec(w.source);
+ if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
+ {
+ var text = lookaheadMatch[1];
+ if(config.browser.isIE)
+ text = text.replace(/\n/g,"\r");
+ createTiddlyElement(w.output,"pre",null,null,text);
+ w.nextMatch = lookaheadRegExp.lastIndex;
+ }
+}
+
+// @Deprecated: Use <br> or <br /> instead of <<br>>
+config.macros.br.handler = function(place)
+{
+ createTiddlyElement(place,"br");
+}
+
+// Find an entry in an array. Returns the array index or null
+// @Deprecated: Use indexOf instead
+Array.prototype.find = function(item)
+{
+ var i = this.indexOf(item);
+ return i == -1 ? null : i;
+}
+
+// Load a tiddler from an HTML DIV. The caller should make sure to later call Tiddler.changed()
+// @Deprecated: Use store.getLoader().internalizeTiddler instead
+Tiddler.prototype.loadFromDiv = function(divRef,title)
+{
+ return store.getLoader().internalizeTiddler(store,this,title,divRef);
+}
+
+// Format the text for storage in an HTML DIV
+// @Deprecated Use store.getSaver().externalizeTiddler instead.
+Tiddler.prototype.saveToDiv = function()
+{
+ return store.getSaver().externalizeTiddler(store,this);
+}
+
+// @Deprecated: Use store.allTiddlersAsHtml() instead
+function allTiddlersAsHtml()
+{
+ return store.allTiddlersAsHtml();
+}
+
+// @Deprecated: Use refreshPageTemplate instead
+function applyPageTemplate(title)
+{
+ refreshPageTemplate(title);
+}
+
+// @Deprecated: Use story.displayTiddlers instead
+function displayTiddlers(srcElement,titles,template,unused1,unused2,animate,slowly)
+{
+ story.displayTiddlers(srcElement,titles,template,animate,slowly);
+}
+
+// @Deprecated: Use story.displayTiddler instead
+function displayTiddler(srcElement,title,template,unused1,unused2,animate,slowly)
+{
+ story.displayTiddler(srcElement,title,template,animate,slowly);
+}
+
+// @Deprecated: Use functions on right hand side directly instead
+var createTiddlerPopup = Popup.create;
+var scrollToTiddlerPopup = Popup.show;
+var hideTiddlerPopup = Popup.remove;
+
+// @Deprecated: Use right hand side directly instead
+var regexpBackSlashEn = new RegExp("\\\\n","mg");
+var regexpBackSlash = new RegExp("\\\\","mg");
+var regexpBackSlashEss = new RegExp("\\\\s","mg");
+var regexpNewLine = new RegExp("\n","mg");
+var regexpCarriageReturn = new RegExp("\r","mg");
+// ---------------------------------------------------------------------------------
+// End of scripts
+merge(config.shadowTiddlers,{SiteTitle:'DevFire'});
+merge(config.shadowTiddlers,{MainMenu:"PageTemplate\nStyleSheet\nMainMenu\nDefaultTiddlers"});
+merge(config.shadowTiddlers,{SiteSubtitle:"a theme for ~TiddlyWiki"});
+merge(config.shadowTiddlers,{DefaultTiddlers:"LorumIpsum"});
+merge(config.shadowTiddlers,{LorumIpsum:"Aenean eros arcu, condimentum nec, dapibus ut, tincidunt sit amet, urna. Quisque viverra, eros sed imperdiet iaculis, est risus facilisis quam, id malesuada arcu nulla luctus urna. Nullam et est. Vestibulum velit sem, faucibus cursus, dapibus vestibulum, pellentesque et, urna. Donec luctus. Donec lectus. Aliquam eget eros facilisis tortor feugiat sollicitudin. Integer lobortis vulputate sapien. Sed iaculis erat ac nunc. Etiam eu enim. Mauris ipsum urna, rhoncus at, bibendum sit amet, euismod eget, dolor. Mauris fermentum quam vitae ligula. Vestibulum in libero feugiat justo dictum consectetuer. Vestibulum euismod purus eget elit. Nunc sed massa porta elit bibendum posuere. Nunc pulvinar justo sit amet odio. In sed est. Phasellus ornare elementum nulla. Nulla ipsum neque, cursus a, viverra a, imperdiet at, enim. Quisque facilisis, diam sed accumsan suscipit, odio arcu hendrerit dolor, quis aliquet massa nulla nec sem.\n!heading 1\n!!heading 2\n!!!heading3\n----\n<<tag button>>\nThis is a link to a [[StyleSheet]] tiddler.\n\n> This is a blockquote\n> This is a blockquote\n> This is a blockquote\n|>|>| !This is a header |h\n|column1|column2|column3|\n|row2| row2 |row2|\n|column1|column2|column3|\n|row2| row2 |row2|\n|column1|column2|column3|\n|row2| row2 |row2|"});
+// ---------------------------------------------------------------------------------
+//]]>
+</script>
+<style type="text/css">
+
+#saveTest {
+ display: none;
+}
+
+.zoomer {
+ display: none;
+}
+
+#messageArea {
+ display: none;
+}
+
+#copyright {
+ display: none;
+}
+
+.popup {
+ position: absolute;
+}
+
+#storeArea {
+ display: none;
+ margin: 4em 10em 3em;
+}
+
+#storeArea div {
+ padding: 0.5em;
+ margin: 1em 0em 0em 0em;
+ border-color: #f0f0f0 #606060 #404040 #d0d0d0;
+ border-style: solid;
+ border-width: 2px;
+ overflow: auto;
+}
+
+#javascriptWarning {
+ width: 100%;
+ text-align: center;
+ font-weight: bold;
+ background-color: #dd1100;
+ color: #fff;
+ padding:1em 0em;
+}
+
+</style>
+<!--POST-HEAD-START-->
+
+<!--POST-HEAD-END-->
+</head>
+<body onload="main();" onunload="if(window.checkUnsavedChanges) checkUnsavedChanges();">
+<!--PRE-BODY-START-->
+
+<!--PRE-BODY-END-->
+ <script type="text/javascript">
+//<![CDATA[
+if (useJavaSaver)
+ document.write("<applet style='position:absolute;left:-1px' name='TiddlySaver' code='TiddlySaver.class' archive='TiddlySaver.jar' width='1' height='1'></applet>");
+//]]>
+ </script>
+ <div id="copyright">
+ Welcome to TiddlyWiki by Jeremy Ruston, Copyright © 2006 Osmosoft Limited
+ </div>
+ <noscript>
+ <div id="javascriptWarning">This page requires JavaScript to function properly</div>
+ </noscript>
+ <div id="saveTest"></div>
+ <div id="contentWrapper"></div>
+ <div id="contentStash"></div>
+ <div id="storeArea">
+<div tiddler="(built-in shadow tiddler)" modifier="CameronRich" modified="200702240024" created="200702240024" tags="">changes, notes and errata</div>
+<div tiddler="Cam" modifier="YourName" modified="200804011313" created="200804011313" tags="">Type the text for 'YourName'</div>
+<div tiddler="Changelog" modifier="YourName" modified="200901301233" created="200702240022" tags="">@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.1@@\n\n!!__SSL Library__\n* Certificate verification now works for Firefox.\n* Extended the openssl API.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.0@@\n\n!!__SSL Library__\n* A self-signed certificate will be verified as ok provided that that it is on the certificate authority list.\n* Certificates are not verified when added as certificate authorities (since self-signed and expired certificates can be added to browsers etc)\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.9@@\n\n!!__SSL Library__\n* Now support MS IIS resource kit certificates (thanks to Carsten Sørensen).\n* Fixed a memory leak when freeing more than one CA certificate.\n* The bigint library had a problem with squaring which affected classical reduction (thanks to Manuel Klimek).\n\n!!__axhttpd__\n* Brought back setuid()/setgid() as an option.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.8@@\n\n!!__SSL Library__\n* Now using a BSD style license.\n* Self-signed certificates can now be automatically generated (the keys still need to be provided).\n* A new API call //ssl_x509_create()// can be used to programatically create the certificate.\n* Certificate/keys can be loaded automatically given a file location.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.7@@\n\n!!__SSL Library__\n\n* Variable sized session id's is now better handled for session caching. It has meant a new API call //ssl_get_session_id_size()// and a change to //ssl_client_new()// to define the session id size.\n* Muliple records with a single header are now better supported (thanks to Hervé Sibert).\n* ~MD2 added for Verisign root cert verification (thanks to Byron Rakitzis).\n* The ~MD5/~SHA1 digests are calculated incrementally to reduce memory (thanks to Byron Rakitzis).\n* The bigint cache is now cleared regularly to reduce memory.\n\n!!__axhttpd__\n\n* Improved the POST handling (thanks to Christian Melki).\n* CSS files now work properly.\n* Lua's CGI launcher location is configurable.\n* //vfork()// is now used for CGI for performance reasons.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.6@@\n\n!!__SSL Library__\n\n* ~RC4 speed improvements\n* Lua samples/bindings now work properly\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.5@@\n\n!!__SSL Library__\n\n* Session id's can now be variable lengths in server hello messages.\n* 0 length client certificates are now supported.\n* ssl_version() now returns just the version and not the date.\n* ssl_write() was not sending complete packets under load.\n\n!!__axhttpd__\n\n* Completely updated the CGI code.\n* Lua now integrated - Lua scripts and Lua Pages now run.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.4@@\n\n!!__SSL Library__\n\n* Fixed a Win32 crypto library issue with non-Administrator users\n* Removed compiler warnings that showed up in ~FC6.\n* GNU TLS certificates are now accepted.\n* Separated the send/receive headers for HMAC calculations.\n* Fixed a compilation problem with swig/perl/~FC6.\n* Fixed an issue with loading PEM CA certificates.\n\n!!__axhttpd__\n\n* Made //setuid()/setgid()// call an mconf option.\n* Made //chroot()// an mconf option. Default to //chdir()// instead.\n* Removed optional permissions checking.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.1@@\n\n!!__SSL Library__\n\n* AES should now work on 16bit processors (there was an alignment problem).\n* Various freed objects are cleared before freeing.\n* Header files now installed in ///usr/local/include/axTLS//.\n* -DCYGWIN replaced with -~DCONFIG_PLATFORM_CYGWIN (and the same for Solaris).\n* removed "-noextern" option in Swig. Fixed some other warnings in Win32.\n* SSLCTX changed to ~SSL_CTX (to be consistent with openssl). SSLCTX still exists for backwards compatibility.\n* malloc() and friends call abort() on failure.\n* Fixed a memory leak in directory listings.\n* Added openssl() compatibility functions.\n* Fixed Cygwin 'make install' issue.\n\n!!__axhttpd__\n\n* main.c now becomes axhttpd.c.\n* Header file issue fixed (in mime_types.c).\n* //chroot()// now used for better security.\n* Basic authentication implemented (via .htpasswd).\n* SSL access/denial protection implemented (via .htaccess).\n* Directory access protection implemented (via .htaccess).\n* Can now have more than one CGI file extension in mconf.\n* "~If-Modified-Since" request now handled properly.\n* Performance tweaks to remove //ssl_find()//.</div>
+<div tiddler="DefaultTiddlers" modifier="CameronRich" modified="200702240019" created="200702240019" tags="">[[Read Me]]</div>
+<div tiddler="License" modifier="YourName" modified="200804011309" created="200702240022" tags="">axTLS uses a BSD style license:\n\nCopyright (c) 2008, Cameron Rich All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this\nlist of conditions and the following disclaimer. Redistributions in binary\nform must reproduce the above copyright notice, this list of conditions and\nthe following disclaimer in the documentation and/or other materials\nprovided with the distribution. Neither the name of the axTLS Project nor\nthe names of its contributors may be used to endorse or promote products\nderived from this software without specific prior written permission. \n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\nOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGE.</div>
+<div tiddler="MainMenu" modifier="CameronRich" modified="200702250353" created="200702240021" tags="">[[Read Me]] \n[[Changelog]]\n[[axhttpd]]\n[[License]]</div>
+<div tiddler="PageTemplate" modifier="YourName" modified="200701122313" created="200701122350" tags="DevFireTheme"><div class='header' macro='gradient vert #390108 #900'>\n<div class='headerShadow'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;\n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n<div class='headerForeground'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;\n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n</div>\n<div id='mainMenu'>\n<div refresh='content' tiddler='MainMenu'></div>\n</div>\n<div id='sidebar'>\n<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>\n<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>\n</div>\n<div id='displayArea'>\n<div id='messageArea'></div>\n<div id='tiddlerDisplay'></div>\n</div></div>
+<div tiddler="Read Me" modifier="YourName" modified="200804011313" created="200702240020" tags="">!@@bgcolor(#ff0000):color(#ffffff):axTLS Quick Start Guide@@\n\nThis is a guide to get a small SSL web-server up and running quickly.\n\n!!__Introduction__\n\nThe axTLS project is an SSL client/server library using the ~TLSv1 protocol. It is designed to be small and fast, and is suited to embedded projects. A web server is included.\n\nThe basic web server + SSL library is around 60-70kB and is configurable for features or size.\n\n!!__Compilation__\n\nAll platforms require GNU make. This means on Win32 that Cygwin needs to be installed with "make" and various developer options selected.\n\nConfiguration now uses a tool called "mconf" which gives a nice way to configure options (similar to what is used in ~BusyBox and the Linux kernel).\n\nYou should be able to compile axTLS simply by extracting it, change into the extracted directory and typing:\n\n{{indent{{{{> make}}}\n\nSelect your platform type, save the configuration, exit, and then type "make" again.\n\nIf all goes well, you should end up with an executable called "axhttpd" (or axhttpd.exe) in the //_stage// directory.\n\nTo play with all the various axTLS options, type:\n\n{{indent{{{{> make menuconfig}}}\n\nSave the new configuration and rebuild.\n\n!!__Running it__\n\nTo run it, go to the //_stage// directory, and type (as superuser):\n\n{{indent{{{{> axhttpd}}}\n\nNote: you may have to set your ~LD_LIBRARY_PATH - e.g. go to //_stage// and type //export ~LD_LIBRARY_PATH=`pwd`//\n\nAnd then point your browser at https://127.0.0.1 And you should see a this html page with a padlock appearing on your browser. or type http://127.0.0.1 to see the same page unencrypted.\n\n!!__The axssl utilities__\n\nThe axssl suite of tools are the SSL test tools in the various language bindings. They are:\n\n* axssl - C sample\n* axssl.csharp - C# sample\n* axssl.vbnet - VB.NET sample\n* axtls.jar - Java sample\n* axssl.pl - Perl sample\n* axssl.lua - Lua sample\n\nAll the tools have identical command-line parameters. e.g. to run something interesting:\n\n{{indent{{{{> axssl s_server -verify -CAfile ../ssl/test/axTLS.ca_x509}}}\n\nand\n\n{{indent{{{{> axssl s_client -cert ../ssl/test/axTLS.x509_1024 -key ../ssl/test/axTLS.key_1024 -reconnect}}}\n\n!!!!C#\n\nIf building under Linux or other non-Win32 platforms, Mono must be installed and the executable is run as:\n\n{{indent{{{{> mono axssl.csharp.exe ...}}}\n\n!!!!Java\n\nThe java version is run as:\n\n{{indent{{{{> java -jar axtls.jar <options>}}}\n\n!!!!Perl\n\n{{indent{{{{> [perl] ./axssl.pl <options>}}}\n\nIf running under Win32, be sure to use the correct version of Perl (i.e. ~ActiveState's version works ok).\n\n!!!!Lua\n\n{{indent{{{{> [lua] ./axssl.lua <options>}}}\n\n!__Known Issues__\n\n* Firefox doesn't handle legacy ~SSLv2 at all well. Disabling ~SSLv2 still initiates a ~SSLv23 handshake (v1.5). And continuous pressing of the "Reload" page instigates a change to ~SSLv3 for some reason (even though the TLS 1.0 option is selected). This will cause a "Firefox and <server> cannot communicate securely because they have no common encryption algorithms" (v1.5), or "Firefox can't connect to <server> because the site uses a security protocol which isn't enabled" (v2.0). See bugzilla issues 343543 and 359484 (Comment #7). It's all broken (hopefully fixed soon).\n* Perl/Java bindings don't work on 64 bit Linux machines. I can't even compile the latest version of Perl on an ~AMD64 box (using ~FC3).\n* Java 1.4 or better is required for the Java interfaces.\n* Processes that fork can't use session resumption unless some form of IPC is used.\n* Ensure libperl.so and libaxtls.so are in the shared library path when running with the perl bindings. A way to do this is with:\n\n{{indent{{{{> export LD_LIBRARY_PATH=`perl -e 'use Config; print $Config{archlib};'`/CORE:.}}}\n* The lua sample requires the luabit library from http://luaforge.net/projects/bit.\n\n!!!!Win32 issues\n\n* Be careful about doing .NET executions on network drives - .NET complains with security exceptions on the binary. //TODO: Add a manifest file to prevent this.//\n* CGI has been removed from Win32 - it needs a lot more work to get it right.\n* The default Microsoft .NET SDK is v2.0.50727. Download from: http://msdn.microsoft.com/netframework/downloads/updates/default.aspx.\n\n!!!!Solaris issues\n\n* mconf doesn't work well - some manual tweaking is required for string values.\n* GNU make is required and needs to be in $PATH.\n* To get swig's library dependencies to work (and for the C library to be found), I needed to type:\n\n{{indent{{{{> export LD_LIBRARY_PATH=/usr/local/gcc-3.3.1/lib:.}}}\n\n!!!!Cygwin issues\n\n* The bindings all compile but don't run under Cygwin with the exception of Perl. This is due to win32 executables being incompatible with Cygwin libraries.\n\n</div>
+<div tiddler="SiteSubtitle" modifier="CameronRich" modified="200702240025" created="200702240025" tags="">changes, notes and errata</div>
+<div tiddler="SiteTitle" modifier="CameronRich" modified="200702240023" created="200702240023" tags="">axTLS Embedded SSL</div>
+<div tiddler="SiteUrl" modifier="CameronRich" modified="200702240025" created="200702240025" tags="">http://axtls.cerocclub.com.au</div>
+<div tiddler="StyleSheet" modifier="CameronRich" modified="200702250600" created="200701122350" tags="DevFireTheme">/***\nhttp://tiddlystyles.com/#theme:DevFire\nAuthor: Clint Checketts\n***/\n\n/*{{{*/\nbody {\nbackground: #000;\n}\n/*}}}*/\n/***\n!Link styles /% ============================================================= %/\n***/\n/*{{{*/\na,\na.button,\n#mainMenu a.button,\n#sidebarOptions .sliderPanel a{\n color: #ffbf00;\n border: 0;\n background: transparent;\n}\n\na:hover,\na.button:hover,\n#mainMenu a.button:hover,\n#sidebarOptions .sliderPanel a:hover\n#sidebarOptions .sliderPanel a:active{\n color: #ff7f00;\n border: 0;\n border-bottom: #ff7f00 1px dashed;\n background: transparent;\n text-decoration: none;\n}\n\n#displayArea .button.highlight{\n color: #ffbf00;\n background: #4c4c4c;\n}\n/*}}}*/\n/***\n!Header styles /% ============================================================= %/\n***/\n/*{{{*/\n.header{\n border-bottom: 2px solid #ffbf00;\n color: #fff;\n}\n\n.headerForeground a {\n color: #fff;\n}\n\n.header a:hover {\n border-bottom: 1px dashed #fff;\n}\n/*}}}*/\n/***\n!Main menu styles /% ============================================================= %/\n***/\n/*{{{*/\n#mainMenu {color: #fff;}\n#mainMenu h1{\n font-size: 1.1em;\n}\n#mainMenu li,#mainMenu ul{\n list-style: none;\n margin: 0;\n padding: 0;\n}\n/*}}}*/\n/***\n!Sidebar styles /% ============================================================= %/\n***/\n/*{{{*/\n#sidebar {\n right: 0;\n color: #fff;\n border: 2px solid #ffbf00;\n border-width: 0 0 2px 2px;\n}\n#sidebarOptions {\n background-color: #4c4c4c;\n padding: 0;\n}\n\n#sidebarOptions a{\n margin: 0;\n color: #ffbf00;\n border: 0;\n}\n#sidebarOptions a:hover {\n color: #4c4c4c;\n background-color: #ffbf00;\n\n}\n\n#sidebarOptions a:active {\n color: #ffbf00;\n background-color: transparent;\n}\n\n#sidebarOptions .sliderPanel {\n background-color: #333;\n margin: 0;\n}\n\n#sidebarTabs {background-color: #4c4c4c;}\n#sidebarTabs .tabSelected {\n padding: 3px 3px;\n cursor: default;\n color: #ffbf00;\n background-color: #666;\n}\n#sidebarTabs .tabUnselected {\n color: #ffbf00;\n background-color: #5f5f5f;\n padding: 0 4px;\n}\n\n#sidebarTabs .tabUnselected:hover,\n#sidebarTabs .tabContents {\n background-color: #666;\n}\n\n.listTitle{color: #FFF;}\n#sidebarTabs .tabContents a{\n color: #ffbf00;\n}\n\n#sidebarTabs .tabContents a:hover{\n color: #ff7f00;\n background: transparent;\n}\n\n#sidebarTabs .txtMoreTab .tabSelected,\n#sidebarTabs .txtMoreTab .tab:hover,\n#sidebarTabs .txtMoreTab .tabContents{\n color: #ffbf00;\n background: #4c4c4c;\n}\n\n#sidebarTabs .txtMoreTab .tabUnselected {\n color: #ffbf00;\n background: #5f5f5f;\n}\n\n.tab.tabSelected, .tab.tabSelected:hover{color: #ffbf00; border: 0; background-color: #4c4c4c;cursor:default;}\n.tab.tabUnselected {background-color: #666;}\n.tab.tabUnselected:hover{color:#ffbf00; border: 0;background-color: #4c4c4c;}\n.tabContents {\n background-color: #4c4c4c;\n border: 0;\n}\n.tabContents .tabContents{background: #666;}\n.tabContents .tabSelected{background: #666;}\n.tabContents .tabUnselected{background: #5f5f5f;}\n.tabContents .tab:hover{background: #666;}\n/*}}}*/\n/***\n!Message area styles /% ============================================================= %/\n***/\n/*{{{*/\n#messageArea {background-color: #666; color: #fff; border: 2px solid #ffbf00;}\n#messageArea a:link, #messageArea a:visited {color: #ffbf00; text-decoration:none;}\n#messageArea a:hover {color: #ff7f00;}\n#messageArea a:active {color: #ff7f00;}\n#messageArea .messageToolbar a{\n border: 1px solid #ffbf00;\n background: #4c4c4c;\n}\n/*}}}*/\n/***\n!Popup styles /% ============================================================= %/\n***/\n/*{{{*/\n.popup {color: #fff; background-color: #4c4c4c; border: 1px solid #ffbf00;}\n.popup li.disabled{color: #fff;}\n.popup a {color: #ffbf00; }\n.popup a:hover { background: transparent; color: #ff7f00; border: 0;}\n.popup hr {color: #ffbf00; background: #ffbf00;}\n/*}}}*/\n/***\n!Tiddler Display styles /% ============================================================= %/\n***/\n/*{{{*/\n.title{color: #fff;}\nh1, h2, h3, h4, h5 {\n color: #fff;\n background-color: transparent;\n border-bottom: 1px solid #333;\n}\n\n.subtitle{\n color: #666;\n}\n\n.viewer {color: #fff; }\n\n.viewer table{background: #666; color: #fff;}\n\n.viewer th {background-color: #996; color: #fff;}\n\n.viewer pre, .viewer code {color: #ddd; background-color: #4c4c4c; border: 1px solid #ffbf00;}\n\n.viewer hr {color: #666;}\n\n.tiddler .button {color: #4c4c4c;}\n.tiddler .button:hover { color: #ffbf00; background-color: #4c4c4c;}\n.tiddler .button:active {color: #ffbf00; background-color: #4c4c4c;}\n\n.toolbar {\n color: #4c4c4c;\n}\n\n.toolbar a.button,\n.toolbar a.button:hover,\n.toolbar a.button:active,\n.editorFooter a{\n border: 0;\n}\n\n.footer {\n color: #ddd;\n}\n\n.selected .footer {\n color: #888;\n}\n\n.highlight, .marked {\n color: #000;\n background-color: #ffe72f;\n}\n.editorFooter {\n color: #aaa;\n}\n\n.tab{\n-moz-border-radius-topleft: 3px;\n-moz-border-radius-topright: 3px;\n}\n\n.tagging,\n.tagged{\n background: #4c4c4c;\n border: 1px solid #4c4c4c; \n}\n\n.selected .tagging,\n.selected .tagged{\n background-color: #333;\n border: 1px solid #ffbf00;\n}\n\n.tagging .listTitle,\n.tagged .listTitle{\n color: #fff;\n}\n\n.tagging .button,\n.tagged .button{\n color: #ffbf00;\n border: 0;\n padding: 0;\n}\n\n.tagging .button:hover,\n.tagged .button:hover{\nbackground: transparent;\n}\n\n.selected .isTag .tagging.simple,\n.selected .tagged.simple,\n.isTag .tagging.simple,\n.tagged.simple {\n float: none;\n display: inline;\n border: 0;\n background: transparent;\n color: #fff;\n margin: 0;\n}\n\n.cascade {\n background: #4c4c4c;\n color: #ddd;\n border: 1px solid #ffbf00;\n}\n/*}}}*/</div>
+<div tiddler="axhttpd" modifier="YourName" modified="200804011308" created="200702242231" tags="">axhttpd is a small embedded web server using the axTLS library. It is based originally on the web server written by Doug Currie which is at http://www.hcsw.org/awhttpd.\n\n!@@bgcolor(#ff0000):color(#ffffff):axhttpd Features@@ \n\n!!__Basic Authentication__\n\nBasic Authentication uses a password file called ".htpasswd", in the directory to be protected. This file is formatted as the familiar colon-separated username/encrypted-password pair, records delimited by newlines. The protection does not carry over to subdirectories. The utility program htpasswd is included to help manually edit .htpasswd files.\n\nThe encryption of this password uses a proprietary algorithm due to the dependency of many crypt libraries on DES. An example is in [[/test_dir/no_http|https://127.0.0.1/test_dir/no_http]] (username 'abcd', password is '1234').\n\n//Note: This is an mconf enabled configuration option.//\n\n!!__SSL Protection__\n\nDirectories/files can be accessed using the 'http' or 'https' uri prefix. If normal http access for a directory needs to be disabled, then put "~SSLRequireSSL" into a '.htaccess' file in the directory to be protected. \n\nConversely, use "~SSLDenySSL" to deny access to directories via SSL.\n\nAn example is in [[/test_dir/no_http|http://127.0.0.1/test_dir/no_http]] and [[/test_dir/no_ssl|https://127.0.0.1/test_dir/no_ssl]].\n\nEntire directories can be denied access with a "Deny all" directive (regardless of SSL or authentication). An example is in [[/test_dir/bin|http://127.0.0.1/test_dir/bin]]\n\n!!__CGI__\n\nMost of the CGI 1.1 variables are now placed into the script environment and should work as normal.\n\n!!__Lua and Lua Pages__\n\nThis is a small scripting language gaining popularity in embedded applications due to its small footprint and fast speed.\n\nLua has been incorporated into the build, so simply select it and it will automatically install. Try pointing your browser at [[test_main.html]|http://127.0.0.1/lua/test_main.html]] to see an example of Lua Pages.\n\n//Note: This is an mconf enabled configuration option.//\n\n!!__Directory Listing__\n\nAn mconf option. Allow the files in directories to be displayed. An example is in [[/test_dir|http://127.0.0.1/test_dir]]\n\n!!__Other Features__\n\n* Timeout - HTTP 1.1 allows for persistent connections. This is the time allowed for this connection in seconds.\n* Daemon - Puts the process in daemon mode. \n* SSL session cache size - The size of the session cache (a heavily loaded server should maintain many sessions). A session will save on expensive SSL handshaking.\n\n</div>
+</div>
+<!--POST-BODY-START-->
+
+<!--POST-BODY-END-->
+ </body>
+</html>
--- /dev/null
+#!/usr/local/bin/lua
+
+require"luasocket"
+
+function receive (connection)
+ connection:settimeout(0)
+ local s, status = connection:receive (2^10)
+ if status == "timeout" then
+ coroutine.yield (connection)
+ end
+ return s, status
+end
+
+function download (host, file, outfile)
+ --local f = assert (io.open (outfile, "w"))
+ local c = assert (socket.connect (host, 80))
+ c:send ("GET "..file.." HTTP/1.0\r\n\r\n")
+ while true do
+ local s, status = receive (c)
+ --f:write (s)
+ if status == "closed" then
+ break
+ end
+ end
+ c:close()
+ --f:close()
+end
+
+local threads = {}
+function get (host, file, outfile)
+ print (string.format ("Downloading %s from %s to %s", file, host, outfile))
+ local co = coroutine.create (function ()
+ return download (host, file, outfile)
+ end)
+ table.insert (threads, co)
+end
+
+function dispatcher ()
+ while true do
+ local n = table.getn (threads)
+ if n == 0 then
+ break
+ end
+ local connections = {}
+ for i = 1, n do
+ local status, res = coroutine.resume (threads[i])
+ if not res then
+ table.remove (threads, i)
+ break
+ else
+ table.insert (connections, res)
+ end
+ end
+ if table.getn (connections) == n then
+ socket.select (connections)
+ end
+ end
+end
+
+local url = arg[1]
+if not url then
+ print (string.format ("usage: %s url [times]", arg[0]))
+ os.exit()
+end
+local times = arg[2] or 5
+
+url = string.gsub (url, "^http.?://", "")
+local _, _, host, file = string.find (url, "^([^/]+)(/.*)")
+local _, _, fn = string.find (file, "([^/]+)$")
+
+for i = 1, times do
+ get (host, file, fn..i)
+end
+
+dispatcher ()
--- /dev/null
+-- This file should be executed before any script in this directory
+-- according to the configuration (cgilua/conf.lua).
+
+pcall (cgilua.enablesession)
+
+local put, mkurlpath = cgilua.put, cgilua.mkurlpath
+
+cgilua.addclosefunction (function ()
+ put [[
+<p>
+<small>
+<a href="test_main.html">Main</a>]]
+ for _, test in {
+ { "Get", "test_main.lua", {ab = "cd", ef = "gh"} },
+ { "Cookies", "test_cookies.lua", },
+ { "FileSystem", "test_fs.lua", },
+ { "Libraries", "test_lib.lua", },
+ { "Session", "test_session.lua", },
+ { "Variables", "test_variables.lp", },
+ } do
+ put (string.format (' · <a href="%s">%s</a>',
+ mkurlpath (test[2], test[3]), test[1]))
+ end
+ put [[
+</small>]]
+end)
--- /dev/null
+<?lua
+-- Tries to load known libraries
+for _, t in ipairs { "lxp", "luasql.postgres", "luasql.mysql", "luasql.oci8", "luasql.sqlite", "luasql.odbc", "socket", "xmlrpc", "soap", "lualdap", "logging", "md5", "zip", "stable", "copas", } do
+ pcall (require, t)
+end
+
+libraries = { "lxp", "luasql", "socket", "xmlrpc", "soap", "lualdap", "logging", "md5", "zip", "stable", "copas", }
+
+local colors = { "#999999", "#CCCCCC", "#FFFFFF", }
+local i = 0
+function color () i = math.mod (i + 1, 3) return colors[i + 1] end
+
+function pack_name (p) return string.gsub (p, "^([^.]+).-", "%1") end
+
+function idx (t, f) return _G[t][f] or _G[t]["_"..f] or "" end
+?>
+<html>
+<head><title>CGILua installation overview</title></head>
+
+<body bgcolor="#FFFFFF">
+<h1>CGILua installation overview</h1>
+
+<table>
+ <tr>
+ <th bgcolor="#999999">Version
+ <th bgcolor="#999999">Copyright
+ <th bgcolor="#999999">Description
+ </tr>
+<?lua
+local support = {
+ { "Lua", "_VERSION" },
+ { "compat-5.1", "_COMPAT51" },
+}
+for _, l in ipairs (support) do bg = color()
+?>
+ <tr>
+ <td bgcolor = "<%= bg %>"><%= tostring(_G[l[2]]) %>
+ <td bgcolor = "<%= bg %>">
+ <td bgcolor = "<%= bg %>">
+ </tr>
+<? end ?>
+ <tr><td colspan="4"></tr>
+<?lua
+local pack = {}
+for i, p in ipairs (libraries) do
+ local s = _G[p]
+ local n = pack_name(p)
+ if type(_G[n]) == "table" and _G[n]._VERSION then
+ pack[n] = true
+ table.insert (pack, n)
+ end
+end
+table.sort (pack)
+for _, p in ipairs (pack) do bg = color() ?>
+ <tr>
+ <td bgcolor = "<%= bg %>"><%= idx(p,"VERSION") %>
+ <td bgcolor = "<%= bg %>"><small><%= idx(p,"COPYRIGHT") %></small>
+ <td bgcolor = "<%= bg %>"><small><%= idx(p,"DESCRIPTION") %></small>
+ </tr>
+<?lua end ?>
+</table>
+
+</body>
+</html>
--- /dev/null
+#!/usr/local/bin/lua
+
+MAX_ROWS = arg[1] or 10
+
+require"postgres"
+
+local env = assert (luasql.postgres ())
+local conn = assert (env:connect ("luasql-test", "tomas"))
+
+-- Apaga restos de outros testes.
+conn:execute "drop table t2"
+conn:execute "drop table t1"
+
+-- Criando as tabelas.
+assert (conn:execute [[create table t1 (
+ a int,
+ b int
+)]])
+assert (conn:execute [[create table t2 (
+ c int,
+ d int
+)]])
+
+-- Preenchedo as tabelas.
+for i = 1, MAX_ROWS do
+ local ii = 2*i
+ assert (conn:execute (string.format ([[
+insert into t1 values (%d, %d);
+insert into t2 values (%d, %d);]],
+ ii, i, ii, i)))
+end
--- /dev/null
+cgilua.htmlheader()
+if ap then
+ local pid, ppid = ap.pid ()
+ if not ppid then
+ ppid = "no parent pid"
+ end
+ cgilua.put ("pid = "..pid.." ("..ppid..")".."\n")
+end
+
+assert(type(stable.get) == "function")
+assert(type(stable.set) == "function")
+
+cgilua.put"stable.pairs = {<br>\n"
+for i, v in stable.pairs () do
+ cgilua.put (i.." = "..tostring(v).."<br>\n")
+end
+cgilua.put"}<br>\n"
+
+local counter = stable.get"counter" or 0
+stable.set ("counter", counter + 1)
+
+local f = stable.get"f"
+if not f then
+ local d = os.date()
+ stable.set ("f", function () return d end)
+else
+ cgilua.put ("f() = "..tostring (f ()))
+end
+
+cgilua.put"<br>\n"
+for i = 1,800 do
+ cgilua.put (i)
+ for ii = 1,1000 do
+ cgilua.put ("<!>")
+ end
+ cgilua.put ("\n")
+end
+cgilua.put ("End")
--- /dev/null
+<?lua
+local cookies = require"cgilua.cookies"
+CL_COOKIE = "cgilua_cookie"
+
+local test = cookies.get (CL_COOKIE)
+cookies.sethtml (CL_COOKIE, os.date())
+?>
+
+<h1>Testing Cookies library</h1>
+
+<%= CL_COOKIE%> = <%= tostring(test)%><br>
+Assigning current date to cookie!<br>
+Reload this script to check cookie's value!
--- /dev/null
+local cookies = require"cgilua.cookies"
+CL_COOKIE = "cgilua_cookie"
+
+local test = cookies.get (CL_COOKIE)
+cookies.set (CL_COOKIE, os.date())
+
+cgilua.htmlheader ()
+cgilua.put ([[
+<h1>Testing Cookies library</h1>
+
+]]..CL_COOKIE..' = '..tostring(test)..[[<br>
+Assigning current date to cookie!<br>
+Reload this script to check cookie's value!
+]])
--- /dev/null
+cgilua.htmlheader()
+cgilua.put"Oi!"
+--io.write"something\n"
+cgilua.errorlog ("eca", "emerg")
--- /dev/null
+function link_dir (dir, base)
+ local path = base.."/"..dir
+ local mode = lfs.attributes (path).mode
+ if mode == "directory" then
+ return string.format ('<a href="%s">%s</a>',
+ cgilua.mkurlpath ("test_fs.lua", { dir = path }),
+ dir)
+ else
+ return dir
+ end
+end
+
+cgilua.htmlheader ()
+cgilua.put ("<h1>Testing Filesystem library</h1>\n")
+cgilua.put ("<table>\n")
+cgilua.put ("<tr><td colspan=2>Testing <b>dir</b></td></tr>\n")
+local i = 0
+local dir = cgi.dir or "."
+for file in lfs.dir (dir) do
+ i = i+1
+ cgilua.put ("<tr><td>"..i.."</td><td>"..link_dir(file, dir).."</td></tr>\n")
+end
+cgilua.put ("</table>\n")
--- /dev/null
+require"htk"
+
+local a_table = {}
+for i = 1, 20 do
+ local l = {}
+ for j = 1, 20 do
+ table.insert (l, HTK.TD { "cell "..i..","..j })
+ end
+ table.insert (a_table, HTK.TR (l))
+end
+
+cgilua.htmlheader()
+cgilua.put (HTK.HTML {
+ HTK.HEAD { HTK.TITLE { "Titulo da Pagina" } },
+ HTK.BODY {
+ bgcolor = "#FFFFFF",
+ HTK.H1 { "Titulo da Pagina" },
+ HTK.P {},
+ "Uma página qualquer",
+ HTK.TABLE (a_table),
+ }
+})
--- /dev/null
+local function getfield (t, f)
+ for w in string.gfind(f, "[%w_]+") do
+ if not t then return nil end
+ t = t[w]
+ end
+ return t
+end
+
+function test_lib (libname)
+ local ok, err = pcall (require, libname)
+ if not ok then
+ cgilua.put ("Library <tt><b>"..libname.."</b></tt> not found<br>\n"..
+ err)
+ else
+ cgilua.put ("Library <tt><b>"..libname.."</b></tt><br>\n")
+ local t = getfield (_G, libname)
+ if type(t) ~= "table" then
+ cgilua.put (tostring(t))
+ else
+ for i, v in pairs (t) do
+ cgilua.put (" "..tostring(i).." = "..tostring(v).."<br>\n")
+ end
+ end
+ end
+ cgilua.put ("\n<p>\n")
+end
+
+cgilua.htmlheader ()
+for _, lib in ipairs { "lfs", "socket", "luasql.postgres", "luasql", "lxp", "lxp.lom", "lualdap", "htk", "xmlrpc", "xmlrpc.http" } do
+ test_lib (lib)
+end
--- /dev/null
+<html>
+<head><title>Test Page</title></head>
+
+<table border>
+ <tr>
+ <th colspan="4"> GET: </td>
+ </tr>
+ <tr>
+ <td>Lua script</td>
+ <td><a href="test_main.lua?field1=ab&field2=cd&field1=ef">module</a></td>
+ </tr>
+ <tr>
+ <td>HTML template</td>
+ <td><a href="test_main.lp?field1=ab&field2=cd&field1=ef">module</a></td>
+ </tr>
+
+ <tr>
+ <th colspan="4"> POST: </td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <form method="POST" action="">
+ <table>
+ <tr>
+ <td colspan="4">
+ field 1: <input type="text" name="field1"><br>
+ field 2: <input type="text" name="field2"><br>
+ field 3:
+ <input type="checkbox" name="field3" value="op 1">op 1
+ <input type="checkbox" name="field3" value="op 2">op 2
+ <input type="checkbox" name="field3" value="op 3">op 3
+ </td>
+ </tr>
+ <tr>
+ <td>Lua script</td>
+ <td>
+ <a href="javascript:document.forms[0].action='test_main.lua';document.forms[0].submit()">module</a>
+ </td>
+ </tr>
+ <tr>
+ <td>HTML template</td>
+ <td>
+ <a href="javascript:document.forms[0].action='test_main.lp';document.forms[0].submit()">module</a>
+ </td>
+ </tr>
+ </table>
+ </form>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan="4"> POST (with upload): </td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <form method="POST" enctype="multipart/form-data" action="">
+ <table>
+ <tr>
+ <td colspan="4">
+ field 1: <input type="text" name="field1"><br>
+ file (binary!): <input type="file" name="file"><br>
+ </td>
+ </tr>
+ <tr>
+ <td>Lua script</td>
+ <td>
+ <a href="javascript:document.forms[1].action='test_main.lua';document.forms[1].submit()">module</a>
+ </td>
+ </tr>
+ <tr>
+ <td>HTML template</td>
+ <td>
+ <a href="javascript:document.forms[1].action='test_main.lp';document.forms[1].submit()">module</a>
+ </td>
+ </tr>
+ </table>
+ </form>
+ </td>
+ </tr>
+ <tr>
+ <th colspan="4"> Cookies: </td>
+ </tr>
+ <tr>
+ <td>Lua script</td>
+ <td><a href="test_cookies.lua">module</a></td>
+ </tr>
+ <tr>
+ <td>HTML template</td>
+ <td><a href="test_cookies.lp">module</a></td>
+ </tr>
+ <tr>
+ <th colspan="4"> Filesystem: </td>
+ </tr>
+ <tr>
+ <td>Lua script</td>
+ <td><a href="test_fs.lua">module</a></td>
+ </tr>
+ <tr>
+ <th colspan="4"> Session: </td>
+ </tr>
+ <tr>
+ <td>Lua script</td>
+ <td><a href="test_session.lua">module</a></td>
+ </tr>
+ <tr>
+ <th colspan="4"> CGI Variables: </td>
+ </tr>
+ <tr>
+ <td>HTML template</td>
+ <td><a href="test_variables.lp">module</a></td>
+ </tr>
+ <tr>
+ <th colspan="4"> Library Overview: </td>
+ </tr>
+ <tr>
+ <td>HTML template</td>
+ <td><a href="overview.lp">module</a></td>
+ </tr>
+ <tr>
+ <th colspan="4"> Concurrency </td>
+ </tr>
+ <tr>
+ <td>Lua script</td>
+ <td><a href="test_conc.lua">module</a></td>
+ </tr>
+</table>
+</html>
--- /dev/null
+<html>
+<head><title>Embeded Lua Test</title></head>
+
+<body>
+cgi = {
+<?lua
+for i,v in pairs (cgi) do
+ if type(v) == "table" then
+ local vv = "{"
+ for a,b in pairs(v) do
+ vv = string.format ("%s%s = %s<br>\n", vv, a, tostring(b))
+ end
+ v = vv.."}"
+ end
+?>
+<%= i %> = <%= tostring(v) %> <br>
+<%
+end
+%>
+}
+<br>
+Remote address: <%= cgilua.servervariable"REMOTE_ADDR" %>
+<br>
+Is persistent = <%= tostring (SAPI.Info.ispersistent) %>
+<br>
+ap = <?lua= tostring(ap) ?> <br>
+lfcgi = <% = tostring(lfcgi) %> <br>
+<%= (ap and ap.handler()) or "" %> <br>
+
+</body>
+</html>
--- /dev/null
+cgilua.htmlheader()
+cgilua.put[[
+<html>
+<head><title>Script Lua Test</title></head>
+
+<body>
+cgi = {
+]]
+
+for i,v in pairs (cgi) do
+ if type(v) == "table" then
+ local vv = "{"
+ for a,b in pairs(v) do
+ vv = string.format ("%s%s = %s<br>\n", vv, a, tostring(b))
+ end
+ v = vv.."}"
+ end
+ cgilua.put (string.format ("%s = %s<br>\n", i, tostring(v)))
+end
+cgilua.put "}<br>\n"
+cgilua.put ("Remote address: "..cgilua.servervariable"REMOTE_ADDR")
+cgilua.put "<br>\n"
+cgilua.put ("Is persistent = "..tostring (SAPI.Info.ispersistent).."<br>\n")
+cgilua.put ("ap="..tostring(ap).."<br>\n")
+cgilua.put ("lfcgi="..tostring(lfcgi).."<br>\n")
+
+-- Checking Virtual Environment
+local my_output = cgilua.put
+cgilua.put = nil
+local status, err = pcall (function ()
+ assert (cgilua.put == nil, "cannot change cgilua.put value")
+end)
+cgilua.put = my_output
+assert (status == true, err)
+
+-- Checking require
+local status, err = pcall (function () require"unknown_module" end)
+assert (status == false, "<tt>unknown_module</tt> loaded!")
+-- assert (package == nil, "Access to <tt>package</tt> table allowed!")
+
+cgilua.put[[
+<p>
+</body>
+</html>
+]]
+cgilua = nil
--- /dev/null
+cgilua.enablesession ()
+
+function pt (tab)
+ for i, v in pairs (tab) do
+ local vv = v
+ if type(v) == "table" then
+ vv = ""
+ for _i, _v in pairs (v) do
+ vv = vv..string.format ("%s = %q, ", _i, _v)
+ end
+ vv = '{'..vv..'}'
+ end
+ cgilua.put (string.format ("%s = %s<br>\n", tostring (i), tostring (vv)))
+ end
+end
+
+
+if cgi.field then
+ if not cgilua.session.data.field then
+ cgilua.session.data.field = {}
+ end
+ table.insert (cgilua.session.data.field, cgi.field)
+end
+cgilua.htmlheader()
+if cgilua.session then
+ cgilua.put "cgi = {<br>\n"
+ pt (cgi)
+ cgilua.put "}<br>\n"
+ cgilua.put "cgilua.session.data = {<br>\n"
+ pt (cgilua.session.data)
+ cgilua.put "}<br>\n"
+
+ cgilua.put [[<form action="]]
+ cgilua.put (cgilua.mkurlpath"test_session.lua")
+ cgilua.put [[" method="POST">
+ field: <input type="text" name="field" value="]]
+ cgilua.put (cgi.field or "")
+ cgilua.put [["><br>
+ <input type="submit"><br>
+</form>]]
+else
+ cgilua.put "Sessions library is not available or not well configured"
+end
--- /dev/null
+local s = require"luasql.postgres"
+
+local env = assert (luasql.postgres ())
+local conn = assert (env:connect ("luasql-test", "tomas"))
+local cur = assert (conn:execute ("select count(*) from fetch_test"))
+
+cgilua.htmlheader()
+cgilua.put ("Total lines at table fetch_test is "..cur:fetch())
+cgilua.put (string.format ("<br>\n%s == %s<br>\n", tostring(s), tostring(luasql)))
+
+cur:close()
+conn:close()
+env:close()
--- /dev/null
+require"postgres"
+
+local env = assert (luasql.postgres ())
+local conn = assert (env:connect ("luasql-test", "tomas"))
+local cur = assert (conn:execute ("select count(*) from t1"))
+local total = tonumber (cur:fetch())
+cur:close()
+local aleatorio = math.random(total)
+local cur = assert (conn:execute ("select * from t1, t2 where b = d and a != "..2*aleatorio))
+
+cgilua.htmlheader()
+cgilua.put ("Aleatorio = "..aleatorio.."<br>\n")
+
+local a,b,c,d = cur:fetch()
+cgilua.put ("<table>\n")
+while a do
+-- cgilua.put ("<tr><td>",a,"<td>",b,"<td>",c,"<td>",d,"</tr>")
+ a,b,c,d = cur:fetch()
+end
+cgilua.put ("</table>\n")
+
+cur:close()
+conn:close()
+env:close()
--- /dev/null
+<table>
+<% for _, var in pairs { "SERVER_SOFTWARE", "SERVER_NAME", "GATEWAY_INTERFACE", "SERVER_PROTOCOL", "SERVER_PORT", "REQUEST_METHOD", "PATH_INFO", "PATH_TRANSLATED", "SCRIPT_NAME", "QUERY_STRING", "REMOTE_HOST", "REMOTE_ADDR", "AUTH_TYPE", "REMOTE_USER", "REMOTE_IDENT", "CONTENT_TYPE", "CONTENT_LENGTH", "HTTP_REFERER", "HTTP_COOKIE", "SCRIPT_FILENAME", "DOCUMENT_ROOT", } do %>
+ <tr><td><%= var %><td>=<td>"<%= cgilua.servervariable(var) or "<i>not defined</i>"%>"</tr>
+<% end %>
+</table>
+
+<p>
+<table>
+<% for _, var in ipairs { "script_file", "script_path", "script_pdir", "script_vdir", "script_vpath", "urlpath", } do %>
+ <tr><td><%= var %><td>=<td>"<%= cgilua[var] %>"</tr>
+<% end %>
+</table>
+
+<p>
--- /dev/null
+SSLRequireSSL
--- /dev/null
+abcd:CQhgDPyy0rvEU8OMxnQIvg==$YdJfIKZimFLYxPf/rbnhtQ==
+yaya:Syuss5jE2FNGVdr0kKGoHg==$WLw/SgHZFuAoOuml3GTJVw==
--- /dev/null
+<html>
+<head><title>axhttpd is running</title></head>
+<body>
+Looks like you got to this directory.
+</body>
+</html>
--- /dev/null
+SSLDenySSL
--- /dev/null
+<html>
+<head><title>axhttpd is running</title></head>
+<body>
+Looks like you got to this directory.
+</body>
+</html>