commit fa18d60b9810eddd4a654bb7ee2d1f2e2086dce1 Author: cameronrich Date: Sat Jul 1 00:39:15 2006 +0000 Initial 1.0.0 git-svn-id: svn://svn.code.sf.net/p/axtls/code/axTLS@2 9a5d90b5-6617-0410-8a86-bb477d3ed2e3 diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..e335b82c8 --- /dev/null +++ b/Makefile @@ -0,0 +1,135 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +-include config/.config + +ifneq ($(strip $(HAVE_DOT_CONFIG)),y) +all: menuconfig +else +all: target +endif + +target : $(TARGET) + +include config/makefile.conf + +# VERSION has to come from the command line +RELEASE=axTLS-$(VERSION) + +# standard version +target: + $(MAKE) -C ssl +ifdef CONFIG_AWHTTPD + $(MAKE) -C httpd untar_web_server + $(MAKE) -C httpd +endif +ifdef CONFIG_BINDINGS + $(MAKE) -C bindings +endif +ifdef CONFIG_SAMPLES + $(MAKE) -C samples +endif + +release: + $(MAKE) -C config/scripts/config clean + -$(MAKE) clean + -@rm config/.* config/config.h + -@rm config/*.msi config/*.back.aip + cd ../; tar cvfz $(RELEASE).tar.gz axTLS; cd -; + +docs: + $(MAKE) -C docsrc doco + +# build the Win32 demo release version +win32_demo: + -@rm -fr ../axTLS.release_test > /dev/null 2>&1 + $(MAKE) win32releaseconf + cd ../; zip $(RELEASE).zip \ + ./axTLS/awhttpd.exe \ + ./axTLS/axssl.exe \ + ./axTLS/axtls.dll \ + ./axTLS/axtls.lib \ + ./axTLS/axtls.static.lib \ + ./axTLS/axtlsj.dll \ + ./axTLS/axssl.csharp.exe \ + ./axTLS/axssl.vbnet.exe \ + ./axTLS/axtls.jar \ + ./axTLS/www/* \ + ./axTLS/www/crypto_files/*; \ + unzip -d axTLS.release_test $(RELEASE).zip; cd -; + +# tidy up things +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) + + + diff --git a/README b/README new file mode 100644 index 000000000..2d6d7b990 --- /dev/null +++ b/README @@ -0,0 +1,156 @@ +######################################################################## +# axTLS Quick-Start Guide +######################################################################## + +This is a guide to get a small SSL web-server up and running quickly. + +######################################################################## +# Introduction +######################################################################## +The 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 (called Anti-Web). + +The web server + SSL library is around 50-60kB and is configurable for +features or size. + +######################################################################## +# Compilation +######################################################################## + +All platforms require GNU make. This means on Win32 that Cygwin needs to be +installed with "make" and various developer options selected. + +Configuration 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). + +You should be able to compile axTLS simply by extracting it, change into +the extracted directory and typing: + +> make + +Select your platform type, save the configuration, exit, and then +type "make" again. + +If all goes well, you should end up with an executable called "awhttpd" (or +awhttpd.exe) in this directory. + +To play with all the various axTLS options, type: + +> make menuconfig + +Save the new configuration and rebuild. + +######################################################################## +# Running it +######################################################################## + +To run it, type (as superuser): + +> awhttpd + +And then point your browser at: + +https://127.0.0.1 + +And you should see a html page with a padlock appearing on your browser. + +or type: + +http://127.0.0.1 + +to see the same page unencrypted. + +See the README in the httpd directory from more configuration information on +Anti-Web. + +Note: libaxtls.so may have to in your shared library path. + +######################################################################## +# The axssl utilities +######################################################################## + +The axssl suite of tools are the SSL test tools in the various language +bindings. They are: + +axssl - C sample +axssl.csharp - C# sample +axssl.vbnet - VB.NET sample +axtls.jar - Java sample +axssl.pl - Perl sample + +All the tools have identical command-line parameters. e.g. to run something +interesting: + +> axssl s_server -verify -CAfile ssl/test/axTLS.ca_x509 + +and + +> axssl s_client -cert ssl/test/axTLS.x509_1024 -key \ + ssl/test/axTLS.key_1024 -reconnect + +C# +== +If building under Linux or other non-Win32 platforms, Mono must be installed +and the executable is run as: + +> mono axssl.csharp.exe ... + +Java +==== +The java version is run as: + +> java -jar axtls.jar + +Perl +==== +> [perl] ./axssl.pl + +If running under Win32, be sure to use the correct version of Perl (i.e. +ActiveState's version works ok). + +######################################################################## +# Known Issues +######################################################################## + +* 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). + +* Java 1.4 or better is required for the Java interfaces. + +* Processes that fork can't use session resumption unless some form of IPC is + used. + +* 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: + + export LD_LIBRARY_PATH=`perl -e 'use Config; print $Config{archlib};'`/CORE:. + +* The default Microsoft .NET SDK is v2.0.50727. Download from: + http://msdn.microsoft.com/netframework/downloads/updates/default.aspx. + +Win32 issues +============ +* 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. + +* The test harness appears to be broken under VC8.0. Debugging shows a problem + the _close() function which is weird. + +Solaris issues +============== +* mconf doesn't work well - some manual tweaking is required for string values. + +* GNU make and GNU patch are required and need to be in $PATH. + +* To get swig's library dependencies to work (and for the C library to be + found), I needed to type: + > export LD_LIBRARY_PATH=/usr/local/gcc-3.3.1/lib:. + +Cygwin issues +============= +* 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. + diff --git a/bindings/Config.in b/bindings/Config.in new file mode 100644 index 000000000..a268f8078 --- /dev/null +++ b/bindings/Config.in @@ -0,0 +1,90 @@ +# +# 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 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): + * Doesn't work under Win32 ActiveState Perl. + * 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: + I'm testing with: + "http://www.activestate.com/Products/ActivePerl" at the moment. + +config CONFIG_PERL_LIB + string "Name of Perl Library" + default "perl58.lib" +endmenu + +endmenu diff --git a/bindings/Makefile b/bindings/Makefile new file mode 100644 index 000000000..47b48befc --- /dev/null +++ b/bindings/Makefile @@ -0,0 +1,63 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +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 + +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 -noextern 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 -noextern axTLSp.i; $(MAKE) + +clean:: + $(MAKE) -C csharp clean + $(MAKE) -C vbnet clean + $(MAKE) -C java clean + $(MAKE) -C perl clean + diff --git a/bindings/README b/bindings/README new file mode 100644 index 000000000..8bc3109c1 --- /dev/null +++ b/bindings/README @@ -0,0 +1,43 @@ +=============================================================================== += 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. diff --git a/bindings/csharp/Makefile b/bindings/csharp/Makefile new file mode 100644 index 000000000..d7fbdb619 --- /dev/null +++ b/bindings/csharp/Makefile @@ -0,0 +1,23 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +include ../../config/.config +include ../../config/makefile.conf + +clean:: + @rm -f axssl* axInterface.cs diff --git a/bindings/csharp/axTLS.cs b/bindings/csharp/axTLS.cs new file mode 100644 index 000000000..4622dc553 --- /dev/null +++ b/bindings/csharp/axTLS.cs @@ -0,0 +1,466 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/** + * 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 availabile 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() + { + byte[] result = new byte[axtls.SSL_SESSION_ID_SIZE]; + IntPtr ptr = axtls.ssl_get_session_id(m_ssl); + Marshal.Copy(ptr, result, 0, axtls.SSL_SESSION_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); + } + } + + /** + * @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_NO_DEFAULT_KEY: Don't use the default key/certificate. The + * user will load the key/certificate explicitly. + * - 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 Socket 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. + * @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 Socket 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 Socket 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(); + return new SSL(axtls. ssl_client_new(m_ctx, client_fd, session_id)); + } + } +} +/** @} */ diff --git a/bindings/generate_SWIG_interface.pl b/bindings/generate_SWIG_interface.pl new file mode 100755 index 000000000..7509e17cf --- /dev/null +++ b/bindings/generate_SWIG_interface.pl @@ -0,0 +1,327 @@ +#!/usr/bin/perl + +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +#=============================================================== +# 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; + 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; + } + else + { + $line =~ s/const uint8_t \*(\w+)/const unsigned char $1\[\]/g; + $line =~ s/uint8_t/unsigned char/g; + } + } + + return $line; +} + +# Parse input file +sub parseFile +{ + foreach $line (@_) + { + # 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"; +} +else +{ +ouch: + die "Usage: $0 [-java | -perl]\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 = ; + +# Open output file +open(DATA_OUT, ">$interfaceFile") || die("Cannot Open File"); + +# +# I wish I could say it was easy to generate the Perl/Java 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 { SSLCTX * }; +%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_SESSION_ID_SIZE);\" + +/* 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); + 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((const char *)\$1, SSL_SESSION_ID_SIZE); + \$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++; + } +} + +%typemap(freearg) unsigned char *in_data { + free(buf\$argnum); +} + +/* 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 + +END + +# Initialise loop variables +$skip = 1; +$splitLine = 0; + +parseFile(@raw_data); + +close(DATA_IN); +close(DATA_OUT); + +#=============================================================== + diff --git a/bindings/generate_interface.pl b/bindings/generate_interface.pl new file mode 100755 index 000000000..a063ea2cc --- /dev/null +++ b/bindings/generate_interface.pl @@ -0,0 +1,302 @@ +#!/usr/bin/perl -w + +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +#=============================================================== +# 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/SSLCTX \* ?/IntPtr /g; + $line =~ s/SSLObjLoader \* ?/IntPtr /g; + $line =~ s/SSL \* ?/IntPtr /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 / 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/SSLCTX \*/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/const char \* ?(\w+)/ByVal $1 As String/g; + $line =~ s/SSLCTX \* ?(\w+)/ByVal $1 As IntPtr/g; + $line =~ s/SSLObjLoader \* ?(\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) + { + # 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 cammand-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 = ; + + +# 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); + +#=============================================================== + diff --git a/bindings/java/Makefile b/bindings/java/Makefile new file mode 100644 index 000000000..a81d8811f --- /dev/null +++ b/bindings/java/Makefile @@ -0,0 +1,93 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +include ../../config/.config +include ../../config/makefile.conf +include ../../config/makefile.java.conf + +all: lib jar + +JAR=../../axtls.jar + +ifdef CONFIG_PLATFORM_WIN32 +TARGET=../../axtlsj.dll +else +TARGET=../../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 + +AXOLOTLS_HOME=../.. +SSL_HOME=$(AXOLOTLS_HOME)/ssl +CONFIG_HOME=$(AXOLOTLS_HOME)/config +JAVA_CLASSES:=$(JAVA_FILES:%.java=classes/axTLSj/%.class) + +ifdef CONFIG_PLATFORM_WIN32 +CFLAGS += /I"$(shell cygpath -w $(SSL_HOME))" +CFLAGS += /I"$(shell cygpath -w $(CONFIG_HOME))" +LDFLAGS += axtls.lib /libpath:"../../" + +include ../../config/makefile.post + +$(TARGET) : $(OBJ) + $(LD) $(LDFLAGS) $(LDSHARED) /out:$@ $(OBJ) +else # Not Win32 + +ifdef CONFIG_PLATFORM_CYGWIN +SSL_HOME:=$(shell cygpath -u $(SSL_HOME)) +CONFIG_HOME:=$(shell cygpath -u $(CONFIG_HOME)) +endif + +CFLAGS += -I$(SSL_HOME) +CFLAGS += -I$(CONFIG_HOME) + +$(TARGET) : $(OBJ) + $(LD) $(LDFLAGS) -L ../../ $(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 . +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/* + diff --git a/bindings/java/SSL.java b/bindings/java/SSL.java new file mode 100644 index 000000000..9d6420630 --- /dev/null +++ b/bindings/java/SSL.java @@ -0,0 +1,125 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/* + * 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 availabile 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); + } +} diff --git a/bindings/java/SSLCTX.java b/bindings/java/SSLCTX.java new file mode 100644 index 000000000..dfd08ec95 --- /dev/null +++ b/bindings/java/SSLCTX.java @@ -0,0 +1,217 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/* + * 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_NO_DEFAULT_KEY: Don't use the default key/certificate. The user + * will load the key/certificate explicitly. + * - 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 Socket 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. + * @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); + } +} diff --git a/bindings/java/SSLClient.java b/bindings/java/SSLClient.java new file mode 100644 index 000000000..ef624d60d --- /dev/null +++ b/bindings/java/SSLClient.java @@ -0,0 +1,66 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/* + * 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 Socket 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); + return new SSL(axtlsj.ssl_client_new(m_ctx, client_fd, session_id)); + } +} diff --git a/bindings/java/SSLReadHolder.java b/bindings/java/SSLReadHolder.java new file mode 100644 index 000000000..0749ab3e8 --- /dev/null +++ b/bindings/java/SSLReadHolder.java @@ -0,0 +1,49 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/* + * 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; +} diff --git a/bindings/java/SSLServer.java b/bindings/java/SSLServer.java new file mode 100644 index 000000000..6f4cf00e8 --- /dev/null +++ b/bindings/java/SSLServer.java @@ -0,0 +1,60 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/* + * 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 Socket 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)); + } +} diff --git a/bindings/java/SSLUtil.java b/bindings/java/SSLUtil.java new file mode 100644 index 000000000..26451b20a --- /dev/null +++ b/bindings/java/SSLUtil.java @@ -0,0 +1,96 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/* + * 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); + } +} + diff --git a/bindings/perl/Makefile b/bindings/perl/Makefile new file mode 100644 index 000000000..99b6e4d24 --- /dev/null +++ b/bindings/perl/Makefile @@ -0,0 +1,81 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +include ../../config/.config +include ../../config/makefile.conf + +all: lib + +ifdef CONFIG_PLATFORM_WIN32 +TARGET=../../axtlsp.dll +else +TARGET=../../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) +AXOLOTLS_HOME=../.. +SSL_HOME=$(AXOLOTLS_HOME)/ssl +CONFIG_HOME=$(AXOLOTLS_HOME)/config +OBJ:=axTLSp_wrap.o +include ../../config/makefile.post + +ifndef CONFIG_PLATFORM_WIN32 + +# +# 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 ../../ -L$(PERL5_CORE) $(LDSHARED) -o $@ $(OBJ) -laxtls -lperl +ifdef CONFIG_PLATFORM_CYGWIN + cd ../../; ln -sf $(notdir $@) axtlsp.dll +endif + @install axtlsp.pm ../../ + +CFLAGS += -D__USE_GNU -I$(CONFIG_HOME) -I$(SSL_HOME) -I$(PERL5_CORE) +else +CFLAGS += /I"`cygpath -w $(CONFIG_HOME)`" /I"`cygpath -w $(SSL_HOME)`" +CFLAGS += /I"$(PERL5_CORE)" +LDFLAGS += $(CONFIG_PERL_LIB) /libpath:"$(PERL5_CORE)" axtls.lib /libpath:"../../" + +$(TARGET) : $(OBJ) + $(LD) $(LDFLAGS) $(LDSHARED) /out:$@ $(OBJ) + @install axtlsp.pm ../../ +endif # WIN32 + +clean:: + @rm -f $(TARGET) axtls* *.i axTLSp* *.c .depend ../../axtlsp.pm diff --git a/bindings/vbnet/Makefile b/bindings/vbnet/Makefile new file mode 100644 index 000000000..5c7a36d6a --- /dev/null +++ b/bindings/vbnet/Makefile @@ -0,0 +1,23 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +include ../../config/.config +include ../../config/makefile.conf + +clean:: + @rm -f axssl* axInterface.vb diff --git a/bindings/vbnet/axTLSvb.vb b/bindings/vbnet/axTLSvb.vb new file mode 100644 index 000000000..7f0819525 --- /dev/null +++ b/bindings/vbnet/axTLSvb.vb @@ -0,0 +1,175 @@ +' +' Copyright(C) 2006 +' +' 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.1 of the License, or +' (at your option As ) 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 Lesser 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 +' + +' +' 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 result(axtls.SSL_SESSION_ID_SIZE) As Byte + Dim ptr As IntPtr = axtls.ssl_get_session_id(m_ssl) + Marshal.Copy(ptr, result, 0, axtls.SSL_SESSION_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 + 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() + Return New SSL( axtls.ssl_client_new(m_ctx, client_fd, session_id)) + End Function + + End Class +End Namespace diff --git a/config/.config b/config/.config new file mode 100644 index 000000000..092035ebf --- /dev/null +++ b/config/.config @@ -0,0 +1,107 @@ +# +# Automatically generated make config: don't edit +# +HAVE_DOT_CONFIG=y +# CONFIG_PLATFORM_LINUX is not set +CONFIG_PLATFORM_CYGWIN=y +# CONFIG_PLATFORM_SOLARIS is not set +# CONFIG_PLATFORM_WIN32 is not set + +# +# General Configuration +# +# CONFIG_DEBUG is not set +# CONFIG_VISUAL_STUDIO_6_0 is not set +# CONFIG_VISUAL_STUDIO_7_0 is not set +# CONFIG_VISUAL_STUDIO_8_0 is not set +CONFIG_VISUAL_STUDIO_6_0_BASE="" +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 is not set +CONFIG_SSL_SKELETON_MODE=y +# CONFIG_SSL_PROT_LOW is not set +# CONFIG_SSL_PROT_MEDIUM is not set +# CONFIG_SSL_PROT_HIGH is not set +# CONFIG_SSL_USE_DEFAULT_KEY is not set +CONFIG_SSL_ENABLE_V23_HANDSHAKE=y +# CONFIG_SSL_HAS_PEM is not set +# CONFIG_SSL_USE_PKCS12 is not set +CONFIG_SSL_EXPIRY_TIME=0 +CONFIG_X509_MAX_CA_CERTS=0 +CONFIG_SSL_MAX_CERTS=2 +CONFIG_USE_DEV_URANDOM=y +# CONFIG_WIN32_USE_CRYPTO_LIB is not set +# CONFIG_PERFORMANCE_TESTING is not set +# CONFIG_SSL_TEST is not set +CONFIG_AWHTTPD=y + +# +# Awhttpd Configuration +# +# CONFIG_HTTP_STATIC_BUILD is not set +CONFIG_HTTP_HAS_SSL=y +CONFIG_HTTP_HTTPS_PORT=443 +# CONFIG_STANDARD_AWHTTPD is not set +CONFIG_HTTP_WEBROOT="www" +CONFIG_HTTP_PORT=80 +# CONFIG_HTTP_USE_TIMEOUT is not set +CONFIG_HTTP_TIMEOUT=0 +CONFIG_HTTP_INITIAL_SLOTS=10 +CONFIG_HTTP_MAX_USERS=100 +CONFIG_HTTP_HAS_CGI=y +CONFIG_HTTP_CGI_EXTENSION=".php" +CONFIG_HTTP_DIRECTORIES=y +# CONFIG_HTTP_PERM_CHECK is not set +# CONFIG_HTTP_HAS_IPV6 is not set +CONFIG_HTTP_VERBOSE=y +# CONFIG_HTTP_IS_DAEMON is not set + +# +# Language Bindings +# +CONFIG_BINDINGS=y +CONFIG_CSHARP_BINDINGS=y +CONFIG_VBNET_BINDINGS=y + +# +# .Net Framework +# +CONFIG_DOT_NET_FRAMEWORK_BASE="c:\\WINDOWS\\Microsoft.NET\\Framework\\v2.0.50727" +CONFIG_JAVA_BINDINGS=y + +# +# Java Home +# +CONFIG_JAVA_HOME="c:\\Program Files\\Java\\jdk1.5.0_06" +# CONFIG_PERL_BINDINGS is not set +CONFIG_PERL_CORE="" +CONFIG_PERL_LIB="" + +# +# Samples +# +CONFIG_SAMPLES=y +CONFIG_C_SAMPLES=y +CONFIG_CSHARP_SAMPLES=y +CONFIG_VBNET_SAMPLES=y +CONFIG_JAVA_SAMPLES=y +# CONFIG_PERL_SAMPLES is not set +# CONFIG_BIGINT_CLASSICAL is not set +# CONFIG_BIGINT_MONTGOMERY is not set +# CONFIG_BIGINT_BARRETT is not set +# CONFIG_BIGINT_CRT is not set +# CONFIG_BIGINT_KARATSUBA is not set +MUL_KARATSUBA_THRESH=0 +SQU_KARATSUBA_THRESH=0 +# CONFIG_BIGINT_SLIDING_WINDOW is not set +# CONFIG_BIGINT_SQUARE is not set +# CONFIG_BIGINT_CHECK_ON is not set diff --git a/config/.config.old b/config/.config.old new file mode 100644 index 000000000..092035ebf --- /dev/null +++ b/config/.config.old @@ -0,0 +1,107 @@ +# +# Automatically generated make config: don't edit +# +HAVE_DOT_CONFIG=y +# CONFIG_PLATFORM_LINUX is not set +CONFIG_PLATFORM_CYGWIN=y +# CONFIG_PLATFORM_SOLARIS is not set +# CONFIG_PLATFORM_WIN32 is not set + +# +# General Configuration +# +# CONFIG_DEBUG is not set +# CONFIG_VISUAL_STUDIO_6_0 is not set +# CONFIG_VISUAL_STUDIO_7_0 is not set +# CONFIG_VISUAL_STUDIO_8_0 is not set +CONFIG_VISUAL_STUDIO_6_0_BASE="" +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 is not set +CONFIG_SSL_SKELETON_MODE=y +# CONFIG_SSL_PROT_LOW is not set +# CONFIG_SSL_PROT_MEDIUM is not set +# CONFIG_SSL_PROT_HIGH is not set +# CONFIG_SSL_USE_DEFAULT_KEY is not set +CONFIG_SSL_ENABLE_V23_HANDSHAKE=y +# CONFIG_SSL_HAS_PEM is not set +# CONFIG_SSL_USE_PKCS12 is not set +CONFIG_SSL_EXPIRY_TIME=0 +CONFIG_X509_MAX_CA_CERTS=0 +CONFIG_SSL_MAX_CERTS=2 +CONFIG_USE_DEV_URANDOM=y +# CONFIG_WIN32_USE_CRYPTO_LIB is not set +# CONFIG_PERFORMANCE_TESTING is not set +# CONFIG_SSL_TEST is not set +CONFIG_AWHTTPD=y + +# +# Awhttpd Configuration +# +# CONFIG_HTTP_STATIC_BUILD is not set +CONFIG_HTTP_HAS_SSL=y +CONFIG_HTTP_HTTPS_PORT=443 +# CONFIG_STANDARD_AWHTTPD is not set +CONFIG_HTTP_WEBROOT="www" +CONFIG_HTTP_PORT=80 +# CONFIG_HTTP_USE_TIMEOUT is not set +CONFIG_HTTP_TIMEOUT=0 +CONFIG_HTTP_INITIAL_SLOTS=10 +CONFIG_HTTP_MAX_USERS=100 +CONFIG_HTTP_HAS_CGI=y +CONFIG_HTTP_CGI_EXTENSION=".php" +CONFIG_HTTP_DIRECTORIES=y +# CONFIG_HTTP_PERM_CHECK is not set +# CONFIG_HTTP_HAS_IPV6 is not set +CONFIG_HTTP_VERBOSE=y +# CONFIG_HTTP_IS_DAEMON is not set + +# +# Language Bindings +# +CONFIG_BINDINGS=y +CONFIG_CSHARP_BINDINGS=y +CONFIG_VBNET_BINDINGS=y + +# +# .Net Framework +# +CONFIG_DOT_NET_FRAMEWORK_BASE="c:\\WINDOWS\\Microsoft.NET\\Framework\\v2.0.50727" +CONFIG_JAVA_BINDINGS=y + +# +# Java Home +# +CONFIG_JAVA_HOME="c:\\Program Files\\Java\\jdk1.5.0_06" +# CONFIG_PERL_BINDINGS is not set +CONFIG_PERL_CORE="" +CONFIG_PERL_LIB="" + +# +# Samples +# +CONFIG_SAMPLES=y +CONFIG_C_SAMPLES=y +CONFIG_CSHARP_SAMPLES=y +CONFIG_VBNET_SAMPLES=y +CONFIG_JAVA_SAMPLES=y +# CONFIG_PERL_SAMPLES is not set +# CONFIG_BIGINT_CLASSICAL is not set +# CONFIG_BIGINT_MONTGOMERY is not set +# CONFIG_BIGINT_BARRETT is not set +# CONFIG_BIGINT_CRT is not set +# CONFIG_BIGINT_KARATSUBA is not set +MUL_KARATSUBA_THRESH=0 +SQU_KARATSUBA_THRESH=0 +# CONFIG_BIGINT_SLIDING_WINDOW is not set +# CONFIG_BIGINT_SQUARE is not set +# CONFIG_BIGINT_CHECK_ON is not set diff --git a/config/.config.tmp b/config/.config.tmp new file mode 100644 index 000000000..eae93ecac --- /dev/null +++ b/config/.config.tmp @@ -0,0 +1,11 @@ +deps_config := \ + ssl/BigIntConfig.in \ + samples/Config.in \ + bindings/Config.in \ + httpd/Config.in \ + ssl/Config.in \ + config/Config.in + +.config include/config.h: $(deps_config) + +$(deps_config): diff --git a/config/Config.in b/config/Config.in new file mode 100644 index 000000000..fea9c0a6d --- /dev/null +++ b/config/Config.in @@ -0,0 +1,112 @@ +# +# 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_SOLARIS + bool "Solaris" + +config CONFIG_PLATFORM_WIN32 + bool "Win32" + +endchoice + +menu "General Configuration" + +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. + +menu "Microsoft Compiler Options" +depends on CONFIG_PLATFORM_WIN32 + +choice + prompt "Compiler" + depends on CONFIG_PLATFORM_WIN32 + default CONFIG_VISUAL_STUDIO_8_0 + +config CONFIG_VISUAL_STUDIO_6_0 + bool "Visual Studio 6.0 (VC98)" + help + Use Microsoft's Visual Studio 6.0 platform. + +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_6_0_BASE + string "Base" + depends on CONFIG_VISUAL_STUDIO_6_0 + default "c:\\Program Files\\Microsoft Visual Studio" + +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_AWHTTPD + bool "Enable HTTP/HTTPS Web Server" + default y + help + Build the AWHTTPD web server + +source httpd/Config.in +source bindings/Config.in +source samples/Config.in +source ssl/BigIntConfig.in diff --git a/config/Rules.mak b/config/Rules.mak new file mode 100644 index 000000000..c0308da05 --- /dev/null +++ b/config/Rules.mak @@ -0,0 +1,220 @@ +# Rules.make for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# 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 . + + +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 diff --git a/config/awhttpd.aip b/config/awhttpd.aip new file mode 100755 index 000000000..3b68600ab --- /dev/null +++ b/config/awhttpd.aip @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/awhttpd.back.aip b/config/awhttpd.back.aip new file mode 100644 index 000000000..7c754f1db --- /dev/null +++ b/config/awhttpd.back.aip @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/awhttpd.msi b/config/awhttpd.msi new file mode 100755 index 000000000..278f10466 Binary files /dev/null and b/config/awhttpd.msi differ diff --git a/config/axtls.RES b/config/axtls.RES new file mode 100644 index 000000000..2929b3b67 Binary files /dev/null and b/config/axtls.RES differ diff --git a/config/axtls.rc b/config/axtls.rc new file mode 100644 index 000000000..0f288aa91 --- /dev/null +++ b/config/axtls.rc @@ -0,0 +1,32 @@ +//Microsoft Visual C++ generated resource script. +// +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#undef APSTUDIO_HIDDEN_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE 9, 1 +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. + +IDI_AXTLS ICON "../www/favicon.ico" + + +#endif +///////////////////////////////////////////////////////////////////////////// + + + diff --git a/config/config.h b/config/config.h new file mode 100644 index 000000000..785747831 --- /dev/null +++ b/config/config.h @@ -0,0 +1,108 @@ +/* + * Automatically generated header file: don't edit + */ + +#define HAVE_DOT_CONFIG 1 +#undef CONFIG_PLATFORM_LINUX +#define CONFIG_PLATFORM_CYGWIN 1 +#undef CONFIG_PLATFORM_SOLARIS +#undef CONFIG_PLATFORM_WIN32 + +/* + * General Configuration + */ +#undef CONFIG_DEBUG +#undef CONFIG_VISUAL_STUDIO_6_0 +#undef CONFIG_VISUAL_STUDIO_7_0 +#undef CONFIG_VISUAL_STUDIO_8_0 +#define CONFIG_VISUAL_STUDIO_6_0_BASE "" +#define CONFIG_VISUAL_STUDIO_7_0_BASE "" +#define CONFIG_VISUAL_STUDIO_8_0_BASE "" +#define CONFIG_EXTRA_CFLAGS_OPTIONS "" +#define CONFIG_EXTRA_LDFLAGS_OPTIONS "" + +/* + * SSL Library + */ +#undef CONFIG_SSL_SERVER_ONLY +#undef CONFIG_SSL_CERT_VERIFICATION +#undef CONFIG_SSL_ENABLE_CLIENT +#undef CONFIG_SSL_FULL_MODE +#define CONFIG_SSL_SKELETON_MODE 1 +#undef CONFIG_SSL_PROT_LOW +#undef CONFIG_SSL_PROT_MEDIUM +#undef CONFIG_SSL_PROT_HIGH +#undef CONFIG_SSL_USE_DEFAULT_KEY +#define CONFIG_SSL_ENABLE_V23_HANDSHAKE 1 +#undef CONFIG_SSL_HAS_PEM +#undef CONFIG_SSL_USE_PKCS12 +#define CONFIG_SSL_EXPIRY_TIME +#define CONFIG_X509_MAX_CA_CERTS +#define CONFIG_SSL_MAX_CERTS 2 +#define CONFIG_USE_DEV_URANDOM 1 +#undef CONFIG_WIN32_USE_CRYPTO_LIB +#undef CONFIG_PERFORMANCE_TESTING +#undef CONFIG_SSL_TEST +#define CONFIG_AWHTTPD 1 + +/* + * Awhttpd Configuration + */ +#undef CONFIG_HTTP_STATIC_BUILD +#define CONFIG_HTTP_HAS_SSL 1 +#define CONFIG_HTTP_HTTPS_PORT 443 +#undef CONFIG_STANDARD_AWHTTPD +#define CONFIG_HTTP_WEBROOT "www" +#define CONFIG_HTTP_PORT 80 +#undef CONFIG_HTTP_USE_TIMEOUT +#define CONFIG_HTTP_TIMEOUT +#define CONFIG_HTTP_INITIAL_SLOTS 10 +#define CONFIG_HTTP_MAX_USERS 100 +#define CONFIG_HTTP_HAS_CGI 1 +#define CONFIG_HTTP_CGI_EXTENSION ".php" +#define CONFIG_HTTP_DIRECTORIES 1 +#undef CONFIG_HTTP_PERM_CHECK +#undef CONFIG_HTTP_HAS_IPV6 +#define CONFIG_HTTP_VERBOSE 1 +#undef CONFIG_HTTP_IS_DAEMON + +/* + * Language Bindings + */ +#define CONFIG_BINDINGS 1 +#define CONFIG_CSHARP_BINDINGS 1 +#define CONFIG_VBNET_BINDINGS 1 + +/* + * .Net Framework + */ +#define CONFIG_DOT_NET_FRAMEWORK_BASE "c:\\WINDOWS\\Microsoft.NET\\Framework\\v2.0.50727" +#define CONFIG_JAVA_BINDINGS 1 + +/* + * Java Home + */ +#define CONFIG_JAVA_HOME "c:\\Program Files\\Java\\jdk1.5.0_06" +#undef CONFIG_PERL_BINDINGS +#define CONFIG_PERL_CORE "" +#define CONFIG_PERL_LIB "" + +/* + * Samples + */ +#define CONFIG_SAMPLES 1 +#define CONFIG_C_SAMPLES 1 +#define CONFIG_CSHARP_SAMPLES 1 +#define CONFIG_VBNET_SAMPLES 1 +#define CONFIG_JAVA_SAMPLES 1 +#undef CONFIG_PERL_SAMPLES +#undef CONFIG_BIGINT_CLASSICAL +#undef CONFIG_BIGINT_MONTGOMERY +#undef CONFIG_BIGINT_BARRETT +#undef CONFIG_BIGINT_CRT +#undef CONFIG_BIGINT_KARATSUBA +#define MUL_KARATSUBA_THRESH +#define SQU_KARATSUBA_THRESH +#undef CONFIG_BIGINT_SLIDING_WINDOW +#undef CONFIG_BIGINT_SQUARE +#undef CONFIG_BIGINT_CHECK_ON diff --git a/config/makefile.conf b/config/makefile.conf new file mode 100644 index 000000000..744234c4c --- /dev/null +++ b/config/makefile.conf @@ -0,0 +1,113 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# +# A standard makefile for all makefiles +# + +ifneq ($(MAKECMDGOALS), clean) + +# Give an initial rule +all: + +# Win32 +ifdef CONFIG_PLATFORM_WIN32 + +ifdef CONFIG_VISUAL_STUDIO_6_0 +CONFIG_VISUAL_STUDIO_6_0_BASE:=$(shell cygpath -w $(CONFIG_VISUAL_STUDIO_6_0_BASE)) +CONFIG_VISUAL_STUDIO_6_0_BASE_UNIX:=$(shell cygpath -u $(CONFIG_VISUAL_STUDIO_6_0_BASE)) +export INCLUDE=$(CONFIG_VISUAL_STUDIO_6_0_BASE)\vc98\Include +export LIB=$(CONFIG_VISUAL_STUDIO_6_0_BASE)\vc98\Lib +PATH:=$(CONFIG_VISUAL_STUDIO_6_0_BASE_UNIX)/common/msdev98/bin:$(CONFIG_VISUAL_STUDIO_6_0_BASE_UNIX)/vc98/bin:$(PATH) +else +ifdef CONFIG_VISUAL_STUDIO_7_0 +CONFIG_VISUAL_STUDIO_7_0_BASE:=$(shell cygpath -w $(CONFIG_VISUAL_STUDIO_7_0_BASE)) +CONFIG_VISUAL_STUDIO_7_0_BASE_UNIX:=$(shell cygpath -u $(CONFIG_VISUAL_STUDIO_7_0_BASE)) +export INCLUDE=$(CONFIG_VISUAL_STUDIO_7_0_BASE)\vc7\include;$(CONFIG_VISUAL_STUDIO_7_0_BASE)\vc7\platformsdk\include +export LIB=$(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:=$(shell cygpath -w $(CONFIG_VISUAL_STUDIO_8_0_BASE)) +CONFIG_VISUAL_STUDIO_8_0_BASE_UNIX:=$(shell cygpath -u $(CONFIG_VISUAL_STUDIO_8_0_BASE)) +export INCLUDE=$(CONFIG_VISUAL_STUDIO_8_0_BASE)\vc\include;$(CONFIG_VISUAL_STUDIO_8_0_BASE)\vc\platformsdk\include +export LIB=$(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) +endif +endif +endif + +CC=cl.exe +LD=link.exe +CFLAGS+=/nologo /W3 /D "WIN32" /D "_MBCS" /D "_CONSOLE" /FD /I"..\ssl" /I"..\config" /D "_CRT_SECURE_NO_DEPRECATE" /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../config +LD=$(CC) + +# Solaris +ifdef CONFIG_PLATFORM_SOLARIS +CFLAGS += -DSOLARIS +LDFLAGS += -lsocket -lnsl -lc +LDSHARED = -G +# Linux/Cygwin +else # Linux +CFLAGS += -Wall -Wstrict-prototypes -Wshadow +LDSHARED = -shared +ifndef CONFIG_PLATFORM_CYGWIN +CFLAGS += -fPIC +else +CFLAGS += -DCYGWIN +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* + diff --git a/config/makefile.dotnet.conf b/config/makefile.dotnet.conf new file mode 100644 index 000000000..7589550c7 --- /dev/null +++ b/config/makefile.dotnet.conf @@ -0,0 +1,53 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +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' diff --git a/config/makefile.java.conf b/config/makefile.java.conf new file mode 100644 index 000000000..1ecce1194 --- /dev/null +++ b/config/makefile.java.conf @@ -0,0 +1,56 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +ifneq ($(MAKECMDGOALS), clean) + +all: test_jdk_location + +test_jdk_location: + @if ! [ -d "$(CONFIG_JAVA_HOME)" ]; then \ + echo "*** Error: JDK path of $(CONFIG_JAVA_HOME) doesn't exist" && exit 1; \ + fi + + +ifdef CONFIG_PLATFORM_CYGWIN +CONFIG_JAVA_HOME:=$(shell cygpath -u $(CONFIG_JAVA_HOME)) +CFLAGS += -I"$(CONFIG_JAVA_HOME)/include" +CFLAGS += -I"$(CONFIG_JAVA_HOME)/include/win32" +JAVA_BIN:=$(CONFIG_JAVA_HOME)/bin +else + +ifdef CONFIG_PLATFORM_WIN32 +CONFIG_JAVA_HOME:=$(shell cygpath -w $(CONFIG_JAVA_HOME)) +CFLAGS += /I"$(CONFIG_JAVA_HOME)\include" +CFLAGS += /I"$(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' diff --git a/config/makefile.post b/config/makefile.post new file mode 100644 index 000000000..033981c4d --- /dev/null +++ b/config/makefile.post @@ -0,0 +1,19 @@ + +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 diff --git a/config/scripts/config/Kconfig-language.txt b/config/scripts/config/Kconfig-language.txt new file mode 100644 index 000000000..493749b32 --- /dev/null +++ b/config/scripts/config/Kconfig-language.txt @@ -0,0 +1,255 @@ +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" ["if" ] + 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" ["if" ] + 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" + 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: + + ::= (1) + '=' (2) + '!=' (3) + '(' ')' (4) + '!' (5) + '||' (6) + '&&' (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" + + +This defines a config symbol and accepts any of above +attributes as options. + +choices: + + "choice" + + + "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" + + +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" + + + "endmenu" + +This defines a menu block, see "Menu structure" above for more +information. The only possible options are dependencies. + +if: + + "if" + + "endif" + +This defines an if block. The dependency expression is appended +to all enclosed menu entries. + +source: + + "source" + +This reads the specified configuration file. This file is always parsed. diff --git a/config/scripts/config/Makefile b/config/scripts/config/Makefile new file mode 100644 index 000000000..739950163 --- /dev/null +++ b/config/scripts/config/Makefile @@ -0,0 +1,121 @@ +# Makefile for axTLS +# +# Copyright (C) 2002 Erik Andersen + +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="" +else +ifeq (/usr/include/ncurses/curses.h, $(wildcard /usr/include/ncurses/curses.h)) + HOSTNCURSES += -I/usr/include/ncurses -DCURSES_LOC="" +else +ifeq (/usr/local/include/ncurses/ncurses.h, $(wildcard /usr/local/include/ncurses/ncurses.h)) + HOSTCFLAGS += -I/usr/local/include/ncurses -DCURSES_LOC="" +else +ifeq (/usr/local/include/ncurses/curses.h, $(wildcard /usr/local/include/ncurses/curses.h)) + HOSTCFLAGS += -I/usr/local/include/ncurses -DCURSES_LOC="" +else +ifeq (/usr/include/ncurses.h, $(wildcard /usr/include/ncurses.h)) + HOSTNCURSES += -DCURSES_LOC="" +else + HOSTNCURSES += -DCURSES_LOC="" +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 + diff --git a/config/scripts/config/a.exe b/config/scripts/config/a.exe new file mode 100755 index 000000000..57824a986 Binary files /dev/null and b/config/scripts/config/a.exe differ diff --git a/config/scripts/config/conf.c b/config/scripts/config/conf.c new file mode 100644 index 000000000..15244678e --- /dev/null +++ b/config/scripts/config/conf.c @@ -0,0 +1,583 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/config/scripts/config/conf.exe b/config/scripts/config/conf.exe new file mode 100755 index 000000000..43dc07c0a Binary files /dev/null and b/config/scripts/config/conf.exe differ diff --git a/config/scripts/config/confdata.c b/config/scripts/config/confdata.c new file mode 100644 index 000000000..a59e24550 --- /dev/null +++ b/config/scripts/config/confdata.c @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/config/scripts/config/expr.c b/config/scripts/config/expr.c new file mode 100644 index 000000000..30e4f9d69 --- /dev/null +++ b/config/scripts/config/expr.c @@ -0,0 +1,1099 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include + +#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, ""); + 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, "", 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); +} diff --git a/config/scripts/config/expr.h b/config/scripts/config/expr.h new file mode 100644 index 000000000..7d39ff43e --- /dev/null +++ b/config/scripts/config/expr.h @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef EXPR_H +#define EXPR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifndef __cplusplus +#include +#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 */ diff --git a/config/scripts/config/lex.zconf.c b/config/scripts/config/lex.zconf.c new file mode 100644 index 000000000..b877bb6b3 --- /dev/null +++ b/config/scripts/config/lex.zconf.c @@ -0,0 +1,3688 @@ + +#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 +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +#include +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 + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#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 + +#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 ""; +} + diff --git a/config/scripts/config/lex.zconf.c_shipped b/config/scripts/config/lex.zconf.c_shipped new file mode 100644 index 000000000..b877bb6b3 --- /dev/null +++ b/config/scripts/config/lex.zconf.c_shipped @@ -0,0 +1,3688 @@ + +#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 +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +#include +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 + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#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 + +#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 ""; +} + diff --git a/config/scripts/config/lkc.h b/config/scripts/config/lkc.h new file mode 100644 index 000000000..b8a67fc9d --- /dev/null +++ b/config/scripts/config/lkc.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2002 Roman Zippel + * 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 */ diff --git a/config/scripts/config/lkc_defs.h b/config/scripts/config/lkc_defs.h new file mode 100644 index 000000000..65240dd9f --- /dev/null +++ b/config/scripts/config/lkc_defs.h @@ -0,0 +1,40 @@ + +/* confdata.c */ +#define conf_parse (*conf_parse_p) +#define conf_read (*conf_read_p) +#define conf_write (*conf_write_p) + +/* menu.c */ +#define rootmenu (*rootmenu_p) + +#define menu_is_visible (*menu_is_visible_p) +#define menu_get_prompt (*menu_get_prompt_p) +#define menu_get_root_menu (*menu_get_root_menu_p) +#define menu_get_parent_menu (*menu_get_parent_menu_p) + +/* symbol.c */ +#define symbol_hash (*symbol_hash_p) +#define sym_change_count (*sym_change_count_p) + +#define sym_lookup (*sym_lookup_p) +#define sym_find (*sym_find_p) +#define sym_re_search (*sym_re_search_p) +#define sym_type_name (*sym_type_name_p) +#define sym_calc_value (*sym_calc_value_p) +#define sym_get_type (*sym_get_type_p) +#define sym_tristate_within_range (*sym_tristate_within_range_p) +#define sym_set_tristate_value (*sym_set_tristate_value_p) +#define sym_toggle_tristate_value (*sym_toggle_tristate_value_p) +#define sym_string_valid (*sym_string_valid_p) +#define sym_string_within_range (*sym_string_within_range_p) +#define sym_set_string_value (*sym_set_string_value_p) +#define sym_is_changable (*sym_is_changable_p) +#define sym_get_choice_prop (*sym_get_choice_prop_p) +#define sym_get_default_prop (*sym_get_default_prop_p) +#define sym_get_string_value (*sym_get_string_value_p) + +#define prop_get_type_name (*prop_get_type_name_p) + +/* expr.c */ +#define expr_compare_type (*expr_compare_type_p) +#define expr_print (*expr_print_p) diff --git a/config/scripts/config/lkc_proto.h b/config/scripts/config/lkc_proto.h new file mode 100644 index 000000000..6dc6d0c48 --- /dev/null +++ b/config/scripts/config/lkc_proto.h @@ -0,0 +1,40 @@ + +/* 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)); diff --git a/config/scripts/config/lxdialog/BIG.FAT.WARNING b/config/scripts/config/lxdialog/BIG.FAT.WARNING new file mode 100644 index 000000000..a8999d82b --- /dev/null +++ b/config/scripts/config/lxdialog/BIG.FAT.WARNING @@ -0,0 +1,4 @@ +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. diff --git a/config/scripts/config/lxdialog/checklist.c b/config/scripts/config/lxdialog/checklist.c new file mode 100644 index 000000000..71de4a191 --- /dev/null +++ b/config/scripts/config/lxdialog/checklist.c @@ -0,0 +1,372 @@ +/* + * 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 */ +} diff --git a/config/scripts/config/lxdialog/colors.h b/config/scripts/config/lxdialog/colors.h new file mode 100644 index 000000000..d34dd37c6 --- /dev/null +++ b/config/scripts/config/lxdialog/colors.h @@ -0,0 +1,161 @@ +/* + * 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]; diff --git a/config/scripts/config/lxdialog/dialog.h b/config/scripts/config/lxdialog/dialog.h new file mode 100644 index 000000000..7bab3ad0e --- /dev/null +++ b/config/scripts/config/lxdialog/dialog.h @@ -0,0 +1,199 @@ + +/* + * 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 +#include +#include +#include +#include +#include + +#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 diff --git a/config/scripts/config/lxdialog/inputbox.c b/config/scripts/config/lxdialog/inputbox.c new file mode 100644 index 000000000..fa7bebc69 --- /dev/null +++ b/config/scripts/config/lxdialog/inputbox.c @@ -0,0 +1,240 @@ +/* + * 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 */ +} diff --git a/config/scripts/config/lxdialog/menubox.c b/config/scripts/config/lxdialog/menubox.c new file mode 100644 index 000000000..873dc587b --- /dev/null +++ b/config/scripts/config/lxdialog/menubox.c @@ -0,0 +1,438 @@ +/* + * 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 */ +} diff --git a/config/scripts/config/lxdialog/msgbox.c b/config/scripts/config/lxdialog/msgbox.c new file mode 100644 index 000000000..93692e1fb --- /dev/null +++ b/config/scripts/config/lxdialog/msgbox.c @@ -0,0 +1,85 @@ +/* + * 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; +} diff --git a/config/scripts/config/lxdialog/textbox.c b/config/scripts/config/lxdialog/textbox.c new file mode 100644 index 000000000..a5a460b5c --- /dev/null +++ b/config/scripts/config/lxdialog/textbox.c @@ -0,0 +1,556 @@ +/* + * 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); +} diff --git a/config/scripts/config/lxdialog/util.c b/config/scripts/config/lxdialog/util.c new file mode 100644 index 000000000..6f83951b9 --- /dev/null +++ b/config/scripts/config/lxdialog/util.c @@ -0,0 +1,375 @@ +/* + * 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 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; +} diff --git a/config/scripts/config/lxdialog/yesno.c b/config/scripts/config/lxdialog/yesno.c new file mode 100644 index 000000000..11fcc25f5 --- /dev/null +++ b/config/scripts/config/lxdialog/yesno.c @@ -0,0 +1,118 @@ +/* + * 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 */ +} diff --git a/config/scripts/config/mconf.c b/config/scripts/config/mconf.c new file mode 100644 index 000000000..406eb29c3 --- /dev/null +++ b/config/scripts/config/mconf.c @@ -0,0 +1,977 @@ +/* + * Copyright (C) 2002 Roman Zippel + * 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 + * + * Directly use liblxdialog library routines. + * 2002-11-14 Petr Baudis + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 to build it in or to removed it.\n" +"You may also press the 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 .\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 and keys to scroll\n" +" unseen options into view.\n" +"\n" +"o To exit a menu use the cursor keys to highlight the button\n" +" and press .\n" +"\n" +" Shortcut: Press or or if there is no hotkey\n" +" using those letters. You may press a single , but\n" +" there is a delayed response which you may find annoying.\n" +"\n" +" Also, the and cursor keys will cycle between and\n" +" \n" +"\n" +"\n" +"Data Entry\n" +"-----------\n" +"o Enter the requested information and press \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 or cursor keys to highlight the help option\n" +" and press . You can try 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 and for those\n" +" who are familiar with less and lynx.\n" +"\n" +"o Press , , or 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" +" 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. " + " selects submenus --->. " + "Highlighted letters are hotkeys. " + "Pressing selectes a feature, while will exclude a feature. " + "Press 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 . " + "Press for additional information about this option.", +inputbox_instructions_int[] = + "Please enter a decimal value. " + "Fractions will not be accepted. " + "Use the key to move from the input field to the buttons below it.", +inputbox_instructions_hex[] = + "Please enter a hexadecimal value. " + "Use the key to move from the input field to the buttons below it.", +inputbox_instructions_string[] = + "Please enter a string value. " + "Use the 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 ( [=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 : "", + 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; +} diff --git a/config/scripts/config/mconf.exe b/config/scripts/config/mconf.exe new file mode 100755 index 000000000..cb7ff192a Binary files /dev/null and b/config/scripts/config/mconf.exe differ diff --git a/config/scripts/config/menu.c b/config/scripts/config/menu.c new file mode 100644 index 000000000..0c13156f3 --- /dev/null +++ b/config/scripts/config/menu.c @@ -0,0 +1,390 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include + +#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 : "", + 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; +} + diff --git a/config/scripts/config/mkconfigs b/config/scripts/config/mkconfigs new file mode 100755 index 000000000..3cb7bb175 --- /dev/null +++ b/config/scripts/config/mkconfigs @@ -0,0 +1,67 @@ +#!/bin/sh +# +# Copyright (C) 2002 Khalid Aziz +# Copyright (C) 2002 Randy Dunlap +# Copyright (C) 2002 Al Stone +# 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 */" diff --git a/config/scripts/config/symbol.c b/config/scripts/config/symbol.c new file mode 100644 index 000000000..ea629728a --- /dev/null +++ b/config/scripts/config/symbol.c @@ -0,0 +1,809 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#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"; +} diff --git a/config/scripts/config/util.c b/config/scripts/config/util.c new file mode 100644 index 000000000..8fc95a2a7 --- /dev/null +++ b/config/scripts/config/util.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2002-2005 Roman Zippel + * Copyright (C) 2002-2005 Sam Ravnborg + * + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#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; +} + diff --git a/config/scripts/config/zconf.l b/config/scripts/config/zconf.l new file mode 100644 index 000000000..55517b287 --- /dev/null +++ b/config/scripts/config/zconf.l @@ -0,0 +1,366 @@ +%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 + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#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); +} + + +{ + "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); +} + +{ + "&&" 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++; + . + <> { + BEGIN(INITIAL); + } +} + +{ + [^'"\\\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; + } + <> { + BEGIN(INITIAL); + } +} + +{ + [ \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; + } + <> { + zconf_endhelp(); + return T_HELPTEXT; + } +} + +<> { + 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 ""; +} diff --git a/config/scripts/config/zconf.tab.c b/config/scripts/config/zconf.tab.c new file mode 100644 index 000000000..cc68dcb9a --- /dev/null +++ b/config/scripts/config/zconf.tab.c @@ -0,0 +1,2130 @@ +/* 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 + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#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 /* 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 /* 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 /* 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 + + + +#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 */ + + + +#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; + } +} + + +/* 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. */ + + + 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 ""; +} + +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" + + diff --git a/config/scripts/config/zconf.tab.c_shipped b/config/scripts/config/zconf.tab.c_shipped new file mode 100644 index 000000000..cc68dcb9a --- /dev/null +++ b/config/scripts/config/zconf.tab.c_shipped @@ -0,0 +1,2130 @@ +/* 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 + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#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 /* 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 /* 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 /* 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 + + + +#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 */ + + + +#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; + } +} + + +/* 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. */ + + + 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 ""; +} + +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" + + diff --git a/config/scripts/config/zconf.tab.h b/config/scripts/config/zconf.tab.h new file mode 100644 index 000000000..3b191ef59 --- /dev/null +++ b/config/scripts/config/zconf.tab.h @@ -0,0 +1,125 @@ +/* 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 */ + diff --git a/config/scripts/config/zconf.tab.h_shipped b/config/scripts/config/zconf.tab.h_shipped new file mode 100644 index 000000000..3b191ef59 --- /dev/null +++ b/config/scripts/config/zconf.tab.h_shipped @@ -0,0 +1,125 @@ +/* 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 */ + diff --git a/config/scripts/config/zconf.y b/config/scripts/config/zconf.y new file mode 100644 index 000000000..cf45da0b2 --- /dev/null +++ b/config/scripts/config/zconf.y @@ -0,0 +1,690 @@ +%{ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#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 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 T_WORD +%token 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 prompt +%type source +%type symbol +%type expr +%type if_expr +%type 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 ""; +} + +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" diff --git a/config/win32config b/config/win32config new file mode 100644 index 000000000..574081492 --- /dev/null +++ b/config/win32config @@ -0,0 +1,115 @@ +# +# 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 +# +# CONFIG_DEBUG is not set + +# +# Microsoft Compiler Options +# +# CONFIG_VISUAL_STUDIO_6_0 is not set +# CONFIG_VISUAL_STUDIO_7_0 is not set +CONFIG_VISUAL_STUDIO_8_0=y +CONFIG_VISUAL_STUDIO_6_0_BASE="" +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_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_USE_DEV_URANDOM is not set +CONFIG_WIN32_USE_CRYPTO_LIB=y +# CONFIG_PERFORMANCE_TESTING is not set +# CONFIG_SSL_TEST is not set +CONFIG_AWHTTPD=y + +# +# Awhttpd Configuration +# +# CONFIG_HTTP_STATIC_BUILD is not set +CONFIG_HTTP_HAS_SSL=y +CONFIG_HTTP_HTTPS_PORT=443 +# CONFIG_STANDARD_AWHTTPD is not set +CONFIG_HTTP_WEBROOT="www" +CONFIG_HTTP_PORT=80 +# CONFIG_HTTP_USE_TIMEOUT is not set +CONFIG_HTTP_TIMEOUT=0 +CONFIG_HTTP_INITIAL_SLOTS=10 +CONFIG_HTTP_MAX_USERS=100 +# CONFIG_HTTP_HAS_CGI is not set +CONFIG_HTTP_CGI_EXTENSION="" +# CONFIG_HTTP_DIRECTORIES is not set +# CONFIG_HTTP_PERM_CHECK is not set +# CONFIG_HTTP_HAS_IPV6 is not set +CONFIG_HTTP_VERBOSE=y +# CONFIG_HTTP_IS_DAEMON is not set + +# +# Language Bindings +# +CONFIG_BINDINGS=y +CONFIG_CSHARP_BINDINGS=y +CONFIG_VBNET_BINDINGS=y + +# +# .Net Framework +# +CONFIG_DOT_NET_FRAMEWORK_BASE="c:\\WINDOWS\\Microsoft.NET\\Framework\\v2.0.50727" +CONFIG_JAVA_BINDINGS=y + +# +# Java Home +# +CONFIG_JAVA_HOME="c:\\Program Files\\Java\\jdk1.5.0_06" +# CONFIG_PERL_BINDINGS is not set +CONFIG_PERL_CORE="" +CONFIG_PERL_LIB="" + +# +# Samples +# +CONFIG_SAMPLES=y +CONFIG_C_SAMPLES=y +CONFIG_CSHARP_SAMPLES=y +CONFIG_VBNET_SAMPLES=y +CONFIG_JAVA_SAMPLES=y +# CONFIG_PERL_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 diff --git a/docsrc/Makefile b/docsrc/Makefile new file mode 100644 index 000000000..574d5ebda --- /dev/null +++ b/docsrc/Makefile @@ -0,0 +1,27 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +include ../config/makefile.conf + +all: + +doco: + doxygen ./axTLS.dox + +clean:: + @-rm -fr html *~ diff --git a/docsrc/axTLS.dox b/docsrc/axTLS.dox new file mode 100644 index 000000000..e4763d6f3 --- /dev/null +++ b/docsrc/axTLS.dox @@ -0,0 +1,1237 @@ +# Doxyfile 1.4.5 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = axTLS + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = NO + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is YES. + +SHOW_DIRECTORIES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +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 ../ssl/bigint.c ../ssl/bigint.h + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = images + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = doco_footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = YES + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = YES + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = CONFIG_SSL_CERT_VERIFICATION CONFIG_SSL_ENABLE_CLIENT CONFIG_SSL_MAX_CLNT_SESSIONS=1 CONFIG_BIGINT_MONTGOMERY CONFIG_BIGINT_BARRETT EXP_FUNC="" STDCALL="" + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = NO + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = NO + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = NO + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = NO + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = NO + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = NO + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = NO + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/docsrc/doco_footer.html b/docsrc/doco_footer.html new file mode 100644 index 000000000..84c2b81e5 --- /dev/null +++ b/docsrc/doco_footer.html @@ -0,0 +1,3 @@ +

+

+Copyright © 2006 diff --git a/docsrc/images/axolotl.jpg b/docsrc/images/axolotl.jpg new file mode 100644 index 000000000..7352bbae8 Binary files /dev/null and b/docsrc/images/axolotl.jpg differ diff --git a/docsrc/images/tsbasbw.gif b/docsrc/images/tsbasbw.gif new file mode 100644 index 000000000..cf03b121b Binary files /dev/null and b/docsrc/images/tsbasbw.gif differ diff --git a/httpd/Config.in b/httpd/Config.in new file mode 100644 index 000000000..6b450f2be --- /dev/null +++ b/httpd/Config.in @@ -0,0 +1,141 @@ +# +# For a description of the syntax of this configuration file, +# see scripts/config/Kconfig-language.txt +# + +menu "Awhttpd Configuration" +depends on CONFIG_AWHTTPD + +config CONFIG_HTTP_STATIC_BUILD + bool "Static Build" + default n + help + Select y if you want awhttp to be a static build (i.e. don't use the + axtls shared library or dll). + +config CONFIG_HTTP_HAS_SSL + bool "Use SSL" + default y + help + Build the HTTP server with SSL capability + +config CONFIG_HTTP_HTTPS_PORT + int "HTTPS port" + default 443 + depends on CONFIG_HTTP_HAS_SSL + help + The port number of the HTTPS server. + + You must be a root user in order to use the default port. + +config CONFIG_STANDARD_AWHTTPD + bool "Use Standard AWHTTPD Configuration" + default n + help + Use the configuration file that awhttpd normally uses. + +config CONFIG_HTTP_WEBROOT + string "Web root location" + default "www" + depends on !CONFIG_STANDARD_AWHTTPD + help + The location of the web root. This is the directory where + index.html lives. + +config CONFIG_HTTP_PORT + int "HTTP port" + default 80 + depends on !CONFIG_STANDARD_AWHTTPD + 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_USE_TIMEOUT + bool "Use Timeout" + default n + depends on !CONFIG_STANDARD_AWHTTPD + help + Enable timeouts to be used. + +config CONFIG_HTTP_TIMEOUT + int "Timeout" + default 5 + depends on CONFIG_HTTP_USE_TIMEOUT + help + Set the timeout in seconds. + +config CONFIG_HTTP_INITIAL_SLOTS + int "Initial Slots" + default 10 + depends on !CONFIG_STANDARD_AWHTTPD + help + Determine the number of slots. + + This is just an initial value to allocate memory. This will go all the + way up to max usrs. + +config CONFIG_HTTP_MAX_USERS + int "Max Users" + default 100 + depends on !CONFIG_STANDARD_AWHTTPD + help + Determine the maximum number of simultaneous users at any time + +config CONFIG_HTTP_HAS_CGI + bool "Enable CGI" + default n + depends on !CONFIG_STANDARD_AWHTTPD + help + Enable the CGI capability. + +config CONFIG_HTTP_CGI_EXTENSION + string "CGI File Extension" + default ".php" + depends on CONFIG_HTTP_HAS_CGI + help + Tell awhhtp what file extension is used for CGI + +config CONFIG_HTTP_DIRECTORIES + bool "Enable Directory Listing" + default n + depends on !CONFIG_STANDARD_AWHTTPD + help + Enable directory listing. + +config CONFIG_HTTP_PERM_CHECK + bool "Permissions Check" + default n + depends on !CONFIG_STANDARD_AWHTTPD + help + Enable permissions checking on the directories before reading the + files in them. + +config CONFIG_HTTP_HAS_IPV6 + bool "Enable IPv6" + default n + depends on !CONFIG_STANDARD_AWHTTPD && !CONFIG_PLATFORM_WIN32 + help + Use IPv6 instead of IPv4. + + Does not work under Win32 + +config CONFIG_HTTP_VERBOSE + bool "Verbose Mode" + default y if CONFIG_SSL_FULL_MODE + default n if !CONFIG_SSL_FULL_MODE + depends on !CONFIG_STANDARD_AWHTTPD + help + Enable extra statements used when using awhttpd. + +config CONFIG_HTTP_IS_DAEMON + bool "Run as a daemon" + default n + depends on !CONFIG_STANDARD_AWHTTPD && !CONFIG_PLATFORM_WIN32 + help + Run awhttpd as a background process. + + Does not work under Win32 + +endmenu + diff --git a/httpd/Makefile b/httpd/Makefile new file mode 100644 index 000000000..66e2908bd --- /dev/null +++ b/httpd/Makefile @@ -0,0 +1,111 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +all : web_server + +include ../config/.config +include ../config/makefile.conf + +ifndef CONFIG_PLATFORM_WIN32 + +ifdef CONFIG_PLATFORM_CYGWIN +TARGET=../awhttpd.exe +else +TARGET=../awhttpd +endif + +ifdef CONFIG_HTTP_STATIC_BUILD +LIBS=../libaxtls.a +else +LIBS=-L../ -laxtls +endif + +CFLAGS += -I../ssl + +else # win32 build +TARGET=../awhttpd.exe + +ifdef CONFIG_HTTP_STATIC_BUILD +LIBS=../axtls.static.lib ..\config\axtls.res +else +LIBS=../axtls.lib ..\config\axtls.res +endif +endif + +ifndef CONFIG_AWHTTPD +web_server: +else + +untar_web_server: awhttpd/Makefile + +awhttpd/Makefile: + tar xvf awhttpd-3.0.7.tar + cat awhttpd.patch | patch -p0 + +web_server : $(TARGET) + +OBJ= \ + cgi.o \ + conn.o \ + main.o \ + net.o \ + proc.o \ + socket.o \ + errors.o \ + misc.o \ + urldecode.o \ + mime_types.o \ + index.o \ + urlencode.o \ + permcheck.o \ + conf.o + +%.o : awhttpd/%.c ../config/.config + $(CC) -c $(CFLAGS) $< + +ifndef CONFIG_PLATFORM_WIN32 + +$(TARGET): $(OBJ) +ifdef CONFIG_HTTP_NO_SSL + $(LD) $(LDFLAGS) -o $@ $(OBJ) +endif + $(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) +ifndef CONFIG_DEBUG +ifndef CONFIG_PLATFORM_SOLARIS + strip --remove-section=.comment $(TARGET) +endif +endif +else # Win32 + +OBJ:=$(OBJ:.o=.obj) +%.obj : awhttpd/%.c + $(CC) $(CFLAGS) $< + +$(TARGET): $(OBJ) +ifdef CONFIG_HTTP_NO_SSL + $(LD) $(LDFLAGS) /out:$@ $(OBJ) +endif + $(LD) $(LDFLAGS) $(LIBS) /out:$@ $(OBJ) +endif + +endif # CONFIG_AWHTTPD + +clean:: + -@rm -f $(TARGET)* + -@rm -fr awhttpd + diff --git a/httpd/awhttpd-3.0.7.tar b/httpd/awhttpd-3.0.7.tar new file mode 100644 index 000000000..79105fbe1 Binary files /dev/null and b/httpd/awhttpd-3.0.7.tar differ diff --git a/httpd/awhttpd.patch b/httpd/awhttpd.patch new file mode 100644 index 000000000..932c0583e --- /dev/null +++ b/httpd/awhttpd.patch @@ -0,0 +1,1768 @@ +diff -Naur awhttpd/aw3.h axTLS/httpd/awhttpd/aw3.h +--- awhttpd/aw3.h 2005-01-23 13:17:14.000000000 +1000 ++++ axTLS/httpd/awhttpd/aw3.h 2006-06-28 20:38:44.921875000 +1000 +@@ -7,17 +7,16 @@ + */ + + +-#include +-#include +-#include +-#include +-#include ++#include "os_port.h" ++#include "ssl.h" + + + + #define BACKLOG 15 + #define VERSION "3.0.7" ++#ifdef CONFIG_HTTP_HAS_IPV6 + #define HAVE_IPV6 ++#endif + + #define MAXFILEPATH 1024 + #define MAXIPLEN 45 +@@ -26,6 +25,7 @@ + #define BLOCKSIZE 4096 + + #define INITIAL_CONNECTION_SLOTS 10 ++#define CONFIG_HTTP_DEFAULT_SSL_OPTIONS 0 + + #define STATE_WANT_TO_READ_HEAD 1 + #define STATE_WANT_TO_SEND_HEAD 2 +@@ -37,7 +37,6 @@ + #define TYPE_HEAD 1 + #define TYPE_POST 2 + +- + struct connstruct { + struct connstruct *next; + +@@ -46,29 +45,46 @@ + + int networkdesc; + int filedesc; ++ ++#if defined(CONFIG_HTTP_DIRECTORIES) || defined(CONFIG_STANDARD_AWHTTPD) ++#ifdef WIN32 ++ HANDLE dirp; ++ WIN32_FIND_DATA file_data; ++#else + DIR *dirp; ++#endif ++#endif + ++#if defined(CONFIG_STANDARD_AWHTTPD) || defined(CONFIG_HTTP_USE_TIMEOUT) + int timeout; ++#endif + + char ip[MAXIPLEN]; + + char actualfile[MAXREQUESTLENGTH]; + char filereq[MAXREQUESTLENGTH]; ++#if defined(CONFIG_HTTP_HAS_CGI) || defined(CONFIG_STANDARD_AWHTTPD) + char cgiargs[MAXREQUESTLENGTH]; + char cgiscriptinfo[MAXREQUESTLENGTH]; + char cgipathinfo[MAXREQUESTLENGTH]; ++#endif + char virtualhostreq[MAXREQUESTLENGTH]; + + int numbytes; + long offset; + char databuf[BLOCKSIZE]; + ++ int is_ssl; + }; + + + struct serverstruct { + struct serverstruct *next; + int sd; ++ int is_ssl; ++#ifdef CONFIG_HTTP_HAS_SSL ++ SSLCTX *ssl_ctx; ++#endif + }; + + +@@ -111,13 +127,20 @@ + + + // Useful macros ++#ifdef CONFIG_STANDARD_AWHTTPD + #define istimedout(tp,ct) ((ct) > (tp)->timeout) + #define updatetimeout(tp,ct) ((tp)->timeout = (ct)+usertimeout) ++#elif CONFIG_HTTP_USE_TIMEOUT ++#define istimedout(tp,ct) ((ct) > (tp)->timeout) ++#define updatetimeout(tp,ct) ((tp)->timeout = (ct)+CONFIG_HTTP_TIMEOUT) ++#else ++#define updatetimeout(tp,ct) /* empty macro */ ++#endif + + + + // conn.c prototypes +-void addconnection(int sd, char *ip); ++void addconnection(int sd, char *ip, int is_ssl); + void removeconnection(struct connstruct *cn); + + +@@ -129,16 +152,17 @@ + void procsendhead(struct connstruct *cn); + void procreadfile(struct connstruct *cn); + void procsendfile(struct connstruct *cn); ++int special_write(struct connstruct *cn, const uint8_t *buf, size_t count); + + + // net.c prototypes + void addtoservers(int sd); +-void selectloop(); ++void selectloop(void); + + + // socket.c prototypes + int pollsocket(int sd, long ustimeout); +-void handlenewconnection(int listenfd); ++void handlenewconnection(int listenfd, int is_ssl); + int openlistener(int port); + int openlistener6(int port); + +@@ -150,9 +174,9 @@ + + + // misc.c prototypes +-void nada(); +-void die(); +-void reaper(); ++void nada(int sigtype); ++void die(int sigtype); ++void reaper(int sigtype); + void stripcrlf(char *p); + char *my_strncpy(char *dest, const char *src, size_t n); + #ifndef __HAVE_ARCH_STRNLEN +@@ -166,12 +190,12 @@ + void buildactualfile(struct connstruct *cn); + int issockwriteable(int sd); + int isdir(char *name); +-void status(); ++void status(void); + int trycgi_withpathinfo(struct connstruct *cn); + + + // mime_types.c prototypes +-char *getmimetype(char *fn); ++const char *getmimetype(char *fn); + + + // urldecode.c prototypes +@@ -188,7 +212,7 @@ + + + // conf.c prototypes +-void defaultconfvals(); ++void defaultconfvals(void); + void procconf(char *filename); + + +@@ -202,4 +226,4 @@ + + + // main.c prototypes +-void initlists(); ++void initlists(void); +diff -Naur awhttpd/cgi.c axTLS/httpd/awhttpd/cgi.c +--- awhttpd/cgi.c 2005-06-04 14:09:52.000000000 +1000 ++++ axTLS/httpd/awhttpd/cgi.c 2006-06-28 20:38:44.921875000 +1000 +@@ -7,29 +7,33 @@ + */ + + +-#include + #include + #include +-#include ++#include + + #include "aw3.h" + + + ++#if defined(CONFIG_HTTP_HAS_CGI) || defined(CONFIG_STANDARD_AWHTTPD) + void addcgiext(char *tp) { + + struct cgiextstruct *ex; + + ex = (struct cgiextstruct *) malloc(sizeof(struct cgiextstruct)); + if (ex == NULL) { ++#ifdef CONFIG_HTTP_VERBOSE + fprintf(stderr, "Serious memory error...\n"); +- exit(0); ++#endif ++ exit(1); + } + + ex->ext = strdup(tp); + if (ex->ext == NULL) { ++#ifdef CONFIG_HTTP_VERBOSE + fprintf(stderr, "Serious memory error...\n"); +- exit(0); ++#endif ++ exit(1); + } + + ex->next = cgiexts; +@@ -43,7 +47,7 @@ + + void gensysenv(struct connstruct *cn) { + +- #ifndef LIMITEDCGI ++#if !defined (LIMITEDCGI) && !defined(WIN32) + + char buf[1024]; + +@@ -54,7 +58,9 @@ + + setenv("AW_VERSION", VERSION, 1); + ++#ifdef CONFIG_STANDARD_AWHTTPD + setenv("AW_QUOTE", quote, 1); ++#endif + + /* Commented this out because (and this is ridiculous) PHP + doesn't seem to work with this variable specified +@@ -70,30 +76,39 @@ + + setenv("QUERY_STRING", cn->cgiargs, 1); + +- return; +- +- #endif +- ++#endif + } + + + + void proccgi(struct connstruct *cn, int has_pathinfo) { + +- int tpipe[2], fv; +- char *myargs[3]; ++ int tpipe[2]; ++ char *myargs[5]; + char buf[MAXREQUESTLENGTH]; ++#ifdef WIN32 ++ int tmp_stdout; ++#else ++ int fv; ++#endif + ++#ifdef CONFIG_STANDARD_AWHTTPD + snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: Anti-Web V%s (%s)\n%s", + VERSION, + quote, (cn->reqtype == TYPE_HEAD) ? "\n" : ""); +- write(cn->networkdesc, buf, strlen(buf)); ++#else ++ snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: Anti-Web V%s\n%s", ++ VERSION, ++ (cn->reqtype == TYPE_HEAD) ? "\n" : ""); ++#endif ++ special_write(cn, buf, strlen(buf)); + + if (cn->reqtype == TYPE_HEAD) { + removeconnection(cn); + return; + } + ++#ifndef WIN32 + if (pipe(tpipe) == -1) { + removeconnection(cn); + return; +@@ -108,7 +123,8 @@ + return; + } + +- if (fv != 0) { ++ if (fv != 0) ++ { + // Close the write descriptor + close(tpipe[1]); + cn->filedesc = tpipe[0]; +@@ -132,19 +148,64 @@ + close(tpipe[1]); + + myargs[0] = cn->actualfile; +- myargs[1] = strdup(cn->cgiargs); ++ myargs[1] = cn->cgiargs; + myargs[2] = NULL; + +- if (!has_pathinfo) +- { +- my_strncpy(cn->cgipathinfo, "/", MAXREQUESTLENGTH); +- my_strncpy(cn->cgiscriptinfo, cn->filereq, MAXREQUESTLENGTH); +- } ++ if (!has_pathinfo) { ++ my_strncpy(cn->cgipathinfo, "/", MAXREQUESTLENGTH); ++ my_strncpy(cn->cgiscriptinfo, cn->filereq, MAXREQUESTLENGTH); ++ } + + gensysenv(cn); + + execv(cn->actualfile, myargs); ++#else /* WIN32 */ ++ if (_pipe(tpipe, 4096, O_BINARY| O_NOINHERIT) == -1) { ++ removeconnection(cn); ++ return; ++ } ++ ++ myargs[0] = "sh"; ++ myargs[1] = "-c"; ++ myargs[2] = cn->actualfile; ++ myargs[3] = cn->cgiargs; ++ myargs[4] = NULL; ++ ++ /* convert all the forward slashes to back slashes */ ++ { ++ char *t = myargs[2]; ++ while ((t = strchr(t, '\\'))) ++ { ++ *t++ = '/'; ++ } ++ } + +- exit(0); ++ tmp_stdout = _dup(_fileno(stdout)); ++ _dup2(tpipe[1], _fileno(stdout)); ++ close(tpipe[1]); + ++ /* change to suit execution method */ ++ if (spawnl(P_NOWAIT, "c:\\Program Files\\cygwin\\bin\\sh.exe", ++ myargs[0], myargs[1], myargs[2], myargs[3], myargs[4]) == -1) { ++ removeconnection(cn); ++ return; ++ } ++ ++ _dup2(tmp_stdout, _fileno(stdout)); ++ close(tmp_stdout); ++ cn->filedesc = tpipe[0]; ++ cn->state = STATE_WANT_TO_READ_FILE; ++ ++ for (;;) ++ { ++ procreadfile(cn); ++ ++ if (cn->filedesc == -1) ++ break; ++ ++ procsendfile(cn); ++ usleep(200000); /* don't know why this delay makes it work (yet) */ ++ } ++#endif + } ++#endif /* CONFIG_HTTP_HAS_CGI */ +diff -Naur awhttpd/conf.c axTLS/httpd/awhttpd/conf.c +--- awhttpd/conf.c 2005-06-04 14:09:52.000000000 +1000 ++++ axTLS/httpd/awhttpd/conf.c 2006-06-28 20:38:44.921875000 +1000 +@@ -10,11 +10,7 @@ + #include + #include + #include +-#include +-#include + #include +-#include +- + #include "aw3.h" + + +@@ -23,21 +19,29 @@ + + int usevirtualhosts; + char *webroot; ++int initialslots; ++int maxusers; ++ ++#ifdef CONFIG_STANDARD_AWHTTPD ++ + int allowdirectorylisting; + int allowcgi; + int permcheck; +-int maxusers; + int usertimeout; +-int initialslots; + char *quote; + ++#endif /* CONFIG_STANDARD_AWHTTPD */ ++ ++ + int numusers; + + + + void defaultconfvals() { + ++#ifdef CONFIG_STANDARD_AWHTTPD + usevirtualhosts = 0; ++ maxusers = 500; + allowdirectorylisting = 0; + allowcgi = 0; + permcheck = 0; +@@ -45,6 +49,13 @@ + usertimeout = 5; + initialslots = 10; + quote = "Fear and loathing on the WWW"; ++#else ++ maxusers = 500; ++ initialslots = CONFIG_HTTP_INITIAL_SLOTS; ++ maxusers = CONFIG_HTTP_MAX_USERS; ++ usevirtualhosts = 1; ++#endif ++ + + // Not really conf stuff: + numusers = 0; +@@ -54,6 +65,7 @@ + } + + ++#ifdef CONFIG_STANDARD_AWHTTPD + void procconf(char *filename) { + + FILE *fp; +@@ -210,11 +222,11 @@ + err++; + } else { + if (setgid(bl->pw_gid) != 0) { +- fprintf(stderr, "WARN: Unable to drop GID to %d\n", bl->pw_gid); ++ fprintf(stderr, "WARN: Unable to drop GID to %ld\n", bl->pw_gid); + warn++; + } + if (setuid(bl->pw_uid) != 0) { +- fprintf(stderr, "WARN: Unable to drop UID to %d\n", bl->pw_uid); ++ fprintf(stderr, "WARN: Unable to drop UID to %ld\n", bl->pw_uid); + warn++; + } + } +@@ -263,3 +275,4 @@ + return; + + } ++#endif /* CONFIG_STANDARD_AWHTTPD */ +diff -Naur awhttpd/conn.c axTLS/httpd/awhttpd/conn.c +--- awhttpd/conn.c 2004-12-07 16:11:02.000000000 +1000 ++++ axTLS/httpd/awhttpd/conn.c 2006-06-28 20:38:44.921875000 +1000 +@@ -9,15 +9,11 @@ + + #include + #include +-#include +-#include + #include +- + #include "aw3.h" + + +- +-void addconnection(int sd, char *ip) { ++void addconnection(int sd, char *ip, int is_ssl) { + struct connstruct *tp; + + // Get ourselves a connstruct +@@ -39,12 +35,21 @@ + usedconns = tp; + + tp->networkdesc = sd; ++#ifdef CONFIG_HTTP_HAS_SSL ++ if (is_ssl) ++ ssl_server_new(servers->ssl_ctx, sd); ++#endif + tp->filedesc = -1; ++#if defined(CONFIG_STANDARD_AWHTTPD) || defined(CONFIG_HTTP_HAS_DIRECTORIES) + tp->dirp = NULL; ++#endif ++ tp->is_ssl = is_ssl; + + *(tp->actualfile) = '\0'; + *(tp->filereq) = '\0'; ++#if defined(CONFIG_STANDARD_AWHTTPD) || defined(CONFIG_HTTP_HAS_CGI) + *(tp->cgiargs) = '\0'; ++#endif + *(tp->virtualhostreq) = '\0'; + + tp->state = STATE_WANT_TO_READ_HEAD; +@@ -57,7 +62,6 @@ + numusers++; + + updatetimeout(tp, time(NULL)); +- + return; + + } +@@ -95,10 +99,22 @@ + freeconns = cn; + + // Close it all down +- if (cn->networkdesc != -1) close(cn->networkdesc); ++ if (cn->networkdesc != -1) { ++#ifdef CONFIG_HTTP_HAS_SSL ++ if (cn->is_ssl) { ++ ssl_free(ssl_find(servers->ssl_ctx, cn->networkdesc)); ++ } ++#endif ++ SOCKET_CLOSE(cn->networkdesc); ++ } + if (cn->filedesc != -1) close(cn->filedesc); ++#if defined(CONFIG_STANDARD_AWHTTPD) || defined(CONFIG_HTTP_HAS_DIRECTORIES) ++#ifdef WIN32 ++ if (cn->dirp != NULL) FindClose(cn->dirp); ++#else + if (cn->dirp != NULL) closedir(cn->dirp); +- ++#endif ++#endif + numusers--; + + return; +diff -Naur awhttpd/errors.c axTLS/httpd/awhttpd/errors.c +--- awhttpd/errors.c 2005-01-23 06:49:29.000000000 +1000 ++++ axTLS/httpd/awhttpd/errors.c 2006-06-28 20:38:44.937500000 +1000 +@@ -8,7 +8,6 @@ + + + #include +-#include + #include + + #include "aw3.h" +@@ -20,7 +19,7 @@ + + snprintf(buf, sizeof(buf), "HTTP/1.1 301 Moved Permanently\nLocation: %s/\n\n\n\n301 Moved Permanently\n\n

Moved Permanently

\nThe document has moved here.

\n


\n\n", cn->filereq, cn->filereq); + +- write(cn->networkdesc, buf, strlen(buf)); ++ special_write(cn, buf, strlen(buf)); + + return; + +@@ -34,7 +33,7 @@ + + snprintf(buf, sizeof(buf), "HTTP/1.0 404 Not Found\nContent-Type: text/html\n\n\n404 Not Found

It ain't there my friend. (404 Not Found)

\n

Anti-Web HTTPD - Take back some simplicity.\n\n"); + +- write(cn->networkdesc, buf, strlen(buf)); ++ special_write(cn, buf, strlen(buf)); + + return; + +@@ -42,6 +41,7 @@ + + + ++/* TODO: this really needs to use the connstruct object */ + void send505(int sd, char *reason) { + + char buf[1024]; +diff -Naur awhttpd/index.c axTLS/httpd/awhttpd/index.c +--- awhttpd/index.c 2005-06-04 14:09:52.000000000 +1000 ++++ axTLS/httpd/awhttpd/index.c 2006-06-28 20:38:44.937500000 +1000 +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + #include + + #include "aw3.h" +@@ -52,7 +51,13 @@ + tp = indexlist; + + while(tp != NULL) { +- snprintf(tbuf, sizeof(tbuf), "%s%s", cn->actualfile, tp->name); ++ sprintf(tbuf, "%s%s%s", cn->actualfile, ++#ifdef WIN32 ++ "\\", ++#else ++ "/", ++#endif ++ tp->name); + + if (stat(tbuf, stp) != -1) { + my_strncpy(cn->actualfile, tbuf, MAXREQUESTLENGTH); +diff -Naur awhttpd/main.c axTLS/httpd/awhttpd/main.c +--- awhttpd/main.c 2005-06-04 14:09:52.000000000 +1000 ++++ axTLS/httpd/awhttpd/main.c 2006-06-28 20:38:44.937500000 +1000 +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + #include + + #include "aw3.h" +@@ -21,10 +20,40 @@ + struct serverstruct *servers; + struct connstruct *usedconns; + struct connstruct *freeconns; ++#if defined(CONFIG_HTTP_HAS_CGI) || defined(CONFIG_STANDARD_AWHTTPD) + struct cgiextstruct *cgiexts; ++#endif + struct indexstruct *indexlist; + ++/* clean up memory for valgrind */ ++static void sigint_cleanup(int sig) ++{ ++ struct serverstruct *sp; ++ struct connstruct *tp; ++ int i; ++ ++ while(servers != NULL) { ++#ifdef CONFIG_HTTP_HAS_SSL ++ if (servers->is_ssl) ++ ssl_ctx_free(servers->ssl_ctx); ++#endif ++ sp = servers->next; ++ free(servers); ++ servers = sp; ++ } ++ free(indexlist->name); ++ free(indexlist); ++ for(i=0; i< INITIAL_CONNECTION_SLOTS; i++) { ++ if (freeconns == NULL) ++ break; ++ ++ tp = freeconns->next; ++ free(freeconns); ++ freeconns = tp; ++ } + ++ exit(0); ++} + + void initlists() { + int i; +@@ -33,15 +62,19 @@ + servers = NULL; + usedconns = NULL; + freeconns = NULL; ++#if defined(CONFIG_HTTP_HAS_CGI) || defined(CONFIG_STANDARD_AWHTTPD) + cgiexts = NULL; ++#endif + indexlist = NULL; + + for(i=0; inext = tp; +@@ -49,6 +82,7 @@ + } + + ++#ifdef CONFIG_STANDARD_AWHTTPD + void usage(char *cmline) { + fprintf(stderr, "Anti-Web V%s (C) 2001-2004 by Hardcore Software and others\n\n", VERSION); + +@@ -65,76 +99,138 @@ + + exit(1); + } ++#endif + + + int main(int argc, char *argv[]) { + ++#ifdef CONFIG_STANDARD_AWHTTPD + char buf[MAXREQUESTLENGTH]; +- int pid, tp; +- ++#endif ++ int tp; ++#if defined(CONFIG_HTTP_IS_DAEMON) || defined(CONFIG_STANDARD_AWHTTPD) ++ int pid; ++#endif ++ ++#ifdef WIN32 ++ WORD wVersionRequested = MAKEWORD(2,2); ++ WSADATA wsaData; ++ WSAStartup(wVersionRequested,&wsaData); ++#endif ++ + initlists(); + ++#ifdef CONFIG_STANDARD_AWHTTPD + if (argc != 2 && argc != 3) usage(argv[0]); + + webroot = strdup(argv[1]); ++#else ++ webroot = CONFIG_HTTP_WEBROOT; ++#endif + + tp = strlen(webroot); + if (webroot[tp-1] == '/') webroot[tp-1] = '\0'; + + if (isdir(webroot) == 0) { ++#ifdef CONFIG_HTTP_VERBOSE + fprintf(stderr, "'%s' is not a directory\n", webroot); ++#endif + exit(1); + } + + defaultconfvals(); + ++#ifdef CONFIG_STANDARD_AWHTTPD + if (argc == 2) { + snprintf(buf, sizeof(buf), "%s/awhttpd.conf", webroot); + procconf(buf); + } else { + if ((tp=openlistener(atoi(argv[2]))) == -1) { ++#ifdef CONFIG_HTTP_VERBOSE + fprintf(stderr, "ERR: Couldn't bind to port %d (IPv4)\n", atoi(argv[2])); ++#endif + exit(1); + } ++ } ++#else /* not command line */ ++ if ((tp=openlistener(CONFIG_HTTP_PORT)) == -1) { ++#ifdef CONFIG_HTTP_VERBOSE ++ fprintf(stderr, "ERR: Couldn't bind to port %d (IPv4)\n", ++ CONFIG_HTTP_PORT); ++#endif ++ exit(1); ++ } ++#endif /* CONFIG_STANDARD_AWHTTPD */ + + addindex("index.html"); + addtoservers(tp); +- setgid(32767); +- setuid(32767); +- } + ++#ifndef WIN32 ++ if (getuid() == 0) ++ { ++ setgid(32767); ++ setuid(32767); ++ } ++#endif ++ ++#ifdef CONFIG_HTTP_HAS_SSL ++ if ((tp=openlistener(CONFIG_HTTP_HTTPS_PORT)) == -1) { ++#ifdef CONFIG_HTTP_VERBOSE ++ fprintf(stderr, "ERR: Couldn't bind to port %d (IPv4)\n", ++ CONFIG_HTTP_HTTPS_PORT); ++#endif ++ exit(1); ++ } ++ ++ addtoservers(tp); ++ servers->ssl_ctx = ssl_ctx_new(CONFIG_HTTP_DEFAULT_SSL_OPTIONS, ++ SSL_DEFAULT_SVR_SESS); ++ servers->is_ssl = 1; ++#endif /* CONFIG_HTTP_HAS_SSL */ ++ ++#if defined (CONFIG_STANDARD_AWHTTPD) + if (permcheck == 1) procpermcheck(webroot); ++#elif defined(CONFIG_HTTP_PERM_CHECK) ++ procpermcheck(webroot); ++#endif ++#if defined(CONFIG_HTTP_HAS_CGI) ++ addcgiext(CONFIG_HTTP_CGI_EXTENSION); ++#endif ++#if defined(CONFIG_HTTP_VERBOSE) ++ printf("awhttpd: listening on ports http:%d and https:%d\n", ++ CONFIG_HTTP_PORT, CONFIG_HTTP_HTTPS_PORT); ++ TTY_FLUSH(); ++#endif + ++#if defined(CONFIG_HTTP_IS_DAEMON) || defined(CONFIG_STANDARD_AWHTTPD) + pid = fork(); + + if(pid > 0) { + status(); + exit(0); + } else if(pid == -1) { ++#ifdef CONFIG_HTTP_VERBOSE + fprintf(stderr,"Anti-Web: Sorry, fork failed... Tough dice.\n"); ++#endif + exit(1); + } + + setsid(); ++#endif + + /* SIGNALS */ +- signal(SIGINT, die); +- signal(SIGQUIT, die); ++ signal(SIGINT, sigint_cleanup); + signal(SIGTERM, die); ++#if defined(CONFIG_HTTP_HAS_CGI) || defined(CONFIG_STANDARD_AWHTTPD) ++#ifndef WIN32 + signal(SIGCHLD, reaper); +- +- #ifndef SOLARIS +- signal(SIGPIPE, nada); +- #endif +- +- #ifdef SOLARIS +- act.sa_handler = nada; +- sigemptyset(&act.sa_mask); +- act.sa_flags = SA_RESTART; +- +- sigaction(SIGPIPE,&act,NULL); +- #endif +- ++#endif ++#endif ++#ifndef WIN32 ++ signal(SIGQUIT, die); ++ signal(SIGPIPE, SIG_IGN); ++#endif ++ + selectloop(); + + return 0; +diff -Naur awhttpd/mime_types.c axTLS/httpd/awhttpd/mime_types.c +--- awhttpd/mime_types.c 2004-01-26 01:08:47.000000000 +1000 ++++ axTLS/httpd/awhttpd/mime_types.c 2006-06-28 20:38:44.937500000 +1000 +@@ -21,13 +21,14 @@ + + + #include ++#include "os_port.h" + + + char mime_default[] = "text/plain"; + + struct { +- char *ext; +- char *type; ++ const char *ext; ++ const char *type; + } mime_table[] = { + + // Fundamentals +@@ -161,7 +162,7 @@ + }; + + +-char *getmimetype(char *name) { ++const char *getmimetype(char *name) { + int namelen, extlen, i; + + namelen = strlen(name); +@@ -178,3 +179,4 @@ + return mime_default; + + } ++ +diff -Naur awhttpd/misc.c axTLS/httpd/awhttpd/misc.c +--- awhttpd/misc.c 2005-01-23 12:59:09.000000000 +1000 ++++ axTLS/httpd/awhttpd/misc.c 2006-06-28 20:38:44.937500000 +1000 +@@ -7,33 +7,33 @@ + */ + + +-#include + #include + #include + #include +-#include ++#include + #include + #include +-#include +-#include +-#include + + #include "aw3.h" + + + + +-void nada() { } ++void nada(int sigtype) { } + + +-void die() { ++void die(int sigtype) { + exit(0); + } + + +-void reaper() { ++#if defined(CONFIG_HTTP_HAS_CGI) || defined(CONFIG_STANDARD_AWHTTPD) ++#ifndef WIN32 ++void reaper(int sigtype) { + wait3(NULL,WNOHANG,NULL); + } ++#endif ++#endif + + + void stripcrlf(char *p) { +@@ -77,6 +77,7 @@ + #endif + + ++#if defined(CONFIG_HTTP_HAS_CGI) || defined(CONFIG_STANDARD_AWHTTPD) + int iscgi(char *fn) { + + struct cgiextstruct *tp; +@@ -97,6 +98,7 @@ + return 0; + + } ++#endif + + + +@@ -235,6 +237,7 @@ + + void buildactualfile(struct connstruct *cn) { + ++#if 0 + char tpbuf[MAXREQUESTLENGTH]; + + if (usevirtualhosts) { +@@ -253,6 +256,26 @@ + webroot, + cn->virtualhostreq, + cn->filereq); ++#endif ++ snprintf(cn->actualfile, MAXREQUESTLENGTH, "%s%s", ++ webroot, ++ cn->filereq); ++ ++ /* Add directory slash if not there */ ++ if (isdir(cn->actualfile) && ++ cn->actualfile[strlen(cn->actualfile)-1] != '/') ++ strcat(cn->actualfile, "/"); ++ ++#ifdef WIN32 ++ /* convert all the forward slashes to back slashes */ ++ { ++ char *t = cn->actualfile; ++ while ((t = strchr(t, '/'))) ++ { ++ *t++ = '\\'; ++ } ++ } ++#endif + + return; + +@@ -279,7 +302,7 @@ + + int isdir(char *tpbuf) { + +- static struct stat st; ++ struct stat st; + + if (stat(tpbuf, &st) == -1) return 0; + +@@ -292,6 +315,7 @@ + + // FIXME: Arg! This function is horrible! Rewrite it + void status() { ++#if defined(CONFIG_STANDARD_AWHTTPD) + + int i; + +@@ -300,14 +324,16 @@ + fprintf(stdout," [*************************************************]\n"); + fprintf(stdout," [ DIRECTORY {%s}",webroot); + if(strlen(webroot)<35) +- for(i=1;i<=35-strlen(webroot);i++) fprintf(stdout," "); ++ for(i=1;i<=35-(int)strlen(webroot);i++) fprintf(stdout," "); + fprintf(stdout,"]\n"); + fprintf(stdout," [*************************************************]\n"); + ++#endif + } + + + ++#if defined(CONFIG_HTTP_HAS_CGI) || defined(CONFIG_STANDARD_AWHTTPD) + /* This function was originally written by Nicolas Benoit + but I've rewritten some parts of it to work under + as many possible AW configurations as possible. +@@ -329,7 +355,8 @@ + while (fr_rs[i] != NULL) { + snprintf(tpfile, sizeof(tpfile), "%s/%s%s", webroot, cn->virtualhostreq, fr_str); + +- if (iscgi(tpfile) && access(tpfile, X_OK) == 0 && isdir(tpfile) == 0) { ++ //if (iscgi(tpfile) && access(tpfile, X_OK) == 0 && isdir(tpfile) == 0) { ++ if (iscgi(tpfile) && isdir(tpfile) == 0) { + /* We've found our CGI file! */ + my_strncpy(cn->actualfile, tpfile, MAXREQUESTLENGTH); + my_strncpy(cn->cgiscriptinfo, fr_str, MAXREQUESTLENGTH); +@@ -349,3 +376,4 @@ + *(cn->cgipathinfo) = '\0'; + return -1; + } ++#endif +diff -Naur awhttpd/net.c axTLS/httpd/awhttpd/net.c +--- awhttpd/net.c 2005-06-04 14:09:52.000000000 +1000 ++++ axTLS/httpd/awhttpd/net.c 2006-06-28 20:38:44.937500000 +1000 +@@ -8,9 +8,7 @@ + + + #include +-#include + #include +-#include + #include + #include + #include +@@ -23,9 +21,11 @@ + void addtoservers(int sd) { + struct serverstruct *tp; + +- tp = (struct serverstruct *) malloc(sizeof(struct serverstruct)); ++ tp = (struct serverstruct *) calloc(1, sizeof(struct serverstruct)); + if (tp == NULL) { ++#ifdef CONFIG_HTTP_VERBOSE + fprintf(stderr, "Serious memory error...\n"); ++#endif + exit(1); + } + +@@ -44,7 +44,9 @@ + struct connstruct *tp, *to; + struct serverstruct *sp; + int rnum, wnum, active; ++#if defined(CONFIG_STANDARD_AWHTTPD) || defined(CONFIG_HTTP_USE_TIMEOUT) + int currtime; ++#endif + + while(1) { // MAIN SELECT LOOP + FD_ZERO(&rfds); +@@ -61,15 +63,19 @@ + + // Add the established sockets + tp = usedconns; ++#if defined(CONFIG_STANDARD_AWHTTPD) || defined(CONFIG_HTTP_USE_TIMEOUT) + currtime = time(NULL); ++#endif + while(tp != NULL) { + ++#if defined(CONFIG_STANDARD_AWHTTPD) || defined(CONFIG_HTTP_USE_TIMEOUT) + if (istimedout(tp, currtime)) { + to = tp; + tp = tp->next; + removeconnection(to); + continue; + } ++#endif + + if (tp->state == STATE_WANT_TO_READ_HEAD) { + FD_SET(tp->networkdesc, &rfds); +@@ -87,10 +93,12 @@ + FD_SET(tp->networkdesc, &wfds); + if (tp->networkdesc > wnum) wnum = tp->networkdesc; + } ++#if defined(CONFIG_HTTP_DIRECTORIES) || defined(CONFIG_STANDARD_AWHTTPD) + if (tp->state == STATE_DOING_DIR) { + FD_SET(tp->networkdesc, &wfds); + if (tp->networkdesc > wnum) wnum = tp->networkdesc; + } ++#endif + tp = tp->next; + } + +@@ -104,7 +112,7 @@ + sp = servers; + while(active > 0 && sp != NULL) { + if (FD_ISSET(sp->sd, &rfds)) { +- handlenewconnection(sp->sd); ++ handlenewconnection(sp->sd, sp->is_ssl); + active--; + } + sp = sp->next; +@@ -112,7 +120,9 @@ + + // Handle the established sockets + tp = usedconns; ++#if defined(CONFIG_STANDARD_AWHTTPD) || defined(CONFIG_HTTP_USE_TIMEOUT) + currtime = time(NULL); ++#endif + while(active > 0 && tp != NULL) { + to = tp; + tp = tp->next; +@@ -141,12 +151,14 @@ + active--; + procsendfile(to); + } ++#if defined(CONFIG_HTTP_DIRECTORIES) || defined(CONFIG_STANDARD_AWHTTPD) + if (to->state == STATE_DOING_DIR) + if (FD_ISSET(to->networkdesc, &wfds)) { + updatetimeout(to, currtime); + active--; + procdodir(to); + } ++#endif + } + + +diff -Naur awhttpd/permcheck.c axTLS/httpd/awhttpd/permcheck.c +--- awhttpd/permcheck.c 2005-01-23 06:49:29.000000000 +1000 ++++ axTLS/httpd/awhttpd/permcheck.c 2006-06-28 20:38:44.937500000 +1000 +@@ -7,21 +7,23 @@ + */ + + +-#include + #include ++#include ++#include + + #include "aw3.h" + ++#if defined(CONFIG_HTTP_PERM_CHECK) || defined (CONFIG_STANDARD_AWHTTPD) + void procpermcheck(char *pathtocheck) { +- ++ char thepath[MAXREQUESTLENGTH]; ++#ifndef WIN32 + DIR *tpdir; + struct dirent *dp; +- char thepath[MAXREQUESTLENGTH]; + + tpdir=opendir(pathtocheck); + + if (tpdir==NULL) { +- printf("WARNING: UID (%d) is unable to read %s\n", getuid(), pathtocheck); ++ printf("WARNING: UID (%d) is unable to read %s\n", (int)getuid(), pathtocheck); + return; + } + +@@ -38,14 +40,56 @@ + } + + if (access(thepath, R_OK) != 0) +- printf("WARNING: UID (%d) is unable to read %s\n", getuid(), thepath); ++ printf("WARNING: UID (%d) is unable to read %s\n", (int)getuid(), thepath); + if (access(thepath, W_OK) == 0) +- printf("SECURITY: UID (%d) is ABLE TO WRITE TO %s\n", getuid(), thepath); ++ printf("SECURITY: UID (%d) is ABLE TO WRITE TO %s\n", (int)getuid(), thepath); + + } + + closedir(tpdir); ++#else /* Win32 */ ++ HANDLE tpdir; ++ WIN32_FIND_DATA file_data; ++ struct stat st; ++ char buf2[1024]; ++ ++ strcpy(buf2, pathtocheck); ++ strcat(buf2, "\\*"); ++ tpdir = FindFirstFile(buf2, &file_data); ++ ++ if (tpdir == INVALID_HANDLE_VALUE) { ++ printf("WARNING: unable to read %s\n", buf2); ++ TTY_FLUSH(); ++ return; ++ } ++ ++ while (FindNextFile(tpdir, &file_data)) { ++ ++ if (strcmp(file_data.cFileName, "..")==0) continue; ++ if (strcmp(file_data.cFileName, ".")==0) continue; ++ ++ snprintf(thepath, sizeof(thepath), "%s\\%s", ++ pathtocheck, file_data.cFileName); + +- return; ++ if (isdir(thepath)) { ++ procpermcheck(thepath); ++ continue; ++ } ++ ++ if (stat(thepath, &st) >= 0) { ++ if ((st.st_mode & _S_IREAD) == 0) { ++ printf("WARNING: unable to read %s\n", thepath); ++ TTY_FLUSH(); ++ } ++ ++ if (st.st_mode & _S_IWRITE) { ++ printf("SECURITY: ABLE TO WRITE TO %s\n", thepath); ++ TTY_FLUSH(); ++ } ++ } ++ } + ++ FindClose(tpdir); ++#endif + } ++#endif /* CONFIG_HTTP_PERM_CHECK */ +diff -Naur awhttpd/proc.c axTLS/httpd/awhttpd/proc.c +--- awhttpd/proc.c 2005-01-23 10:59:41.000000000 +1000 ++++ axTLS/httpd/awhttpd/proc.c 2006-06-28 20:47:25.109375000 +1000 +@@ -13,14 +13,12 @@ + #include + #include + #include +-#include + #include + #include + + #include "aw3.h" + +- +- ++static int special_read(struct connstruct *cn, void *buf, size_t count); + + // Returns 1 if elems should continue being read, 0 otherwise + int procheadelem(struct connstruct *cn, char *buf) { +@@ -53,7 +51,9 @@ + + my_strncpy(cn->filereq, segs[0], MAXREQUESTLENGTH); + ++#if defined(CONFIG_HTTP_HAS_CGI) || defined(CONFIG_STANDARD_AWHTTPD) + if (segs[1] != NULL) my_strncpy(cn->cgiargs, segs[1], MAXREQUESTLENGTH); ++#endif + + } else if (strcmp(words[0], "Host:")==0) { + +@@ -85,19 +85,22 @@ + + return 1; + +-} +- + ++} + ++#if defined(CONFIG_HTTP_DIRECTORIES) || defined(CONFIG_STANDARD_AWHTTPD) + void procdirlisting(struct connstruct *cn) { + + char buf[MAXREQUESTLENGTH]; ++ char actualfile[1024]; + ++#ifndef CONFIG_HTTP_DIRECTORIES + if (allowdirectorylisting == 0) { + send404(cn); + removeconnection(cn); + return; + } ++#endif + + if (cn->reqtype == TYPE_HEAD) { + snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nContent-Type: text/html\n\n"); +@@ -107,7 +110,17 @@ + return; + } + +- cn->dirp = opendir(cn->actualfile); ++ strcpy(actualfile, cn->actualfile); ++#ifdef WIN32 ++ strcat(actualfile, "*"); ++ cn->dirp = FindFirstFile(actualfile, &cn->file_data); ++ if (cn->dirp == INVALID_HANDLE_VALUE) { ++ send404(cn); ++ removeconnection(cn); ++ return; ++ } ++#else ++ cn->dirp = opendir(actualfile); + if (cn->dirp == NULL) { + send404(cn); + removeconnection(cn); +@@ -116,12 +129,13 @@ + + // Get rid of the "." + readdir(cn->dirp); ++#endif + + // If the browser doesn't specify a virtual host, the client will + // see "http://default/thedir/" instead of "http://thehost.com/thedir/" + // Consider this punishment for using such an old browser. + snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nContent-Type: text/html\n\n\nDirectory Listing\n

Directory listing of http://%s%s


\n", cn->virtualhostreq, cn->filereq); +- write(cn->networkdesc, buf, strlen(buf)); ++ special_write(cn, buf, strlen(buf)); + + cn->state = STATE_DOING_DIR; + +@@ -134,36 +148,48 @@ + + void procdodir(struct connstruct *cn) { + ++#ifndef WIN32 + struct dirent *dp; ++#endif + char buf[MAXREQUESTLENGTH]; +- char encbuf[sizeof(dp->d_name)*3+1]; ++ char encbuf[1024]; + int putslash; ++ char *file; + + do { + +- if ((dp = readdir(cn->dirp)) == NULL) { ++#ifdef WIN32 ++ if (!FindNextFile(cn->dirp, &cn->file_data)) { ++#else ++ if ((dp = readdir(cn->dirp)) == NULL) { ++#endif + snprintf(buf, sizeof(buf), "

End of Anti-Web directory listing.\n"); +- write(cn->networkdesc, buf, strlen(buf)); ++ special_write(cn, buf, strlen(buf)); + removeconnection(cn); + return; + } + ++#ifdef WIN32 ++ file = cn->file_data.cFileName; ++#else ++ file = dp->d_name; ++#endif + if (cn->filereq[0] == '/' && cn->filereq[1] == '\0' && +- strcmp(dp->d_name, "..") == 0) continue; ++ strcmp(file, "..") == 0) continue; + +- snprintf(buf, sizeof(buf), "%s%s", cn->actualfile, dp->d_name); ++ snprintf(buf, sizeof(buf), "%s%s", cn->actualfile, file); + putslash = isdir(buf); + +- urlencode(dp->d_name, encbuf); ++ urlencode(file, encbuf); + snprintf(buf, sizeof(buf), "%s%s
\n", +- encbuf, putslash ? "/" : "", dp->d_name, putslash ? "/" : ""); +- write(cn->networkdesc, buf, strlen(buf)); ++ encbuf, putslash ? "/" : "", file, putslash ? "/" : ""); ++ special_write(cn, buf, strlen(buf)); + + } while (issockwriteable(cn->networkdesc)); + + return; + } +- ++#endif + + + +@@ -172,9 +198,10 @@ + char buf[MAXREQUESTLENGTH*4], *tp, *next; + int rv; + +- rv = read(cn->networkdesc, buf, sizeof(buf)-1); +- if (rv == 0 || rv == -1) { +- removeconnection(cn); ++ rv = special_read(cn, buf, sizeof(buf)-1); ++ if (rv <= 0) { ++ if (rv < 0) ++ removeconnection(cn); + return; + } + +@@ -217,36 +244,97 @@ + void procsendhead(struct connstruct *cn) { + + char buf[1024]; ++ char actualfile[1024]; + struct stat stbuf; + +- if (stat(cn->actualfile, &stbuf) == -1) { ++ strcpy(actualfile, cn->actualfile); ++ ++#ifdef WIN32 ++ /* stat() under win32 can't deal with trail slash */ ++ if (actualfile[strlen(actualfile)-1] == '\\') ++ actualfile[strlen(actualfile)-1] = 0; ++#endif ++ ++ if (stat(actualfile, &stbuf) == -1) { ++#if defined(CONFIG_HTTP_HAS_CGI) || defined(CONFIG_STANDARD_AWHTTPD) ++#ifndef CONFIG_HTTP_HAS_CGI + if (allowcgi != 0) { ++#endif + if (trycgi_withpathinfo(cn) == 0) { // We Try To Find A CGI + proccgi(cn,1); + return; + } ++#ifndef CONFIG_HTTP_HAS_CGI + } ++#endif ++#endif + + send404(cn); + removeconnection(cn); + return; + } + ++#if defined(CONFIG_HTTP_HAS_CGI) || defined(CONFIG_STANDARD_AWHTTPD) + if (iscgi(cn->actualfile)) { ++#ifndef WIN32 + // Set up CGI script +- if (allowcgi == 0 || +- access(cn->actualfile, X_OK) != 0 || +- isdir(cn->actualfile)) { ++ if ( ++#ifndef CONFIG_HTTP_HAS_CGI ++ allowcgi == 0 || ++#endif ++ (stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile)) { ++ send404(cn); ++ removeconnection(cn); ++ return; ++ } ++#endif ++ ++ proccgi(cn,0); ++ return; ++ } ++#endif ++ ++ if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { ++ if (cn->filereq[strlen(cn->filereq)-1] != '/') { ++ send301(cn); ++ removeconnection(cn); ++ return; ++ } ++ ++ // Check to see if this dir has an index file ++ if (procindex(cn, &stbuf) == 0) { ++#if defined(CONFIG_HTTP_DIRECTORIES) || defined(CONFIG_STANDARD_AWHTTPD) ++ // If not, we do a directory listing of it ++ procdirlisting(cn); ++#else + send404(cn); + removeconnection(cn); ++#endif + return; + } + +- proccgi(cn,0); +- return; +- } ++#if defined(CONFIG_HTTP_HAS_CGI) || defined(CONFIG_STANDARD_AWHTTPD) ++ // If the index is a CGI file, handle it like any other CGI ++ if (iscgi(cn->actualfile)) { ++ // Set up CGI script ++#ifndef CONFIG_HTTP_HAS_CGI ++ if (allowcgi == 0 || ++ (stbuf.st_mode & S_IEXEC) == 0 != 0 || isdir(cn->actualfile)) { ++#else ++ if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile)) { ++#endif ++ send404(cn); ++ removeconnection(cn); ++ return; ++ } + ++ proccgi(cn,0); ++ return; ++ } ++#endif ++ // If the index isn't a CGI, we continue on with the index file + ++ } + if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { + if (cn->filereq[strlen(cn->filereq)-1] != '/') { + send301(cn); +@@ -256,16 +344,24 @@ + + // Check to see if this dir has an index file + if (procindex(cn, &stbuf) == 0) { ++#if defined(CONFIG_HTTP_DIRECTORIES) || defined(CONFIG_STANDARD_AWHTTPD) + // If not, we do a directory listing of it + procdirlisting(cn); ++#endif + return; + } + ++#if defined(CONFIG_HTTP_HAS_CGI) || defined(CONFIG_STANDARD_AWHTTPD) + // If the index is a CGI file, handle it like any other CGI + if (iscgi(cn->actualfile)) { + // Set up CGI script +- if (allowcgi == 0 || +- access(cn->actualfile, X_OK) != 0 || ++ if ( ++#ifdef CONFIG_HTTP_HAS_CGI ++ (stbuf.st_mode & S_IEXEC) == 0 || ++#else ++ allowcgi == 0 || ++ (stbuf.st_mode & S_IEXEC) == 0 || ++#endif + isdir(cn->actualfile)) { + send404(cn); + removeconnection(cn); +@@ -275,6 +371,7 @@ + proccgi(cn,0); + return; + } ++#endif + // If the index isn't a CGI, we continue on with the index file + + } +@@ -282,6 +379,7 @@ + if (cn->offset == -1 || cn->offset >= stbuf.st_size) { + cn->offset = -1; + ++#if defined (CONFIG_STANDARD_AWHTTPD) + snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: Anti-Web V%s (%s)\nContent-Type: %s\nContent-Length: %ld\nLast-Modified: %s\n", + VERSION, + quote, +@@ -299,15 +397,41 @@ + (long) stbuf.st_size - cn->offset, + ctime(&(stbuf.st_mtime))); // ctime() has a \n on the end + } ++#else ++#ifdef CONFIG_HTTP_VERBOSE ++ printf("awhttpd: %s send %s\n", ++ cn->is_ssl ? "https" : "http", cn->actualfile); ++ TTY_FLUSH(); ++#endif ++ snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: Anti-Web V%s\nContent-Type: %s\nContent-Length: %ld\nLast-Modified: %s\n", ++ VERSION, ++ getmimetype(cn->actualfile), ++ (long) stbuf.st_size, ++ ctime(&(stbuf.st_mtime))); // ctime() has a \n on the end ++ } else { ++ snprintf(buf, sizeof(buf), "HTTP/1.1 206 OK\nServer: Anti-Web V%s\nContent-Type: %s\nContent-Range: %ld-%ld/%ld\nContent-Length: %ld\nLast-Modified: %s\n", ++ VERSION, ++ getmimetype(cn->actualfile), ++ cn->offset, ++ (long) stbuf.st_size-1, ++ (long) stbuf.st_size, ++ (long) stbuf.st_size - cn->offset, ++ ctime(&(stbuf.st_mtime))); // ctime() has a \n on the end ++ } ++#endif /* CONFIG_HTTP_USE_QUOTE */ + +- write(cn->networkdesc, buf, strlen(buf)); ++ special_write(cn, buf, strlen(buf)); + + if (cn->reqtype == TYPE_HEAD) { + removeconnection(cn); + return; + } else { ++ int flags = O_RDONLY; ++#ifdef WIN32 ++ flags |= O_BINARY; ++#endif + +- cn->filedesc = open(cn->actualfile, O_RDONLY); ++ cn->filedesc = open(cn->actualfile, flags); + if (cn->filedesc == -1) { + send404(cn); + removeconnection(cn); +@@ -318,7 +442,23 @@ + lseek(cn->filedesc, cn->offset, SEEK_SET); + } + ++#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 + return; + } + +@@ -328,13 +468,13 @@ + + void procreadfile(struct connstruct *cn) { + +- int rv; +- +- rv = read(cn->filedesc, cn->databuf, BLOCKSIZE); ++ int rv = read(cn->filedesc, cn->databuf, BLOCKSIZE); + + if (rv == 0 || rv == -1) { +- removeconnection(cn); +- return; ++ close(cn->filedesc); ++ cn->filedesc = -1; ++ removeconnection(cn); ++ return; + } + + cn->numbytes = rv; +@@ -347,11 +487,9 @@ + + void procsendfile(struct connstruct *cn) { + +- int rv; ++ int rv = special_write(cn, cn->databuf, cn->numbytes); + +- rv = write(cn->networkdesc, cn->databuf, cn->numbytes); +- +- if (rv == -1) ++ if (rv < 0) + removeconnection(cn); + else if (rv == cn->numbytes) + cn->state = STATE_WANT_TO_READ_FILE; +@@ -361,7 +499,47 @@ + memmove(cn->databuf, cn->databuf + rv, cn->numbytes - rv); + cn->numbytes -= rv; + } ++} + +- return; ++int special_write(struct connstruct *cn, ++ const uint8_t *buf, size_t count) ++{ ++ int res; ++ ++#ifdef CONFIG_HTTP_HAS_SSL ++ if (cn->is_ssl) ++ { ++ SSL *ssl = ssl_find(servers->ssl_ctx, cn->networkdesc); ++ if (ssl) ++ { ++ res = ssl_write(ssl, (unsigned char *)buf, count); ++ } ++ else ++ return -1; ++ } ++ else ++#endif ++ res = SOCKET_WRITE(cn->networkdesc, buf, count); ++ ++ return res; ++} ++ ++static int special_read(struct connstruct *cn, void *buf, size_t count) ++{ ++ int res; ++ ++#ifdef CONFIG_HTTP_HAS_SSL ++ if (cn->is_ssl) ++ { ++ SSL *ssl = ssl_find(servers->ssl_ctx, cn->networkdesc); ++ unsigned char *read_buf; ++ ++ if ((res = ssl_read(ssl, &read_buf)) > SSL_OK) ++ memcpy(buf, read_buf, res > (int)count ? count : res); ++ } ++ else ++#endif ++ res = SOCKET_READ(cn->networkdesc, buf, count); + ++ return res; + } +diff -Naur awhttpd/socket.c axTLS/httpd/awhttpd/socket.c +--- awhttpd/socket.c 2004-04-25 13:03:05.000000000 +1000 ++++ axTLS/httpd/awhttpd/socket.c 2006-06-28 20:38:44.953125000 +1000 +@@ -8,19 +8,11 @@ + + + #include +-#include +-#include + #include +-#include +-#include +-#include +-#include + #include +-#include + #include + + +- + #include "aw3.h" + + +@@ -62,7 +54,7 @@ + + #ifdef HAVE_IPV6 + +-void handlenewconnection(int listenfd) { ++void handlenewconnection(int listenfd, int is_ssl) { + + struct sockaddr_in6 their_addr; + int tp = sizeof(their_addr); +@@ -82,7 +74,7 @@ + *ipbuf = '\0'; + } + +- if (checkmaxusers(connfd)) addconnection(connfd, ipbuf); ++ if (checkmaxusers(connfd)) addconnection(connfd, ipbuf, is_ssl); + + return; + +@@ -90,19 +82,18 @@ + + #else + +-void handlenewconnection(int listenfd) { ++void handlenewconnection(int listenfd, int is_ssl) { + + struct sockaddr_in their_addr; + int tp = sizeof(struct sockaddr_in); + int connfd; +- char ipbuf[100]; + + connfd = accept(listenfd, (struct sockaddr *)&their_addr, &tp); + + if (connfd == -1) return; + + if (checkmaxusers(connfd)) +- addconnection(connfd, inet_ntoa(their_addr.sin_addr)); ++ addconnection(connfd, inet_ntoa(their_addr.sin_addr), is_ssl); + + return; + } +@@ -113,8 +104,12 @@ + + + int openlistener(int port) { +- +- int tp=0,sd; ++ int sd; ++#ifdef WIN32 ++ char tp=1; ++#else ++ int tp=1; ++#endif + struct sockaddr_in my_addr; + + if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) return -1; +@@ -125,7 +120,7 @@ + setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &tp, sizeof(tp)); + + my_addr.sin_family = AF_INET; // host byte order +- my_addr.sin_port = htons(port); // short, network byte order ++ my_addr.sin_port = htons((short)port); // short, network byte order + my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP + + memset(&(my_addr.sin_zero), 0, 8); // zero the rest of the struct +diff -Naur awhttpd/urlencode.c axTLS/httpd/awhttpd/urlencode.c +--- awhttpd/urlencode.c 2004-05-14 10:53:47.000000000 +1000 ++++ axTLS/httpd/awhttpd/urlencode.c 2006-06-28 20:38:44.953125000 +1000 +@@ -13,7 +13,7 @@ + + #include + #include +- ++#include + #include "aw3.h" + + +@@ -37,7 +37,7 @@ + (*p > 'Z' && *p < '_') || + (*p > '_' && *p < 'a') || + (*p > 'z' && *p < 0xA1)) { +- sprintf(tp, "%%%02X", *p); ++ sprintf((char *)tp, "%%%02X", *p); + tp += 3; + } else { + *tp = *p; diff --git a/samples/Config.in b/samples/Config.in new file mode 100644 index 000000000..a17f252f9 --- /dev/null +++ b/samples/Config.in @@ -0,0 +1,56 @@ +# +# 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). + +endmenu + diff --git a/samples/Makefile b/samples/Makefile new file mode 100644 index 000000000..4a7acd786 --- /dev/null +++ b/samples/Makefile @@ -0,0 +1,46 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +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 + +clean:: + $(MAKE) -C c clean + $(MAKE) -C csharp clean + $(MAKE) -C vbnet clean + $(MAKE) -C java clean + $(MAKE) -C perl clean diff --git a/samples/c/Makefile b/samples/c/Makefile new file mode 100644 index 000000000..656b8cb6c --- /dev/null +++ b/samples/c/Makefile @@ -0,0 +1,67 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +all : sample + +include ../../config/.config +include ../../config/makefile.conf + +ifndef CONFIG_PLATFORM_WIN32 + +ifdef CONFIG_PLATFORM_CYGWIN +TARGET=../../axssl.exe +else +TARGET=../../axssl +endif # cygwin + +LIBS=../../libaxtls.a +CFLAGS += -I../../ssl -I../../config +else +TARGET=../../axssl.exe +LIBS=../../axtls.lib +CFLAGS += /I"..\..\ssl" /I"..\..\config" +endif + +ifndef CONFIG_C_SAMPLES +sample: + +else +sample : $(TARGET) +OBJ= axssl.o +include ../../config/makefile.post + +ifndef CONFIG_PLATFORM_WIN32 + +$(TARGET): $(OBJ) $(LIBS) + $(LD) $(LDFLAGS) -o $@ $^ +ifndef CONFIG_DEBUG +ifndef CONFIG_PLATFORM_SOLARIS + strip --remove-section=.comment $(TARGET) +endif # SOLARIS +endif # CONFIG_DEBUG +else # Win32 + +$(TARGET): $(OBJ) $(LIBS) + $(LD) $(LDFLAGS) ..\..\config\axtls.res /out:$@ $^ +endif + +endif # CONFIG_C_SAMPLES + +clean:: + -@rm -f ../../axssl* + diff --git a/samples/c/axssl.c b/samples/c/axssl.c new file mode 100644 index 000000000..955340ca8 --- /dev/null +++ b/samples/c/axssl.c @@ -0,0 +1,862 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/** + * @file axssl.c + * + * 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 +#include +#include +#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(SOLARIS) + signal(SIGPIPE, SIG_IGN); /* ignore pipe errors */ +#endif + + 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; + SSLCTX *ssl_ctx; + int server_fd, client_len, res = 0; +#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++; + } + + /* 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. + *************************************************************************/ + 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 + + 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 > 0) /* display our interesting output */ + { + printf("%s", read_buf); + TTY_FLUSH(); + } + else if (res < 0 && !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; + SSLCTX *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++; + } + + 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(); + } + + /************************************************************************* + * This is where the interesting stuff happens. Up until now we've + * just been setting up sockets etc. Now we do the SSL handshake. + *************************************************************************/ + 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); + + /* Try session resumption? */ + if (reconnect) + { + while (reconnect--) + { + ssl = ssl_client_new(ssl_ctx, client_fd, 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); + } + + /* 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%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] [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); + + printf("-----BEGIN SSL SESSION PARAMETERS-----\n"); + for (i = 0; i < SSL_SESSION_ID_SIZE; i++) + { + printf("%02x", session_id[i]); + } + printf("\n-----END SSL SESSION PARAMETERS-----\n"); + TTY_FLUSH(); +} diff --git a/samples/csharp/Makefile b/samples/csharp/Makefile new file mode 100644 index 000000000..8e299fd74 --- /dev/null +++ b/samples/csharp/Makefile @@ -0,0 +1,36 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +include ../../config/.config +include ../../config/makefile.conf +include ../../config/makefile.dotnet.conf + +all : sample +TARGET=../../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) diff --git a/samples/csharp/axssl.cs b/samples/csharp/axssl.cs new file mode 100644 index 000000000..ca8281d65 --- /dev/null +++ b/samples/csharp/axssl.cs @@ -0,0 +1,744 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/** + * axssl.cs + * + * 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) + { + 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" + 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.cs.exe [s_server|s_client] [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(); + + Console.WriteLine("-----BEGIN SSL SESSION PARAMETERS-----"); + foreach (byte b in session_id) + { + Console.Write("{0:x02}", b); + } + + Console.WriteLine("\n-----END SSL SESSION PARAMETERS-----"); + } +} diff --git a/samples/java/Makefile b/samples/java/Makefile new file mode 100644 index 000000000..0bedf5221 --- /dev/null +++ b/samples/java/Makefile @@ -0,0 +1,39 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +include ../../config/.config +include ../../config/makefile.conf +include ../../config/makefile.java.conf + +all : sample +JAR=../../axtls.jar +CLASSES=../../bindings/java/classes +sample : $(JAR) + +$(JAR) : $(CLASSES)/axssl.class $(wildcard $(CLASSES)/axTLSj/*.class) + jar mcvf manifest.mf $@ -C $(CLASSES) . + +JAVA_FILES= axssl.java +JAVA_CLASSES:=$(JAVA_FILES:%.java=$(CLASSES)/axTLSj/%.class) + +$(CLASSES)/%.class : %.java + javac -d $(CLASSES) -classpath $(CLASSES) $^ + +clean:: + -@rm -f $(TARGET) + diff --git a/samples/java/axssl.java b/samples/java/axssl.java new file mode 100644 index 000000000..b193725ef --- /dev/null +++ b/samples/java/axssl.java @@ -0,0 +1,760 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/* + * axssl.java + * + * 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) + { + 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" + 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] " + + "[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(); + int i; + + System.out.println("-----BEGIN SSL SESSION PARAMETERS-----"); + bytesToHex(session_id); + System.out.println("-----END SSL SESSION PARAMETERS-----"); + } +} diff --git a/samples/java/manifest.mf b/samples/java/manifest.mf new file mode 100644 index 000000000..b906ed29e --- /dev/null +++ b/samples/java/manifest.mf @@ -0,0 +1 @@ +Main-Class: axssl diff --git a/samples/perl/Makefile b/samples/perl/Makefile new file mode 100644 index 000000000..da910f9b7 --- /dev/null +++ b/samples/perl/Makefile @@ -0,0 +1,31 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +include ../../config/.config +include ../../config/makefile.conf + +all: samples +TARGET=../../axssl.pl +samples: $(TARGET) + +$(TARGET): axssl.pl + @cd ../../; ln -sf samples/perl/axssl.pl axssl.pl + +clean:: + -@rm -f $(TARGET) + diff --git a/samples/perl/axssl.pl b/samples/perl/axssl.pl new file mode 100755 index 000000000..ce0266b02 --- /dev/null +++ b/samples/perl/axssl.pl @@ -0,0 +1,633 @@ +#!/usr/bin/perl -w +# +# Copyright(C) 2006 +# +# 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.1 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 Lesser 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 +# + +# +# axssl.pl +# +# 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; +} + +# +# 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; + + while (1) + { + ($res, $buf) = axtlsp::ssl_read($ssl, undef); + last if $res != $axtlsp::SSL_OK; + + # check when the connection has been established + last if axtlsp::ssl_handshake_status($ssl) == $axtlsp::SSL_OK; + + # could do something else here + } + + if ($res == $axtlsp::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 (1) + { + ($res, $buf) = axtlsp::ssl_read($ssl, undef); + last if $res != $axtlsp::SSL_OK; + + # could do something else here + } + + if ($res < $axtlsp::SSL_OK) + { + printf("CONNECTION CLOSED\n") if not $quiet; + last; + } + + printf($$buf); + } + } + elsif (!$quiet) + { + axtlsp::ssl_display_error($res); + } + + # client was disconnected or the handshake failed. + 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; + while ($reconnect--) + { + $ssl = axtlsp::ssl_client_new($ssl_ctx, $native_sock, $session_id); + + $res = axtlsp::ssl_handshake_status($ssl); + if ($res != $axtlsp::SSL_OK) + { + if (!$quiet) + { + axtlsp::ssl_display_error($res); + } + + 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); + } + + # check the return status + $res = axtlsp::ssl_handshake_status($ssl); + if ($res != $axtlsp::SSL_OK) + { + if (!$quiet) + { + axtlsp::ssl_display_error($res); + } + + exit 1; + } + + if (!$quiet) + { + my $common_name = axtlsp::ssl_get_cert_dn($ssl, + $axtlsp::SSL_X509_CERT_COMMON_NAME); + + printf("Common Name:\t\t%s\n", $common_name) if defined $common_name; + display_session_id($ssl); + display_cipher($ssl); + } + + while () + { + 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] [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 default DER format. 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); + + printf("-----BEGIN SSL SESSION PARAMETERS-----\n"); + printf(unpack("H*", $$session_id)); + printf("\n-----END SSL SESSION PARAMETERS-----\n"); +} diff --git a/samples/vbnet/Makefile b/samples/vbnet/Makefile new file mode 100644 index 000000000..dab5f9599 --- /dev/null +++ b/samples/vbnet/Makefile @@ -0,0 +1,36 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +include ../../config/.config +include ../../config/makefile.conf +include ../../config/makefile.dotnet.conf + +# only build on Win32 platforms +ifdef GO_DOT_NET +all : sample +TARGET=../../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) + diff --git a/samples/vbnet/axssl.vb b/samples/vbnet/axssl.vb new file mode 100644 index 000000000..4eb210a3f --- /dev/null +++ b/samples/vbnet/axssl.vb @@ -0,0 +1,682 @@ +' +' Copyright(C) 2006 +' +' 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.1 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 Lesser 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 +' + +' +' @file axssl.vb +' +' 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 & 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() + + 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 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.vb.exe [s_server|s_client] [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 + 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 diff --git a/ssl/BigIntConfig.in b/ssl/BigIntConfig.in new file mode 100644 index 000000000..04c7438c0 --- /dev/null +++ b/ssl/BigIntConfig.in @@ -0,0 +1,132 @@ +# +# 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 + + + diff --git a/ssl/Config.in b/ssl/Config.in new file mode 100644 index 000000000..ff3aba597 --- /dev/null +++ b/ssl/Config.in @@ -0,0 +1,250 @@ +# +# 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. + + 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 may be several times 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 advantage of a built-in private key/certificate is that no file + system is required for access. + + 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_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/Opera may be a problem - see Mozilla bug report 148876). + + 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 + PKCS12 certificates combine private keys and certificates together in + one file. + + PKCS8 private keys are also suppported (as it is a subset of PKCS12). + + 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 PKCS12 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_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" + default y if !CONFIG_VISUAL_STUDIO_6_0 + default n if CONFIG_VISUAL_STUDIO_6_0 + 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. If using Visual Studio + 6.0, then the SDK containing the crypto libraries must be used. + +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 + help + Used for sanity checking the SSL handshaking. + + This is a testing tool and is normally disabled. + +endmenu diff --git a/ssl/Makefile b/ssl/Makefile new file mode 100644 index 000000000..2b0b6aa65 --- /dev/null +++ b/ssl/Makefile @@ -0,0 +1,86 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +include ../config/.config +include ../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=../libaxtls.a +TARGET2=../libaxtls.so +else +TARGET1=../axtls.lib +TARGET2=../axtls.dll +STATIC_LIB=../axtls.static.lib +endif + +libs: $(TARGET1) $(TARGET2) + +OBJ=\ + aes.o \ + asn1.o \ + bigint.o \ + crypto_misc.o \ + hmac.o \ + loader.o \ + md5.o \ + p12.o \ + rsa.o \ + rc4.o \ + sha1.o \ + tls1.o \ + tls1_svr.o \ + tls1_clnt.o + +ifdef CONFIG_PLATFORM_WIN32 +OBJ+=os_port.o +endif + +include ../config/makefile.post + +ifndef CONFIG_PLATFORM_WIN32 + +$(TARGET1) : $(OBJ) + $(AR) -r $@ $(OBJ) + +$(TARGET2) : $(OBJ) + $(LD) $(LDFLAGS) $(LDSHARED) -o $@ $(OBJ) + +else # Win32 + +$(TARGET1) : $(OBJ) + $(AR) /out:$@ $(OBJ) + +$(TARGET2) : $(OBJ) + cp $(TARGET1) $(STATIC_LIB) + $(LD) $(LDFLAGS) $(LDSHARED) /out:$@ $(OBJ) + +endif + +clean:: + $(MAKE) -C test clean + -@rm -f *.pch ../*.so ../*.a ../*.dll ../*.lib ../*.exp ../*.pdb ../*.ilk + diff --git a/ssl/aes.c b/ssl/aes.c new file mode 100644 index 000000000..7c41c753f --- /dev/null +++ b/ssl/aes.c @@ -0,0 +1,477 @@ +/* + * Copyright(C) 2006 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @file aes.c + * + * 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 +#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 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 puting 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)) + +/* some macros to do endian independent byte extraction */ +#define n2l(c,l) l=ntohl(*c); c++ +#define l2n(l,c) *c++=htonl(l) + +/* + * 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; irounds+1); + for (i = words; i> 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) +{ + uint32_t tin0, tin1, tin2, tin3; + uint32_t tout0, tout1, tout2, tout3; + uint32_t tin[4]; + uint32_t *iv = (uint32_t *)ctx->iv; + uint32_t *msg_32 = (uint32_t *)msg; + uint32_t *out_32 = (uint32_t *)out; + + n2l(iv, tout0); + n2l(iv, tout1); + n2l(iv, tout2); + n2l(iv, tout3); + iv -= 4; + + for (length -= 16; length >= 0; length -= 16) + { + n2l(msg_32, tin0); + n2l(msg_32, tin1); + n2l(msg_32, tin2); + n2l(msg_32, tin3); + tin[0] = tin0^tout0; + tin[1] = tin1^tout1; + tin[2] = tin2^tout2; + tin[3] = tin3^tout3; + + AES_encrypt(ctx, tin); + + tout0 = tin[0]; + l2n(tout0, out_32); + tout1 = tin[1]; + l2n(tout1, out_32); + tout2 = tin[2]; + l2n(tout2, out_32); + tout3 = tin[3]; + l2n(tout3, out_32); + } + + l2n(tout0, iv); + l2n(tout1, iv); + l2n(tout2, iv); + l2n(tout3, iv); +} + +/** + * 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) +{ + uint32_t tin0, tin1, tin2, tin3; + uint32_t xor0,xor1,xor2,xor3; + uint32_t tout0,tout1,tout2,tout3; + uint32_t data[4]; + uint32_t *iv = (uint32_t *)ctx->iv; + uint32_t *msg_32 = (uint32_t *)msg; + uint32_t *out_32 = (uint32_t *)out; + + n2l(iv ,xor0); + n2l(iv, xor1); + n2l(iv, xor2); + n2l(iv, xor3); + iv -= 4; + + for (length-=16; length >= 0; length -= 16) + { + n2l(msg_32, tin0); + n2l(msg_32, tin1); + n2l(msg_32, tin2); + n2l(msg_32, tin3); + + data[0] = tin0; + data[1] = tin1; + data[2] = tin2; + data[3] = tin3; + + AES_decrypt(ctx, data); + + tout0 = data[0]^xor0; + tout1 = data[1]^xor1; + tout2 = data[2]^xor2; + tout3 = data[3]^xor3; + + xor0 = tin0; + xor1 = tin1; + xor2 = tin2; + xor3 = tin3; + + l2n(tout0, out_32); + l2n(tout1, out_32); + l2n(tout2, out_32); + l2n(tout3, out_32); + } + + l2n(xor0, iv); + l2n(xor1, iv); + l2n(xor2, iv); + l2n(xor3, iv); +} + +/** + * 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; + uint32_t *k = (uint32_t*)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 + diff --git a/ssl/asn1.c b/ssl/asn1.c new file mode 100644 index 000000000..fa44dfbe6 --- /dev/null +++ b/ssl/asn1.c @@ -0,0 +1,868 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/** + * @file asn1.c + * + * Some primitive asn methods for extraction rsa modulus information. It also + * is used for retrieving information from X.509 certificates. + */ + +#include +#include +#include +#include +#include "crypto.h" + +#define SIG_OID_PREFIX_SIZE 8 + +#define SIG_TYPE_MD2 0x02 +#define SIG_TYPE_MD5 0x04 +#define SIG_TYPE_SHA1 0x05 + +/* 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 +}; + +/* CN, O, OU */ +static uint8_t g_dn_types[] = { 3, 10, 11 }; + +static 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; + + *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, *priv_exp, *pub_exp; + int mod_len, priv_len, pub_len; +#ifdef CONFIG_BIGINT_CRT + uint8_t *p, *q, *dP, *dQ, *qInv; + 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) + */ +static 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. + */ +static 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) + goto end_pnt_str; + + (*offset)++; + len = get_asn1_length(buf, offset); + *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. + */ +static 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. + */ +static 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, *pub_exp; + + 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)++; + + 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. + */ +static 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); + 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; + + 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 + */ +static 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 */ +} + +/** + * Retrieve the signature from a certificate. + */ +const uint8_t *x509_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 + +/** + * Read the signature type of the certificate. We only support RSA-MD5 and + * RSA-SHA1 signature types. + */ +static 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 (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; + if (asn1_skip_obj(cert, offset, ASN1_NULL)) + goto end_check_sig; + ret = X509_OK; + +end_check_sig: + return ret; +} + +/** + * 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 (either SHA1 or MD5) */ + if (x509_ctx->sig_type == SIG_TYPE_MD5) + { + MD5_CTX md5_ctx; + uint8_t md5_dgst[MD5_SIZE]; + MD5Init(&md5_ctx); + MD5Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + MD5Final(&md5_ctx, md5_dgst); + 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]; + SHA1Init(&sha_ctx); + SHA1Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA1Final(&sha_ctx, sha_dgst); + x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_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 +/** + * Do some basic checks on the certificate chain. + * + * Certificate verification consists of a number of checks: + * - A root certificate exists in the certificate store. + * - The date of the certificate is after the start date. + * - The date of the certificate is before the finish date. + * - The certificate chain is valid. + * - That the certificate(s) are not self-signed. + * - 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; + bigint *mod, *expn; + struct timeval tv; + int match_ca_cert = 0; + + if (cert == NULL || ca_cert_ctx == NULL) + { + ret = X509_VFY_ERROR_NO_TRUSTED_CERT; + goto end_verify; + } + + /* last cert in the chain - look for a trusted cert */ + if (cert->next == NULL) + { + 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) + { + match_ca_cert = 1; + break; + } + + i++; + } + + if (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) + { + next_cert = ca_cert_ctx->cert[i]; + } + else /* trusted cert not found */ + { + ret = X509_VFY_ERROR_NO_TRUSTED_CERT; + goto end_verify; + } + } + else + { + next_cert = cert->next; + } + + 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; + } + + /* check the chain integrity */ + if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn)) + { + ret = X509_VFY_ERROR_INVALID_CHAIN; + goto end_verify; + } + + /* check for self-signing */ + if (!match_ca_cert && asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0) + { + ret = X509_VFY_ERROR_SELF_SIGNED; + goto end_verify; + } + + /* check the signature */ + ctx = cert->rsa_ctx->bi_ctx; + mod = next_cert->rsa_ctx->m; + expn = next_cert->rsa_ctx->e; + cert_sig = RSA_sign_verify(ctx, cert->signature, cert->sig_len, + bi_clone(ctx, mod), bi_clone(ctx, expn)); + + if (cert_sig) + { + ret = cert->digest ? /* check the signature */ + bi_compare(cert_sig, cert->digest) : + X509_VFY_ERROR_UNSUPPORTED_DIGEST; + bi_free(ctx, cert_sig); + + if (ret) + goto end_verify; + } + else + { + ret = X509_VFY_ERROR_BAD_SIGNATURE; + goto end_verify; + } + + /* go down the certificate chain using recursion. */ + if (ret == 0 && cert->next) + { + ret = x509_verify(ca_cert_ctx, next_cert); + } + +end_verify: + return ret; +} +#endif + +#if defined (CONFIG_SSL_FULL_MODE) +/** + * Used for diagnostics. + */ +void x509_print(CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert) +{ + if (cert == NULL) + return; + + printf("---------------- CERT DEBUG ----------------\n"); + printf("* CA Cert Distinguished Name\n"); + if (cert->ca_cert_dn[X509_COMMON_NAME]) + { + printf("Common Name (CN):\t%s\n", cert->ca_cert_dn[X509_COMMON_NAME]); + } + + if (cert->ca_cert_dn[X509_ORGANIZATION]) + { + printf("Organization (O):\t%s\n", cert->ca_cert_dn[X509_ORGANIZATION]); + } + + if (cert->ca_cert_dn[X509_ORGANIZATIONAL_TYPE]) + { + printf("Organizational Unit (OU): %s\n", + cert->ca_cert_dn[X509_ORGANIZATIONAL_TYPE]); + } + + printf("* Cert Distinguished Name\n"); + if (cert->cert_dn[X509_COMMON_NAME]) + { + printf("Common Name (CN):\t%s\n", cert->cert_dn[X509_COMMON_NAME]); + } + + if (cert->cert_dn[X509_ORGANIZATION]) + { + printf("Organization (O):\t%s\n", cert->cert_dn[X509_ORGANIZATION]); + } + + if (cert->cert_dn[X509_ORGANIZATIONAL_TYPE]) + { + printf("Organizational Unit (OU): %s\n", + cert->cert_dn[X509_ORGANIZATIONAL_TYPE]); + } + + printf("Not Before:\t\t%s", ctime(&cert->not_before)); + printf("Not After:\t\t%s", ctime(&cert->not_after)); + printf("RSA bitsize:\t\t%d\n", cert->rsa_ctx->num_octets*8); + printf("Sig Type:\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; + } + + printf("Verify:\t\t\t"); + + if (ca_cert_ctx) + { + x509_display_error(x509_verify(ca_cert_ctx, cert)); + } + + printf("\n"); +#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(ca_cert_ctx, cert->next); + } +} + +void x509_display_error(int error) +{ + switch (error) + { + case X509_NOT_OK: + printf("X509 not ok"); + break; + + case X509_VFY_ERROR_NO_TRUSTED_CERT: + printf("No trusted cert is available"); + break; + + case X509_VFY_ERROR_BAD_SIGNATURE: + printf("Bad signature"); + break; + + case X509_VFY_ERROR_NOT_YET_VALID: + printf("Cert is not yet valid"); + break; + + case X509_VFY_ERROR_EXPIRED: + printf("Cert has expired"); + break; + + case X509_VFY_ERROR_SELF_SIGNED: + printf("Cert is self-signed"); + break; + + case X509_VFY_ERROR_INVALID_CHAIN: + printf("Chain is invalid (check order of certs)"); + break; + + case X509_VFY_ERROR_UNSUPPORTED_DIGEST: + printf("Unsupported digest"); + break; + + case X509_INVALID_PRIV_KEY: + printf("Invalid private key"); + break; + } +} +#endif /* CONFIG_SSL_FULL_MODE */ + diff --git a/ssl/bigint.c b/ssl/bigint.c new file mode 100644 index 000000000..9702dc4fc --- /dev/null +++ b/ssl/bigint.c @@ -0,0 +1,1508 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/** + * @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 + * + * and GMP . It gets most of its implementation + * detail from "The Handbook of Applied Cryptography" + * + * @{ + */ + +#include +#include +#include +#include +#include +#include "bigint.h" +#include "crypto.h" + +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); +#endif + +/** + * @brief Start a new bigint context. + * @return A bigint context. + */ +BI_CTX *bi_initialize(void) +{ + BI_CTX *ctx = (BI_CTX *)calloc(1, sizeof(BI_CTX)); + + ctx->active_list = NULL; + ctx->active_count = 0; + ctx->free_list = NULL; + ctx->free_count = 0; + ctx->mod_offset = 0; +#ifdef CONFIG_BIGINT_MONTGOMERY + ctx->use_classical = 0; +#endif + + /* 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) +{ + bigint *p, *pn; + + 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(); + } + + for (p = ctx->free_list; p != NULL; p = pn) + { + pn = p->next; + free(p->comps); + free(p); + } + + free(ctx); +} + +/** + * @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 referent 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 elligible 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 additon 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<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 it's 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, n = bia->size, 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 blob = (long_comp)w[i+j]+carry; + + if (u) /* previous overflow */ + { + blob += COMP_RADIX; + } + + u = 0; + if (xx & COMP_BIG_MSB) /* check for overflow */ + { + u = 1; + } + + tmp = 2*xx + blob; + 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 of 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(); + } + + 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; + int 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. + * @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_residue(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]; + } +#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. + * @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 +/** @} */ diff --git a/ssl/bigint.h b/ssl/bigint.h new file mode 100644 index 000000000..c98b3837d --- /dev/null +++ b/ssl/bigint.h @@ -0,0 +1,97 @@ +/* + * Copyright(C) 2006 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef BIGINT_HEADER +#define BIGINT_HEADER + +#include "config.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 + +#if !defined(CONFIG_BIGINT_MONTGOMERY) || !defined(CONFIG_BIGINT_BARRETT) +#define CONFIG_BIGINT_CLASSICAL 1 +#endif + +#include "os_port.h" +#include "bigint_impl.h" + +#ifndef CONFIG_BIGINT_CHECK_ON +#define check(A) /**< disappears in normal production mode */ +#endif +BI_CTX *bi_initialize(void); +void bi_terminate(BI_CTX *ctx); +void bi_permanent(bigint *bi); +void bi_depermanent(bigint *bi); +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_CLASSICAL) +#define bi_residue(A, B) bi_mod(A, B) +#elif defined(CONFIG_BIGINT_BARRETT) +#define bi_residue(A, B) bi_barrett(A, B) +bigint *bi_barrett(BI_CTX *ctx, bigint *bi); +#else /* CONFIG_BIGINT_MONTGOMERY */ +#define bi_residue(A, B) bi_mont(A, B) +bigint *bi_mont(BI_CTX *ctx, bigint *bixy); +#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 + +#endif diff --git a/ssl/bigint_impl.h b/ssl/bigint_impl.h new file mode 100644 index 000000000..1897fec16 --- /dev/null +++ b/ssl/bigint_impl.h @@ -0,0 +1,106 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +#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_BIG_MSB 0x8000000000000000i64 +#else +#define COMP_RADIX 4294967296ULL /**< Max component + 1 */ +#define COMP_BIG_MSB 0x8000000000000000ULL /**< (Max dbl comp + 1)/ 2 */ +#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. */ + +#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 */ + +#endif diff --git a/ssl/cert.h b/ssl/cert.h new file mode 100644 index 000000000..21697abaa --- /dev/null +++ b/ssl/cert.h @@ -0,0 +1,37 @@ +unsigned char default_certificate[] = { + 0x30, 0x82, 0x01, 0x92, 0x30, 0x81, 0xfc, 0x02, 0x09, 0x00, 0xf1, 0xc3, + 0x87, 0xc0, 0xd4, 0xf4, 0x57, 0xc2, 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, 0x5c, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0xd1, 0x3b, + 0x30, 0x5f, 0xa9, 0x01, 0x42, 0x3d, 0x86, 0x6d, 0x72, 0xbe, 0x40, 0x6e, + 0x51, 0xc1, 0x49, 0x7f, 0x57, 0x75, 0xa1, 0x2d, 0x36, 0xe5, 0xc1, 0x3d, + 0x0f, 0x20, 0x1a, 0xd1, 0x23, 0x6d, 0xfa, 0x74, 0xd2, 0x3e, 0x23, 0xb0, + 0x70, 0xfc, 0xa0, 0x6a, 0xde, 0xec, 0x41, 0x88, 0x84, 0xfe, 0x54, 0x15, + 0x6b, 0x61, 0xc5, 0x16, 0x62, 0xb8, 0x93, 0x41, 0xf1, 0x4f, 0x3d, 0xff, + 0x2e, 0xbd, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, + 0x81, 0x00, 0x0a, 0x45, 0x3e, 0x8b, 0xc0, 0x5a, 0xf5, 0xc5, 0xe7, 0x49, + 0x6f, 0x8a, 0xab, 0xbe, 0x30, 0x7e, 0x13, 0x05, 0x7f, 0xd2, 0x9e, 0x13, + 0x34, 0xd5, 0xd4, 0x4b, 0xd4, 0xb7, 0xd2, 0xb3, 0x12, 0x16, 0xf4, 0x5a, + 0xaf, 0xb5, 0x71, 0xbc, 0xb3, 0xf5, 0x96, 0x96, 0x23, 0xf4, 0xf4, 0x75, + 0x24, 0x64, 0x99, 0x30, 0x6f, 0xc1, 0xea, 0x14, 0x78, 0xca, 0xe9, 0x85, + 0x46, 0x3c, 0x1e, 0x97, 0xd1, 0x4f, 0x80, 0xd7, 0x16, 0x09, 0x6e, 0x03, + 0x5c, 0x05, 0xaa, 0xcf, 0x75, 0x10, 0x17, 0xba, 0x19, 0xb4, 0x92, 0xfa, + 0x2b, 0xe5, 0xc9, 0xa5, 0x0d, 0x20, 0xc0, 0x2f, 0x8d, 0xc5, 0xcf, 0x91, + 0x44, 0x63, 0x4b, 0x32, 0x52, 0xbb, 0x74, 0xb8, 0xaa, 0x16, 0x1f, 0xd5, + 0xa9, 0x92, 0xde, 0x8f, 0x95, 0xf2, 0xf7, 0x73, 0x34, 0x27, 0x26, 0x41, + 0x88, 0xb5, 0x7c, 0xf0, 0xff, 0x9c, 0xd3, 0xc8, 0x1d, 0xec +}; +unsigned int default_certificate_len = 406; diff --git a/ssl/crypto.h b/ssl/crypto.h new file mode 100644 index 000000000..df25e6402 --- /dev/null +++ b/ssl/crypto.h @@ -0,0 +1,292 @@ +/* + * Copyright(C) 2006 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @file crypto.h + */ + +#ifndef HEADER_CRYPTO_H +#define HEADER_CRYPTO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bigint.h" + +/************************************************************************** + * AES declarations + **************************************************************************/ + +#define AES_MAXROUNDS 14 + +typedef struct aes_key_st +{ + uint16_t rounds; + uint16_t key_size; + uint32_t ks[(AES_MAXROUNDS+1)*8]; + uint8_t iv[16]; +} 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 +{ + int 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 SHA1Init(SHA1_CTX *); +void SHA1Update(SHA1_CTX *, const uint8_t * msg, int len); +void SHA1Final(SHA1_CTX *, uint8_t *digest); + +/************************************************************************** + * MD5 declarations + **************************************************************************/ + +/* MD5 context. */ + +#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; + +void MD5Init(MD5_CTX *); +void MD5Update(MD5_CTX *, const uint8_t *msg, int len); +void MD5Final(MD5_CTX *, uint8_t *digest); + +/************************************************************************** + * 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); + +/************************************************************************** + * RNG declarations + **************************************************************************/ +void RNG_initialize(const uint8_t *seed_buf, int size); +void RNG_terminate(void); +void get_random(int num_rand_bytes, uint8_t *rand_data); +void get_random_NZ(int num_rand_bytes, uint8_t *rand_data); + +/************************************************************************** + * 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; + bigint *sig_m; /* signature modulus */ + 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(RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, + int is_decryption); +bigint *RSA_private(RSA_CTX *c, bigint *bi_msg); +#ifdef CONFIG_SSL_CERT_VERIFICATION +bigint *RSA_raw_sign_verify(RSA_CTX *c, bigint *bi_msg); +bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, + bigint *modulus, bigint *pub_exp); +bigint *RSA_public(RSA_CTX *c, bigint *bi_msg); +int RSA_encrypt(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 + +/************************************************************************** + * ASN1 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_TYPE 2 + +#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_SEQUENCE 0x30 +#define ASN1_SET 0x31 +#define ASN1_IMPLICIT_TAG 0x80 +#define ASN1_EXPLICIT_TAG 0xa0 + +#define SALT_SIZE 8 + +struct _x509_ctx +{ + char *ca_cert_dn[X509_NUM_DN_TYPES]; + char *cert_dn[X509_NUM_DN_TYPES]; +#if defined(_WIN32_WCE) + long not_before; + long not_after; +#else + time_t not_before; + time_t not_after; +#endif + 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 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 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); +const uint8_t *x509_get_signature(const uint8_t *asn1_signature, int *len); +#endif +#ifdef CONFIG_SSL_FULL_MODE +void x509_print(CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert); +void x509_display_error(int error); +#endif + +/************************************************************************** + * MISC declarations + **************************************************************************/ + +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); + +typedef struct +{ + uint8_t *data; + int max_len; + int index; +} BUF_MEM; + +BUF_MEM buf_new(void); +void buf_grow(BUF_MEM *bm, int len); +void buf_free(BUF_MEM *bm); +int get_file(const char *filename, uint8_t **buf); + +#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG) +void print_blob(const char *format, const uint8_t *data, int size, ...); +#else + #define print_blob(...) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ssl/crypto_misc.c b/ssl/crypto_misc.c new file mode 100644 index 000000000..b98181f02 --- /dev/null +++ b/ssl/crypto_misc.c @@ -0,0 +1,307 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/** + * @file misc.c + * + * Some misc. routines to help things out + */ + +#include +#include +#include +#include +#include "crypto.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"; + +/** + * Allocate a new memory buffer + */ +BUF_MEM buf_new() +{ + BUF_MEM bm; + bm.data = (uint8_t *)malloc(2048); /* should be enough to start with */ + bm.max_len = 2048; + bm.index = 0; + return bm; +} + +/** + * Grow a buffer if necessary + */ +void buf_grow(BUF_MEM *bm, int len) +{ + if (len <= bm->max_len) + { + return; + } + + bm->data = (uint8_t *)realloc(bm->data, len+1024); /* just to be sure */ + bm->max_len = len+1024; +} + +/** + * Free a buffer + */ +void buf_free(BUF_MEM *bm) +{ + free(bm->data); + bm->data = NULL; +} + +#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) + { + 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. + */ +void RNG_initialize(const uint8_t *seed_buf, int size) +{ + if (rng_ref_count == 0) + { +#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM) + if ((rng_fd = open("/dev/urandom", O_RDONLY)) < 0) + { + printf(unsupported_str); + exit(1); + } +#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB) + if (!CryptAcquireContext(&gCryptProv, + NULL, NULL, PROV_RSA_FULL, 0)) + { + printf("%s CryptoLib %x", 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. + */ +void 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 + */ +void 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 + */ +void 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 */ +void print_blob(const char *format, const unsigned char *data, + int size, ...) {} +#endif + diff --git a/ssl/hmac.c b/ssl/hmac.c new file mode 100644 index 000000000..289892a48 --- /dev/null +++ b/ssl/hmac.c @@ -0,0 +1,90 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/** + * @file hmac.c + * + * HMAC implementation - This code was originally taken from RFC2104 + */ + +#include +#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; + } + + MD5Init(&context); + MD5Update(&context, k_ipad, 64); + MD5Update(&context, msg, length); + MD5Final(&context, digest); + MD5Init(&context); + MD5Update(&context, k_opad, 64); + MD5Update(&context, digest, MD5_SIZE); + MD5Final(&context, digest); +} + +/** + * 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; + } + + SHA1Init(&context); + SHA1Update(&context, k_ipad, 64); + SHA1Update(&context, msg, length); + SHA1Final(&context, digest); + SHA1Init(&context); + SHA1Update(&context, k_opad, 64); + SHA1Update(&context, digest, SHA1_SIZE); + SHA1Final(&context, digest); +} diff --git a/ssl/loader.c b/ssl/loader.c new file mode 100644 index 000000000..5f43d4982 --- /dev/null +++ b/ssl/loader.c @@ -0,0 +1,450 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/** + * 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 +#include +#include + +#include "ssl.h" + +static int do_obj(SSLCTX *ssl_ctx, int obj_type, + SSLObjLoader *ssl_obj, const char *password); +#ifdef CONFIG_SSL_HAS_PEM +static int ssl_obj_PEM_load(SSLCTX *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(SSLCTX *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(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(SSLCTX *ssl_ctx, int mem_type, + const uint8_t *data, int len, const char *password) +{ + int ret; + + SSLObjLoader *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(SSLCTX *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; +} + +/* + * Release things. + */ +void ssl_obj_free(SSLObjLoader *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 + +/* 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 +}; + +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," +}; + +static int base64_decode(const uint8_t *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; + + *outlen = z; + ret = 0; + +error: +#ifdef CONFIG_SSL_FULL_MODE + if (ret < 0) + { + printf("Error: Invalid base64 file\n"); + } +#endif + return ret; +} + +/** + * Take a base64 blob of data and decrypt it (using AES) into its + * proper ASN.1 form. + */ +static int pem_decrypt(const uint8_t *where, const uint8_t *end, + const char *password, SSLObjLoader *ssl_obj) +{ + int ret = -1; + int is_aes_256 = 0; + uint8_t *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) + { +#ifdef CONFIG_SSL_FULL_MODE + printf("Error: need a password for this PEM file\n"); +#endif + goto error; + } + + if ((start = (uint8_t *)strstr( + (const char *)where, aes_str[0]))) /* AES128? */ + { + start += strlen(aes_str[0]); + } + else if ((start = (uint8_t *)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"); +#endif + goto error; + } + + /* convert from hex to binary - assumes uppercase hex */ + for (i = 0; i < IV_SIZE; i++) + { + uint8_t 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 */ + MD5Init(&md5_ctx); + MD5Update(&md5_ctx, (const uint8_t *)password, strlen(password)); + MD5Update(&md5_ctx, iv, SALT_SIZE); + MD5Final(&md5_ctx, key); + + if (is_aes_256) + { + MD5Init(&md5_ctx); + MD5Update(&md5_ctx, key, MD5_SIZE); + MD5Update(&md5_ctx, (const uint8_t *)password, strlen(password)); + MD5Update(&md5_ctx, iv, SALT_SIZE); + MD5Final(&md5_ctx, &key[MD5_SIZE]); + } + + /* 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(SSLCTX *ssl_ctx, int is_cacert, uint8_t *where, + int remain, const char *password) +{ + int ret = SSL_OK; + SSLObjLoader *ssl_obj = NULL; + int i, pem_size, obj_type; + uint8_t *start = NULL, *end = NULL; + + for (i = 0; i < NUM_PEM_TYPES; i++) + { + if ((start = (uint8_t *)strstr((const char *)where, begins[i])) && + (end = (uint8_t *)strstr((const char *)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((const char *)start, "Proc-Type:") && + strstr((const char *)start, "4,ENCRYPTED")) + { + /* check for encrypted PEM file */ + if ((pem_size = 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; + } + + /* In a format we can now understand - so process it */ + if ((ret = do_obj(ssl_ctx, obj_type, ssl_obj, password))) + { + ssl_obj_free(ssl_obj); + goto error; + } + + end += strlen(ends[i]); + remain -= strlen(ends[i]); + while (remain > 0 && (*end == '\r' || *end == '\n')) + { + end++; + remain--; + } + + ssl_obj_free(ssl_obj); + 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: + return ret; +} + +/* + * Load a file into memory that is in ASCII PEM format. + */ +static int ssl_obj_PEM_load(SSLCTX *ssl_ctx, int obj_type, + SSLObjLoader *ssl_obj, const char *password) +{ + uint8_t *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 = 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 */ diff --git a/ssl/md5.c b/ssl/md5.c new file mode 100644 index 000000000..95adab864 --- /dev/null +++ b/ssl/md5.c @@ -0,0 +1,288 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/** + * @file md5.c + * + * This file implements the MD5 algorithm as defined in RFC1321 + */ + +#include +#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 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. + */ +void MD5Init(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. + */ +void MD5Update(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 + */ +void MD5Final(MD5_CTX *ctx, uint8_t *digest) +{ + 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); + MD5Update(ctx, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update(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; + + /* Zeroize sensitive information. + */ + memset(x, 0, sizeof(x)); +} + +/** + * 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); +} diff --git a/ssl/os_port.c b/ssl/os_port.c new file mode 100644 index 000000000..b278c4a29 --- /dev/null +++ b/ssl/os_port.c @@ -0,0 +1,61 @@ +/* + * Copyright(C) 2006 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @file os_port.c + * + * OS specific functions. + */ +#ifdef WIN32 + +#include +#include "os_port.h" + +/** + * gettimeofday() not in Win32 + */ +EXP_FUNC void 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 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); +} + +#endif diff --git a/ssl/os_port.h b/ssl/os_port.h new file mode 100644 index 000000000..73f4d9be2 --- /dev/null +++ b/ssl/os_port.h @@ -0,0 +1,145 @@ +/* + * Copyright(C) 2006 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @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 + +#if defined(WIN32) || defined(CYGWIN) +#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 +#define abort() exit(1) +#else +#include +#include +#include +#include +#endif /* _WIN32_WCE */ + +#include +#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 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 lseek(A,B,C) _lseek(A,B,C) +#define strdup(A) _strdup(A) + +/* 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") + +#ifdef CONFIG_WIN32_USE_CRYPTO_LIB +#pragma comment(lib, "AdvAPI32.lib") +#endif + +#define uint8_t unsigned char +#define uint16_t unsigned short +#ifndef INT16 +typedef signed short INT16; +#endif + +#define int16_t INT16 +#define uint32_t UINT32 +#define uint64_t UINT64 +#define int64_t INT64 + +extern EXP_FUNC void gettimeofday(struct timeval* t,void* timezone); +extern EXP_FUNC int strcasecmp(const char *s1, const char *s2); + +#else /* Not Win32 */ + +#ifdef SOLARIS +#include +#else +#include +#endif /* Not Solaris */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 TTY_FLUSH() + +#endif /* Not Win32 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ssl/p12.c b/ssl/p12.c new file mode 100644 index 000000000..ec84b8b14 --- /dev/null +++ b/ssl/p12.c @@ -0,0 +1,431 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/** + * 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 +#include +#include + +#include "ssl.h" + +/* all commented out if not used */ +#ifdef CONFIG_SSL_USE_PKCS12 + +#define BLOCK_SIZE 64 + +static int p8_decrypt(const char *password, const uint8_t *salt, int iter, + uint8_t *priv_key, int priv_key_len); +static int p8_add_key(SSLCTX *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(SSLCTX *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; + + 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(password, salt, iterations, priv_key, len); + ret = p8_add_key(ssl_ctx, priv_key); + +error: + free(version); + return ret; +} + +/* + * Take the unencrypted pkcs8 and turn it into a private key + */ +static int p8_add_key(SSLCTX *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; +} + +/* + * Decrypt a pkcs8 block. + */ +static int p8_decrypt(const char *password, const uint8_t *salt, int iter, + uint8_t *priv_key, int priv_key_len) +{ + uint8_t p[BLOCK_SIZE*2]; + uint8_t d[BLOCK_SIZE]; + uint8_t Ai[SHA1_SIZE]; + SHA1_CTX sha_ctx; + RC4_CTX rc4_ctx; + uint8_t *uni_pass = NULL; + int i; + int uni_pass_len = 0; + int id = 1; /* key id */ + + if (password == NULL) + { + password = ""; + } + + uni_pass = (uint8_t *)malloc((strlen(password)+1)*2); + + /* modify the password into a unicode version */ + for (i = 0; i < (int)strlen(password); i++) + { + uni_pass[uni_pass_len++] = 0; + uni_pass[uni_pass_len++] = password[i]; + } + + uni_pass[uni_pass_len++] = 0; /* null terminate */ + uni_pass[uni_pass_len++] = 0; + + 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 */ + SHA1Init(&sha_ctx); + SHA1Update(&sha_ctx, d, sizeof(d)); + SHA1Update(&sha_ctx, p, sizeof(p)); + SHA1Final(&sha_ctx, Ai); + + for (i = 1; i < iter; i++) + { + SHA1Init(&sha_ctx); + SHA1Update(&sha_ctx, Ai, SHA1_SIZE); + SHA1Final(&sha_ctx, Ai); + } + + /* do the decryption */ + RC4_setup(&rc4_ctx, Ai, 16); + RC4_crypt(&rc4_ctx, priv_key, priv_key, priv_key_len); + free(uni_pass); + return 0; +} + +/* + * Take a raw pkcs12 block and the decrypt it and turn it into a certificates + * and keys. + */ +int pkcs12_decode(SSLCTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password) +{ + uint8_t *buf = ssl_obj->buf; + int all_ok = 0, len, iterations, key_offset, offset = 0; + int all_certs = 0; + uint8_t *version = NULL, *cert, *mac; + SHA1_CTX sha_ctx; + char sha[SHA1_SIZE]; + const uint8_t *salt; + int ret; + 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) + goto error; + + /* work out the MAC of this bit */ + key_offset = offset; + asn1_skip_obj(buf, &key_offset, ASN1_SEQUENCE); + SHA1Init(&sha_ctx); + SHA1Update(&sha_ctx, &buf[offset], key_offset-offset); + SHA1Final(&sha_ctx, sha); + + /* 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 || + 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(password, salt, iterations, cert, len)) < 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; + + asn1_skip_obj(cert, &cert_offset, ASN1_SEQUENCE); + + if (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(password, salt, iterations, cert, len)) < 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; + + 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(password, salt, iterations, mac, SHA1_SIZE)) < 0) + goto error; + + /* TODO: actually memcmp the MAC - there is something wrong at the moment */ + /* print_blob("MAC orig", sha, SHA1_SIZE); */ + /* print_blob("MAC calc", mac, SHA1_SIZE); */ + + all_ok = 1; + +error: + free(version); + return all_ok ? SSL_OK : SSL_ERROR_NOT_SUPPORTED; +} + +/* + * 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, ret = SSL_NOT_OK; + uint8_t *iter = NULL; + + /* 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 agorithm 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 + ret = SSL_ERROR_NOT_SUPPORTED; + 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); + ret = SSL_OK; /* got here - we are ok */ + +error: + return ret; +} + +#endif diff --git a/ssl/private_key.h b/ssl/private_key.h new file mode 100644 index 000000000..180d5722d --- /dev/null +++ b/ssl/private_key.h @@ -0,0 +1,30 @@ +unsigned char default_private_key[] = { + 0x30, 0x82, 0x01, 0x3d, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xd1, 0x3b, + 0x30, 0x5f, 0xa9, 0x01, 0x42, 0x3d, 0x86, 0x6d, 0x72, 0xbe, 0x40, 0x6e, + 0x51, 0xc1, 0x49, 0x7f, 0x57, 0x75, 0xa1, 0x2d, 0x36, 0xe5, 0xc1, 0x3d, + 0x0f, 0x20, 0x1a, 0xd1, 0x23, 0x6d, 0xfa, 0x74, 0xd2, 0x3e, 0x23, 0xb0, + 0x70, 0xfc, 0xa0, 0x6a, 0xde, 0xec, 0x41, 0x88, 0x84, 0xfe, 0x54, 0x15, + 0x6b, 0x61, 0xc5, 0x16, 0x62, 0xb8, 0x93, 0x41, 0xf1, 0x4f, 0x3d, 0xff, + 0x2e, 0xbd, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x41, 0x00, 0x91, 0x79, + 0xc4, 0xed, 0x8e, 0x35, 0xa8, 0xd7, 0xdc, 0x62, 0xb6, 0xf8, 0x1f, 0x16, + 0x55, 0x53, 0xbe, 0x05, 0x83, 0x4a, 0xef, 0x50, 0xdf, 0xad, 0xa9, 0xc9, + 0x09, 0x7e, 0x3a, 0x07, 0x15, 0xc8, 0xfd, 0x16, 0xbb, 0xc0, 0xe4, 0x98, + 0xd1, 0x45, 0x99, 0x60, 0x75, 0x6c, 0x64, 0x65, 0x89, 0xc7, 0x1e, 0x35, + 0xa2, 0xcd, 0x14, 0x05, 0x38, 0x39, 0x15, 0x1a, 0xb8, 0x0f, 0x05, 0x96, + 0x01, 0x01, 0x02, 0x21, 0x00, 0xe8, 0xeb, 0xd7, 0xa8, 0xdf, 0xd8, 0x90, + 0xaa, 0x3c, 0x21, 0xa4, 0x04, 0x31, 0x6a, 0xd3, 0x21, 0xd8, 0x25, 0x98, + 0x4f, 0xb8, 0x28, 0x93, 0x2b, 0xb9, 0xe9, 0x5f, 0xb9, 0xa3, 0x65, 0x77, + 0x7d, 0x02, 0x21, 0x00, 0xe5, 0xf6, 0x6f, 0xeb, 0x50, 0xc4, 0x3b, 0x01, + 0xc3, 0x42, 0x7d, 0x50, 0x33, 0x7a, 0x09, 0xdc, 0x08, 0xe5, 0x76, 0xf3, + 0xbd, 0xea, 0x0f, 0xe5, 0xf1, 0xd3, 0x3d, 0x2f, 0x63, 0xe2, 0xb8, 0x41, + 0x02, 0x21, 0x00, 0xdd, 0xcf, 0xb2, 0xe9, 0x9c, 0x7a, 0x75, 0x91, 0xd8, + 0x7f, 0xc4, 0xdd, 0x45, 0x5e, 0x50, 0xc0, 0x3b, 0x41, 0xda, 0x21, 0x98, + 0xe3, 0xf2, 0xfb, 0x42, 0x29, 0xaf, 0xc2, 0x6e, 0x8b, 0x73, 0x55, 0x02, + 0x21, 0x00, 0xc3, 0x5d, 0x6a, 0xd5, 0xb2, 0x87, 0x13, 0x4e, 0x3b, 0x11, + 0x78, 0x9e, 0xb3, 0x2c, 0xe1, 0xc5, 0x72, 0x35, 0x67, 0xaa, 0x49, 0x54, + 0xd9, 0x6e, 0xd3, 0xd4, 0x4f, 0x2d, 0xbc, 0xa1, 0x37, 0x41, 0x02, 0x21, + 0x00, 0xc4, 0x69, 0x08, 0x53, 0x3b, 0x32, 0xb4, 0xb6, 0x6b, 0x1b, 0x9c, + 0xf3, 0xf1, 0xf3, 0x1a, 0x4a, 0x96, 0xff, 0x70, 0x25, 0x20, 0x1a, 0x9d, + 0x65, 0xb8, 0xa5, 0x8f, 0x9c, 0xc7, 0x77, 0x64, 0x74 +}; +unsigned int default_private_key_len = 321; diff --git a/ssl/rc4.c b/ssl/rc4.c new file mode 100644 index 000000000..a9ce82ccb --- /dev/null +++ b/ssl/rc4.c @@ -0,0 +1,83 @@ +/* + * Copyright(C) 2006 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @file rc4.c + * + * An implementation of the RC4/ARC4 algorithm + * + * Originally written by Christophe Devine + */ + +#include +#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, *m, a; + + 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, x, y, *m, a, b; + out = (uint8_t *)msg; + + x = ctx->x; + y = ctx->y; + m = ctx->m; + + for (i = 0; i < length; i++) + { + x =(uint8_t)(x + 1); a = m[x]; + y =(uint8_t)(y + a); + m[x] = b = m[y]; + m[y] = a; + out[i] ^= m[(uint8_t)(a + b)]; + } + + ctx->x = x; + ctx->y = y; +} diff --git a/ssl/rsa.c b/ssl/rsa.c new file mode 100644 index 000000000..c6fe654cb --- /dev/null +++ b/ssl/rsa.c @@ -0,0 +1,337 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/** + * @file rsa.c + * + * Implements the RSA public encryption algorithm. Uses the bigint library to + * perform its calculations. + */ + +#include +#include +#include +#include +#include "crypto.h" + +#ifdef CONFIG_BIGINT_CRT +static bigint *bi_crt(RSA_CTX *rsa, bigint *bi); +#endif + +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 = bi_initialize(); + *ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX)); /* reset to all 0 */ + 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); +} + +/** + * @fn int RSA_decrypt(RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data) + * @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(RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, + int is_decryption) +{ + int byte_size = ctx->num_octets; + uint8_t *block; + int i, size; + bigint *decrypted_bi, *dat_bi; + + 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 */ + block = (uint8_t *)malloc(byte_size); + 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); + } + + free(block); + return size ? size : -1; +} + +/** + * @fn bigint *RSA_private(RSA_CTX *c, bigint *bi_msg) + * Performs m = c^d mod n + */ +bigint *RSA_private(RSA_CTX *c, bigint *bi_msg) +{ +#ifdef CONFIG_BIGINT_CRT + return bi_crt(c, bi_msg); +#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_BIGINT_CRT +/** + * Use the Chinese Remainder Theorem to quickly perform RSA decrypts. + * This should really be in bigint.c (and was at one stage), but needs + * access to the RSA_CTX context... + */ +static bigint *bi_crt(RSA_CTX *rsa, bigint *bi) +{ + BI_CTX *ctx = rsa->bi_ctx; + 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), rsa->dP); + + ctx->mod_offset = BIGINT_Q_OFFSET; + m2 = bi_mod_power(ctx, bi, rsa->dQ); + + h = bi_subtract(ctx, bi_add(ctx, m1, rsa->p), bi_copy(m2), NULL); + h = bi_multiply(ctx, h, rsa->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, rsa->q, h)); +} +#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 + +#ifdef CONFIG_SSL_CERT_VERIFICATION +/** + * Performs c = m^e mod n + */ +bigint *RSA_public(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(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); + return byte_size; +} + +/** + * Take a signature and decrypt it. + */ +bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, + bigint *modulus, bigint *pub_exp) +{ + uint8_t *block = (uint8_t *)malloc(sig_len); + int i, size; + bigint *decrypted_bi, *dat_bi; + bigint *bir = NULL; + + /* 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 = x509_get_signature(&block[i], &len); + + if (sig_ptr) + { + bir = bi_import(ctx, sig_ptr, len); + } + } + + free(block); + return bir; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ diff --git a/ssl/sha1.c b/ssl/sha1.c new file mode 100644 index 000000000..e1d259c6e --- /dev/null +++ b/ssl/sha1.c @@ -0,0 +1,244 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/** + * @file sha1.c + * + * SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995. + * This code was originally taken from RFC3174 + */ + +#include +#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 SHA1Init(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 SHA1Update(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 SHA1Final(SHA1_CTX *ctx, uint8_t *digest) +{ + 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); +} diff --git a/ssl/ssl.h b/ssl/ssl.h new file mode 100644 index 000000000..687104e62 --- /dev/null +++ b/ssl/ssl.h @@ -0,0 +1,416 @@ +/* + * Copyright(C) 2006 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @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 and Perl. + * - A very small footprint for a HTTPS server (around 50-60kB 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 +#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. + * 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 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 availabile if verification has been enabled. + * - SSL_NO_DEFAULT_KEY: Don't use the default key/certificate. The user will + * load the key/certificate explicitly. + * - 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 SSLCTX * 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(SSLCTX *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(SSLCTX *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. + * @return An SSL object reference. Use ssl_handshake_status() to check + * if a handshake succeeded. + */ +EXP_FUNC SSL * STDCALL ssl_client_new(SSLCTX *ssl_ctx, int client_fd, const uint8_t *session_id); + +/** + * @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. + * @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. + * @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(SSLCTX *ssl_ctx, int client_fd); + +/** + * @brief Get the session id for a handshake. + * + * This will be a 32 byte sequence and is availabile 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(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(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(SSL *ssl); + +/** + * @brief Retrieve various parameters about the TLS 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(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 mode must be enabled. + */ +EXP_FUNC const char * STDCALL ssl_get_cert_dn(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). + * @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 mode. + */ +EXP_FUNC int STDCALL ssl_obj_load(SSLCTX *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(SSLCTX *ssl_ctx, int obj_type, const uint8_t *data, int len, const char *password); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ssl/test/Makefile b/ssl/test/Makefile new file mode 100644 index 000000000..ddf3526b9 --- /dev/null +++ b/ssl/test/Makefile @@ -0,0 +1,65 @@ +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +all: + +include ../../config/.config +include ../../config/makefile.conf + +ifdef CONFIG_PERFORMANCE_TESTING +all: performance +endif + +ifdef CONFIG_SSL_TEST +all: ssltesting +endif + +ifndef CONFIG_PLATFORM_WIN32 +performance: ../../perf_bigint +ssltesting: ../../ssltest +LIBS=../../libaxtls.a +CFLAGS += -I../../ssl -I../../config + +../../perf_bigint: perf_bigint.o $(LIBS) + $(CC) $(LDFLAGS) -o $@ $^ + +../../ssltest: ssltest.o $(LIBS) + $(CC) $(LDFLAGS) -o $@ -lpthread $^ +else +performance: ../../perf_bigint.exe +ssltesting: ../../ssltest.exe +CFLAGS += /I".." /I"../../config" + +%.obj : %.c + $(CC) $(CFLAGS) $< + +OBJLIST=..\aes.obj ..\asn1.obj ..\bigint.obj ..\crypto_misc.obj ..\hmac.obj \ + ..\md5.obj ..\loader.obj ..\p12.obj ..\os_port.obj ..\rc4.obj \ + ..\rsa.obj ..\sha1.obj ..\tls1.obj ..\tls1_clnt.obj ..\tls1_svr.obj + +../../perf_bigint.exe: perf_bigint.obj $(OBJLIST) + $(LD) $(LDFLAGS) /out:$@ $^ + +../../ssltest.exe: ssltest.obj $(OBJLIST) + $(LD) $(LDFLAGS) /out:$@ $^ +endif + +clean:: + -@rm -f ../../perf_bigint* ../../ssltest* + +include ../../config/makefile.post diff --git a/ssl/test/axTLS.ca_key.pem b/ssl/test/axTLS.ca_key.pem new file mode 100644 index 000000000..7c8ac8af2 --- /dev/null +++ b/ssl/test/axTLS.ca_key.pem @@ -0,0 +1,15 @@ +-----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----- diff --git a/ssl/test/axTLS.ca_x509.cer b/ssl/test/axTLS.ca_x509.cer new file mode 100644 index 000000000..9c9936b8e Binary files /dev/null and b/ssl/test/axTLS.ca_x509.cer differ diff --git a/ssl/test/axTLS.ca_x509.pem b/ssl/test/axTLS.ca_x509.pem new file mode 100644 index 000000000..86f659710 --- /dev/null +++ b/ssl/test/axTLS.ca_x509.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB3zCCAUgCCQCdbnM4pjqlWjANBgkqhkiG9w0BAQUFADA0MTIwMAYDVQQKEylh +eFRMUyBQcm9qZWN0IERvZGd5IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNjA2 +MDcxMTQ0MzJaFw0zMzEwMjMxMTQ0MzJaMDQxMjAwBgNVBAoTKWF4VExTIFByb2pl +Y3QgRG9kZ3kgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQCnZdk20fYWh8O6kDTt0AuJWyp0YIrb7W1UNNMPXI5wA4J59IVj +Nmk5wocm9+Hqzbg7rORAN/mHPBhzLAjhnm1HODs36hW15DtbDkkH4wCM/Tsyv79m +n0xq1V6peK3t9vi2D4p/IRjHkYR2jm+BeknopijhY0kHHfpGTHa2DnVirwIDAQAB +MA0GCSqGSIb3DQEBBQUAA4GBAB0LgNo0oCcwIie5plgwwFybQ8x95q6e3wndM/Mp +3gjcAFbGuchpo3dfFlTcRI0KyERb3q1MVxPM4sff9nT7EdHVyK9s8/ITkP2dcTKc +flbcTEfJVIeM8L2P5F41Hvn9GuGcMW8EmsC06gdbp1LLnqsdrXdMNBsAUBXfgPrU ++UcZ +-----END CERTIFICATE----- diff --git a/ssl/test/axTLS.device_key b/ssl/test/axTLS.device_key new file mode 100644 index 000000000..4e981d143 Binary files /dev/null and b/ssl/test/axTLS.device_key differ diff --git a/ssl/test/axTLS.device_key.pem b/ssl/test/axTLS.device_key.pem new file mode 100644 index 000000000..2bcf5e37b --- /dev/null +++ b/ssl/test/axTLS.device_key.pem @@ -0,0 +1,15 @@ +-----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----- diff --git a/ssl/test/axTLS.encrypted.p8 b/ssl/test/axTLS.encrypted.p8 new file mode 100644 index 000000000..8b0a7eb41 Binary files /dev/null and b/ssl/test/axTLS.encrypted.p8 differ diff --git a/ssl/test/axTLS.encrypted_pem.p8 b/ssl/test/axTLS.encrypted_pem.p8 new file mode 100644 index 000000000..19ca3c5ea --- /dev/null +++ b/ssl/test/axTLS.encrypted_pem.p8 @@ -0,0 +1,11 @@ +-----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----- diff --git a/ssl/test/axTLS.key_1024 b/ssl/test/axTLS.key_1024 new file mode 100644 index 000000000..5b6ba1d03 Binary files /dev/null and b/ssl/test/axTLS.key_1024 differ diff --git a/ssl/test/axTLS.key_1024.pem b/ssl/test/axTLS.key_1024.pem new file mode 100644 index 000000000..4f5ad4ece --- /dev/null +++ b/ssl/test/axTLS.key_1024.pem @@ -0,0 +1,15 @@ +-----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----- diff --git a/ssl/test/axTLS.key_2048 b/ssl/test/axTLS.key_2048 new file mode 100644 index 000000000..0af642de2 Binary files /dev/null and b/ssl/test/axTLS.key_2048 differ diff --git a/ssl/test/axTLS.key_2048.pem b/ssl/test/axTLS.key_2048.pem new file mode 100644 index 000000000..beddb721b --- /dev/null +++ b/ssl/test/axTLS.key_2048.pem @@ -0,0 +1,27 @@ +-----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----- diff --git a/ssl/test/axTLS.key_4096 b/ssl/test/axTLS.key_4096 new file mode 100644 index 000000000..c205382ab Binary files /dev/null and b/ssl/test/axTLS.key_4096 differ diff --git a/ssl/test/axTLS.key_4096.pem b/ssl/test/axTLS.key_4096.pem new file mode 100644 index 000000000..9929467f4 --- /dev/null +++ b/ssl/test/axTLS.key_4096.pem @@ -0,0 +1,51 @@ +-----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----- diff --git a/ssl/test/axTLS.key_512 b/ssl/test/axTLS.key_512 new file mode 100644 index 000000000..7ae50f23b Binary files /dev/null and b/ssl/test/axTLS.key_512 differ diff --git a/ssl/test/axTLS.key_512.pem b/ssl/test/axTLS.key_512.pem new file mode 100644 index 000000000..1e2fb41f8 --- /dev/null +++ b/ssl/test/axTLS.key_512.pem @@ -0,0 +1,9 @@ +-----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----- diff --git a/ssl/test/axTLS.key_aes128.pem b/ssl/test/axTLS.key_aes128.pem new file mode 100644 index 000000000..8961bd9a5 --- /dev/null +++ b/ssl/test/axTLS.key_aes128.pem @@ -0,0 +1,12 @@ +-----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----- diff --git a/ssl/test/axTLS.key_aes256.pem b/ssl/test/axTLS.key_aes256.pem new file mode 100644 index 000000000..7671a302f --- /dev/null +++ b/ssl/test/axTLS.key_aes256.pem @@ -0,0 +1,12 @@ +-----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----- diff --git a/ssl/test/axTLS.noname.p12 b/ssl/test/axTLS.noname.p12 new file mode 100644 index 000000000..9d27999fa Binary files /dev/null and b/ssl/test/axTLS.noname.p12 differ diff --git a/ssl/test/axTLS.unencrypted.p8 b/ssl/test/axTLS.unencrypted.p8 new file mode 100644 index 000000000..d04694b1f Binary files /dev/null and b/ssl/test/axTLS.unencrypted.p8 differ diff --git a/ssl/test/axTLS.unencrypted_pem.p8 b/ssl/test/axTLS.unencrypted_pem.p8 new file mode 100644 index 000000000..e07375a84 --- /dev/null +++ b/ssl/test/axTLS.unencrypted_pem.p8 @@ -0,0 +1,10 @@ +-----BEGIN PRIVATE KEY----- +MIIBVwIBADANBgkqhkiG9w0BAQEFAASCAUEwggE9AgEAAkEA0TswX6kBQj2GbXK+ +QG5RwUl/V3WhLTblwT0PIBrRI236dNI+I7Bw/KBq3uxBiIT+VBVrYcUWYriTQfFP +Pf8uvQIDAQABAkEAkXnE7Y41qNfcYrb4HxZVU74Fg0rvUN+tqckJfjoHFcj9FrvA +5JjRRZlgdWxkZYnHHjWizRQFODkVGrgPBZYBAQIhAOjr16jf2JCqPCGkBDFq0yHY +JZhPuCiTK7npX7mjZXd9AiEA5fZv61DEOwHDQn1QM3oJ3AjldvO96g/l8dM9L2Pi +uEECIQDdz7LpnHp1kdh/xN1FXlDAO0HaIZjj8vtCKa/CbotzVQIhAMNdatWyhxNO +OxF4nrMs4cVyNWeqSVTZbtPUTy28oTdBAiEAxGkIUzsytLZrG5zz8fMaSpb/cCUg +Gp1luKWPnMd3ZHQ= +-----END PRIVATE KEY----- diff --git a/ssl/test/axTLS.withCA.p12 b/ssl/test/axTLS.withCA.p12 new file mode 100644 index 000000000..ae029dee0 Binary files /dev/null and b/ssl/test/axTLS.withCA.p12 differ diff --git a/ssl/test/axTLS.withoutCA.p12 b/ssl/test/axTLS.withoutCA.p12 new file mode 100644 index 000000000..c4eb54c44 Binary files /dev/null and b/ssl/test/axTLS.withoutCA.p12 differ diff --git a/ssl/test/axTLS.withoutCA.ya b/ssl/test/axTLS.withoutCA.ya new file mode 100644 index 000000000..9e1bd632a Binary files /dev/null and b/ssl/test/axTLS.withoutCA.ya differ diff --git a/ssl/test/axTLS.x509_1024.cer b/ssl/test/axTLS.x509_1024.cer new file mode 100644 index 000000000..fc92d0564 Binary files /dev/null and b/ssl/test/axTLS.x509_1024.cer differ diff --git a/ssl/test/axTLS.x509_1024.pem b/ssl/test/axTLS.x509_1024.pem new file mode 100644 index 000000000..81f3eaf1c --- /dev/null +++ b/ssl/test/axTLS.x509_1024.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB1zCCAUACCQDxw4fA1PRXwzANBgkqhkiG9w0BAQUFADA0MTIwMAYDVQQKEylh +eFRMUyBQcm9qZWN0IERvZGd5IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNjA2 +MDcxMTQ0MzJaFw0zMzEwMjMxMTQ0MzJaMCwxFjAUBgNVBAoTDWF4VExTIFByb2pl +Y3QxEjAQBgNVBAMTCTEyNy4wLjAuMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC +gYEA2OC/Fd7qr+jV/QuoqLPXRl2nJmwMtdm8xvjAeND2VmX4KUgOewumJX7oe3lv +OOW1t/TgnJFg9AbzQB75kRmpL0dDtZse3PaqHEl5ISjLqklz2QkFTALyTE1sHICn +FJFE/BKz4efjT0S6jMN0OehM0NRMJGG0QJWMwAq3AjkxhZMCAwEAATANBgkqhkiG +9w0BAQUFAAOBgQALRyRSfbZjeLyA3YdskEwzw1ynlwkcCU+bbrNaPkaSGseHFVnh +iFzOauKWqjLswu14i+CQZpMUw5irMzXTfV1RCpy5EFhHepiVZP9MXYIZ+eoPXprL +Midkym9YitDANvS5YzSl2jZQNknStzohM1s+1l8MmYO3sveLRMRec0GpAg== +-----END CERTIFICATE----- diff --git a/ssl/test/axTLS.x509_2048.cer b/ssl/test/axTLS.x509_2048.cer new file mode 100644 index 000000000..c0badf728 Binary files /dev/null and b/ssl/test/axTLS.x509_2048.cer differ diff --git a/ssl/test/axTLS.x509_2048.pem b/ssl/test/axTLS.x509_2048.pem new file mode 100644 index 000000000..1ed0141af --- /dev/null +++ b/ssl/test/axTLS.x509_2048.pem @@ -0,0 +1,15 @@ +-----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----- diff --git a/ssl/test/axTLS.x509_4096.cer b/ssl/test/axTLS.x509_4096.cer new file mode 100644 index 000000000..40bbe94fd Binary files /dev/null and b/ssl/test/axTLS.x509_4096.cer differ diff --git a/ssl/test/axTLS.x509_4096.pem b/ssl/test/axTLS.x509_4096.pem new file mode 100644 index 000000000..b7aed1cab --- /dev/null +++ b/ssl/test/axTLS.x509_4096.pem @@ -0,0 +1,20 @@ +-----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----- diff --git a/ssl/test/axTLS.x509_512.cer b/ssl/test/axTLS.x509_512.cer new file mode 100644 index 000000000..48c6e13aa Binary files /dev/null and b/ssl/test/axTLS.x509_512.cer differ diff --git a/ssl/test/axTLS.x509_512.pem b/ssl/test/axTLS.x509_512.pem new file mode 100644 index 000000000..8191e489f --- /dev/null +++ b/ssl/test/axTLS.x509_512.pem @@ -0,0 +1,11 @@ +-----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----- diff --git a/ssl/test/axTLS.x509_aes128.pem b/ssl/test/axTLS.x509_aes128.pem new file mode 100644 index 000000000..9a75fe960 --- /dev/null +++ b/ssl/test/axTLS.x509_aes128.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBkjCB/AIJAPHDh8DU9FfHMA0GCSqGSIb3DQEBBQUAMDQxMjAwBgNVBAoTKWF4 +VExTIFByb2plY3QgRG9kZ3kgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTA2MDYw +NzExNDQzMloXDTMzMTAyMzExNDQzMlowLDEWMBQGA1UEChMNYXhUTFMgUHJvamVj +dDESMBAGA1UEAxMJMTI3LjAuMC4xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMDo +g6K2iXFftW+Qk+rrzkMGWrtfY6YSxPstPRrI7akluUEoyWGITXbK6L3QfERrf2eu +CnWyciQiHVRoHC0EgZUCAwEAATANBgkqhkiG9w0BAQUFAAOBgQBT6YhR8x/bBteK +lr8E0l4mATOnYlsmge+z/SFYs4bDBofqlwQCVJXNSBA4ZsEjgP9qIWTu/85QrVGq +LrkewSM6Oeh95LGnE+uhJVtIX++O+Hsex3H1UL067dCG99XmDhqbEU9AI6YSZu2p +cjoSowFELtOoG667+id9QObfV3EQoQ== +-----END CERTIFICATE----- diff --git a/ssl/test/axTLS.x509_aes256.pem b/ssl/test/axTLS.x509_aes256.pem new file mode 100644 index 000000000..4f3074e01 --- /dev/null +++ b/ssl/test/axTLS.x509_aes256.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBkjCB/AIJAPHDh8DU9FfIMA0GCSqGSIb3DQEBBQUAMDQxMjAwBgNVBAoTKWF4 +VExTIFByb2plY3QgRG9kZ3kgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTA2MDYw +NzExNDQzMloXDTMzMTAyMzExNDQzMlowLDEWMBQGA1UEChMNYXhUTFMgUHJvamVj +dDESMBAGA1UEAxMJMTI3LjAuMC4xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANAW +9PdXa5u4gWi5VB5p/eQmOtteRq9/54JkiEs8cVNrTQgZsjjU1LGedE3JwBqZ1EIW +HGPjcGg5dVxFjkn7RekCAwEAATANBgkqhkiG9w0BAQUFAAOBgQBmJMt0Crdd/BPn +EdmzsVXou0zTizTC8wyUPMVpg/KzzP7fhZux/ZIrH9/RVcJd9y+B2/mXc3C+K99+ +TXQoYKsLGArfDPzmpy1wPrdEcB1A9gkWDl1Uq6xRyvrVm3gX8NTITRuGKL9njgWx +2SrApIBtOOUOinYtfH3745cVVl5HOA== +-----END CERTIFICATE----- diff --git a/ssl/test/axTLS.x509_bad_after.pem b/ssl/test/axTLS.x509_bad_after.pem new file mode 100644 index 000000000..79eb9ccd6 --- /dev/null +++ b/ssl/test/axTLS.x509_bad_after.pem @@ -0,0 +1,11 @@ +-----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----- diff --git a/ssl/test/axTLS.x509_bad_before.pem b/ssl/test/axTLS.x509_bad_before.pem new file mode 100644 index 000000000..fe72b541b --- /dev/null +++ b/ssl/test/axTLS.x509_bad_before.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBkjCB/AIJAPHDh8DU9FfJMA0GCSqGSIb3DQEBBQUAMDQxMjAwBgNVBAoTKWF4 +VExTIFByb2plY3QgRG9kZ3kgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTI0MTIz +MTE0MDAwMFoXDTI1MTIzMTE0MDAwMFowLDEWMBQGA1UEChMNYXhUTFMgUHJvamVj +dDESMBAGA1UEAxMJMTI3LjAuMC4xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANE7 +MF+pAUI9hm1yvkBuUcFJf1d1oS025cE9DyAa0SNt+nTSPiOwcPygat7sQYiE/lQV +a2HFFmK4k0HxTz3/Lr0CAwEAATANBgkqhkiG9w0BAQUFAAOBgQApbldYefE8A0ez +SYvAuCtYxx/2KHwBRD/cR0q7widl9WGjVC/dsnbFo109vHEr3FP1HVYSI0aweiaK +XZmpUyJ9DprbbWQqaLuDnqIH8X7kfiMuO7/LGQc812iDJI2Akxp9cIlPBFBD8GVx ++0EphzSodDDlLD8bPqLaWTE+8Ydtjw== +-----END CERTIFICATE----- diff --git a/ssl/test/axTLS.x509_device.cer b/ssl/test/axTLS.x509_device.cer new file mode 100644 index 000000000..c966743c9 Binary files /dev/null and b/ssl/test/axTLS.x509_device.cer differ diff --git a/ssl/test/axTLS.x509_device.pem b/ssl/test/axTLS.x509_device.pem new file mode 100644 index 000000000..e9cbaaf31 --- /dev/null +++ b/ssl/test/axTLS.x509_device.pem @@ -0,0 +1,24 @@ +-----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----- diff --git a/ssl/test/deutsche_telecom.x509_ca b/ssl/test/deutsche_telecom.x509_ca new file mode 100644 index 000000000..0f4b96a0d Binary files /dev/null and b/ssl/test/deutsche_telecom.x509_ca differ diff --git a/ssl/test/equifax.x509_ca b/ssl/test/equifax.x509_ca new file mode 100644 index 000000000..79b0a3f98 Binary files /dev/null and b/ssl/test/equifax.x509_ca differ diff --git a/ssl/test/killopenssl.sh b/ssl/test/killopenssl.sh new file mode 100755 index 000000000..17950fbae --- /dev/null +++ b/ssl/test/killopenssl.sh @@ -0,0 +1,2 @@ +#!/bin/sh +ps -ef|grep openssl | /usr/bin/awk '{print $2}' |xargs kill -9 diff --git a/ssl/test/make_certs.sh b/ssl/test/make_certs.sh new file mode 100755 index 000000000..57d2a10f8 --- /dev/null +++ b/ssl/test/make_certs.sh @@ -0,0 +1,162 @@ +#!/bin/sh + +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# +# 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_512.cer | sed -e \ + "s/axTLS_x509_512_cer/default_certificate/" > ../../ssl/cert.h +xxd -i axTLS.key_512 | sed -e \ + "s/axTLS_key_512/default_private_key/" > ../../ssl/private_key.h diff --git a/ssl/test/microsoft.x509_ca b/ssl/test/microsoft.x509_ca new file mode 100644 index 000000000..b90803452 Binary files /dev/null and b/ssl/test/microsoft.x509_ca differ diff --git a/ssl/test/microsoft.x509_ca.pem b/ssl/test/microsoft.x509_ca.pem new file mode 100644 index 000000000..478e60b07 --- /dev/null +++ b/ssl/test/microsoft.x509_ca.pem @@ -0,0 +1,24 @@ +-----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----- diff --git a/ssl/test/perf_bigint.c b/ssl/test/perf_bigint.c new file mode 100644 index 000000000..116a1ba01 --- /dev/null +++ b/ssl/test/perf_bigint.c @@ -0,0 +1,218 @@ +/* + * Copyright(C) 2006 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @file perf_bigint.c + * + * Some performance testing of bigint. + */ + +#include +#include +#include +#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 +} diff --git a/ssl/test/ssltest.c b/ssl/test/ssltest.c new file mode 100644 index 000000000..7c547ef22 --- /dev/null +++ b/ssl/test/ssltest.c @@ -0,0 +1,1714 @@ +/* + * Copyright(C) 2006 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * ssltest.c + * + * 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 +#include +#include +#include +#include +#include +#include + +#ifndef WIN32 +#include +#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))) + { + fprintf(stderr, "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))) + { + fprintf(stderr, "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))) + { + fprintf(stderr, "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))) + { + fprintf(stderr, "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])) + { + fprintf(stderr, "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); + + SHA1Init(&ctx); + SHA1Update(&ctx, (const uint8_t *)in_str, strlen(in_str)); + SHA1Final(&ctx, digest); + + if (memcmp(digest, ct, sizeof(ct))) + { + fprintf(stderr, "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); + + SHA1Init(&ctx); + SHA1Update(&ctx, (const uint8_t *)in_str, strlen(in_str)); + SHA1Final(&ctx, digest); + + if (memcmp(digest, ct, sizeof(ct))) + { + fprintf(stderr, "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); + + MD5Init(&ctx); + MD5Update(&ctx, (const uint8_t *)in_str, strlen(in_str)); + MD5Final(&ctx, digest); + + if (memcmp(digest, ct, sizeof(ct))) + { + fprintf(stderr, "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); + + MD5Init(&ctx); + MD5Update(&ctx, (const uint8_t *)in_str, strlen(in_str)); + MD5Final(&ctx, digest); + + if (memcmp(digest, ct, sizeof(ct))) + { + fprintf(stderr, "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; + 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))) + { + fprintf(stderr, "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)) + { + fprintf(stderr, "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; + SSLCTX *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); + + /* Verisign use MD2 which is not supported */ + 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)) != + X509_VFY_ERROR_UNSUPPORTED_DIGEST) + { + printf("Cert #5\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 #6\n"); + ssl_display_error(res); + goto bad_cert; + } + + x509_free(x509_ctx); + free(buf); + res = 0; /* all ok */ + printf("All Certificate tests passed\n"); + +bad_cert: + 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"); + 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( + SVR_CTX *svr_test_ctx, + 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; + SSLCTX *ssl_ctx = NULL; + struct sockaddr_in client_addr; + uint8_t *read_buf; + int 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); + 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", read_buf) == NULL) + { + printf("SSL server test \"%s\" passed\n", testname); + TTY_FLUSH(); + ret = 0; + break; + } + } + + ssl_free(ssl); + } + + 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"); + + /* Go through the algorithms */ + + /* + * TLS1 client hello + */ + if ((ret = SSL_server_test(NULL, "TLSv1", "-cipher RC4-SHA -tls1", + NULL, NULL, NULL, NULL, NULL, DEFAULT_SVR_OPTION))) + goto cleanup; + + /* + * AES128-SHA + */ + if ((ret = SSL_server_test(NULL, "AES256-SHA", "-cipher AES128-SHA", + DEFAULT_CERT, NULL, DEFAULT_KEY, NULL, NULL, + DEFAULT_SVR_OPTION))) + goto cleanup; + + /* + * AES256-SHA + */ + if ((ret = SSL_server_test(NULL, "AES256-SHA", "-cipher AES128-SHA", + DEFAULT_CERT, NULL, DEFAULT_KEY, NULL, NULL, + DEFAULT_SVR_OPTION))) + goto cleanup; + + /* + * RC4-SHA + */ + if ((ret = SSL_server_test(NULL, "RC4-SHA", "-cipher RC4-SHA", + DEFAULT_CERT, NULL, DEFAULT_KEY, NULL, NULL, + DEFAULT_SVR_OPTION))) + goto cleanup; + + /* + * RC4-MD5 + */ + if ((ret = SSL_server_test(NULL, "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(NULL, "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(NULL, "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(NULL, "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(NULL, "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(NULL, "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(NULL, "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(NULL, "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(NULL, "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(); + + /* this test should fail */ + if ((ret = SSL_server_test(NULL, "Bogus cert", "-cipher RC4-SHA", + "ssl/test/axTLS.x509_crud.cer", NULL, + "ssl/test/axTLS.key_512", NULL, + NULL, DEFAULT_SVR_OPTION)) != SSL_ERROR_INVALID_KEY) + goto cleanup; + + printf("SSL server test \"%s\" passed\n", "Bogus cert"); + TTY_FLUSH(); + + /* this test should fail */ + if ((ret = SSL_server_test(NULL, "Bogus private key", + "-cipher RC4-SHA", + "ssl/test/axTLS.x509_device.cer", NULL, + "ssl/test/axTLS.crud", NULL, + NULL, DEFAULT_SVR_OPTION)) != SSL_ERROR_INVALID_KEY) + goto cleanup; + + printf("SSL server test \"%s\" passed\n", "Bogus private key"); + TTY_FLUSH(); + + /* + * Key in PEM format + */ + if ((ret = SSL_server_test(NULL, "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(NULL, "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(NULL, "Cert chain in PEM format", + "-cipher RC4-SHA", + "ssl/test/axTLS.x509_device.pem", + NULL, "ssl/test/axTLS.device_key.pem", + NULL, NULL, DEFAULT_SVR_OPTION))) + goto cleanup; + + /* + * AES128 Encrypted key + */ + if ((ret = SSL_server_test(NULL, "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(NULL, "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(NULL, "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(NULL, "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(NULL, "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(NULL, "pkcs 12 no CA", "-cipher RC4-SHA", + DEFAULT_CERT, NULL, "ssl/test/axTLS.withoutCA.p12", + NULL, "abcd", DEFAULT_SVR_OPTION))) + goto cleanup; + + if ((ret = SSL_server_test(NULL, "pkcs 12 with CA", "-cipher RC4-SHA", + NULL, NULL, "ssl/test/axTLS.withCA.p12", + NULL, "abcd", DEFAULT_SVR_OPTION))) + goto cleanup; + + ret = 0; + +cleanup: + if (ret) + fprintf(stderr, "Error: A server test failed\n"); + 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, + SSLCTX **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 (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; + } + + 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; + } + + ssl = ssl_client_new(*ssl_ctx, client_fd, 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); + 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; + SSLCTX *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("Expired cert (verify now) should fail!", + &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"); + ret = 0; + + /* There is no "ERROR" from openssl */ + if ((ret = SSL_client_test("Expired cert (verify later) should fail!", + &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) + fprintf(stderr, "Error: A client test failed\n"); + + return ret; +} + +#if 0 +/************************************************************************** + * Multi-Threading Tests + * + **************************************************************************/ +#define NUM_THREADS 1 +#define NUM_THREADS_STR "1" + +static SSL *my_ssls[NUM_THREADS*3]; /* enough for all client fds */ + +typedef struct +{ + SSLCTX *ssl_ctx; + int port; + int thread_id; +} multi_t; + +int do_connect(multi_t *multi_data) +{ + int res = 1, client_fd, i; + SSL *ssl = NULL; + char tmp[5]; + + /* make sure other threads work before this one */ + if (multi_data->thread_id == NUM_THREADS) + { + sleep(2); /* sets the maximum time this test will run */ + } + + if ((client_fd = client_socket_init(multi_data->port)) < 0) + goto client_test_exit; + sleep(0); + + ssl = ssl_client_new(multi_data->ssl_ctx, client_fd, NULL); + + if ((res = ssl_handshake_status(ssl))) + goto client_test_exit; + + sprintf(tmp, "%d\n", multi_data->thread_id); + for (i = 0; i < 100; i++) + { + ssl_write(ssl, (uint8_t *)tmp, strlen(tmp)+1); + } + + res = 0; +client_test_exit: + ssl_free(ssl); + close(client_fd); + free(multi_data); + return 0; +} + +int multi_thread_test(void) +{ + int server_fd; + SSLCTX *ssl_server_ctx = NULL; + uint8_t buf[1024]; + pthread_t threads[NUM_THREADS]; + int i, res = 1; + struct sockaddr_in client_addr; + int clnt_len = sizeof(client_addr); + fd_set read_set; + int max_fd; + int death_total = 0; + SSLCTX *ssl_client_ctx = ssl_ctx_new(DEFAULT_CLNT_OPTION, + SSL_DEFAULT_CLNT_SESS, NULL); + + printf("Do multi-threading test (takes a minute)\n"); + + FD_ZERO(&read_set); + + if ((server_fd = server_socket_init(&g_port)) < 0) + goto error; + + FD_SET(server_fd, &read_set); + max_fd = server_fd; + + ssl_server_ctx = ssl_ctx_new(DEFAULT_SVR_OPTION|SSL_SERVER_VERIFY_LATER, + SSL_DEFAULT_SVR_SESS, NULL); + + for (i = 0; i < NUM_THREADS; i++) + { + multi_t *multi_data = (multi_t *)malloc(sizeof(multi_t)); + multi_data->ssl_ctx = ssl_server_ctx; + multi_data->port = g_port; + multi_data->thread_id = i+1; + if (pthread_create(&threads[i], NULL, + (void *(*)(void *))do_connect, (void *)multi_data) < 0) + goto error; + } + + sleep(1); + + for (;;) + { + fd_set rdfs = read_set; + int n; + + if ((n = select(max_fd+1, &rdfs, NULL, NULL, 0)) > 0) + { + while (n) + { + /* check for server */ + if (FD_ISSET(server_fd, &rdfs)) + { + int client_fd = accept(server_fd, + (struct sockaddr *)&client_addr, &clnt_len); + + if (client_fd < 0) + goto error; + + if (client_fd > max_fd) /* set max fd */ + { + max_fd = client_fd; + } + + my_ssls[client_fd] = ssl_server_new( + ssl_server_ctx, client_fd); + FD_SET(client_fd, &read_set); + + if (--n == 0) + continue; + } + + i = server_fd; + + while (++i <= max_fd && n) + { + if (FD_ISSET(i, &rdfs)) + { + SSL *ssl; + ssl = my_ssls[i]; + res = ssl_read(ssl, &read_buf); + n--; + + /* kill the client */ + if (res != SSL_OK) + { + if (res == SSL_ERROR_CONN_LOST) + { + ssl_free(ssl); + my_ssls[i] = NULL; + close(i); + FD_CLR(i, &read_set); + death_total++; + } + else if (res > 0) + { + if (strcmp(NUM_THREADS_STR "\n", + (const char *)buf) == 0) + { + sleep(1); /* allow rest of data */ + goto all_ok; + } + } + else /* some problem */ + { + printf("Got some problem %d\n", res); + goto error; + } + } /* if */ + } /* if */ + } /* for */ + } + } + } + +all_ok: + printf("Multi-thread test passed (%d)\n", death_total); + res = 0; +error: + ssl_ctx_free(ssl_server_ctx); + ssl_ctx_free(ssl_client_ctx); + close(server_fd); + return res; +} +#endif + +/************************************************************************** + * 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 + + bi_ctx = bi_initialize(); + + if (AES_test(bi_ctx)) + goto cleanup; + TTY_FLUSH(); + + if (RC4_test(bi_ctx)) + goto cleanup; + TTY_FLUSH(); + + if (MD5_test(bi_ctx)) + goto cleanup; + TTY_FLUSH(); + + if (SHA1_test(bi_ctx)) + goto cleanup; + TTY_FLUSH(); + + if (HMAC_test(bi_ctx)) + goto cleanup; + TTY_FLUSH(); + + if (BIGINT_test(bi_ctx)) + goto cleanup; + TTY_FLUSH(); + + bi_terminate(bi_ctx); + + if (RSA_test()) + goto cleanup; + TTY_FLUSH(); + + if (cert_tests()) + goto cleanup; + TTY_FLUSH(); + + 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 0 + if (multi_thread_test()) + goto cleanup; + +#endif + + ret = 0; /* all ok */ +cleanup: + + if (ret) + { + fprintf(stderr, "Error: Some tests failed!\n"); + } + + close(fd); + return ret; +} diff --git a/ssl/test/test_axssl.sh b/ssl/test/test_axssl.sh new file mode 100755 index 000000000..4a22985fd --- /dev/null +++ b/ssl/test/test_axssl.sh @@ -0,0 +1,117 @@ +#!/bin/sh + +# +# Copyright(C) 2006 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# +# Test the various axssl bindings +# + +if [ `uname -s` == "Linux" ]; then +# JAVA_BIN=/usr/local/jdk142/bin + JAVA_BIN=/usr/lib/java/bin + KILL_AXSSL="killall axssl" + KILL_CSHARP="killall mono" + KILL_PERL="killall /usr/bin/perl" + RUN_CSHARP="mono" + KILL_JAVA="killall $JAVA_BIN/java" +else + JAVA_BIN="/cygdrive/c/Program Files/Java/jdk1.5.0_06/bin" + KILL_AXSSL="kill %1" + KILL_CSHARP="kill %1" + KILL_PERL="kill %1" + KILL_JAVA="kill %1" +fi + +SERVER_ARGS="s_server -accept 15001 -verify -CAfile ./ssl/test/axTLS.ca_x509.cer" +CLIENT_ARGS="s_client -reconnect -connect localhost:15001 -verify -CAfile ./ssl/test/axTLS.ca_x509.cer -key ./ssl/test/axTLS.key_1024 -cert ./ssl/test/axTLS.x509_1024.cer" + +# check pem arguments +SERVER_PEM_ARGS="s_server -accept 15001 -pass abcd -key ./ssl/test/axTLS.key_aes128.pem -cert ./ssl/test/axTLS.x509_aes128.pem" +CLIENT_PEM_ARGS="s_client -connect localhost:15001 -CAfile ./ssl/test/axTLS.ca_x509.pem -key ./ssl/test/axTLS.key_1024.pem -cert ./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 +fi + +if [ -f ./axtls.jar ]; then +echo "########################## JAVA SAMPLE ###########################" +"$JAVA_BIN/java" -jar ./axtls.jar $SERVER_ARGS & +echo "Java Test passed" | "$JAVA_BIN/java" -jar ./axtls.jar $CLIENT_ARGS +$KILL_JAVA +sleep 1 + +"$JAVA_BIN/java" -jar ./axtls.jar $SERVER_PEM_ARGS & +echo "Java Test passed" | "$JAVA_BIN/java" -jar ./axtls.jar $CLIENT_PEM_ARGS +$KILL_JAVA +sleep 1 +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 +sleep 1 +$KILL_CSHARP +sleep 1 + +$RUN_CSHARP ./axssl.csharp.exe $SERVER_PEM_ARGS & +echo "C# Test passed" | $RUN_CSHARP ./axssl.csharp.exe $CLIENT_PEM_ARGS +sleep 1 +$KILL_CSHARP +sleep 1 +fi + +if [ -x ./axssl.vbnet.exe ]; then +echo "######################## VB.NET SAMPLE ###########################" +./axssl.vbnet $SERVER_ARGS & +sleep 1 +echo "VB.NET Test passed" | ./axssl.vbnet.exe $CLIENT_ARGS +kill %1 +sleep 1 + +./axssl.vbnet $SERVER_PEM_ARGS & +sleep 1 +echo "VB.NET Test passed" | ./axssl.vbnet.exe $CLIENT_PEM_ARGS +kill %1 +sleep 1 +fi + +if [ -f ./axssl.pl ]; then +echo "########################## PERL SAMPLE ###########################" +./axssl.pl $SERVER_ARGS & +echo "Perl Test passed" | ./axssl.pl $CLIENT_ARGS +$KILL_PERL +sleep 1 + +./axssl.pl $SERVER_PEM_ARGS & +echo "Perl Test passed" | ./axssl.pl $CLIENT_PEM_ARGS +$KILL_PERL +sleep 1 +fi diff --git a/ssl/test/thawte.x509_ca b/ssl/test/thawte.x509_ca new file mode 100644 index 000000000..59b1059f8 Binary files /dev/null and b/ssl/test/thawte.x509_ca differ diff --git a/ssl/test/verisign.x509_ca b/ssl/test/verisign.x509_ca new file mode 100644 index 000000000..d2ea1289d Binary files /dev/null and b/ssl/test/verisign.x509_ca differ diff --git a/ssl/test/verisign.x509_ca.pem b/ssl/test/verisign.x509_ca.pem new file mode 100644 index 000000000..d5ef5d241 --- /dev/null +++ b/ssl/test/verisign.x509_ca.pem @@ -0,0 +1,16 @@ +-----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----- diff --git a/ssl/test/verisign.x509_my_cert b/ssl/test/verisign.x509_my_cert new file mode 100644 index 000000000..426c9ff7f Binary files /dev/null and b/ssl/test/verisign.x509_my_cert differ diff --git a/ssl/test/verisign.x509_my_cert.pem b/ssl/test/verisign.x509_my_cert.pem new file mode 100644 index 000000000..5b6c1ffed --- /dev/null +++ b/ssl/test/verisign.x509_my_cert.pem @@ -0,0 +1,25 @@ +-----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----- diff --git a/ssl/tls1.c b/ssl/tls1.c new file mode 100644 index 000000000..f3a4a1c5d --- /dev/null +++ b/ssl/tls1.c @@ -0,0 +1,2041 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +/** + * Common ssl/tlsv1 code to both the client and server implementations. + */ + +#include +#include +#include +#include +#include "ssl.h" + +/* Don't import the default key/certificate if not used */ +#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE) +#include "cert.h" +#include "private_key.h" +#endif + +/* 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_SESS *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, + 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 SSLCTX *STDCALL ssl_ctx_new(uint32_t options, int num_sessions) +{ + SSLCTX *ssl_ctx = (SSLCTX *)calloc(1, sizeof (SSLCTX)); + ssl_ctx->options = options; +#ifndef CONFIG_SSL_SKELETON_MODE + ssl_ctx->num_sessions = num_sessions; +#endif + +#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE) + if (~options & SSL_NO_DEFAULT_KEY) + { + ssl_obj_memory_load(ssl_ctx, SSL_OBJ_RSA_KEY, default_private_key, + default_private_key_len, NULL); + ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, + default_certificate, default_certificate_len, NULL); + } +#endif + +#ifndef CONFIG_SSL_SKELETON_MODE + if (num_sessions) + { + ssl_ctx->ssl_sessions = (SSL_SESS **) + calloc(1, num_sessions*sizeof(SSL_SESS *)); + } +#endif + +#ifdef CONFIG_SSL_CERT_VERIFICATION + ssl_ctx->ca_cert_ctx = (CA_CERT_CTX *)calloc(1, sizeof(CA_CERT_CTX)); +#endif + + return ssl_ctx; +} + +/* + * Remove a client/server context. + */ +EXP_FUNC void STDCALL ssl_ctx_free(SSLCTX *ssl_ctx) +{ + SSL *ssl; + int i; + + if (ssl_ctx == NULL) + return; + + ssl = ssl_ctx->sess_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; + 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) +{ + SSLCTX *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; + + /* adjust the server SSL list */ + if (ssl->prev) + { + ssl->prev->next = ssl->next; + } + else + { + ssl_ctx->sess_head = ssl->next; + } + + if (ssl->next) + { + ssl->next->prev = ssl->prev; + } + else + { + ssl_ctx->sess_tail = ssl->prev; + } + + /* may already be free - but be sure */ + free(ssl->all_pkts); + free(ssl->final_finish_mac); + free(ssl->key_block); + free(ssl->encrypt_ctx); + free(ssl->decrypt_ctx); + free(ssl->master_secret); + buf_free(&ssl->bm_buf); +#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 ret = send_packet(ssl, PT_APP_PROTOCOL_DATA, out_data, out_len); + + /* make sure there is no problem with overflow due to padding etc */ + if (ret > out_len) + { + ret = out_len; + } + + return ret; +} + +/** + * Add a certificate to the certificate chain. + */ +int add_cert(SSLCTX *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; + + 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(SSLCTX *ssl_ctx, const uint8_t *buf, int len) +{ + int ret = SSL_ERROR_NO_CERT_DEFINED; + int i = 0; + int offset; + X509_CTX *cert = NULL; + 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; + + /* make sure the cert is valid */ + cert = ca_cert_ctx->cert[i]; + if ((ret = x509_verify(ca_cert_ctx, cert))) + { + x509_free(cert); /* get rid of it */ + ca_cert_ctx->cert[i] = NULL; + 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(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_TYPE]; + + 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_TYPE]; + + default: + return NULL; + } +} + +#endif + +/* + * Find an ssl object based on the client's file descriptor. + */ +EXP_FUNC SSL * STDCALL ssl_find(SSLCTX *ssl_ctx, int client_fd) +{ + SSL *ssl = ssl_ctx->sess_head; + + /* search through all the ssl entries */ + while (ssl) + { + if (ssl->client_fd == client_fd) + return ssl; + + ssl = ssl->next; + } + + return NULL; +} + +/* + * Force the client to perform its handshake again. + */ +EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl) +{ + int ret = SSL_OK; + +#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(SSLCTX *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->bm_buf = buf_new(); + ssl->client_fd = client_fd; + ssl->flag = SSL_NEED_RECORD; + ssl->certs = ssl_ctx->certs; + ssl->chain_length = ssl_ctx->chain_length; +#ifdef CONFIG_ENABLE_VERIFICATION + ssl->ca_cert_ctx = ssl_ctx->ca_cert_ctx; +#endif + + /* a bit hacky but saves a few bytes of memory */ + ssl->flag |= ssl_ctx->options; + + /* build up a linked list, so we can remove it all later */ + if (ssl_ctx->sess_head == NULL) + { + ssl_ctx->sess_head = ssl; + ssl_ctx->sess_tail = ssl; + } + else + { + ssl->prev = ssl_ctx->sess_tail; + ssl_ctx->sess_tail->next = ssl; + ssl_ctx->sess_tail = ssl; + } + + return ssl; +} + +/* + * Add a private key to a context. + */ +int add_private_key(SSLCTX *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, + 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 *)malloc(hmac_len); + uint8_t *t_ptr = t_buf; + + memcpy(t_buf, (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE) ? + ssl->write_sequence : ssl->read_sequence, 8); + t_buf += 8; + + memcpy(t_buf, ssl->record_buf, SSL_RECORD_SIZE); + t_buf += SSL_RECORD_SIZE; + + memcpy(t_buf, buf, buf_len); + + ssl->cipher_info->hmac(t_ptr, 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->record_buf, 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 + + free(t_ptr); +} + +/** + * Verify that the digest of a packet is correct. + */ +static int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len) +{ + unsigned char 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->record_buf[3] = hmac_offset >> 8; /* insert size */ + ssl->record_buf[4] = hmac_offset & 0xff; + + add_hmac_digest(ssl, mode, 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) +{ + int new_len = ssl->all_pkts_len + len; + ssl->all_pkts = (uint8_t *)realloc(ssl->all_pkts, new_len); + memcpy(&ssl->all_pkts[ssl->all_pkts_len], pkt, len); + ssl->all_pkts_len = new_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->client_random, SSL_RANDOM_SIZE); + memcpy(&buf[45], ssl->server_random, SSL_RANDOM_SIZE); + ssl->master_secret = (uint8_t *)malloc(SSL_SECRET_SIZE); + prf(premaster_secret, SSL_SECRET_SIZE, buf, 77, ssl->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) +{ + unsigned char mac_buf[128]; + unsigned char *q = mac_buf; + MD5_CTX md5_ctx; + SHA1_CTX sha1_ctx; + + if (label) + { + strcpy((char *)q, label); + q += strlen(label); + } + + MD5Init(&md5_ctx); + MD5Update(&md5_ctx, ssl->all_pkts, ssl->all_pkts_len); + MD5Final(&md5_ctx, q); + q += MD5_SIZE; + + SHA1Init(&sha1_ctx); + SHA1Update(&sha1_ctx, ssl->all_pkts, ssl->all_pkts_len); + SHA1Final(&sha1_ctx, q); + q += SHA1_SIZE; + + if (label) + { + prf(ssl->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->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_RECORD_SIZE]; + int ret; + + rec_buf[0] = protocol; + rec_buf[1] = 0x03; /* version = 3.1 (TLS) */ + rec_buf[2] = 0x01; + rec_buf[3] = ssl->bm_buf.index >> 8; + rec_buf[4] = ssl->bm_buf.index & 0xff; + + DISPLAY_BYTES(ssl, "sending %d bytes", rec_buf, 5, 5); + DISPLAY_BYTES(ssl, "sending %d bytes", ssl->bm_buf.data, + ssl->bm_buf.index, ssl->bm_buf.index); + + /* 2 system calls, but what the hell it makes life a lot simpler */ + ret = SOCKET_WRITE(ssl->client_fd, rec_buf, SSL_RECORD_SIZE); + + if (ret > 0) + { + ret = SOCKET_WRITE(ssl->client_fd, ssl->bm_buf.data, ssl->bm_buf.index); + } + + SET_SSL_FLAG(SSL_NEED_RECORD); /* reset for next time */ + ssl->bm_buf.index = 0; + + if (ret < 0) + { + ret = SSL_ERROR_CONN_LOST; + } + else if (protocol != PT_APP_PROTOCOL_DATA) + { + /* always return SSL_OK during handshake */ + return 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; + ssl->bm_buf.index = msg_length; + buf_grow(&ssl->bm_buf, msg_length+32); + + /* 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_buf.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; + ssl->record_buf[0] = protocol; + ssl->record_buf[3] = length >> 8; + ssl->record_buf[4] = length & 0xff; + + if (protocol == PT_HANDSHAKE_PROTOCOL) + { + DISPLAY_STATE(ssl, 1, ssl->bm_buf.data[0], 0); + + if (ssl->bm_buf.data[0] != HS_HELLO_REQUEST) + { + add_packet(ssl, ssl->bm_buf.data, ssl->bm_buf.index); + } + } + + /* add the packet digest */ + msg_length += ssl->cipher_info->digest_size; + ssl->bm_buf.index = msg_length; + + add_hmac_digest(ssl, mode, ssl->bm_buf.data, length, + &ssl->bm_buf.data[length]); + + /* add padding? */ + if (ssl->cipher_info->padding_size) + { + int last_blk_size = msg_length%ssl->cipher_info->padding_size; + int 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_buf.data[msg_length], pad_bytes-1, pad_bytes); + msg_length += pad_bytes; + ssl->bm_buf.index = msg_length; + } + + DISPLAY_BYTES(ssl, "unencrypted write", ssl->bm_buf.data, msg_length); + increment_write_sequence(ssl); + + /* now encrypt the packet */ + ssl->cipher_info->encrypt(ssl->encrypt_ctx, ssl->bm_buf.data, + ssl->bm_buf.data, msg_length); + } + else if (protocol == PT_HANDSHAKE_PROTOCOL) + { + DISPLAY_STATE(ssl, 1, ssl->bm_buf.data[0], 0); + + if (ssl->bm_buf.data[0] != HS_HELLO_REQUEST) + { + add_packet(ssl, ssl->bm_buf.data, ssl->bm_buf.index); + } + } + + return send_raw_packet(ssl, protocol); +} + +/** + * 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); + int key_block_existed = 1; + + /* only do once in a handshake */ + if (ssl->key_block == NULL) + { + ssl->key_block = (uint8_t *)malloc(ciph_info->key_block_size); + +#if 0 + print_blob("client", ssl->client_random, 32); + print_blob("server", ssl->server_random, 32); + print_blob("master", ssl->master_secret, SSL_SECRET_SIZE); +#endif + generate_key_block(ssl->client_random, ssl->server_random, + ssl->master_secret, ssl->key_block, ciph_info->key_block_size); +#if 0 + print_blob("keyblock", ssl->key_block, ciph_info->key_block_size); +#endif + key_block_existed = 0; + } + + q = ssl->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 /* RC4 has no IV */ + if (ciph_info->iv_size) + { + 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); + + if (ssl->final_finish_mac == NULL) + { + ssl->final_finish_mac = (uint8_t *)malloc(SSL_FINISHED_HASH_SIZE); + } + + /* now initialise the ciphers */ + if (is_client) + { + finished_digest(ssl, server_finished, ssl->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->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; + + /* clean up if possible */ + if (key_block_existed) + { + free(ssl->key_block); + ssl->key_block = NULL; + } +} + +/** + * Read the SSL connection. + */ +int basic_read(SSL *ssl, uint8_t **in_data) +{ + int ret = SSL_OK, version = -1; + int read_len, is_record; + uint8_t *buf = ssl->bm_buf.data; + int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); + + read_len = SOCKET_READ(ssl->client_fd, &buf[ssl->bm_buf.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_buf.data[ssl->bm_buf.index], read_len, read_len); + + ssl->got_bytes += read_len; + ssl->bm_buf.index += read_len; + + /* haven't quite got what we want, so try again later */ + if (ssl->got_bytes < ssl->need_bytes) + { + return SSL_OK; + } + + ssl->got_bytes = 0; + + if (IS_SET_SSL_FLAG(SSL_NEED_RECORD)) + { + /* check for sslv2 "client hello" TODO: this shouldn't be here. */ + 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 */ + } + + version = (buf[1] << 4) + buf[2]; + ssl->need_bytes = (buf[3] << 8) + buf[4]; + + /* should be 3.1 (TLSv1) */ + if (version != 0x31) + { + /* if we are talking to a client that talks v3.2, then we'll wear + * it - we'll respond in v3.1 mode anyway. */ + if (version < 0x31 || !IS_SET_SSL_FLAG(SSL_IS_CLIENT)) + { + ret = SSL_ERROR_INVALID_VERSION; + ssl_display_error(ret); + goto error; + } + } + + CLR_SSL_FLAG(SSL_NEED_RECORD); + memcpy(ssl->record_buf, buf, 3); /* store for hmac */ + is_record = 1; + } + else + { + SET_SSL_FLAG(SSL_NEED_RECORD); + ssl->need_bytes = SSL_RECORD_SIZE; + is_record = 0; + } + + if (is_record) + { + ssl->record_type = buf[0]; + } + else 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 */ + if (!is_record) + { + switch (ssl->record_type) + { + case PT_HANDSHAKE_PROTOCOL: + 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; + } + + SET_SSL_FLAG(SSL_RX_ENCRYPTED); + set_key_block(ssl, 0); + memset(ssl->read_sequence, 0, 8); + break; + + case PT_APP_PROTOCOL_DATA: + *in_data = ssl->bm_buf.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_buf.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_buf.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_buf.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->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_buf.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_buf.index, SSL_FINISHED_HASH_SIZE+4); + + /* check that we all work before we continue */ + if (memcmp(ssl->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); + } + } + + /* Don't need this stuff anymore */ + free(ssl->all_pkts); + ssl->all_pkts = NULL; + ssl->all_pkts_len = 0; + + free(ssl->master_secret); + ssl->master_secret = NULL; + + free(ssl->final_finish_mac); + ssl->final_finish_mac = NULL; + + /* 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_buf.data; + int offset = 7; + int chain_length; + + buf[0] = HS_CERTIFICATE; + buf[1] = 0; + buf[4] = 0; + buf[7] = 0; + + while (i < ssl->chain_length) + { + SSL_CERT *cert = &ssl->certs[i]; + buf[offset++] = 0; + buf[offset++] = cert->size >> 8; /* cert 1 length */ + buf[offset++] = cert->size & 0xff; + buf_grow(&ssl->bm_buf, offset + cert->size); + 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_buf.index = offset; + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset); +} + +#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_SESS *ssl_session_update(int max_sessions, + SSL_SESS *ssl_sessions[], SSL *ssl, + const uint8_t *session_id) +{ + time_t tm = time(NULL); + time_t oldest_sess_time = tm; + SSL_SESS *oldest_sess = NULL; + int i; + + /* no sessions? Then bail */ + if (max_sessions == 0) + { + return NULL; + } + + 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->master_secret = (uint8_t *)malloc(SSL_SECRET_SIZE); + ssl->session_index = i; + memcpy(ssl->master_secret, + ssl_sessions[i]->master_secret, SSL_SECRET_SIZE); + SET_SSL_FLAG(SSL_SESSION_RESUME); + 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_SESS *)calloc(1, sizeof(SSL_SESS)); + ssl_sessions[i]->conn_time = tm; + ssl->session_index = i; + 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)); + return oldest_sess; +} + +/** + * Free an existing session. + */ +static void session_free(SSL_SESS *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_SESS **ssl_sessions, SSL *ssl) +{ + if (ssl->ssl_ctx->num_sessions) + { + session_free(ssl_sessions, ssl->session_index); + ssl->session = NULL; + } +} +#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(SSL *ssl) +{ + return ssl->session_id; +} + +/* + * Return the cipher id (in the SSL form). + */ +EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(SSL *ssl) +{ + return ssl->cipher; +} + +/* + * Return the status of the handshake. + */ +EXP_FUNC int STDCALL ssl_handshake_status(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(SSL *ssl) +{ + int ret = x509_verify(ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx); + + 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; + int pkt_size = ssl->bm_buf.index; + int cert_size, offset = 5; + int total_cert_size = (ssl->bm_buf.data[offset]<<8) + + ssl->bm_buf.data[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 = (ssl->bm_buf.data[offset]<<8) + ssl->bm_buf.data[offset+1]; + offset += 2; + + if (x509_new(&ssl->bm_buf.data[offset], NULL, chain)) + { + ret = SSL_ERROR_BAD_CERTIFICATE; + goto error; + } + + 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); + } + + DISPLAY_CERT(ssl, "process_certificate", *x509_ctx); + ssl->next_state = is_client ? HS_SERVER_HELLO_DONE : HS_CLIENT_KEY_XCHG; +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 char *label, const X509_CTX *x509_ctx) +{ + if (!IS_SET_SSL_FLAG(SSL_DISPLAY_CERTS)) + return; + + x509_print(ssl->ssl_ctx->ca_cert_ctx, x509_ctx); + TTY_FLUSH(); +} + +/** + * Debugging routine to display RSA objects + */ +void DISPLAY_RSA(SSL *ssl, const char *label, 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) + { + x509_display_error(error_code - SSL_X509_OFFSET); + printf("\n"); + 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 */ + +/** + * 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(SSLCTX *ssl_ctx, + int client_fd, const uint8_t *session_id) +{ + printf(unsupported_str); + return NULL; +} +#endif + +#if !defined(CONFIG_SSL_CERT_VERIFICATION) +EXP_FUNC int STDCALL ssl_verify_cert(SSL *ssl) +{ + printf(unsupported_str); + return -1; +} + +EXP_FUNC const char * STDCALL ssl_get_cert_dn(SSL *ssl, int component) +{ + printf(unsupported_str); + return NULL; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ + +#endif /* CONFIG_BINDINGS */ + diff --git a/ssl/tls1.h b/ssl/tls1.h new file mode 100644 index 000000000..be8cc1f95 --- /dev/null +++ b/ssl/tls1.h @@ -0,0 +1,249 @@ +/* + * Copyright(C) 2006 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @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 + +#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 */ + +#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_SESS; + +typedef struct +{ + uint8_t *buf; + int size; +} SSL_CERT; + +struct _SSL +{ + uint32_t flag; + uint16_t need_bytes; + uint16_t got_bytes; + uint8_t record_type; + uint8_t chain_length; + uint8_t cipher; + int16_t next_state; + int16_t hs_status; + uint8_t *all_pkts; + int all_pkts_len; + int client_fd; + const cipher_info_t *cipher_info; + uint8_t *final_finish_mac; + uint8_t *key_block; + void *encrypt_ctx; + void *decrypt_ctx; + BUF_MEM bm_buf; + struct _SSL *next; /* doubly linked list */ + struct _SSL *prev; + SSL_CERT *certs; + struct _SSLCTX *ssl_ctx; /* back reference to a clnt/svr ctx */ +#ifndef CONFIG_SSL_SKELETON_MODE + uint16_t session_index; + SSL_SESS *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 client_random[SSL_RANDOM_SIZE]; /* client's random sequence */ + uint8_t server_random[SSL_RANDOM_SIZE]; /* server's random sequence */ + uint8_t *master_secret; + uint8_t read_sequence[8]; /* 64 bit sequence number */ + uint8_t write_sequence[8]; /* 64 bit sequence number */ + uint8_t record_buf[SSL_RECORD_SIZE]; /* storage for hmac calls later */ +}; + +typedef struct _SSL SSL; + +struct _SSLCTX +{ + uint32_t options; + uint8_t chain_length; + RSA_CTX *rsa_ctx; +#ifdef CONFIG_SSL_CERT_VERIFICATION + CA_CERT_CTX *ca_cert_ctx; +#endif + SSL *sess_head; + SSL *sess_tail; + SSL_CERT certs[CONFIG_SSL_MAX_CERTS]; +#ifndef CONFIG_SSL_SKELETON_MODE + uint16_t num_sessions; + SSL_SESS **ssl_sessions; +#endif +}; + +typedef struct _SSLCTX SSLCTX; + +extern const uint8_t ssl_prot_prefs[NUM_PROTOCOLS]; + +SSL *ssl_new(SSLCTX *ssl_ctx, int client_fd); +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(SSLCTX *ssl_ctx, const uint8_t *buf, int len); +int add_private_key(SSLCTX *ssl_ctx, SSLObjLoader *ssl_obj); +void ssl_obj_free(SSLObjLoader *ssl_obj); +int pkcs8_decode(SSLCTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password); +int pkcs12_decode(SSLCTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password); +#ifdef CONFIG_SSL_CERT_VERIFICATION +int add_cert_auth(SSLCTX *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 char *label, const X509_CTX *x509_ctx); +void DISPLAY_RSA(SSL *ssl, const char *label, 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,C) +#define DISPLAY_RSA(A,B,C) +#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_SESS *ssl_session_update(int max_sessions, + SSL_SESS *ssl_sessions[], SSL *ssl, + const uint8_t *session_id); +void kill_ssl_session(SSL_SESS **ssl_sessions, SSL *ssl); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ssl/tls1_clnt.c b/ssl/tls1_clnt.c new file mode 100644 index 000000000..704387642 --- /dev/null +++ b/ssl/tls1_clnt.c @@ -0,0 +1,330 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +#include +#include +#include +#include + +#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(SSLCTX *ssl_ctx, int client_fd, const uint8_t *session_id) +{ + int ret; + SSL *ssl = ssl_new(ssl_ctx, client_fd); + + if (session_id && ssl_ctx->num_sessions) + { + memcpy(ssl->session_id, session_id, SSL_SESSION_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) + { + ret = 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); + break; + + case HS_HELLO_REQUEST: + 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_buf.index = 0; + ssl->next_state = HS_SERVER_HELLO; + ssl->hs_status = SSL_NOT_OK; /* not connected */ + + /* 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_buf.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->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 bu user */ + { + buf[offset++] = SSL_SESSION_ID_SIZE; + memcpy(&buf[offset], ssl->session_id, SSL_SESSION_ID_SIZE); + offset += SSL_SESSION_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_buf.data; + int pkt_size = ssl->bm_buf.index; + int offset; + int ret = SSL_OK; + int num_sessions = ssl->ssl_ctx->num_sessions; + + /* check that we are talking to a TLSv1 server */ + if (buf[4] != 0x03 || buf[5] != 0x01) + { + return SSL_ERROR_INVALID_VERSION; + } + + /* get the server random value */ + memcpy(ssl->server_random, &buf[6], SSL_RANDOM_SIZE); + offset = 7 + SSL_RANDOM_SIZE; /* skip of session id size */ + + 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], SSL_SESSION_ID_SIZE); + } + + memcpy(ssl->session_id, &buf[offset], SSL_SESSION_ID_SIZE); + offset += SSL_SESSION_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; + + PARANOIA_CHECK(pkt_size, offset); + +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_buf.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, "send_client_key_xchg", ssl->x509_ctx->rsa_ctx); + enc_secret_size = RSA_encrypt(ssl->x509_ctx->rsa_ctx, premaster_secret, + SSL_SECRET_SIZE, &buf[6], 0); + 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) +{ + /* 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); + return SSL_OK; +} + +/* + * Send a certificate verify message. + */ +static int send_cert_verify(SSL *ssl) +{ + uint8_t *buf = ssl->bm_buf.data; + uint8_t dgst[MD5_SIZE+SHA1_SIZE]; + RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx; + int n, ret; + + DISPLAY_RSA(ssl, "send_cert_verify", rsa_ctx); + + buf[0] = HS_CERT_VERIFY; + buf[1] = 0; + + finished_digest(ssl, NULL, dgst); /* calculate the digest */ + n = RSA_encrypt(rsa_ctx, dgst, sizeof(dgst), &buf[6], 1); + + 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 */ diff --git a/ssl/tls1_svr.c b/ssl/tls1_svr.c new file mode 100644 index 000000000..ff0eb62a5 --- /dev/null +++ b/ssl/tls1_svr.c @@ -0,0 +1,435 @@ +/* + * Copyright(C) 2006 + * + * 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.1 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 Lesser 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 + */ + +#include +#include +#include + +#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(SSLCTX *ssl_ctx, int client_fd) +{ + SSL *ssl = ssl_new(ssl_ctx, client_fd); + ssl->next_state = HS_CLIENT_HELLO; + ssl->hs_status = SSL_NOT_OK; /* not connected */ + 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); + break; + } + + return ret; +} + +/* + * Process a client hello message. + */ +static int process_client_hello(SSL *ssl) +{ + uint8_t *buf = ssl->bm_buf.data; + int pkt_size = ssl->bm_buf.index; + int i, j, cs_len, id_len, offset = 6 + SSL_RANDOM_SIZE; + int ret = SSL_OK; + + memcpy(ssl->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_buf.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); + + /* must be 3.1 (TLSv1) */ + 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->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_buf.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->server_random, &buf[6], SSL_RANDOM_SIZE); + offset = 6 + SSL_RANDOM_SIZE; + + /* send a session id - and put it into the cache */ + buf[offset++] = SSL_SESSION_ID_SIZE; + +#ifndef CONFIG_SSL_SKELETON_MODE + if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) + { + /* retrieve id from session cache */ + memcpy(&buf[offset], ssl->session->session_id, + SSL_SESSION_ID_SIZE); + memcpy(ssl->session_id, ssl->session->session_id, SSL_SESSION_ID_SIZE); + } + else /* generate our own session id */ +#endif + { + get_random(SSL_SESSION_ID_SIZE, &buf[offset]); + memcpy(ssl->session_id, &buf[offset], SSL_SESSION_ID_SIZE); + +#ifndef CONFIG_SSL_SKELETON_MODE + /* store id in session cache */ + if (ssl->ssl_ctx->num_sessions) + { + memcpy(ssl->session->session_id, + ssl->session_id, SSL_SESSION_ID_SIZE); + } +#endif + } + + offset += SSL_SESSION_ID_SIZE; + + 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_buf.data; + int pkt_size = ssl->bm_buf.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; + + DISPLAY_RSA(ssl, "process_client_key_xchg", rsa_ctx); + + /* 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); + premaster_size = RSA_decrypt(rsa_ctx, &buf[offset], premaster_secret, 1); + + 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: + 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_buf.data; + int pkt_size = ssl->bm_buf.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, "process_cert_verify", x509_ctx->rsa_ctx); + n = RSA_decrypt(x509_ctx->rsa_ctx, &buf[6], dgst_buf, 0); + + 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 diff --git a/www/crypto_files/crypto_2600des.gif b/www/crypto_files/crypto_2600des.gif new file mode 100644 index 000000000..10610c126 Binary files /dev/null and b/www/crypto_files/crypto_2600des.gif differ diff --git a/www/crypto_files/crypto_3ways.gif b/www/crypto_files/crypto_3ways.gif new file mode 100644 index 000000000..5da7683eb Binary files /dev/null and b/www/crypto_files/crypto_3ways.gif differ diff --git a/www/crypto_files/crypto_backrsa.jpg b/www/crypto_files/crypto_backrsa.jpg new file mode 100644 index 000000000..53fafd777 Binary files /dev/null and b/www/crypto_files/crypto_backrsa.jpg differ diff --git a/www/crypto_files/crypto_cert.gif b/www/crypto_files/crypto_cert.gif new file mode 100644 index 000000000..ec3d19168 Binary files /dev/null and b/www/crypto_files/crypto_cert.gif differ diff --git a/www/crypto_files/crypto_des.gif b/www/crypto_files/crypto_des.gif new file mode 100644 index 000000000..8588179ef Binary files /dev/null and b/www/crypto_files/crypto_des.gif differ diff --git a/www/crypto_files/crypto_ecc.gif b/www/crypto_files/crypto_ecc.gif new file mode 100644 index 000000000..be218e25a Binary files /dev/null and b/www/crypto_files/crypto_ecc.gif differ diff --git a/www/crypto_files/crypto_sslv3.gif b/www/crypto_files/crypto_sslv3.gif new file mode 100644 index 000000000..872cbc0b3 Binary files /dev/null and b/www/crypto_files/crypto_sslv3.gif differ diff --git a/www/crypto_files/crypto_types.gif b/www/crypto_files/crypto_types.gif new file mode 100644 index 000000000..d43072b14 Binary files /dev/null and b/www/crypto_files/crypto_types.gif differ diff --git a/www/crypto_files/kerberos.gif b/www/crypto_files/kerberos.gif new file mode 100644 index 000000000..d22b5acb3 Binary files /dev/null and b/www/crypto_files/kerberos.gif differ diff --git a/www/favicon.ico b/www/favicon.ico new file mode 100644 index 000000000..9f6f30e4c Binary files /dev/null and b/www/favicon.ico differ diff --git a/www/index.html b/www/index.html new file mode 100644 index 000000000..86133dd77 --- /dev/null +++ b/www/index.html @@ -0,0 +1,3718 @@ +An Overview of Cryptography + + + + +
+

+ +An Overview of Cryptography + +

+

+Gary C. Kessler
+May 1998
+(26 September 2005) +

+
+
+

+A much shorter, edited version of this paper appears in the 1999 Edition of Handbook on Local Area Networks, published by Auerbach in September 1998. Since that time, this article has taken on a life of its own... +

+
+
+ +
+ + +
+

CONTENTS

+ + +
  + + +

FIGURES

+
    +
  1. Three types of cryptography: secret-key, public key, and hash function. +
  2. Sample application of the three cryptographic techniques for secure communication. +
  3. Kerberos architecture. +
  4. GTE Cybertrust Global Root-issued certificate (Netscape Navigator). +
  5. Sample entries in Unix/Linux password files. +
  6. DES enciphering algorithm. +
  7. A PGP signed message. +
  8. A PGP encrypted message. +
  9. The decrypted message. +
  10. IPsec Authentication Header format. +
  11. IPsec Encapsulating Security Payload format. +
  12. IPsec tunnel and transport modes for AH. +
  13. IPsec tunnel and transport modes for ESP. +
  14. SSL v3 configuration screen (Netscape Navigator). +
  15. SSL/TLS protocol handshake. +
  16. Elliptic curve addition. +
  17. AES pseudocode. +
+

TABLES

+
    +
  1. Minimum Key Lengths for Symmetric Ciphers. +
  2. Contents of an X.509 V3 Certificate. +
  3. Other Crypto Algorithms and Systems of Note. +
  4. ECC and RSA Key Comparison. +
+
+
+ +
+
+

1. INTRODUCTION

+

+Does increased security provide comfort to paranoid +people? Or does security provide some very basic protections that we +are naive to believe that we don't need? During this time when the +Internet provides essential communication between tens of millions of +people and is being increasingly used as a tool for commerce, security +becomes a tremendously important issue to deal with. +

+There are many aspects to security and many +applications, ranging from secure commerce and payments to private +communications and protecting passwords. One essential aspect for +secure communications is that of cryptography, which is the focus of +this chapter. But it is important to note that while cryptography is necessary for secure communications, it is not by itself sufficient. +The reader is advised, then, that the topics covered in this chapter +only describe the first of many steps necessary for better security in +any number of situations. +

+This paper has two major purposes. The first is to +define some of the terms and concepts behind basic cryptographic +methods, and to offer a way to compare the myriad cryptographic schemes +in use today. The second is to provide some real examples of +cryptography in use today. +

+I would like to say at the outset that this paper is very focused on terms, concepts, and schemes in current +use and is not a treatise of the whole field. No mention is made here +about pre-computerized crypto schemes, the difference between a +substitution and transposition cipher, cryptanalysis, or other history. +Interested readers should check out some of the books in the +bibliography below for this detailed — and interesting! — background +information.

+ +
+

2. THE PURPOSE OF CRYPTOGRAPHY

+

+Cryptography is the science of writing in secret code +and is an ancient art; the first documented use of cryptography in +writing dates back to circa 1900 B.C. when an Egyptian scribe used +non-standard hieroglyphs in an inscription. Some experts argue that +cryptography appeared spontaneously sometime after writing was +invented, with applications ranging from diplomatic missives to +war-time battle plans. It is no surprise, then, that new forms of +cryptography came soon after the widespread development of computer +communications. In data and telecommunications, cryptography is +necessary when communicating over any untrusted medium, which includes +just about any network, particularly the Internet.

+

+Within the context of any application-to-application communication, there are some specific security requirements, including:

+
    +
  • Authentication: The process of proving one's +identity. (The primary forms of host-to-host authentication on the +Internet today are name-based or address-based, both of which are +notoriously weak.)
  • +
  • Privacy/confidentiality: Ensuring that no one can read the message except the intended receiver.
  • +
  • Integrity: Assuring the receiver that the received message has not been altered in any way from the original.
  • +
  • Non-repudiation: A mechanism to prove that the sender really sent this message.
  • +
+

+Cryptography, then, not only protects data from theft or +alteration, but can also be used for user authentication. There are, in +general, three types of cryptographic schemes typically used to +accomplish these goals: secret key (or symmetric) cryptography, +public-key (or asymmetric) cryptography, and hash functions, each of +which is described below. In all cases, the initial unencrypted data is +referred to as plaintext. It is encrypted into ciphertext, which will in turn (usually) be decrypted into usable plaintext.

+

+In many of the descriptions below, two communicating +parties will be referred to as Alice and Bob; this is the common +nomenclature in the crypto field and literature to make it easier to +identify the communicating parties. If there is a third or fourth party +to the communication, they will be referred to as Carol and Dave. +Mallory is a malicious party, Eve is an eavesdropper, and Trent is a +trusted third party.

+ +
+

3. TYPES OF CRYPTOGRAPHIC ALGORITHMS

+

+There are several ways of classifying cryptographic +algorithms. For purposes of this paper, they will be categorized based +on the number of keys that are employed for encryption and decryption, +and further defined by their application and use. The three types of +algorithms that will be discussed are (Figure 1): +

    +
  • Secret Key Cryptography (SKC): Uses a single key for both encryption and decryption +
  • Public Key Cryptography (PKC): Uses one key for encryption and another for decryption +
  • Hash Functions: Uses a mathematical transformation to irreversibly "encrypt" information +
+
+
+ +

+

FIGURE 1: Three types of cryptography: secret-key, public key, and hash function.

+
+
+ +

+

3.1. Secret Key Cryptography

+

+With secret key cryptography, a single key is +used for both encryption and decryption. As shown in Figure 1A, the +sender uses the key (or some set of rules) to encrypt the plaintext and +sends the ciphertext to the receiver. The receiver applies the same key +(or ruleset) to decrypt the message and recover the plaintext. Because +a single key is used for both functions, secret key cryptography is +also called symmetric encryption.

+

+With this form of cryptography, it is obvious that the +key must be known to both the sender and the receiver; that, in fact, +is the secret. The biggest difficulty with this approach, of course, is +the distribution of the key.

+

+Secret key cryptography schemes are generally categorized as being either stream ciphers or block ciphers. +Stream ciphers operate on a single bit (byte or computer word) at a +time and implement some form of feedback mechanism so that the key is +constantly changing. A block cipher is so-called because the scheme +encrypts one block of data at a time using the same key on each block. +In general, the same plaintext block will always encrypt to the same +ciphertext when using the same key in a block cipher whereas the same +plaintext will encrypt to different ciphertext in a stream cipher.

+

+Stream ciphers come in several flavors but two are worth mentioning here. Self-synchronizing stream ciphers calculate each bit in the keystream as a function of the previous n +bits in the keystream. It is termed "self-synchronizing" because the +decryption process can stay synchronized with the encryption process +merely by knowing how far into the n-bit keystream it is. One problem is error propagation; a garbled bit in transmission will result in n garbled bits at the receiving side. Synchronous stream ciphers +generate the keystream in a fashion independent of the message stream +but by using the same keystream generation function at sender and +receiver. While stream ciphers do not propagate transmission errors, +they are, by their nature, periodic so that the keystream will +eventually repeat.

+

+Block ciphers can operate in one of several modes; the following four are the most important:

+
    +
  • Electronic Codebook (ECB) mode is the +simplest, most obvious application: the secret key is used to encrypt +the plaintext block to form a ciphertext block. Two identical plaintext +blocks, then, will always generate the same ciphertext block. Although +this is the most common mode of block ciphers, it is susceptible to a +variety of brute-force attacks.
  • +
  • Cipher Block Chaining (CBC) mode adds a feedback mechanism +to the encryption scheme. In CBC, the plaintext is exclusively-ORed +(XORed) with the previous ciphertext block prior to encryption. In this +mode, two identical blocks of plaintext never encrypt to the same +ciphertext.
  • +
  • Cipher Feedback (CFB) mode is a block cipher implementation +as a self-synchronizing stream cipher. CFB mode allows data to be +encrypted in units smaller than the block size, which might be useful +in some applications such as encrypting interactive terminal input. If +we were using 1-byte CFB mode, for example, each incoming character is +placed into a shift register the same size as the block, encrypted, and +the block transmitted. At the receiving side, the ciphertext is +decrypted and the extra bits in the block (i.e., everything above and +beyond the one byte) are discarded.
  • +
  • Output Feedback (OFB) mode is a block cipher implementation +conceptually similar to a synchronous stream cipher. OFB prevents the +same plaintext block from generating the same ciphertext block by using +an internal feedback mechanism that is independent of both the +plaintext and ciphertext bitstreams.
  • +
+ +

+Secret key cryptography algorithms that are in use today include:

+
    +
  • Data Encryption Standard (DES): The most +common SKC scheme used today, DES was designed by IBM in the 1970s and +adopted by the National Bureau of Standards (NBS) [now the National +Institute for Standards and Technology (NIST)] in 1977 for commercial +and unclassified government applications. DES is a block-cipher +employing a 56-bit key that operates on 64-bit blocks. DES has a +complex set of rules and transformations that were designed +specifically to yield fast hardware implementations and slow software +implementations, although this latter point is becoming less +significant today since the speed of computer processors is several +orders of magnitude faster today than twenty years ago. IBM also +proposed a 112-bit key for DES, which was rejected at the time by the +government; the use of 112-bit keys was considered in the 1990s, +however, conversion was never seriously considered.

    +

    +DES is defined in American National Standard X3.92 and three Federal Information Processing Standards (FIPS):

    + +

    +Information about vulnerabilities of DES can be obtained from the Electronic Frontier Foundation.

    +

    +Two important variants that strengthen DES are:

    +
      +
    • Triple-DES (3DES): A variant of DES that employs up to +three 56-bit keys and makes three encryption/decryption passes over the +block; 3DES is also described in FIPS 46-3 and is the recommended replacement to DES.

    • +
    • DESX: +A variant devised by Ron Rivest. By combining 64 additional key bits to +the plaintext prior to encryption, effectively increases the keylength +to 120 bits.

    • +
    +

    +More detail about DES, 3DES, and DESX can be found below in Section 5.4.

  • + +
  • Advanced Encryption Standard (AES): In 1997, NIST +initiated a very public, 4-1/2 year process to develop a new secure +cryptosystem for U.S. government applications. The result, the Advanced Encryption Standard, became the official successor to DES in December 2001. AES uses an SKC scheme called Rijndael, +a block cipher designed by Belgian cryptographers Joan Daemen and +Vincent Rijmen. The algorithm can use a variable block length and key +length; the latest specification allowed any combination of keys +lengths of 128, 192, or 256 bits and blocks of length 128, 192, or 256 +bits. NIST initially selected Rijndael in October 2000 and formal +adoption as the AES standard came in December 2001. FIPS PUB 197 +describes a 128-bit block cipher employing a 128-, 192-, or 256-bit +key. The AES process and Rijndael algorithm are described in more +detail below in Section 5.9.

  • + +
  • CAST-128/256: CAST-128, described in Request for Comments (RFC) 2144, is a DES-like substitution-permutation crypto algorithm, employing a 128-bit key operating on a 64-bit block. CAST-256 (RFC 2612) +is an extension of CAST-128, using a 128-bit block size and a variable +length (128, 160, 192, 224, or 256 bit) key. CAST is named for its +developers, Carlisle Adams and Stafford Tavares and is available +internationally. CAST-256 was one of the Round 1 algorithms in the AES +process.

  • + +
  • International Data Encryption Algorithm (IDEA): +Secret-key cryptosystem written by Xuejia Lai and James Massey, in 1992 +and patented by Ascom; a 64-bit SKC block cipher using a 128-bit key. +Also available internationally.

  • + +
  • Rivest Ciphers (aka Ron's Code): Named for Ron Rivest, a series of SKC algorithms.

    +
      +
    • RC1: Designed on paper but never implemented.

    • +
    • RC2: A 64-bit block cipher using variable-sized keys +designed to replace DES. It's code has not been made public although +many companies have licensed RC2 for use in their products. Described +in RFC 2268.

    • +
    • RC3: Found to be breakable during development.

    • +
    • RC4: A +stream cipher using variable-sized keys; it is widely used in +commercial cryptography products, although it can only be exported +using keys that are 40 bits or less in length.

      +

    • RC5: A block-cipher supporting a variety of block sizes, key sizes, and number of encryption passes over the data. Described in RFC 2040.

    • +
    • RC6: An improvement over RC5, RC6 was one of the AES Round 2 algorithms.

    • +
    + +
  • Blowfish: +A symmetric 64-bit block cipher invented by Bruce Schneier; optimized +for 32-bit processors with large data caches, it is significantly +faster than DES on a Pentium/PowerPC-class machine. Key lengths can +vary from 32 to 448 bits in length. Blowfish, available freely and +intended as a substitute for DES or IDEA, is in use in over 80 products.

  • + +
  • Twofish: +A 128-bit block cipher using 128-, 192-, or 256-bit keys. Designed to +be highly secure and highly flexible, well-suited for large +microprocessors, 8-bit smart card microprocessors, and dedicated +hardware. Designed by a team led by Bruce Schneier and was one of the +Round 2 algorithms in the AES process.

  • + +
  • Camellia: +A secret-key, block-cipher crypto algorithm developed jointly by Nippon +Telegraph and Telephone (NTT) Corp. and Mitsubishi Electric Corporation +(MEC) in 2000. Camellia has some characteristics in common with AES: a +128-bit block size, support for 128-, 192-, and 256-bit key lengths, +and suitability for both software and hardware implementations on +common 32-bit processors as well as 8-bit processors (e.g., smart +cards, cryptographic hardware, and embedded systems). Also described in + RFC 3713.

  • + +
  • MISTY1: Developed at Mitsubishi Electric Corp., a block +cipher using a 128-bit key and 64-bit blocks, and a variable number of +rounds. Designed for hardware and software implementations, and is +resistant to differential and linear cryptanalysis. Described in RFC 2994.

  • + +
  • Secure and Fast Encryption Routine (SAFER): Secret-key crypto scheme designed for implementation in software. Versions have been defined for 40-, 64-, and 128-bit keys.

  • + +
  • KASUMI: +A block cipher using a 128-bit key that is part of the Third-Generation +Partnership Project (3gpp), formerly known as the Universal Mobile +Telecommunications System (UMTS). KASUMI is the intended +confidentiality and integrity algorithm for both message content and +signaling data for emerging mobile communications systems.

  • + +
  • SEED: +A block cipher using 128-bit blocks and 128-bit keys. Developed by the +Korea Information Security Agency (KISA) and adopted as a national +standard encryption algorithm in South Korea. Also described in RFC 4009.

  • + +
  • Skipjack: +SKC scheme proposed for Capstone. Although the details of the algorithm +were never made public, Skipjack was a block cipher using an 80-bit key +and 32 iteration cycles per 64-bit block.

  • +
+ +

3.2. Public-Key Cryptography

+

+Public-key cryptography has been said to be the +most significant new development in cryptography in the last 300-400 +years. Modern PKC was first described publicly by Stanford University +professor Martin Hellman and graduate student Whitfield Diffie in 1976. +Their paper described a two-key crypto system in which two parties +could engage in a secure communication over a non-secure communications +channel without having to share a secret key.

+

+PKC depends upon the existence of so-called one-way functions, +or mathematical functions that are easy to computer whereas their +inverse function is relatively difficult to compute. Let me give you +two simple examples:

+
    +
  1. Multiplication vs. factorization: Suppose I +tell you that I have two numbers, 9 and 16, and that I want to +calculate the product; it should take almost no time to calculate the +product, 144. Suppose instead that I tell you that I have a number, +144, and I need you tell me which pair of integers I multiplied +together to obtain that number. You will eventually come up with the +solution but whereas calculating the product took milliseconds, +factoring will take longer because you first need to find the 8 pair of +integer factors and then determine which one is the correct pair.
  2. +
  3. Exponentiation vs. logarithms: Suppose I tell you that I want to take the number 3 to the 6th power; again, it is easy to calculate 36=729. But if I tell you that I have the number 729 and want you to tell me the two integers that I used, x and y so that logx 729 = y, it will take you longer to find all possible solutions and select the pair that I used.
  4. +
+

+While the examples above are trivial, they do represent +two of the functional pairs that are used with PKC; namely, the ease of +multiplication and exponentiation versus the relative difficulty of +factoring and calculating logarithms, respectively. The mathematical +"trick" in PKC is to find a trap door in the one-way function so that the inverse calculation becomes easy given knowledge of some item of information.

+

+Generic PKC employs two keys that are mathematically +related although knowledge of one key does not allow someone to easily +determine the other key. One key is used to encrypt the plaintext and +the other key is used to decrypt the ciphertext. The important point +here is that it does not matter which key is applied first, but +that both keys are required for the process to work (Figure 1B). +Because a pair of keys are required, this approach is also called asymmetric cryptography.

+

+In PKC, one of the keys is designated the public key and may be advertised as widely as the owner wants. The other key is designated the private key +and is never revealed to another party. It is straight forward to send +messages under this scheme. Suppose Alice wants to send Bob a message. +Alice encrypts some information using Bob's public key; Bob decrypts +the ciphertext using his private key. This method could be also used to +prove who sent a message; Alice, for example, could encrypt some +plaintext with her private key; when Bob decrypts using Alice's public +key, he knows that Alice sent the message and Alice cannot deny having +sent the message (non-repudiation).

+ +

+Public-key cryptography algorithms that are in use today for key exchange or digital signatures include:

+
    +
  • RSA: The first, and still most common, +PKC implementation, named for the three MIT mathematicians who +developed it — Ronald Rivest, Adi Shamir, and Leonard Adleman. RSA +today is used in hundreds of software products and can be used for key +exchange, digital signatures, or encryption of small blocks of data. +RSA uses a variable size encryption block and a variable size key. The +key-pair is derived from a very large number, n, that is the +product of two prime numbers chosen according to special rules; these +primes may be 100 or more digits in length each, yielding an n with roughly twice as many digits as the prime factors. The public key information includes n and a derivative of one of the factors of n; an attacker cannot determine the prime factors of n +(and, therefore, the private key) from this information alone and that +is what makes the RSA algorithm so secure. (Some descriptions of PKC +erroneously state that RSA's safety is due to the difficulty in factoring +large prime numbers. In fact, large prime numbers, like small prime +numbers, only have two factors!) The ability for computers to factor +large numbers, and therefore attack schemes such as RSA, is rapidly +improving and systems today can find the prime factors of numbers with +more than 140 digits. The presumed protection of RSA, however, is that +users can easily increase the key size to always stay ahead of the +computer processing curve. As an aside, the patent for RSA expired in +September 2000 which does not appear to have affected RSA's popularity +one way or the other. A detailed example of RSA is presented below in Section 5.3.

  • + +
  • Diffie-Hellman: +After the RSA algorithm was published, Diffie and Hellman came up with +their own algorithm. D-H is used for secret-key key exchange only, and +not for authentication or digital signatures. More detail about +Diffie-Hellman can be found below in Section 5.2.

  • + +
  • Digital Signature Algorithm (DSA): +The algorithm specified in NIST's Digital Signature Standard (DSS), +provides digital signature capability for the authentication of +messages.

  • + +
  • ElGamal: Designed by Taher Elgamal, a PKC system similar to Diffie-Hellman and used for key exchange.

  • + +
  • Elliptic Curve Cryptography (ECC): A PKC algorithm based +upon elliptic curves. ECC can offer levels of security with small keys +comparable to RSA and other PKC methods. It was designed for devices +with limited compute power and/or memory, such as smartcards and PDAs. +More detail about ECC can be found below in Section 5.8. Other references include "The Importance of ECC" Web page and the "Online Elliptic Curve Cryptography Tutorial", both from Certicom.

  • + +
  • Public-Key Cryptography Standards (PKCS): A set of interoperable standards and guidelines for public-key cryptography, designed by RSA Data Security Inc. +

      +
    • PKCS #1: RSA Cryptography Standard (Also RFC 3447)
    • +
    • PKCS #2: Incorporated into PKCS #1.
    • +
    • PKCS #3: Diffie-Hellman Key-Agreement Standard
    • +
    • PKCS #4: Incorporated into PKCS #1.
    • +
    • PKCS #5: Password-Based Cryptography Standard (PKCS #5 V2.0 is also RFC 2898)
    • +
    • PKCS #6: Extended-Certificate Syntax Standard (being phased out in favor of X.509v3)
    • +
    • PKCS #7: Cryptographic Message Syntax Standard (Also RFC 2315)
    • +
    • PKCS #8: Private-Key Information Syntax Standard
    • +
    • PKCS #9: Selected Attribute Types (Also RFC 2985)
    • +
    • PKCS #10: Certification Request Syntax Standard (Also RFC 2986)
    • +
    • PKCS #11: Cryptographic Token Interface Standard
    • +
    • PKCS #12: Personal Information Exchange Syntax Standard
    • +
    • PKCS #13: Elliptic Curve Cryptography Standard
    • +
    • PKCS #14: Pseudorandom Number Generation Standard is no longer available
    • + +
    • PKCS #15: Cryptographic Token Information Format Standard
    • +
    + +
  • Cramer-Shoup: A public-key cryptosystem proposed by R. Cramer and V. Shoup of IBM in 1998.

  • + +
  • Key Exchange Algorithm (KEA): A variation on Diffie-Hellman; proposed as the key exchange method for Capstone.

  • + +
  • LUC: +A public-key cryptosystem designed by P.J. Smith and based on Lucas +sequences. Can be used for encryption and signatures, using integer +factoring.

  • +
+ +

+For additional information on PKC algorithms, see "Public-Key Encryption", Chapter 8 in Handbook of Applied Cryptography, by A. Menezes, P. van Oorschot, and S. Vanstone (CRC Press, 1996).

+ +
+
+

+A digression: Who invented PKC? I tried to be +careful in the first paragraph of this section to state that Diffie and +Hellman "first described publicly" a PKC scheme. Although I have +categorized PKC as a two-key system, that has been merely for +convenience; the real criteria for a PKC scheme is that it allows two +parties to exchange a secret even though the communication with the +shared secret might be overheard. There seems to be no question that +Diffie and Hellman were first to publish; their method is described in +the classic paper, "New Directions in Cryptography," published in the +November 1976 issue of IEEE Transactions on Information Theory. +As shown below, Diffie-Hellman uses the idea that finding logarithms is +relatively harder than exponentiation. And, indeed, it is the precursor +to modern PKC which does employ two keys. Rivest, Shamir, and Adleman +described an implementation that extended this idea in their paper "A +Method for Obtaining Digital Signatures and Public-Key Cryptosystems," +published in the February 1978 issue of the Communications of the ACM (CACM). +Their method, of course, is based upon the relative ease of finding the +product of two large prime numbers compared to finding the prime +factors of a large number.

+

+Some sources, though, credit Ralph Merkle with first +describing a system that allows two parties to share a secret although +it was not a two-key system, per se. A Merkle Puzzle works +where Alice creates a large number of encrypted keys, sends them all to +Bob so that Bob chooses one at random and then lets Alice know which he +has selected. An eavesdropper will see all of the keys but can't learn +which key Bob has selected (because he has encrypted the response with +the chosen key). In this case, Eve's effort to break in is the square +of the effort of Bob to choose a key. While this difference may be +small it is often sufficient. Merkle apparently took a computer science +course at UC Berkeley in 1974 and described his method, but had +difficulty making people understand it; frustrated, he dropped the +course. Meanwhile, he submitted the paper "Secure Communication Over +Insecure Channels" which was published in the CACM in April +1978; Rivest et al.'s paper even makes reference to it. Merkle's method +certainly wasn't published first, but did he have the idea first?

+

+An interesting question, maybe, but who really knows? +For some time, it was a quiet secret that a team at the UK's Government +Communications Headquarters (GCHQ) had first developed PKC in the early +1970s. Because of the nature of the work, GCHQ kept the original memos +classified. In 1997, however, the GCHQ changed their posture when they +realized that there was nothing to gain by continued silence. Documents +show that a GCHQ mathematician named James Ellis started research into +the key distribution problem in 1969 and that by 1975, Ellis, Clifford +Cocks, and Malcolm Williamson had worked out all of the fundamental +details of PKC, yet couldn't talk about their work. (They were, of +course, barred from challenging the RSA patent!) After more than 20 +years, Ellis, Cocks, and Williamson have begun to get their due credit.

+

+And the National Security Agency (NSA) claims to have +knowledge of this type of algorithm as early as 1966 but there is no +supporting documentation... yet. So this really was a digression...

+
+
+ +

3.3. Hash Functions

+

+Hash functions, also called message digests and one-way encryption, +are algorithms that, in some sense, use no key (Figure 1C). Instead, a +fixed-length hash value is computed based upon the plaintext that makes +it impossible for either the contents or length of the plaintext to be +recovered. Hash algorithms are typically used to provide a digital fingerprint +of a file's contents, often used to ensure that the file has not been +altered by an intruder or virus. Hash functions are also commonly +employed by many operating systems to encrypt passwords. Hash +functions, then, help preserve the integrity of a file.

+

+Hash functions are sometimes misunderstood and some +sources claim that no two files can have the same hash value. This +isn't true, strictly speaking. Consider a hash function that provides a +128-bit hash value. There are, obviously, 2128 possible hash values. But there are a lot more than 2128 possible +files. Therefore, there have to be multiple files — in fact, there have +to be an infinite number of files! — that can have the same 128-bit +hash value. The difficulty is finding two files with the same +hash! What is, indeed, very hard to do is to try to create a file that +has a given hash value so as to force a hash value collision.

+ +

+Hash algorithms that are in common use today include:

+
    +
  • Message Digest (MD) algorithms: A series of byte-oriented algorithms that produce a 128-bit hash value from an arbitrary-length message.

    +
      +
    • MD2 (RFC 1319): Designed for systems with limited memory, such as smart cards.

    • +
    • MD4 (RFC 1320): Developed by Rivest, similar to MD2 but designed specifically for fast processing in software.

    • +
    • MD5 (RFC 1321: +Also developed by Rivest after potential weaknesses were reported in +MD4; this scheme is similar to MD4 but is slower because more +manipulation is made to the original data. MD5 has been implemented in +a large number of products although several weaknesses in the algorithm +were demonstrated by German cryptographer Hans Dobbertin in 1996.

    • +
    + +
  • Secure Hash Algorithm (SHA): Algorithm for NIST's +Secure Hash Standard (SHS). SHA-1 produces a 160-bit hash value and was +originally published as FIPS 180-1 and RFC 3174. FIPS 180-2 +describes five algorithms in the SHS: SHA-1 plus SHA-224, SHA-256, +SHA-384, and SHA-512 which can produce hash values that are 224, 256, +384, or 512 bits in length, respectively.

  • + +
  • RIPEMD: A series of message digests that initially came from the RIPE (RACE Integrity Primitives Evaluation) project. RIPEMD-160 +was designed by Hans Dobbertin, Antoon Bosselaers, and Bart Preneel, +and optimized for 32-bit processors to replace the then-current 128-bit +hash functions. Other versions include RIPEMD-256, RIPEMD-320, and +RIPEMD-128.

  • + +
  • HAVAL (HAsh of VAriable Length): +Designed by Y. Zheng, J. Pieprzyk and J. Seberry, a hash algorithm with +many levels of security. HAVAL can create hash values that are 128, +160, 192, 224, or 256 bits in length.

  • +
+

+For additional information, see David Hopwood's MessageDigest Algorithms page.

+ +

3.4. Why Three Encryption Techniques?

+

+So, why are there so many different types of cryptographic schemes? Why can't we do everything we need with just one? +

+The answer is that each scheme is optimized for some +specific application(s). Hash functions, for example, are well-suited +for ensuring data integrity because any change made to the contents of +a message will result in the receiver calculating a different hash +value than the one placed in the transmission by the sender. Since it +is highly unlikely that two different messages will yield the same hash +value, data integrity is ensured to a high degree of confidence. +

+Secret key cryptography, on the other hand, is ideally suited to encrypting messages. The sender can generate a session key on a per-message basis to encrypt the message; the receiver, of course, needs the same session key to decrypt the message. +

+Key exchange, of course, is a key application of +public-key cryptography (no pun intended). Asymmetric schemes can also +be used for non-repudiation; if the receiver can obtain the session key +encrypted with the sender's private key, then only this sender could +have sent the message. Public-key cryptography could, theoretically, +also be used to encrypt messages although this is rarely done because +secret-key cryptography operates about 1000 times faster than +public-key cryptography. +

+
+
+ +

+

FIGURE 2: Sample application of the three cryptographic techniques for secure communication.

+
+
+
+

+Figure 2 puts all of this together and shows how a hybrid cryptographic scheme combines all of these functions to form a secure transmission comprising digital signature and digital envelope. In this example, the sender of the message is Alice and the receiver is Bob. +

+A digital envelope comprises an encrypted message and an +encrypted session key. Alice uses secret key cryptography to encrypt +her message using the session key, which she generates at +random with each session. Alice then encrypts the session key using +Bob's public key. The encrypted message and encrypted session key +together form the digital envelope. Upon receipt, Bob recovers the +session secret key using his private key and then decrypts the +encrypted message. +

+The digital signature is formed in two steps. First, +Alice computes the hash value of her message; next, she encrypts the +hash value with her private key. Upon receipt of the digital signature, +Bob recovers the hash value calculated by Alice by decrypting the +digital signature with Alice's public key. Bob can then apply the hash +function to Alice's original message, which he has already decrypted +(see previous paragraph). If the resultant hash value is not the same +as the value supplied by Alice, then Bob knows that the message has +been altered; if the hash values are the same, Bob should believe that +the message he received is identical to the one that Alice sent. +

+This scheme also provides nonrepudiation since it proves +that Alice sent the message; if the hash value recovered by Bob using +Alice's public key proves that the message has not been altered, then +only Alice could have created the digital signature. Bob also has proof +that he is the intended receiver; if he can correctly decrypt the +message, then he must have correctly decrypted the session key meaning +that his is the correct private key.

+ +

3.5. The Significance of Key Length

+

+In a recent article in the industry literature (circa +9/98), a writer made the claim that 56-bit keys do not provide as +sufficient protection for DES today as they did in 1975 because +computers are 1000 times faster today than in 1975. Therefore, the +writer went on, we should be using 56,000-bit keys today instead of +56-bit keys to provide adequate protection. The conclusion was then +drawn that because 56,000-bit keys are infeasible (true), we should accept the fact that we have to live with weak cryptography (false!). +The major error here is that the writer did not take into account that +the number of possible key values double whenever a single bit is added +to the key length; thus, a 57-bit key has twice as many values as a +56-bit key (because 257 is two times 256). In fact, a 66-bit key would have 1024 times the possible values as a 56-bit key.

+ +

+But this does bring up the issue, what is the precise significance of key length as it affects the level of protection?

+

+In cryptography, size does matter. The larger the key, +the harder it is to crack a block of encrypted data. The reason that +large keys offer more protection is almost obvious; computers have made +it easier to attack ciphertext by using brute force methods rather than +by attacking the mathematics (which are generally well-known anyway). +With a brute force attack, the attacker merely generates every possible +key and applies it to the ciphertext. Any resulting plaintext that +makes sense offers a candidate for a legitimate key. This was the +basis, of course, of the EFF's attack on DES.

+

+Until the mid-1990s or so, brute force attacks were +beyond the capabilities of computers that were within the budget of the +attacker community. Today, however, significant compute power is +commonly available and accessible. General purpose computers such as +PCs are already being used for brute force attacks. For serious +attackers with money to spend, such as some large companies or +governments, Field Programmable Gate Array (FPGA) or +Application-Specific Integrated Circuits (ASIC) technology offers the +ability to build specialized chips that can provide even faster and +cheaper solutions than a PC. Consider that an AT&T ORCA chip (FPGA) +costs $200 and can test 30 million DES keys per second, while a $10 +ASIC chip can test 200 million DES keys per second (compared to a PC +which might be able to test 40,000 keys per second).

+

+The table below shows what DES key sizes are needed to +protect data from attackers with different time and financial +resources. This information is not merely academic; one of the basic +tenets of any security system is to have an idea of what you are protecting and from who +are you protecting it! The table clearly shows that a 40-bit key is +essentially worthless today against even the most unsophisticated +attacker. On the other hand, 56-bit keys are fairly strong unless you +might be subject to some pretty serious corporate or government +espionage. But note that even 56-bit keys are declining in their value +and that the times in the table (1995 data) are worst cases.

+ +
+ + + + + + + + + + + + + +
+TABLE 1. Minimum Key Lengths for Symmetric Ciphers. +
Type of Attacker +Budget +Tool +Time and Cost
Per Key Recovered +
Key Length Needed
For Protection
In Late-1995 +
40 bits +56 bits +
Pedestrian Hacker +Tiny +Scavanged
computer
time +
1 week +Infeasible +45 +
$400 +FPGA +5 hours
($0.08) +
38 years
($5,000) +
50 +
Small Business +$10,000 +FPGA +12 minutes
($0.08) +
18 months
($5,000) +
55 +
Corporate Department +$300K +FPGA +24 seconds
($0.08) +
19 days
($5,000) +
60 +
ASIC +0.18 seconds
($0.001) +
3 hours
($38) +
Big Company +$10M +FPGA +7 seconds
($0.08) +
13 hours
($5,000) +
70 +
ASIC +0.005 seconds
($0.001) +
6 minutes
($38) +
Intelligence Agency +$300M +ASIC +0.0002 seconds
($0.001) +
12 seconds
($38) +
75 +
+
+

+ +

+So, how big is big enough? DES, invented in 1975, is +still in use today, nearly 25 years later. If we take that to be a +design criteria (i.e., a 20-plus year lifetime) and we believe Moore's +Law ("computing power doubles every 18 months"), then a key size +extension of 14 bits (i.e., a factor of more than 16,000) should be +adequate. The 1975 DES proposal suggested 56-bit keys; by 1995, a +70-bit key would have been required to offer equal protection and an +85-bit key will be necessary by 2015.

+

+The discussion above suggests that a 128- or 256-bit key +for SKC will suffice for some time because that key length keeps us +ahead of the brute force capabilities of the attackers. While a large +key is good, a huge key may not always be better. That is, many +public-key cryptosystems use 1024- or 2048-bit keys; expanding the key +to 4096 bits probably doesn't add any protection at this time but it +does add significantly to processing time.

+

+The most effective large-number factoring methods today +use a mathematical Number Field Sieve to find a certain number of +relationships and then uses a matrix operation to solve a linear +equation to produce the two prime factors. The sieve step actually +involves a large number of operations of operations that can be +performed in parallel; solving the linear equation, however, requires a +supercomputer. Indeed, finding the solution to the RSA-140 challenge in +February 1999 — factoring a 140-digit (465-bit) prime number — required +200 computers across the Internet about 4 weeks for the first step and +a Cray computer 100 hours and 810 MB of memory to do the second step.

+

+In early 1999, Shamir (of RSA fame) described a new +machine that could increase factorization speed by 2-3 orders of +magnitude. Although no detailed plans were provided nor is one known to +have been built, the concepts of TWINKLE (The Weizmann Institute Key Locating Engine) +could result in a specialized piece of hardware that would cost about +$5000 and have the processing power of 100-1000 PCs. There still appear +to be many engineering details that have to be worked out before such a +machine could be built. Furthermore, the hardware improves the sieve +step only; the matrix operation is not optimized at all by this design +and the complexity of this step grows rapidly with key length, both in +terms of processing time and memory requirements. Nevertheless, this +plan conceptually puts 512-bit keys within reach of being factored. +Although most PKC schemes allow keys that are 1024 bits and longer, +Shamir claims that 512-bit RSA keys "protect 95% of today's E-commerce +on the Internet." (See Bruce Schneier's Crypto-Gram (May 15, 1999) for more information, as well as the comments from RSA Labs.)

+

+It is also interesting to note that while cryptography +is good and strong cryptography is better, long keys may disrupt the +nature of the randomness of data files. Shamir and van Someren ("Playing hide and seek with stored keys") +have noted that a new generation of viruses can be written that will +find files encrypted with long keys, making them easier to find by +intruders and, therefore, more prone to attack.

+

+Finally, U.S. government policy has tightly controlled +the export of crypto products since World War II. Until recently, +export outside of North America of cryptographic products using keys +greater than 40 bits in length was prohibited, which made those +products essentially worthless in the marketplace, particularly for +electronic commerce. More recently, the U.S. Commerce Department +relaxed the regulations, allowing the general export of 56-bit SKC and +1024-bit PKC products (certain sectors, such as health care and +financial, allow the export of products with even larger keys). The +Commerce Department's Bureau of Export Administration maintains a Commercial Encryption Export Controls web page with more information. The potential impact of this policy on U.S. businesses is well beyond the scope of this paper.

+

+Much of the discussion above, including the table, are based on the paper "Minimal Key Lengths for Symmetric Ciphers to Provide Adequate Commercial Security" by M. Blaze, W. Diffie, R.L. Rivest, B. Schneier, T. Shimomura, E. Thompson, and M. Wiener.

+

+On a related topic, public key crypto schemes can be +used for several purposes, including key exchange, digital signatures, +authentication, and more. In those PKC systems used for SKC key +exchange, the PKC key lengths are chosen so to be resistant to some +selected level of attack. The length of the secret keys exchanged via +that system have to have at least the same level of attack resistance. +Thus, the three parameters of such a system — system strength, secret +key strength, and public key strength — must be matched. This topic is +explored in more detail in Determining Strengths For Public Keys Used For Exchanging Symmetric Keys (RFC 3766).

+ +
+

4. TRUST MODELS

+

+Secure use of cryptography requires trust. While secret +key cryptography can ensure message confidentiality and hash codes can +ensure integrity, none of this works without trust. In SKC, Alice and +Bob had to share a secret key. PKC solved the secret distribution +problem, but how does Alice really know that Bob is who he says he is? +Just because Bob has a public and private key, and purports to be +"Bob," how does Alice know that a malicious person (Mallory) is not +pretending to be Bob? +

+There are a number of trust models employed by various cryptographic schemes. This section will explore three of them: +

+
    +
  • The web of trust employed by Pretty Good Privacy (PGP) users, who hold their own set of trusted public keys. +
  • Kerberos, a secret key distribution scheme using a trusted third party. +
  • Certificates, which allow a set of trusted third parties to authenticate each other and, by implication, each other's users. +
+

+Each of these trust models differs in complexity, general applicability, scope, and scalability. +

+

4.1. PGP Web of Trust

+

+Pretty Good Privacy (described more below in Section 5.5) +is a widely used private e-mail scheme based on public key methods. A +PGP user maintains a local keyring of all their known and trusted +public keys. The user makes their own determination about the +trustworthiness of a key using what is called a "web of trust." +

+If Alice needs Bob's public key, Alice can ask Bob for +it in another e-mail or, in many cases, download the public key from an +advertised server; this server might a well-known PGP key repository or +a site that Bob maintains himself. In fact, Bob's public key might be +stored or listed in many places. (The author's public key, for example, +can be found at http://www.garykessler.net/kumquat_pubkey.html.) Alice is prepared to believe that Bob's public key, as stored at these locations, is valid. +

+Suppose Carol claims to hold Bob's public key and offers +to give the key to Alice. How does Alice know that Carol's version of +Bob's key is valid or if Carol is actually giving Alice a key that will +allow Mallory access to messages? The answer is, "It depends." If Alice +trusts Carol and Carol says that she thinks that her version of Bob's +key is valid, then Alice may — at her option — trust +that key. And trust is not necessarily transitive; if Dave has a copy +of Bob's key and Carol trusts Dave, it does not necessarily follow that +Alice trusts Dave even if she does trust Carol. +

+The point here is that who Alice trusts and how she +makes that determination is strictly up to Alice. PGP makes no +statement and has no protocol about how one user determines whether +they trust another user or not. In any case, encryption and signatures +based on public keys can only be used when the appropriate public key +is on the user's keyring. +

+

4.2. Kerberos

+

+Kerberos is a commonly used authentication scheme on the +Internet. Developed by MIT's Project Athena, Kerberos is named for the +three-headed dog who, according to Greek mythology, guards the entrance +of Hades (rather than the exit, for some reason!). +

+ +Kerberos employs a client/server architecture and +provides user-to-server authentication rather than host-to-host +authentication. In this model, security and authentication will be +based on secret key technology where every host on the network has its +own secret key. It would clearly be unmanageable if every host had to +know the keys of all other hosts so a secure, trusted host somewhere on +the network, known as a Key Distribution Center (KDC), knows the keys +for all of the hosts (or at least some of the hosts within a portion of +the network, called a realm). In this way, when a new node is +brought online, only the KDC and the new node need to be configured +with the node's key; keys can be distributed physically or by some +other secure means. +
+
+

+ +

+

FIGURE 3: Kerberos architecture.

+
+
+
The Kerberos Server/KDC has two main +functions (Figure 3), known as the Authentication Server (AS) and +Ticket-Granting Server (TGS). The steps in establishing an +authenticated session between an application client and the application +server are: +

+
    +
  1. The Kerberos client software +establishes a connection with the Kerberos server's AS function. The AS +first authenticates that the client is who it purports to be. The AS +then provides the client with a secret key for this login session (the TGS session key) +and a ticket-granting ticket (TGT), which gives the client permission +to talk to the TGS. The ticket has a finite lifetime so that the +authentication process is repeated periodically. +
  2. The client now communicates with the TGS +to obtain the Application Server's key so that it (the client) can +establish a connection to the service it wants. The client supplies the +TGS with the TGS session key and TGT; the TGS responds with an +application session key (ASK) and an encrypted form of the Application +Server's secret key; this secret key is never sent on the network in any other form. +
  3. The client has now authenticated itself and +can prove its identity to the Application Server by supplying the +Kerberos ticket, application session key, and encrypted Application +Server secret key. The Application Server responds with similarly +encrypted information to authenticate itself to the client. At this +point, the client can initiate the intended service requests (e.g., +Telnet, FTP, HTTP, or e-commerce transaction session establishment). +
+

+The current shipping version of this protocol is Kerberos V5 (described in RFC 1510), +although Kerberos V4 still exists and is seeing some use. While the +details of their operation, functional capabilities, and message +formats are different, the conceptual overview above pretty much holds +for both. One primary difference is that Kerberos V4 uses only DES to +generate keys and encrypt messages, while V5 allows other schemes to be +employed (although DES is still the most widely algorithm used). +

+

4.3. Public Key Certificates and Certificate Authorities

+

+Certificates and Certificate Authorities (CA) +are necessary for widespread use of cryptography for e-commerce +applications. While a combination of secret and public key cryptography +can solve the business issues discussed above, crypto cannot alone +address the trust issues that must exist between a customer and vendor +in the very fluid, very dynamic e-commerce relationship. How, for +example, does one site obtain another party's public key? How does a +recipient determine if a public key really belongs to the sender? How +does the recipient know that the sender is using their public key for a +legitimate purpose for which they are authorized? When does a public +key expire? How can a key be revoked in case of compromise or loss? +

+The basic concept of a certificate is one that is +familiar to all of us. A driver's license, credit card, or SCUBA +certification, for example, identify us to others, indicate something +that we are authorized to do, have an expiration date, and identify the +authority that granted the certificate. +

+As complicated as this may sound, it really isn't! +Consider driver's licenses. I have one issued by the State of Vermont. +The license establishes my identity, indicates the type of vehicles +that I can operate and the fact that I must wear corrective lenses +while doing so, identifies the issuing authority, and notes that I am +an organ donor. When I drive outside of Vermont, the other +jurisdictions throughout the U.S. recognize the authority of Vermont to +issue this "certificate" and they trust the information it contains. +Now, when I leave the U.S., everything changes. When I am in Canada and +many other countries, they will accept not the Vermont license, per se, +but any license issued in the U.S.; some other countries may +not recognize the Vermont driver's license as sufficient bona fides +that I can drive. This analogy represents the certificate chain, where +even certificates carry certificates. +

+For purposes of electronic transactions, certificates are digital documents. The specific functions of the certificate include: +

    +
  • Establish identity: Associate, or bind, a public key to an individual, organization, corporate position, or other entity. +
  • Assign authority: Establish what actions the holder may or may not take based upon this certificate. +
  • Secure confidential information (e.g., encrypting the session's symmetric key for data confidentiality). +
+

+Typically, a certificate contains a public key, a name, +an expiration date, the name of the authority that issued the +certificate (and, therefore, is vouching for the identity of the user), +a serial number, any pertinent policies describing how the certificate +was issued and/or how the certificate may be used, the digital +signature of the certificate issuer, and perhaps other information. +
+
+

+ +

+

FIGURE 4: GTE Cybertrust Global Root-issued certificate as viewed
by Netscape Navigator V4.

+
+
+
+

+A sample abbreviated certificate is +shown in Figure 4. This is a typical certificate found in a browser; +while this one is issued by GTE Cybertrust, many so-called root-level +certificates can be found shipped with browsers. When the browser makes +a connection to a secure Web site, the Web server sends its public key +certificate to the browser. The browser then checks the certificate's +signature against the public key that it has stored; if there is a +match, the certificate is taken as valid and the Web site verified by +this certificate is considered to be "trusted." +

+
+ + +
+TABLE 2. Contents of an X.509 V3 Certificate. +
+
    +version number
    +certificate serial number
    +signature algorithm identifier
    +issuer's name and unique identifier
    +validity (or operational) period
    +subject's name and unique identifier
    +subject public key information
    +standard extensions
    +
      +certificate appropriate use definition
      +key usage limitation definition
      +certificate policy information
      +
    +other extensions
    +
      +Application-specific
      +CA-specific
      +
    +
+
+
+

+

+The most widely accepted certificate format is the one +defined in International Telecommunication Union Telecommunication +Standardization Sector (ITU-T) Recommendation X.509. Rec. X.509 is a +specification used around the world and any applications complying with +X.509 can share certificates. Most certificates today comply with X.509 +Version 3 and contain the information listed in Table 2. +

+Certificate authorities are the repositories for +public-keys and can be any agency that issues certificates. A company, +for example, may issue certificates to its employees, a +college/university to its students, a store to its customers, an +Internet service provider to its users, or a government to its +constituents.

+When a sender needs an intended receiver's public key, +the sender must get that key from the receiver's CA. That scheme is +straight-forward if the sender and receiver have certificates issued by +the same CA. If not, how does the sender know to trust the +foreign CA? One industry wag has noted, about trust: "You are either +born with it or have it granted upon you." Thus, some CAs will be +trusted because they are known to be reputable, such as the CAs +operated by AT&T, BBN, Canada Post Corp., CommerceNet, GTE Cybertrust, MCI, Nortel EnTrust, Thawte, the U.S. Postal Service, and VeriSign. +CAs, in turn, form trust relationships with other CAs. Thus, if a user +queries a foreign CA for information, the user may ask to see a list of +CAs that establish a "chain of trust" back to the user. +

+One major feature to look for in a CA is their +identification policies and procedures. When a user generates a key +pair and forwards the public key to a CA, the CA has to check the +sender's identification and takes any steps necessary to assure itself +that the request is really coming from the advertised sender. Different +CAs have different identification policies and will, therefore, be +trusted differently by other CAs. Verification of identity is just of +many issues that are part of a CA's Certification Practice Statement +(CPS) and policies; other issues include how the CA protects the public +keys in its care, how lost or compromised keys are revoked, and how the +CA protects its own private keys. +

+

4.4. Summary

+

+The paragraphs above describe three very different trust +models. It is hard to say that any one is better than the others; it +depend upon your application. One of the biggest and fastest growing +applications of cryptography today, though, is electronic commerce +(e-commerce), a term that itself begs for a formal definition. +

+PGP's web of trust is easy to maintain and very much +based on the reality of users as people. The model, however, is +limited; just how many public keys can a single user reliably store and +maintain? And what if you are using the "wrong" computer when you want +to send a message and can't access your keyring? How easy it is to +revoke a key if it is compromised? PGP may also not scale well to an +e-commerce scenario of secure communication between total strangers on +short-notice. +

+Kerberos overcomes many of the problems of PGP's web of +trust, in that it is scalable and its scope can be very large. However, +it also requires that the Kerberos server have a priori +knowledge of all client systems prior to any transactions, which makes +it unfeasible for "hit-and-run" client/server relationships as seen in +e-commerce. +

+Certificates and the collection of CAs will form a +Public Key Infrastructure (PKI). In the early days of the Internet, +every host had to maintain a list of every other host; the Domain Name +System (DNS) introduced the idea of a distributed database for this +purpose and the DNS is one of the key reasons that the Internet has +grown as it has. A PKI will fill a similar void in the e-commerce and +PKC realm. +

+While certificates and the benefits of a PKI are most +often associated with electronic commerce, the applications for PKI are +much broader and include secure electronic mail, payments and +electronic checks, Electronic Data Interchange (EDI), secure transfer +of Domain Name System (DNS) and routing information, electronic forms, +and digitally signed documents. A single "global PKI" is still many +years away, that is the ultimate goal of today's work as international +electronic commerce changes the way in which we do business in a +similar way in which the Internet has changed the way in which we +communicate. +

+
+ +

5. CRYPTOGRAPHIC ALGORITHMS IN ACTION

+

+The paragraphs above have provided an overview of the +different types of cryptographic algorithms, as well as some examples +of some available protocols and schemes. Table 3 provides an even +longer list of some of the schemes employed today for a variety of +functions, most notably electronic commerce. The paragraphs below will +show several real cryptographic applications that many of us employ +(knowingly or not) everyday; for password protection and private +communication. +

+
+ + + + +
TABLE 3. Other Crypto Algorithms and Systems of Note.

Capstone +A now-defunct U.S. National Institute +of Standards and Technology (NIST) and National Security Agency (NSA) +project under the Bush Sr. and Clinton administrations for publicly +available strong cryptography with keys escrowed by the government +(NIST and the Treasury Dept.). Capstone included in one or more +tamper-proof computer chips for implementation (Clipper), a secret key +encryption algorithm (Skipjack), digital signature algorithm (DSA), key +exchange algorithm (KEA), and hash algorithm (SHA). +
Clipper +The computer chip that would implement the Skipjack encryption scheme. See also EPIC's The Clipper Chip Web page. + +
Escrowed Encryption Standard (EES) +Largely unused, a controversial +crypto scheme employing the SKIPJACK secret key crypto algorithm and a +Law Enforcement Access Field (LEAF) creation method. LEAF was one part +of the key escrow system and allowed for decryption of ciphertext +messages that had been legally intercepted by law enforcement agencies. +Described more in FIPS 185. + +
Federal Information Processing Standards (FIPS) +These computer security- and +crypto-related FIPS are produced by the U.S. National Institute of +Standards and Technology (NIST) as standards for the U.S. Government. +
Fortezza (formerly called Tessera) +A PCMCIA card developed by NSA that +implements the Capstone algorithms, intended for use with the Defense +Messaging Service (DMS). + +
IP Security Protocol (IPsec) +The IPsec protocol suite is used to +provide privacy and authentication services at the IP layer. An +overview of the protocol suite and of the documents comprising IPsec +can be found in RFC 2411. Other documents include: +
    +
  • RFC 2401: IP security architecture. +
  • RFC 2402: +IP Authentication Header (AH), one of the two primary IPsec functions; +AH provides connectionless integrity and data origin authentication for +IP datagrams and protects against replay attacks. +
  • RFC 2403: Describes use of the HMAC with MD5 algorithm for data origin authentication and integrity protection in both AH and ESP. +
  • RFC 2404: Describes use of the HMAC with SHA-1 algorithm for data origin authentication and integrity protection in both AH and ESP. +
  • RFC 2405: Describes use of DES-CBC (DES in Cipher Block Chaining Mode) for confidentiality in ESP. +
  • RFC 2406: +IP Encapsulating Security Payload (ESP), the other primary IPsec +function; ESP provides a variety of security services within IPsec. +
  • RFC 2407: Describes the application of ISAKMP to IPsec. +
  • RFC 2408: Describes ISAKMP, a framework for key management and security associations. +
  • RFC 2409: +The Internet Key Exchange (IKE) algorithm, using part of Oakley and +part of SKEME in conjunction with ISAKMP to obtain authenticated keying +material for use with ISAKMP, and for other security associations such +as AH and ESP. +
  • RFC 2410: Defines use of the NULL encryption algorithm (i.e., provides authentication and integrity without confidentiality) in ESP. +
  • RFC 2412: Describes OAKLEY, a key determination and distribution protocol. +
  • RFC 2451: Describes use of Cipher Block Chaining (CBC) mode cipher algorithms with ESP. +
  • RFCs 2522 and 2523: Description of Photuris, a session-key management protocol for IPsec. +
+

+IPsec was first proposed for use with IP version 6 (IPv6), but can also be employed with the current IP version, IPv4. +

+(See more detail about IPsec below in Section 5.6.) + +

Internet Security Association and Key Management Protocol (ISAKMP/OAKLEY) +ISAKMP/OAKLEY provide an infrastructure for Internet secure communications. ISAKMP, designed by the National Security Agency (NSA) and described in RFC 2408, +is a framework for key management and security associations, +independent of the key generation and cryptographic algorithms actually +employed. The OAKLEY Key Determination Protocol, described in RFC 2412, is a key determination and distribution protocol using a variation of Diffie-Hellman. + +
Kerberos +A secret-key encryption and +authentication system, designed to authenticate requests for network +resources within a user domain rather than to authenticate messages. +Kerberos also uses a trusted third-party approach; a client +communications with the Kerberos server to obtain "credentials" so that +it may access services at the application server. Kerberos V4 uses DES +to generate keys and encrypt messages; DES is also commonly used in +Kerberos V5, although other schemes could be employed. +

Microsoft added support for Kerberos V5 — with some proprietary +extensions — in Windows 2000. There are many Kerberos articles posted +at Microsoft's Knowledge Base, notably "Basic Overview of Kerberos User Authentication Protocol in Windows 2000," "Windows 2000 Kerberos 5 Ticket Flags and KDC Options for AS_REQ and TGS_REQ Messages," and "Kerberos Administration in Windows 2000." + +

Keyed-Hash Message Authentication Code (HMAC) +A message authentication scheme based +upon secret key cryptography and the secret key shared between two +parties rather than public key methods. Described in FIPS 198 and RFC 2104. + +
Message Digest Cipher (MDC) +Invented by Peter Gutman, MDC turns a one-way hash function into a block cipher. + +
MIME Object Security Standard (MOSS) +Designed as a successor to PEM to provide PEM-based security services to MIME messages. + +
Pretty Good Privacy (PGP) +A family of cryptographic routines +for e-mail and file storage applications developed by Philip +Zimmermann. PGP 2.6.x uses RSA for key management and digital +signatures, IDEA for message encryption, and MD5 for computing the +message's hash value; more information can also be found in RFC 1991. +PGP 5.x (formerly known as "PGP 3") uses Diffie-Hellman/DSS for key +management and digital signatures; IDEA, CAST, or 3DES for message +encryption; and MD5 or SHA for computing the message's hash value. +OpenPGP, described in RFC 2440, is an open definition of security software based on PGP 5.x. +

+(See more detail about PGP below in Section 5.5.) + +

Privacy Enhanced Mail (PEM) +Provides secure electronic mail over +the Internet and includes provisions for encryption (DES), +authentication, and key management (DES, RSA). May be superseded by +S/MIME and PEM-MIME. Developed by IETF PEM Working Group and defined in +four RFCs: +
  • RFC 1421: Part I, Message Encryption and Authentication Procedures +
  • RFC 1422: Part II, Certificate-Based Key Management +
  • RFC 1423: Part III, Algorithms, Modes, and Identifiers +
  • RFC 1424: Part IV, Key Certification and Related Services + + +
  • Private Communication Technology (PCT) +Developed by Microsoft and Visa for +secure communication on the Internet. Similar to SSL, PCT supports +Diffie-Hellman, Fortezza, and RSA for key establishment; DES, RC2, RC4, +and triple-DES for encryption; and DSA and RSA message signatures. A +companion to SET. +
    Secure Electronic Transactions (SET) +A merging of two other protocols: +SEPP (Secure Electronic Payment Protocol), an open specification for +secure bank card transactions over the Internet, developed by +CyberCash, GTE, IBM, MasterCard, and Netscape; and STT (Secure +Transaction Technology), a secure payment protocol developed by +Microsoft and Visa International. Supports DES and RC4 for encryption, +and RSA for signatures, key exchange, and public-key encryption of bank +card numbers. SET is a companion to the PCT protocol. +
    Secure Hypertext Transfer Protocol (S-HTTP) +An extension to HTTP to provide +secure exchange of documents over the World Wide Web. Supported +algorithms include RSA and Kerberos for key exchange, DES, IDEA, RC2, +and Triple-DES for encryption. +
    Secure Multipurpose Internet Mail Extensions (S/MIME) +An IETF secure e-mail scheme intended to supercede PEM. S/MIME, described in RFCs 2311 and 2312, adds digital signature and encryption capability to Internet MIME messages. + +
    Secure Sockets Layer (SSL) +Developed by Netscape Communications +to provide application-independent security and privacy over the +Internet. SSL is designed so that protocols such as HTTP, FTP (File +Transfer Protocol), and Telnet can operate over it transparently. SSL +allows both server authentication (mandatory) and client authentication +(optional). RSA is used during negotiation to exchange keys and +identify the actual cryptographic algorithm (DES, IDEA, RC2, RC4, or +3DES) to use for the session. SSL also uses MD5 for message digests and +X.509 public-key certificates. (Found to be breakable soon after the +IETF announced formation of group to work on TLS.) +

    +(See more detail about SSL below in Section 5.7.) + +

    Server Gated Cryptography (SGC) +Microsoft extension to SSL that +provides strong encryption for online banking and other financial +applications using RC2 (128-bit key), RC4 (128-bit key), DES (56-bit +key), or 3DES (equivalent of 168-bit key). Use of SGC requires a +Windows NT Server running Internet Information Server (IIS) 4.0 with a +valid SGC certificate. SGC is available in 32-bit Windows versions of +Internet Explorer (IE) 4.0, and support for Mac, Unix, and 16-bit +Windows versions of IE is expected in the future. +
    Simple Key-Management for Internet Protocol (SKIP) +Key management scheme for secure IP +communication, specifically for IPsec, and designed by Aziz and Diffie. +SKIP essentially defines a public key infrastructure for the Internet +and even uses X.509 certificates. Most public key cryptosystems assign +keys on a per-session basis, which is inconvenient for the Internet +since IP is connectionless. Instead, SKIP provides a basis for secure +communication between any pair of Internet hosts. SKIP can employ DES, +3DES, IDEA, RC2, RC5, MD5, and SHA-1. +
    Transport Layer Security (TLS) +IETF specification (RFC 2246) +intended to replace SSL. Employs Triple-DES (secret key cryptography), +SHA (hash), Diffie-Hellman (key exchange), and DSS (digital +signatures). +

    +(See more detail about TLS below in Section 5.7.) + +

    X.509 +ITU-T recommendation for the format +of certificates for the public key infrastructure. Certificates map +(bind) a user identity to a public key. The IETF application of X.509 +certificates is documented in RFC 2459. An Internet X.509 Public Key Infrastructure is further defined in RFC 2510 (Certificate Management Protocols) and RFC 2527 (Certificate Policy and Certification Practices Framework). +
    + +

    +

    5.1. Password Protection

    +

    +Nearly all modern multiuser computer and network +operating systems employ passwords at the very least to protect and +authenticate users accessing computer and/or network resources. But +passwords are not typically kept on a host or server in plaintext, but are generally encrypted using some sort of hash scheme.

    + +
    +
    + +
    +
    A) /etc/passwd file
    +
    + root:Jbw6BwE4XoUHo:0:0:root:/root:/bin/bash
    + carol:FM5ikbQt1K052:502:100:Carol Monaghan:/home/carol:/bin/bash
    + alex:LqAi7Mdyg/HcQ:503:100:Alex Insley:/home/alex:/bin/bash
    + gary:FkJXupRyFqY4s:501:100:Gary Kessler:/home/gary:/bin/bash
    + todd:edGqQUAaGv7g6:506:101:Todd Pritsky:/home/todd:/bin/bash
    + josh:FiH0ONcjPut1g:505:101:Joshua Kessler:/home/webroot:/bin/bash
    +
    +B.1) /etc/passwd file (with shadow passwords)
    +
    + root:x:0:0:root:/root:/bin/bash
    + carol:x:502:100:Carol Monaghan:/home/carol:/bin/bash
    + alex:x:503:100:Alex Insley:/home/alex:/bin/bash
    + gary:x:501:100:Gary Kessler:/home/gary:/bin/bash
    + todd:x:506:101:Todd Pritsky:/home/todd:/bin/bash
    + josh:x:505:101:Joshua Kessler:/home/webroot:/bin/bash
    +
    +B.2) /etc/shadow file
    +
    + root:AGFw$1$P4u/uhLK$l2.HP35rlu65WlfCzq:11449:0:99999:7:::
    + carol:kjHaN%35a8xMM8a/0kMl1?fwtLAM.K&kw.:11449:0:99999:7:::
    + alex:1$1KKmfTy0a7#3.LL9a8H71lkwn/.hH22a:11449:0:99999:7:::
    + gary:9ajlknknKJHjhnu7298ypnAIJKL$Jh.hnk:11449:0:99999:7:::
    + todd:798POJ90uab6.k$klPqMt%alMlprWqu6$.:11492:0:99999:7:::
    + josh:Awmqpsui*787pjnsnJJK%aappaMpQo07.8:11492:0:99999:7:::
    +
    +

    +

    FIGURE 5: Sample entries in Unix/Linux password files.

    +
    +
    + +

    +Unix/Linux, for example, uses a well-known hash via its crypt() function. Passwords are stored in the /etc/passwd +file (Figure 5A); each record in the file contains the username, hashed +password, user's individual and group numbers, user's name, home +directory, and shell program; these fields are separated by colons (:). +Note that each password is stored as a 13-byte string. The first two +characters are actually a salt, randomness added to each +password so that if two users have the same password, they will still +be encrypted differently; the salt, in fact, provides a means so that a +single password might have 4096 different encryptions. The remaining 11 +bytes are the password hash, calculated using DES.

    +

    +As it happens, the /etc/passwd file is +world-readable on Unix systems. This fact, coupled with the weak +encryption of the passwords, resulted in the development of the shadow password +system where passwords are kept in a separate, non-world-readable file +used in conjunction with the normal password file. When shadow +passwords are used, the password entry in /etc/passwd is replaced with a "*" or "x" (Figure 5B.1) and the MD5 hash of the passwords are stored in /etc/shadow along with some other account information (Figure 5B.2).

    +
    +

    +Windows NT uses a similar scheme to store passwords in +the Security Access Manager (SAM) file. In the NT case, all passwords +are hashed using the MD4 algorithm, resulting in a 128-bit (16-byte) +hash value (they are then obscured using an undocumented mathematical transformation that was a secret until distributed on the Internet). The password password, for example, might be stored as the hash value (in hexadecimal) 60771b22d73c34bd4a290a79c8b09f18.

    +

    +Passwords are not saved in plaintext on computer systems +precisely so they cannot be easily compromised. For similar reasons, we +don't want passwords sent in plaintext across a network. But for remote +logon applications, how does a client system identify itself or a user +to the server? One mechanism, of course, is to send the password as a +hash value and that, indeed, may be done. A weakness of that approach, +however, is that an intruder can grab the password off of the network +and use an off-line attack (such as a dictionary attack where +an attacker takes every known word and encrypts it with the network's +encryption algorithm, hoping eventually to find a match with a +purloined password hash). In some situations, an attacker only has to +copy the hashed password value and use it later on to gain unauthorized +entry without ever learning the actual password.

    +

    +An even stronger authentication method uses the password +to modify a shared secret between the client and server, but never +allows the password in any form to go across the network. This is the +basis for the Challenge Handshake Authentication Protocol (CHAP), the +remote logon process used by Windows NT.

    +

    +As suggested above, Windows NT passwords are stored in a +security file on a server as a 16-byte hash value. In truth, Windows NT +stores two hashes; a weak hash based upon the old LAN Manager +(LanMan) scheme and the newer NT hash. When a user logs on to a server +from a remote workstation, the user is identified by the username, sent +across the network in plaintext (no worries here; it's not a secret +anyway!). The server then generates a 64-bit random number and sends it +to the client (also in plaintext). This number is the challenge.

    +

    +Using the LanMan scheme, the client system then encrypts +the challenge using DES. Recall that DES employs a 56-bit key, acts on +a 64-bit block of data, and produces a 64-bit output. In this case, the +64-bit data block is the random number. The client actually uses three +different DES keys to encrypt the random number, producing three +different 64-bit outputs. The first key is the first seven bytes (56 +bits) of the password's hash value, the second key is the next seven +bytes in the password's hash, and the third key is the remaining two +bytes of the password's hash concatenated with five zero-filled bytes. +(So, for the example above, the three DES keys would be 60771b22d73c34, bd4a290a79c8b0, and 9f180000000000.) Each key is applied to the random number resulting in three 64-bit outputs, which comprise the response. +Thus, the server's 8-byte challenge yields a 24-byte response from the +client and this is all that would be seen on the network. The server, +for its part, does the same calculation to ensure that the values match.

    +

    +There is, however, a significant weakness to this +system. Specifically, the response is generated in such a way as to +effectively reduce 16-byte hash to three smaller hashes, of length +seven, seven, and two. Thus, a password cracker has to break at most a +7-byte hash. One Windows NT vulnerability test program that I have used +in the past will report passwords that are "too short," defined as +"less than 8 characters." When I asked how the program knew that +passwords were too short, the software's salespeople suggested to me +that the program broke the passwords to determine their length. This is +undoubtedly not true; all the software really has to do is look at the +second 7-byte block and some known value indicates that it is empty, +which would indicate a password of seven or less characters.

    +

    +Consider the following example, showing the LanMan hash +of two different short passwords (take a close look at the last 8 +bytes):

    + + + + +
    AA: +89D42A44E77140AAAAD3B435B51404EE +
    AAA: +1C3A2B6D939A1021AAD3B435B51404EE +
    + +

    +Note that the NT hash provides no such clue:

    + + + + +
    AA: +C5663434F963BE79C8FD99F535E7AAD8 +
    AAA: +6B6E0FB2ED246885B98586C73B5BFB77 +
    + +

    +It is worth noting that the discussion above describes the Microsoft version of CHAP, or MS-CHAP (MS-CHAPv2 is described in RFC 2759). +MS-CHAP assumes that it is working with hashed values of the password +as the key to encrypting the challenge. More traditional CHAP (RFC 1994) +assumes that it is starting with passwords in plaintext. The relevance +of this observation is that a CHAP client, for example, cannot be +authenticated by an MS-CHAP server; both client and server must use the +same CHAP version.

    + +

    5.2. Some of the Finer Details of Diffie-Hellman

    +

    +The first published public-key crypto algorithm was +Diffie-Hellman. The mathematical "trick" of this scheme is that it is +relatively easy to compute exponents compared to computing discrete +logarithms. Diffie-Hellman allows two parties — the ubiquitous Alice +and Bob — to generate a secret key; they need to exchange some +information over an unsecure communications channel to perform the +calculation but an eavesdropper cannot determine the shared key based +upon this information.

    +

    +Diffie-Hellman works like this. Alice and Bob start by agreeing on a large prime number, n. They also have to choose some number g so that g<n.

    +

    +There is actually another constraint on g, specifically that it must be primitive with respect to n. Primitive is a definition that is a little beyond the scope of our discussion but basically g is primitive to n if we can find integers i so that gi += j mod n for all values of j from 1 to n-1. As an example, 2 is not +primitive to 7 because the set of powers of 2 from 1 to 6, mod 7 = +{2,4,1,2,4,1}. On the other hand, 3 is primitive to 7 because the set +of powers of 3 from 1 to 6, mod 7 = {3,2,6,4,5,1}.

    +

    +(The definition of primitive introduced a new term to some readers, namely mod. The phrase x mod y (and read as written!) means "take the remainder after dividing x by y." Thus, 1 mod 7 = 1, 9 mod 6 = 3, and 8 mod 8 = 0.)

    +

    +Anyway, either Alice or Bob selects n and g; they then +tell the other party what the values are. Alice and Bob then work +independently:

    + +
    + + +
    +
    Alice...

    +Choose a large random number, x
    +Send to Bob: X = gx mod n
    +Compute: KA = Yx mod n
    +
    +
    Bob...

    +Choose a large random number, y
    +Send to Alice: Y = gy mod n
    +Compute: KB = Xy mod n
    +
    +
    + +

    +Note that x and y are kept secret while X +and Y are openly shared; these are the private and public keys, +respectively. Based on their own private key and the public key learned +from the other party, Alice and Bob have computed their secret keys, KA and KB, respectively, which are equal to gxy mod n.

    +

    +Perhaps a small example will help here. Although Alice +and Bob will really choose large values for n and g, I will use small +values for example only; let's use n=7 and g=3.

    + +
    + + +
    +
    Alice...

    +Choose x=2
    +Send to Bob: X = 32 mod 7 = 2
    +KA = 62 mod 7 = 1
    +
    +
    Bob...

    +Choose y=3
    +Send to Alice: Y = 33 mod 7 = 6
    +KB = 23 mod 7 = 1
    +
    +
    + +

    +In this example, then, Alice and Bob will both find the secret key 1 which is, indeed, 36 +mod 7. If an eavesdropper (Mallory) was listening in on the information +exchange between Alice and Bob, he would learn g, n, X, and Y which is +a lot of information but insufficient to compromise the key; as long as +x and y remain unknown, K is safe. As said above, calculating X as gx is a lot easier than finding x as logg X!

    +
    +

    +A short digression on modulo arithmetic. In the paragraph above, we noted that 36 mod 7 = 1. This can be confirmed, of course, by noting that:

    +

    +36 = 729 = 104*7 + 1

    +

    +There is a nice property of modulo arithmetic, however, +that makes this determination a little easier, namely: (a mod x)(b mod +x) = (ab mod x). Therefore, one possible shortcut is to note that 36 = (33)(33). Therefore, 36 mod 7 = (33 mod 7)(33 mod 7) = (27 mod 7)(27 mod 7) = 6*6 mod 7 = 36 mod 7 = 1.

    +
    +

    +Diffie-Hellman can also be used to allow key sharing +amongst multiple users. Note again that the Diffie-Hellman algorithm is +used to generate secret keys, not to encrypt and decrypt messages.

    + +

    5.3. Some of the Finer Details of RSA Public-Key Cryptography

    +

    +Unlike Diffie-Hellman, RSA can be used for key exchange +as well as digital signatures and the encryption of small blocks of +data. Today, RSA is primary used to encrypt the session key used for +secret key encryption (message integrity) or the message's hash value +(digital signature). RSA's mathematical hardness comes from the ease in +calculating large numbers and the difficulty in finding the prime +factors of those large numbers. Although employed with numbers using +hundreds of digits, the math behind RSA is relatively straight-forward.

    +

    +To create an RSA public/private key pair, here are the basic steps:

    +
      +
    1. Choose two prime numbers, p and q. From these numbers you can calculate the modulus, n = pq. +
    2. Select a third number, e, that is relatively prime to (i.e., +it does not divide evenly into) the product (p-1)(q-1). The number e is +the public exponent. +
    3. Calculate an integer d from the quotient (ed-1)/[(p-1)(q-1)]. The number d is the private exponent. +
    +

    +The public key is the number pair (n,e). Although these +values are publicly known, it is computationally infeasible to +determine d from n and e if p and q are large enough.

    +

    +To encrypt a message, M, with the public key, create the ciphertext, C, using the equation:

    +
      +C = Me mod n +
    +

    +The receiver then decrypts the ciphertext with the private key using the equation:

    +
      +M = Cd mod n +
    +

    +Now, this might look a bit complex and, indeed, the +mathematics does take a lot of computer power given the large size of +the numbers; since p and q may be 100 digits (decimal) or more, d and e +will be about the same size and n may be over 200 digits. Nevertheless, +a simple example may help. In this example, the values for p, q, e, and +d are purposely chosen to be very small and the reader will see exactly +how badly these values perform, but hopefully the algorithm will be +adequately demonstrated:

    +
      +
    1. Select p=3 and q=5. +
    2. The modulus n = pq = 15. +
    3. The value e must be relatively prime to (p-1)(q-1) = (2)(4) = 8. Select e=11 +
    4. The value d must be chosen so that (ed-1)/[(p-1)(q-1)] is an +integer. Thus, the value (11d-1)/[(2)(4)] = (11d-1)/8 must be an +integer. Calculate one possible value, d=3. +
    5. Let's say we wish to send the string SECRET. For this +example, we will convert the string to the decimal representation of +the ASCII values of the characters, which would be 83 69 67 82 69 84. +
    6. The sender encrypts each digit one at a time (we have to +because the modulus is so small) using the public key value +(e,n)=(11,15). Thus, each ciphertext character Ci = Mi11 mod 15. The input digit string 0x836967826984 will be transmitted as 0x2c696d286924. +
    7. The receiver decrypts each digit using the private key value (d,n)=(3,15). Thus, each plaintext character Mi = Ci3 mod 15. The input digit string 0x2c696d286924 will be converted to 0x836967826984 and, presumably, reassembled as the plaintext string SECRET. +
    +

    +Again, the example above uses small values for +simplicity and, in fact, shows the weakness of small values; note that +4, 6, and 9 do not change when encrypted, and that the values 2 and 8 +encrypt to 8 and 2, respectively. Nevertheless, this simple example +demonstrates how RSA can be used to exchange information.

    + +

    +RSA keylengths of 512 and 768 bits are considered to be +pretty weak. The minimum suggested RSA key is 1024 bits; 2048 and 3072 +bits are even better.

    + +

    +As an aside, Adam Back (http://www.cypherspace.org/~adam/) wrote a two-line Perl script to implement RSA. It employs dc, an arbitrary precision arithmetic package that ships with most UNIX systems:

    + + +
    +
    print pack"C*",split/\D+/,`echo "16iII*o\U@{$/=$z;[(pop,pop,unpack"H*",<>
    +)]}\EsMsKsN0[lN*1lK[d2%Sa2/d0<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<J]dsJxp"|dc`
    +
    +
    + +

    5.4. Some of the Finer Details of DES, Breaking DES, and DES Variants

    +

    +The Data Encryption Standard (DES) has been in use since +the mid-1970s, adopted by the National Bureau of Standards (NBS) [now +the National Institute for Standards and Technology (NIST)] as Federal +Information Processing Standard 46 (FIPS 46-3) and by the American National Standards Institute (ANSI) as X3.92.

    +

    +As mentioned earlier, DES uses the Data Encryption +Algorithm (DEA), a secret key block-cipher employing a 56-bit key +operating on 64-bit blocks. FIPS 81 +describes four modes of DES operation: Electronic Codebook (ECB), +Cipher Block Chaining (CBC), Cipher Feedback (CFB), and Output Feedback +(OFB). Despite all of these options, ECB is the most commonly deployed +mode of operation.

    +

    +Although other block ciphers will replace DES, it is +still interesting to see how DES encryption is performed. Not only is +it sort of interesting, but DES remains in many products and we will +continue to see DES for some years to come.

    + +

    DES Operational Overview

    +

    +DES uses a 56-bit key. In fact, the 56-bit key is +divided into eight 7-bit blocks and an 8th odd parity bit is added to +each block (i.e., a "0" or "1" is added to the block so that there are +an odd number of 1 bits in each 8-bit block). By using the 8 parity +bits for rudimentary error detection, a DES key is actually 64 bits in +length for computational purposes (although it only has 56 bits worth +of randomness, or entropy).

    + +
    +
    + +

    +

    FIGURE 6: DES enciphering algorithm.

    +
    +
    +
    +

    +DES then acts on 64-bit blocks of the +plaintext, invoking 16 rounds of permutations, swaps, and substitutes, +as shown in Figure 6. The standard includes tables describing all of +the selection, permutation, and expansion operations mentioned below; +these aspects of the algorithm are not secrets. The basic DES steps are:

    +
      +
    1. The 64-bit block to be encrypted +undergoes an initial permutation (IP), where each bit is moved to a new +bit position; e.g., the 1st, 2nd, and 3rd bits are moved to the 58th, +50th, and 42nd position, respectively.

      +
    2. The 64-bit permuted input is divided into two 32-bit blocks, called left and right, respectively. The initial values of the left and right blocks are denoted L0 and R0.

      +
    3. There are then 16 rounds of operation on the L and R blocks. During each iteration (where n ranges from 1 to 16), the following formulae apply: + +At any given step in the process, then, the new L block +value is merely taken from the prior R block value. The new R block is +calculated by taking the bit-by-bit exclusive-OR (XOR) of the prior L +block with the results of applying the DES cipher function, f, to the prior R block and Kn. (Kn +is a 48-bit value derived from the 64-bit DES key. Each round uses a +different 48 bits according to the standard's Key Schedule algorithm.) +

      +The cipher function, f, combines the 32-bit R block +value and the 48-bit subkey in the following way. First, the 32 bits in +the R block are expanded to 48 bits by an expansion function (E); the +extra 16 bits are found by repeating the bits in 16 predefined +positions. The 48-bit expanded R-block is then ORed with the 48-bit +subkey. The result is a 48-bit value that is then divided into eight +6-bit blocks. These are fed as input into 8 selection (S) boxes, +denoted S1,...,S8. Each 6-bit input yields a +4-bit output using a table lookup based on the 64 possible inputs; this +results in a 32-bit output from the S-box. The 32 bits are then +rearranged by a permutation function (P), producing the results from +the cipher function. +

      +

    4. The results from the final DES round — i.e., L16 and R16 — are recombined into a 64-bit value and fed into an inverse initial permutation (IP-1). +At this step, the bits are rearranged into their original positions, so +that the 58th, 50th, and 42nd bits, for example, are moved back into +the 1st, 2nd, and 3rd positions, respectively. The output from IP-1 is the 64-bit ciphertext block. +
    +

    +Consider this example with the given 56-bit key and input:

    + + +

    Breaking DES

    +

    +The mainstream cryptographic community +has long held that DES's 56-bit key was too short to withstand a +brute-force attack from modern computers. Remember Moore's Law: +computer power doubles every 18 months. Given that increase in power, a +key that could withstand a brute-force guessing attack in 1975 could +hardly be expected to withstand the same attack a quarter century later.

    +

    +DES is even more vulnerable to a +brute-force attack because it is often used to encrypt words, meaning +that the entropy of the 64-bit block is, effectively, greatly reduced. +That is, if we are encrypting random bit streams, then a given byte +might contain any one of 28 (256) possible values and the entire 64-bit block has 264, +or about 18.5 quintillion, possible values. If we are encrypting words, +however, we are most likely to find a limited set of bit patterns; +perhaps 70 or so if we account for upper and lower case letters, the +numbers, space, and some punctuation. This means that only about ¼ of the bit combinations of a given byte are likely to occur.

    +

    +Despite this criticism, the U.S. +government insisted throughout the mid-1990s that 56-bit DES was secure +and virtually unbreakable if appropriate precautions were taken. In +response, RSA Laboratories sponsored a series of cryptographic challenges to prove that DES was no longer appropriate for use.

    +

    +DES Challenge I was launched in March 1997. It was +completed in 84 days by R. Verser in a collaborative effort using +thousands of computers on the Internet.

    +

    +The first DES II challenge lasted 40 days in early 1998. This problem was solved by distributed.net, +a worldwide distributed computing network using the spare CPU cycles of +computers around the Internet (participants in distributed.net's +activities load a client program that runs in the background, +conceptually similar to the SETI @Home "Search for Extraterrestrial +Intelligence" project). The distributed.net systems were checking 28 billion keys per second by the end of the project.

    +

    +The second DES II challenge lasted less than 3 days. On +July 17, 1998, the Electronic Frontier Foundation (EFF) announced the +construction of hardware that could brute-force a DES key in an average +of 4.5 days. Called Deep Crack, the device could check 90 billion keys +per second and cost only about $220,000 including design (it was +erroneously and widely reported that subsequent devices could be built +for as little as $50,000). Since the design is scalable, this suggests +that an organization could build a DES cracker that could break 56-bit +keys in an average of a day for as little as $1,000,000. Information +about the hardware design and all software can be obtained from the EFF.

    +

    +The DES III challenge, launched in January 1999, was +broken is less than a day by the combined efforts of Deep Crack and +distributed.net. This is widely considered to have been the final nail +in DES's coffin.

    +

    +The Deep Crack algorithm is actually quite interesting. +The general approach that the DES Cracker Project took was not to break +the algorithm mathematically but instead to launch a brute-force attack +by guessing every possible key. A 56-bit key yields 256, or +about 72 quadrillion, possible values. So the DES cracker team looked +for any shortcuts they could find! First, they assumed that some +recognizable plaintext would appear in the decrypted string even though +they didn't have a specific known plaintext block. They then applied +all 256 possible key values to the 64-bit block (I don't +mean to make this sound simple!). The system checked to see if the +decrypted value of the block was "interesting," which they defined as +bytes containing one of the alphanumeric characters, space, or some +punctuation. Since the likelihood of a single byte being "interesting" +is about ¼, then the likelihood of the entire 8-byte stream being +"interesting" is about ¼8, or 1/65536 (½16). This dropped the number of possible keys that might yield positive results to about 240, or about a trillion.

    +

    +They then made the assumption that an "interesting" +8-byte block would be followed by another "interesting" block. So, if +the first block of ciphertext decrypted to something interesting, they +decrypted the next block; otherwise, they abandoned this key. Only if +the second block was also "interesting" did they examine the key +closer. Looking for 16 consecutive bytes that were "interesting" meant +that only 224, or 16 million, keys needed to be examined +further. This further examination was primarily to see if the text made +any sense. Note that possible "interesting" blocks might be 1hJ5&aB7 or DEPOSITS; +the latter is more likely to produce a better result. And even a slow +laptop today can search through lists of only a few million items in a +relatively short period of time. (Interested readers are urged to read Cracking DES and EFF's Cracking DES page.)

    +

    +It is well beyond the scope of this paper to discuss +other forms of breaking DES and other codes. Nevertheless, it is worth +mentioning a couple of forms of cryptanalysis that have been shown to +be effective against DES. Differential cryptanalysis, invented +in 1990 by E. Biham and A. Shamir (of RSA fame), is a chosen-plaintext +attack. By selecting pairs of plaintext with particular differences, +the cryptanalyst examines the differences in the resultant ciphertext +pairs. Linear plaintext, invented by M. Matsui, uses a linear +approximation to analyze the actions of a block cipher (including DES). +Both of these attacks can be more efficient than brute force.

    + +

    DES Variants

    +

    +Once DES was "officially" broken, several variants +appeared. But none of them came overnight; work at hardening DES had +already been underway. In the early 1990s, there was a proposal to +increase the security of DES by effectively increasing the key length +by using multiple keys with multiple passes. But for this scheme to +work, it had to first be shown that the DES function is not a group, +as defined in mathematics. If DES was a group, then we could show that +for two DES keys, X1 and X2, applied to some plaintext (P), we can find +a single equivalent key, X3, that would provide the same result; i.e.,:

    +

    +EX2(EX1(P)) = EX3(P)

    +

    +where EX(P) represents DES encryption of some plaintext P using DES key X. +If DES were a group, it wouldn't matter how many keys and passes we +applied to some plaintext; we could always find a single 56-bit key +that would provide the same result.

    +

    +As it happens, DES was proven to not be a group so that +as we apply additional keys and passes, the effective key length +increases. One obvious choice, then, might be to use two keys and two +passes, yielding an effective key length of 112 bits. Let's call this +Double-DES. The two keys, Y1 and Y2, might be applied as follows:

    +

    +C = EY2(EY1(P))
    +P = DY1(DY2(C))

    +

    +where EY(P) and DY(C) represent DES encryption and decryption, respectively, of some plaintext P and ciphertext C, respectively, using DES key Y.

    +

    +So far, so good. But there's an interesting attack that +can be launched against this "Double-DES" scheme. First, notice that +the applications of the formula above can be thought of with the +following individual steps (where C' and P' are intermediate results):

    +

    +C' = EY1(P) and C = EY2(C')
    +P' = DY2(C) and P = DY1(P')

    +

    +Unfortunately, C'=P'. That leaves us vulnerable to a simple known plaintext +attack (sometimes called "Meet-in-the-middle") where the attacker knows +some plaintext (P) and its matching ciphertext (C). To obtain C', the +attacker needs to try all 256 possible values of Y1 applied to P; to obtain P', the attacker needs to try all 256 possible values of Y2 applied to C. Since C'=P', the attacker knows when a match has been achieved — after only 256 + 256 = 257 key searches, only twice the work of brute-forcing DES. So "Double-DES" won't work.

    +

    +Triple-DES (3DES), based upon the Triple Data Encryption Algorithm (TDEA), is described in FIPS 46-3. +3DES, which is not susceptible to a meet-in-the-middle attack, employs +three DES passes and one, two, or three keys called K1, K2, and K3. +Generation of the ciphertext (C) from a block of plaintext (P) is +accomplished by:

    +

    +C = EK3(DK2(EK1(P)))

    +

    +where EK(P) and DK(P) represent DES encryption and decryption, respectively, of some plaintext P using DES key K. (For obvious reasons, this is sometimes referred to as an encrypt-decrypt-encrypt mode operation.)

    +

    +Decryption of the ciphertext into plaintext is accomplished by:

    +

    +P = DK1(EK2(DK3(C)))

    +

    +The use of three, independent 56-bit keys provides 3DES +with an effective key length of 168 bits. The specification also +defines use of two keys where, in the operations above, K3 = K1; this +provides an effective key length of 112 bits. Finally, a third keying +option is to use a single key, so that K3 = K2 = K1 (in this case, the +effective key length is 56 bits and 3DES applied to some plaintext, P, +will yield the same ciphertext, C, as normal DES would with that same +key). Given the relatively low cost of key storage and the modest +increase in processing due to the use of longer keys, the best +recommended practices are that 3DES be employed with three keys.

    +

    +Another variant of DES, called DESX, is due to Ron +Rivest. Developed in 1996, DESX is a very simple algorithm that greatly +increases DES's resistance to brute-force attacks without increasing +its computational complexity. In DESX, the plaintext input is XORed +with 64 additional key bits prior to encryption and the output is +likewise XORed with the 64 key bits. By adding just two XOR operations, +DESX has an effective keylength of 120 bits against an exhaustive +key-search attack. As it happens, DESX is no more immune to other types +of more sophisticated attacks, such as differential or linear +cryptanalysis, but brute-force is the primary attack vector on DES.

    + +

    5.5. Pretty Good Privacy (PGP)

    +

    +Pretty Good Privacy (PGP) is one of today's most widely used public key cryptography programs. Developed by Philip Zimmermann +in the early 1990s and long the subject of controversy, PGP is +available as a plug-in for many e-mail clients, such as Claris Emailer, +Microsoft Outlook/Outlook Express, and Qualcomm Eudora.

    +

    +PGP can be used to sign or encrypt e-mail messages with +the mere click of the mouse. Depending upon the version of PGP, the +software uses SHA or MD5 for calculating the message hash; CAST, +Triple-DES, or IDEA for encryption; and RSA or DSS/Diffie-Hellman for +key exchange and digital signatures.

    +

    +When PGP is first installed, the user has to create a +key-pair. One key, the public key, can be advertised and widely +circulated. The private key is protected by use of a passphrase. The passphrase has to be entered every time the user accesses their private key.

    + +
    +
    + +
    +
    + -----BEGIN PGP SIGNED MESSAGE-----
    + Hash: SHA1
    +
    + Hi Carol.
    +
    + What was that pithy Groucho Marx quote?
    +
    + /kess
    +
    + -----BEGIN PGP SIGNATURE-----
    + Version: PGP for Personal Privacy 5.0
    + Charset: noconv
    +
    + iQA/AwUBNFUdO5WOcz5SFtuEEQJx/ACaAgR97+vvDU6XWELV/GANjAAgBtUAnjG3
    + Sdfw2JgmZIOLNjFe7jP0Y8/M
    + =jUAU
    + -----END PGP SIGNATURE-----
    +
    +

    +

    FIGURE 7: A PGP signed message. The sender uses their private +key; at the destination, the sender's e-mail address yields the public +key from the receiver's keyring.

    +
    +
    + +
    +

    +Figure 7 shows a PGP signed message. This message will +not be kept secret from an eavesdropper, but a recipient can be assured +that the message has not been altered from what the sender transmitted. +In this instance, the sender signs the message using their own private +key. The receiver uses the sender's public key to verify the signature; +the public key is taken from the receiver's keyring based on the +sender's e-mail address. Note that the signature process does not work +unless the sender's public key is on the receiver's keyring.

    + +
    +
    + +
    +
    +-----BEGIN PGP MESSAGE-----
    +Version: PGP for Personal Privacy 5.0
    +MessageID: DAdVB3wzpBr3YRunZwYvhK5gBKBXOb/m
    +
    +qANQR1DBwU4D/TlT68XXuiUQCADfj2o4b4aFYBcWumA7hR1Wvz9rbv2BR6WbEUsy
    +ZBIEFtjyqCd96qF38sp9IQiJIKlNaZfx2GLRWikPZwchUXxB+AA5+lqsG/ELBvRa
    +c9XefaYpbbAZ6z6LkOQ+eE0XASe7aEEPfdxvZZT37dVyiyxuBBRYNLN8Bphdr2zv
    +z/9Ak4/OLnLiJRk05/2UNE5Z0a+3lcvITMmfGajvRhkXqocavPOKiin3hv7+Vx88
    +uLLem2/fQHZhGcQvkqZVqXx8SmNw5gzuvwjV1WHj9muDGBY0MkjiZIRI7azWnoU9
    +3KCnmpR60VO4rDRAS5uGl9fioSvze+q8XqxubaNsgdKkoD+tB/4u4c4tznLfw1L2
    +YBS+dzFDw5desMFSo7JkecAS4NB9jAu9K+f7PTAsesCBNETDd49BTOFFTWWavAfE
    +gLYcPrcn4s3EriUgvL3OzPR4P1chNu6sa3ZJkTBbriDoA3VpnqG3hxqfNyOlqAka
    +mJJuQ53Ob9ThaFH8YcE/VqUFdw+bQtrAJ6NpjIxi/x0FfOInhC/bBw7pDLXBFNaX
    +HdlLQRPQdrmnWskKznOSarxq4GjpRTQo4hpCRJJ5aU7tZO9HPTZXFG6iRIT0wa47
    +AR5nvkEKoIAjW5HaDKiJriuWLdtN4OXecWvxFsjR32ebz76U8aLpAK87GZEyTzBx
    +dV+lH0hwyT/y1cZQ/E5USePP4oKWF4uqquPee1OPeFMBo4CvuGyhZXD/18Ft/53Y
    +WIebvdiCqsOoabK3jEfdGExce63zDI0=
    +=MpRf
    +-----END PGP MESSAGE-----
    +
    +

    +

    FIGURE 8: A PGP encrypted message. The receiver's e-mail +address is the pointer to the public key in the sender's keyring. At +the destination side, the receiver uses their own private key.

    +
    +
    + +
    +

    +Figure 8 shows a PGP encrypted message (PGP compresses +the file, where practical, prior to encryption because encrypted files +lose their randomness and, therefore, cannot be compressed). In this +case, public key methods are used to exchange the session key for the +actual message encryption using secret-key cryptography. In this case, +the receiver's e-mail address is the pointer to the public key in the +sender's keyring; in fact, the same message can be sent to multiple +recipients and the message will not be significantly longer since all +that needs to be added is the session key encrypted by each receiver's +private key. When the message is received, the recipient must use their +private key to extract the session secret key to successfully decrypt +the message (Figure 9).

    + +
    +
    + +
    +
    + Hi Gary,
    +
    + "Outside of a dog, a book is man's best friend.
    + Inside of a dog, it's too dark to read."
    +
    + Carol
    +
    +

    +

    FIGURE 9: The decrypted message.

    +
    +
    + +
    +

    +It is worth noting that PGP was one of the first +so-called "hybrid cryptosystems" that combined aspects of SKC and PKC. +When Zimmermann was first designing PGP in the late-1980s, he wanted to +use RSA to encrypt the entire message. The PCs of the days, however, +suffered significant performance degradation when executing RSA so he +hit upon the idea of using SKC to encrypt the message and PKC to +encrypt the SKC key.

    +

    +The state of PGP is in flux as of the fall of 2002. +Zimmermann sold PGP to Network Associates, Inc. (NAI) in 1997 and +himself resigned from NAI in early 2001. In March 2002, NAI announced +that they were dropping support for the commercial version of PGP +having failed to find a buyer for the product willing to pay what NAI +wanted. In August 2002, PGP was purchased from NAI by PGP Corp. (http://www.pgp.com/).

    +
    + +

    5.6. IP Security (IPsec) Protocol

    +
    +

    +NOTE: The information in this section assumes +that the reader is familiar with the Internet Protocol (IP), at least +to the extent of the packet format and header contents. More +information about IP can be found in An Overview of TCP/IP Protocols and the Internet. More information about IPv6 can be found in IPv6: The Next Generation Internet Protocol.

    +
    +

    +The Internet and the TCP/IP protocol suite were not +built with security in mind. This statement is not meant as a +criticism; the baseline UDP, TCP, IP, and ICMP protocols were written +in 1980 and built for the relatively closed ARPANET community. TCP/IP +wasn't designed for the commercial-grade financial transactions that +they now see nor for virtual private networks (VPNs) on the Internet. +To bring TCP/IP up to today's security necessities, the Internet +Engineering Task Force (IETF) formed the IP Security Protocol Working Group +which, in turn, developed the IP Security (IPsec) protocol. IPsec is +not a single protocol, in fact, but a suite of protocols providing a +mechanism to provide data integrity, authentication, privacy, and +nonrepudiation for the classic Internet Protocol (IP). Although +intended primarily for IP version 6 (IPv6), IPsec can also be employed +by the current version of IP, namely IP version 4 (IPv4).

    +

    +As shown in Table 3, IPsec is described in nearly a dozen RFCs. RFC 2401, in particular, describes the overall IP security architecture and RFC 2411 provides an overview of the IPsec protocol suite and the documents describing it.

    +

    +IPsec can provide either message authentication and/or +encryption. The latter requires more processing than the former, but +will probably end up being the preferred usage for applications such as +VPNs and secure electronic commerce.

    +

    +Central to IPsec is the concept of a security association (SA). +Authentication and confidentiality using AH or ESP use SAs and a +primary role of IPsec key exchange it to establish and maintain SAs. An +SA is a simplex (one-way or unidirectional) logical connection between +two communicating IP endpoints that provides security services to the +traffic carried by it using either AH or ESP procedures. The endpoint +of an SA can be an IP host or IP security gateway (e.g., a proxy +server, VPN server, etc.). Providing security to the more typical +scenario of two-way (bi-directional) communication between two +endpoints requires the establishment of two SAs (one in each direction).

    +

    +An SA is uniquely identified by a 3-tuple composed of:

    +
      +
    • Security Parameter Index (SPI), a 32-bit identifier of the connection
    • +
    • IP Destination Address
    • +
    • security protocol (AH or ESP) identifier
    • +
    +

    +The IP Authentication Header (AH), described in RFC 2402, provides a mechanism for data integrity and data origin authentication for IP packets using HMAC with MD5 (RFC 2403), HMAC with SHA-1 (RFC 2404), or HMAC with RIPEMD (RFC 2857).

    + +
    +
    + +
    +
    +    0                   1                   2                   3
    +    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   | Next Header   |  Payload Len  |          RESERVED             |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                 Security Parameters Index (SPI)               |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                    Sequence Number Field                      |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                                                               |
    +   +                Authentication Data (variable)                 |
    +   |                                                               |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +
    +

    +

    FIGURE 10: IPsec Authentication Header format. (From RFC 2402)

    +
    +
    +

    +

    +Figure 10 shows the format of the IPsec AH. The AH is +merely an additional header in a packet, more or less representing +another protocol layer above IP (this is shown in Figure 12 below). Use +of the IP AH is indicated by placing the value 51 (0x33) in the IPv4 +Protocol or IPv6 Next Header field in the IP packet header. The AH +follows mandatory IPv4/IPv6 header fields and precedes higher layer +protocol (e.g., TCP, UDP) information. The contents of the AH are:

    +
      +
    • Next Header: An 8-bit field that identifies the type of the next payload after the Authentication Header.
    • +
    • Payload Length: An 8-bit field that indicates the length of +AH in 32-bit words (4-byte blocks), minus "2". [The rationale for this +is somewhat counter intuitive but technically important. All IPv6 +extension headers encode the header extension length (Hdr Ext Len) +field by first subtracting 1 from the header length, which is measured +in 64-bit words. Since AH was originally developed for IPv6, it is an +IPv6 extension header. Since its length is measured in 32-bit words, +however, the Payload Length is calculated by subtracting 2 (32 bit +words) to maintain consistency with IPv6 coding rules.] In the default +case, the three 32-bit word fixed portion of the AH is followed by a +96-bit authentication value, so the Payload Length field value would be +4.
    • +
    • Reserved: This 16-bit field is reserved for future use and always filled with zeros.
    • +
    • Security Parameters Index (SPI): An arbitrary 32-bit value +that, in combination with the destination IP address and security +protocol, uniquely identifies the Security Association for this +datagram. The value 0 is reserved for local, implementation-specific +uses and values between 1-255 are reserved by the Internet Assigned +Numbers Authority (IANA) for future use.
    • +
    • Sequence Number: A 32-bit field containing a sequence number +for each datagram; initially set to 0 at the establishment of an SA. AH +uses sequence numbers as an anti-replay mechanism, to prevent a +"person-in-the-middle" attack. If anti-replay is enabled (the default), +the transmitted Sequence Number is never allowed to cycle back to 0; +therefore, the sequence number must be reset to 0 by establishing a new +SA prior to the transmission of the 232nd packet.
    • +
    • Authentication Data: A variable-length, 32-bit aligned field +containing the Integrity Check Value (ICV) for this packet (default +length = 96 bits). The ICV is computed using the authentication +algorithm specified by the SA, such as DES, MD5, or SHA-1. Other +algorithms may also be supported.
    • +
    +

    +The IP Encapsulating Security Payload (ESP), described in RFC 2406, +provides message integrity and privacy mechanisms in addition to +authentication. As in AH, ESP uses HMAC with MD5, SHA-1, or RIPEMD +authentication (RFC 2403/RFC 2404/RFC 2857); privacy is provided using DES-CBC encryption (RFC 2405), NULL encryption (RFC 2410), other CBC-mode algorithms (RFC 2451), or AES (RFC 3686).

    + +
    +
    + +
    +
    +    0                   1                   2                   3
    +    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |               Security Parameters Index (SPI)                 |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                      Sequence Number                          |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                    Payload Data (variable)                    |
    +   ~                                                               ~
    +   |                                                               |
    +   +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |               |     Padding (0-255 bytes)                     |
    +   +-+-+-+-+-+-+-+-+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                               |  Pad Length   | Next Header   |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +   |                 Authentication Data (variable)                |
    +   ~                                                               ~
    +   |                                                               |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +
    +

    +

    FIGURE 11: IPsec Encapsulating Security Payload format. (From RFC 2406)

    +
    +
    +

    +

    +Figure 11 shows the format of the IPsec ESP information. +Use of the IP ESP format is indicated by placing the value 50 (0x32) in +the IPv4 Protocol or IPv6 Next Header field in the IP packet header. +The ESP header (i.e., SPI and sequence number) follows mandatory +IPv4/IPv6 header fields and precedes higher layer protocol (e.g., TCP, +UDP) information. The contents of the ESP packet are:

    +
      +
    • Security Parameters Index: (see description for this field in the AH, above.)
    • +
    • Sequence Number: (see description for this field in the AH, above.)
    • +
    • Payload Data: A variable-length field containing data as +described by the Next Header field. The contents of this field could be +encrypted higher layer data or an encrypted IP packet.
    • +
    • Padding: Between 0 and 255 octets of padding may be added to +the ESP packet. There are several applications that might use the +padding field. First, the encryption algorithm that is used may require +that the plaintext be a multiple of some number of bytes, such as the +block size of a block cipher; in this case, the Padding field is used +to fill the plaintext to the size required by the algorithm. Second, +padding may be required to ensure that the ESP packet and resulting +ciphertext terminate on a 4-byte boundary. Third, padding may be used +to conceal the actual length of the payload. Unless another value is +specified by the encryption algorithm, the Padding octets take on the +value 1, 2, 3, ... starting with the first Padding octet. This scheme +is used because, in addition to being simple to implement, it provides +some protection against certain forms of "cut and paste" attacks.
    • +
    • Pad Length: An 8-bit field indicating the number of bytes in the Padding field; contains a value between 0-255.
    • +
    • Next Header: An 8-bit field that identifies the type of data +in the Payload Data field, such as an IPv6 extension header or a higher +layer protocol identifier.
    • +
    • Authentication Data: (see description for this field in the AH, above.)
    • +
    +

    +Two types of SAs are defined in IPsec, regardless of whether AH or ESP is employed. A transport mode SA +is a security association between two hosts. Transport mode provides +the authentication and/or encryption service to the higher layer +protocol. This mode of operation is only supported by IPsec hosts. A tunnel mode SA +is a security association applied to an IP tunnel. In this mode, there +is an "outer" IP header that specifies the IPsec destination and an +"inner" IP header that specifies the destination for the IP packet. +This mode of operation is supported by both hosts and security gateways.

    + +
    +
    + +
    +
    +    ORIGINAL PACKET BEFORE APPLYING AH
    +
    +            ----------------------------
    +      IPv4  |orig IP hdr  |     |      |
    +            |(any options)| TCP | Data |
    +            ----------------------------
    +
    +            ---------------------------------------
    +      IPv6  |             | ext hdrs |     |      |
    +            | orig IP hdr |if present| TCP | Data |
    +            ---------------------------------------
    +
    +
    +    AFTER APPLYING AH (TRANSPORT MODE)
    +
    +            ---------------------------------
    +      IPv4  |orig IP hdr  |    |     |      |
    +            |(any options)| AH | TCP | Data |
    +            ---------------------------------
    +            |<------- authenticated ------->|
    +                 except for mutable fields
    +
    +            ------------------------------------------------------------
    +      IPv6  |             |hop-by-hop, dest*, |    | dest |     |      |
    +            |orig IP hdr  |routing, fragment. | AH | opt* | TCP | Data |
    +            ------------------------------------------------------------
    +            |<---- authenticated except for mutable fields ----------->|
    +
    +                 * = if present, could be before AH, after AH, or both
    +
    +
    +    AFTER APPLYING AH (TUNNEL MODE)
    +
    +          ------------------------------------------------
    +    IPv4  | new IP hdr* |    | orig IP hdr*  |    |      |
    +          |(any options)| AH | (any options) |TCP | Data |
    +          ------------------------------------------------
    +          |<- authenticated except for mutable fields -->|
    +
    +          |           in the new IP hdr                  |
    +
    +          --------------------------------------------------------------
    +    IPv6  |           | ext hdrs*|    |            | ext hdrs*|   |    |
    +          |new IP hdr*|if present| AH |orig IP hdr*|if present|TCP|Data|
    +          --------------------------------------------------------------
    +          |<-- authenticated except for mutable fields in new IP hdr ->|
    +
    +           * = construction of outer IP hdr/extensions and modification
    +               of inner IP hdr/extensions is discussed below.
    +
    +

    +

    FIGURE 12: IPsec tunnel and transport modes for AH. (Adapted from RFC 2402)

    +
    +
    +

    +

    +Figure 12 show the IPv4 and IPv6 packet formats when +using AH in both transport and tunnel modes. Initially, an IPv4 packet +contains a normal IPv4 header (which may contain IP options), followed +by the higher layer protocol header (e.g., TCP or UDP), followed by the +higher layer data itself. An IPv6 packet is similar except that the +packet starts with the mandatory IPv6 header followed by any IPv6 +extension headers, and then followed by the higher layer data.

    +

    +Note that in both transport and tunnel modes, the entire IP packet is covered by the authentication except for the mutable fields. A field is mutable +if its value might change during transit in the network; IPv4 mutable +fields include the fragment offset, time to live, and checksum fields. +Note, in particular, that the address fields are not mutable.

    +
    + +
    +
    + +
    +
    +    ORIGINAL PACKET BEFORE APPLYING ESP
    +
    +            ----------------------------
    +      IPv4  |orig IP hdr  |     |      |
    +            |(any options)| TCP | Data |
    +            ----------------------------
    +
    +            ---------------------------------------
    +      IPv6  |             | ext hdrs |     |      |
    +            | orig IP hdr |if present| TCP | Data |
    +            ---------------------------------------
    +
    +
    +    AFTER APPLYING ESP (TRANSPORT MODE)
    +
    +            -------------------------------------------------
    +      IPv4  |orig IP hdr  | ESP |     |      |   ESP   | ESP|
    +            |(any options)| Hdr | TCP | Data | Trailer |Auth|
    +            -------------------------------------------------
    +                                |<----- encrypted ---->|
    +                          |<------ authenticated ----->|
    +
    +            ---------------------------------------------------------
    +      IPv6  | orig |hop-by-hop,dest*,|ESP|dest|   |    | ESP   | ESP|
    +            |IP hdr|routing,fragment.|hdr|opt*|TCP|Data|Trailer|Auth|
    +            ---------------------------------------------------------
    +                                         |<---- encrypted ---->|
    +                                     |<---- authenticated ---->|
    +
    +                * = if present, could be before ESP, after ESP, or both
    +
    +
    +    AFTER APPLYING ESP (TUNNEL MODE)
    +
    +            -----------------------------------------------------------
    +      IPv4  | new IP hdr  | ESP | orig IP hdr   |   |    | ESP   | ESP|
    +            |(any options)| hdr | (any options) |TCP|Data|Trailer|Auth|
    +
    +            -----------------------------------------------------------
    +                                |<--------- encrypted ---------->|
    +                          |<----------- authenticated ---------->|
    +
    +            ------------------------------------------------------------
    +      IPv6  | new+ |new ext |ESP| orig+|orig ext |   |    | ESP   | ESP|
    +            |IP hdr| hdrs+  |hdr|IP hdr| hdrs+   |TCP|Data|Trailer|Auth|
    +            ------------------------------------------------------------
    +                                |<--------- encrypted ----------->|
    +                            |<---------- authenticated ---------->|
    +
    +               + = if present
    +
    +

    +

    FIGURE 13: IPsec tunnel and transport modes for ESP. (Adapted from RFC 2406)

    +
    +
    +

    +

    +Figure 13 shows the IPv4 and IPv6 packet formats when using ESP in both transport and tunnel modes.

    +
      +
    • As with AH, we start with a standard IPv4 or IPv6 packet.
    • +
    • In transport mode, the higher layer header and data, as well as ESP +trailer information, is encrypted and the entire ESP packet is +authenticated. In the case of IPv6, some of the IPv6 extension options +can precede or follow the ESP header.
    • +
    • In tunnel mode, the original IP packet is encrypted and placed +inside of an "outer" IP packet, while the entire ESP packet is +authenticated.
    • +
    +

    +Note a significant difference in the scope of ESP and +AH. AH authenticates the entire packet transmitted on the network +whereas ESP only covers a portion of the packet transmitted on the +network (the higher layer data in transport mode and the entire +original packet in tunnel mode). The reason for this is +straight-forward; in AH, the authentication data for the transmission +fits neatly into an additional header whereas ESP creates an entirely +new packet which is the one encrypted and/or authenticated. But the +ramifications are significant. ESP transport mode as well as AH in both +modes protect the IP address fields of the original transmissions. +Thus, using IPsec in conjunction with network address translation (NAT) +might be problematic because NAT changes the values of these fields after IPsec processing.

    +

    +The third component of IPsec is the establishment of +security associations and key management. These tasks can be +accomplished in one of two ways.

    +

    +The simplest form of SA and key management is manual +management. In this method, a security administer or other individual +manually configures each system with the key and SA management data +necessary for secure communication with other systems. Manual +techniques are practical for small, reasonably static environments but +they do not scale well.

    +

    +For successful deployment of IPsec, however, a scalable, +automated SA/key management scheme is necessary. Several protocols have +defined for these functions:

    +
      +
    • The Internet Security Association and Key Management +Protocol (ISAKMP) defines procedures and packet formats to establish, +negotiate, modify and delete security associations, and provides the +framework for exchanging information about authentication and key +management (RFC 2407/RFC 2408). ISAKMP's security association and key management is totally separate from key exchange.
    • +
    • The OAKLEY Key Determination Protocol (RFC 2412) +describes a scheme by which two authenticated parties can exchange key +information. OAKLEY uses the Diffie-Hellman key exchange algorithm.
    • +
    • The Internet Key Exchange (IKE) algorithm (RFC 2409) is the default automated key management protocol for IPsec.
    • +
    • An alternative to IKE is Photuris (RFC 2522/RFC 2523), +a scheme for establishing short-lived session-keys between two +authenticated parties without passing the session-keys across the +Internet. IKE typically creates keys that may have very long lifetimes.
    • +
    +

    +On a final note, IPsec authentication for both AH and ESP uses a scheme called HMAC, a keyed-hashing message authentication code described in FIPS 198 and RFC 2104. +HMAC uses a shared secret key between two parties rather than public +key methods for message authentication. The generic HMAC procedure can +be used with just about any hash algorithm, although IPsec specifies +support for at least MD5 and SHA-1 because of their widespread use.

    +

    +In HMAC, both parties share a secret key. The secret key +will be employed with the hash algorithm in a way that provides mutual +authentication without transmitting the key on the line. IPsec key +management procedures will be used to manage key exchange between the +two parties.

    +

    +Recall that hash functions operate on a fixed-size block +of input at one time; MD5 and SHA-1, for example, work on 64 byte +blocks. These functions then generate a fixed-size hash value; MD5 and +SHA-1, in particular, produce 16 byte (128 bit) and 20 byte (160 bit) +output strings, respectively. For use with HMAC, the secret key (K) +should be at least as long as the hash output.

    +

    +The following steps provide a simplified, although +reasonably accurate, description of how the HMAC scheme would work with +a particular plaintext MESSAGE:

    +
      +
    1. Pad K so that it is as long as an input block; call this padded key Kp.
    2. +
    3. Compute the hash of the padded key followed by the message, i.e., HASH (Kp:MESSAGE).
    4. +
    5. Transmit MESSAGE and the hash value.
    6. +
    7. The receiver does the same procedure to pad K to create Kp.
    8. +
    9. The receiver computes HASH (Kp:MESSAGE).
    10. +
    11. The receiver compares the computed hash value with the received +hash value. If they match, then the sender must know the secret key and +the message is authenticated.
    12. +
    +
    + +

    +

    5.7. The SSL "Family" of Secure Transaction Protocols for the World Wide Web

    +

    +The Secure Sockets Layer (SSL) +protocol was developed by Netscape Communications to provide +application-independent secure communication over the Internet for +protocols such as the Hypertext Transfer Protocol (HTTP). SSL employs +RSA and X.509 certificates during an initial handshake used to +authenticate the server (client authentication is optional). The client +and server then agree upon an encryption scheme; SSL v2 supports RC2 +and RC4 with 40-bit keys, while SSL v3 adds support for DES, RC4 with a +128-bit key, and 3DES with a 168-bit key, all along with either MD5 or +SHA-1 message hashes. SSL v3 is the commonly supported version on +servers today, although some implementations of SSL v2 will still be +found; both are supported by most common browsers (Figure 14).

    + +
    +
    + +

    +

    FIGURE 14: SSL v3 configuration screen (Netscape Navigator).

    +
    +
    +
    +

    +In 1997, SSL v3 was found to be breakable. By this time, +the Internet Engineering Task Force (IETF) had already started work on +a new, non-proprietary protocol called Transport Layer Security (TLS), +described in RFC 2246. +TLS extends SSL and supports additional crypto schemes, such as +Diffie-Hellman key exchange and DSS digital signatures. TLS is backward +compatible with SSL (and, in fact, is recognized as SSL v3.1).

    + +
    +
    +
                           CLIENT       SERVER
    + (using URL of form https://)       (listening on port 443) 
    +
    +                  ClientHello ---->
    +
    +                                    ServerHello
    +                                    Certificate*
    +                                    ServerKeyExchange*
    +                                    CertificateRequest*
    +                              <---- ServerHelloDone
    +
    +                 Certificate*
    +            ClientKeyExchange
    +            CertifcateVerify*
    +           [ChangeCipherSpec]
    +                     Finished ---->
    +
    +                                    [ChangeCipherSpec]
    +                              <---- Finished
    +
    +             Application Data <---> Application Data
    +
    +
    +
    +* Optional or situation-dependent messages;
    +  not always sent
    +
    +                                     Adapted from RFC 2246
    +
    +
    +

    FIGURE 15: SSL/TLS protocol handshake.

    +
    +
    +
    +

    +Figure 15 shows the basic TLS (and SSL) message exchanges: +

      +
    1. URLs specifying the protocol https:// are +directed to HTTP servers secured using SSL/TLS. The client will +automatically try to make a TCP connection to the server at port 443. +The client initiates the secure connection by sending a ClientHello +message containing a Session identifier, highest SSL version number +supported by the client, and lists of supported crypto and compression +schemes (in preference order). +
    2. The server examines the Session ID and if it is still in the +server's cache, it will attempt to re-establish a previous session with +this client. If the Session ID is not recognized, the server will +continue with the handshake to establish a secure session by responding +with a ServerHello message. The ServerHello +repeats the Session ID, indicates the SSL version to use for this +connection (which will be the highest SSL version supported by the +server and client), and specifies which encryption method and +compression method to be used for this connection. +
    3. There are a number of other optional messages that the server might send, including: +
        +
      • Certificate, which carries the server's +X.509 public key certificate (and, generally, the server's public key). +This message will always be sent unless the client and server have +already agreed upon some form of anonymous key exchange. (This message +is normally sent.) +
      • ServerKeyExchange, which will carry a premaster secret when +the server's Certificate message does not contain enough data for this purpose; used in some key exchange schemes. +
      • CertificateRequest, used to request the client's certificate in those scenarios where client authentication is performed. +
      • ServerHelloDone, indicating that the server has completed its portion of the key exchange handshake. +
      +
    4. The client now responds with a series of mandatory and optional messages: +
        +
      • Certificate, contains the client's public key certificate when it has been requested by the server. +
      • ClientKeyExchange, which usually carries the secret key to be used with the secret key crypto scheme. +
      • CertificateVerify, used to provide explicit verification of a client's certificate if the server is authenticating the client. +
      +
    5. TLS includes the change cipher spec protocol to indicate +changes in the encryption method. This protocol contains a single +message, ChangeCipherSpec, which is encrypted and compressed using the current (rather than the new) encryption and compression schemes. The ChangeCipherSpec +message is sent by both client and server to notify the other station +that all following information will employ the newly negotiated cipher +spec and keys. +
    6. The Finished message is sent after a ChangeCipherSpec message to confirm that the key exchange and authentication processes were successful. +
    7. At this point, both client and server can exchange application data using the session encryption and compression schemes. + +

      + +Side Note: It would probably be helpful to make some mention of +SSL as it is used today. Most of us have used SSL to engage in a +secure, private transaction with some vendor. The steps are something +like this. During the SSL exchange with the vendor's secure server, the +server sends its certificate to our client software. The certificate +includes the vendor's public key and a signature from the CA that +issued the vendor's certificate. Our browser software is shipped with +the major CAs' certificates which contains their public key; in that +way we authenticate the server. Note that the server does not +use a certificate to authenticate us! Instead, we are generally +authenticated when we provide our credit card number; the server checks +to see if the card purchase will be authorized by the credit card +company and, if so, considers us valid and authenticated! While +bidirectional authentication is certainly supported by SSL, this form +of asymmetric authentication is more commonly employed today since most +users don't have certificates. +

      +Microsoft's +Server Gated Cryptography (SGC) +protocol is another extension to SSL/TLS. For several decades, it has +been illegal to generally export products from the U.S. that employed +secret-key cryptography with keys longer than 40 bits. For that reason, +SSL/TLS has an exportable version with weak (40-bit) keys and a +domestic (North American) version with strong (128-bit) keys. Within +the last several years, however, use of strong SKC has been approved +for the worldwide financial community. SGC is an extension to SSL that +allows financial institutions using Windows NT servers to employ strong +cryptography. Both the client and server must implement SGC and the +bank must have a valid SGC certificate. During the initial handshake, +the server will indicate support of SGC and supply its SGC certificate; +if the client wishes to use SGC and validates the server's SGC +certificate, the session can employ 128-bit RC2, 128-bit RC4, 56-bit +DES, or 168-bit 3DES. Microsoft supports SGC in the Windows 95/98/NT +versions of Internet Explorer 4.0, Internet Information Server (IIS) +4.0, and Money 98. +

      As mentioned above, SSL was designed to provide +application-independent transaction security for the Internet. Although +the discussion above has focused on HTTP over SSL (https/TCP port 443), +SSL is also applicable to: +

      +
      + + + + + + + + +
      Protocol +  +TCP Port Name/Number + +
      File Transfer Protocol (FTP) +  +ftps-data/989 & ftps/990 + +
      Internet Message Access Protocol v4 (IMAP4) +  +imaps/993 + +
      Lightweight Directory Access Protocol (LDAP) +  +ldaps/636 + +
      Network News Transport Protocol (NNTP) +  +nntps/563 + +
      Post Office Protocol v3 (POP3) +  +pop3s/995 + +
      Telnet +  +telnets/992 +
      +
      +

      + +

      5.8. Elliptic Curve Cryptography

      +

      In general, public-key cryptography systems use hard-to-solve +problems as the basis of the algorithm. The most predominant algorithm +today for public-key cryptography is RSA, based on the prime factors of +very large integers. While RSA can be successfully attacked, the +mathematics of the algorithm have not been comprised, per se; instead, +computational brute-force has broken the keys. The defense is "simple" +— keep the size of the integer to be factored ahead of the +computational curve!

      +

      +In 1985, Elliptic Curve Cryptography (ECC) was proposed independently +by cryptographers Victor Miller (IBM) and Neal Koblitz (University of +Washington). ECC is based on the difficulty of solving the Elliptic +Curve Discrete Logarithm Problem (ECDLP). Like the prime factorization +problem, ECDLP is another "hard" problem that is deceptively simple to +state: Given two points, P and Q, on an elliptic curve, find the +integer n, if it exists, such that P = nQ.

      +

      +Elliptic curves combine number theory and algebraic geometry. These +curves can be defined over any field of numbers (i.e., real, integer, +complex) although we generally see them used over finite fields for +applications in cryptography. An elliptic curve consists of the set of +real numbers (x, y) that satisfies the equation:

      +

      +y2 = x3 + ax + b

      +

      +The set of all of the solutions to the equation forms the elliptic curve. Changing a and b +changes the shape of the curve, and small changes in these parameters +can result in major changes in the set of (x,y) solutions.

      +
      +
      + +

      +

      FIGURE 16: Elliptic curve addition.

      +
      +
      +
      +

      +Figure 16 shows the addition of two points on an elliptic curve. +Elliptic curves have the interesting property that adding two points on +the elliptic curve yields a third point on the curve. Therefore, adding +two points, P1 and P2, gets us to point P3, also on the curve. Small +changes in P1 or P2 can cause a large change in the position of P3.

      +

      +So let's go back to the original problem statement from above. The +point Q is calculated as a multiple of the starting point, P, or, Q = nP. An attacker might know P and Q but finding the integer, n, is a difficult problem to solve. Q is the public key, then, and n is the private key.

      +

      +RSA has been the mainstay of PKC for over two decades. But ECC is +exciting because of their potential to provide similar levels of +security compared to RSA but with significantly reduced key sizes. +Certicom Corp. (www.certicom.com), one of the major proponents of ECC, suggests the key size relationship between ECC and RSA per the following table:

      +
      + + + + + + + + +
      +TABLE 4. ECC and RSA Key Comparison. +
      RSA Key Size +Time to Break Key
      (MIPS Years) +
      ECC Key Size +RSA:ECC Key-Size
      Ratio + +
      512 +104 +106 +5:1 + +
      768 +108 +132 +6:1 + +
      1,024 +1011 +160 +7:1 + +
      2,048 +1020 +210 +10:1 + +
      21,000 +1078 +600 +35:1 +
      +
      +

      +

      +Since the ECC key sizes are so much shorter than comparable RSA keys, +the length of the public key and private key is much shorter in +elliptic curve cryptosystems. Presumably, this translates into faster +processing, and lower demands on memory and bandwidth. In practice, the +final results are not yet in; RSA, Inc. notes that ECC is faster than +RSA for signing and decryption, but slower than RSA for signature +verification and encryption.

      +

      +Nevertheless, ECC is particularly useful in applications where memory, +bandwidth, and/or computational power is limited (e.g., a smartcard) +and it is in this area that ECC use is expected to grow. A major +champion of ECC today is Certicom; readers are urged to see their ECC online tutorial.

      +

      + +

      5.9. The Advanced Encryption Standard and Rijndael

      +

      +The search for a replacement to DES started in January 1997 when NIST +announced that it was looking for an Advanced Encryption Standard. In +September of that year, they put out a formal Call for Algorithms and +in August 1998 announced that 15 candidate algorithms were being +considered (Round 1). In April 1999, NIST announced that the 15 had +been whittled down to five finalists (Round 2): MARS (multiplication, addition, rotation and substitution) from IBM; Ronald Rivest's RC6; Rijndael from a Belgian team; Serpent, developed jointly by a team from England, Israel, and Norway; and Twofish, developed by Bruce Schneier. In October 2000, NIST announced their selection: Rijndael.

      +

      +The remarkable thing about this entire process has been the openness as +well as the international nature of the "competition." NIST has +maintained an excellent Web site devoted to keeping the public fully +informed, at http://csrc.nist.gov/encryption/aes/. Their Overview of the AES Development Effort has full details of the process, algorithms, and comments so I will not repeat everything here.

      +

      +In October 2000, NIST released the Report on the Development of the Advanced Encryption Standard (AES) +that compared the five Round 2 algorithms in a number of categories. +The table below summarizes the relative scores of the five schemes +(1=low, 3=high):

      + + + + + + + + + + +
      +Algorithm +
      Category +MARS +RC6 +Rijndael +Serpent +Twofish +
      General security +3 +2 +2 +3 +3 +
      Implementation of security +1 +1 +3 +3 +2 +
      Software performance +2 +2 +3 +1 +1 +
      Smart card performance +1 +1 +3 +3 +2 +
      Hardware performance +1 +2 +3 +3 +2 +
      Design features +2 +1 +2 +1 +3 +
      + +

      +With the report came the recommendation that Rijndael be named the AES. In February 2001, NIST released the Draft Federal Information Processing Standard (FIPS) AES Specification +for public review and comment. AES contains a subset of Rijndael's +capabilities (e.g., AES only supports a 128-bit block size) and uses +some slightly different nomenclature and terminology, but to understand +one is to understand both. The 90-day comment period ended on May 29, +2001 and the U.S. Department of Commerce officially adopted AES in +December 2001, published as FIPS PUB 197.

      + +

      AES (Rijndael) Overview

      +

      +Rijndael (pronounced as in "rain doll" or "rhine dahl") is a block +cipher designed by Joan Daemen and Vincent Rijmen, both cryptographers +in Belgium. Rijndael can operate over a variable-length block using +variable-length keys; the version 2 specification +submitted to NIST describes use of a 128-, 192-, or 256-bit key to +encrypt data blocks that are 128, 192, or 256 bits long; note that all +nine combinations of key length and block length are possible. The +algorithm is written in such a way that block length and/or key length +can easily be extended in multiples of 32 bits and it is specifically +designed for efficient implementation in hardware or software on a +range of processors. The design of Rijndael was strongly influenced by +the block cipher called Square, also designed by Daemen and Rijmen.

      +

      +Rijndael is an iterated block cipher, meaning that the initial input +block and cipher key undergoes multiple rounds of transformation before +producing the output. Each intermediate cipher result is called a State.

      +

      +For ease of description, the block and cipher key are often represented +as an array of columns where each array has 4 rows and each column +represents a single byte (8 bits). The number of columns in an array +representing the state or cipher key, then, can be calculated as the +block or key length divided by 32 (32 bits = 4 bytes). An array +representing a State will have Nb columns, where Nb +values of 4, 6, and 8 correspond to a 128-, 192-, and 256-bit block, +respectively. Similarly, an array representing a Cipher Key will have Nk columns, where Nk values of 4, 6, and 8 correspond to a 128-, 192-, and 256-bit key, respectively. An example of a 128-bit State (Nb=4) and 192-bit Cipher Key (Nk=6) is shown below:

      + + + +
      + + + + + + + + + + + + + + + + + + + + + +
      s0,0s0,1s0,2s0,3
      s1,0s1,1s1,2s1,3
      s2,0s2,1s2,2s2,3
      s3,0s3,1s3,2s3,3
      + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      k0,0k0,1k0,2k0,3k0,4k0,5
      k1,0k1,1k1,2k1,3k1,4k1,5
      k2,0k2,1k2,2k2,3k2,4k2,5
      k3,0k3,1k3,2k3,3k3,4k3,5
      +
      + +

      +The number of transformation rounds (Nr) in Rijndael is a function of the block length and key length, and is given by the table below:

      + + + + + + + +
      No. of Rounds
      Nr +
      Block Size +
      128 bits
      Nb = 4 +
      192 bits
      Nb = 6 +
      256 bits
      Nb = 8 + +
      Key
      Size +
      128 bits
      Nk = 4 +
      10 +12 +14 +
      192 bits
      Nk = 6 +
      12 +12 +14 +
      256 bits
      Nk = 8 +
      14 +14 +14 +
      + +

      +Now, having said all of this, the AES version of Rijndael does not +support all nine combinations of block and key lengths, but only the +subset using a 128-bit block size. NIST calls these supported variants +AES-128, AES-192, and AES-256 where the number refers to the key size. +The Nb, Nk, and Nr values supported in AES are:

      + + + + + + + +
      +Parameters +
      Variant +Nb +Nk +Nr +
      AES-128 +4 +4 +10 +
      AES-192 +4 +6 +12 +
      AES-256 +4 +8 +14 +
      + +

      +The AES/Rijndael cipher itself has three operational stages:

      +
        +
      • AddRound Key transformation +
      • Nr-1 Rounds comprising: +
          +
        • SubBytes transformation +
        • ShiftRows transformation +
        • MixColumns transformation +
        • AddRoundKey transformation +
        +
      • A final Round comprising: +
          +
        • SubBytes transformation +
        • ShiftRows transformation +
        • AddRoundKey transformation +
        +
      + +

      +The paragraphs below will describe the operations mentioned above. The +nomenclature used below is taken from the AES specification although +references to the Rijndael specification are made for completeness. The +arrays s and s' refer to the State before and after a transformation, respectively (NOTE: +The Rijndael specification uses the array nomenclature a and b to refer +to the before and after States, respectively). The subscripts i and j are used to indicate byte locations within the State (or Cipher Key) array.

      + +

      The SubBytes transformation

      +

      +The substitute bytes (called ByteSub in Rijndael) transformation operates on each of the State bytes independently and changes the byte value. An S-box, or substitution table, +controls the transformation. The characteristics of the S-box +transformation as well as a compliant S-box table are provided in the +AES specification; as an example, an input State byte value of 107 +(0x6b) will be replaced with a 127 (0x7f) in the output State and an +input value of 8 (0x08) would be replaced with a 48 (0x30).

      +

      +One way to think of the SubBytes transformation is that a given byte in +State s is given a new value in State s' according to the S-box. The +S-box, then, is a function on a byte in State s so that:

      + +

      s'i,j = S-box (si,j)

      + +

      +The more general depiction of this transformation is shown by:

      + + + +
      + + + + + + + + + + + + + + + + + + + + + +
      s0,0s0,1s0,2s0,3
      s1,0s1,1s1,2s1,3
      s2,0s2,1s2,2s2,3
      s3,0s3,1s3,2s3,3
      + +
      + + +
      ====>
      + +
      + + +
      S-box
      + +
      + + +
      ====>
      + +
      + + + + + + + + + + + + + + + + + + + + + +
      s'0,0s'0,1s'0,2s'0,3
      s'1,0s'1,1s'1,2s'1,3
      s'2,0s'2,1s'2,2s'2,3
      s'3,0s'3,1s'3,2s'3,3
      +
      + +

      The ShiftRows transformation

      +

      +The shift rows (called ShiftRow in Rijndael) +transformation cyclically shifts the bytes in the bottom three rows of +the State array. According to the more general Rijndael specification, +rows 2, 3, and 4 are cyclically left-shifted by C1, C2, and C3 bytes, +respectively, per the table below:

      + + + + + + +
      Nb +C1 +C2 +C3 +
      4 +1 +2 +3 +
      6 +1 +2 +3 +
      8 +1 +3 +4 +
      + +

      +The current version of AES, of course, only allows a block size of 128 bits (Nb = 4) so that C1=1, C2=2, and C3=3. The diagram below shows the effect of the ShiftRows transformation on State s:

      + + + +
      + + + + + + + + + + + + + + + + + + + + + + +
      State s
      s0,0s0,1s0,2s0,3
      s1,0s1,1s1,2s1,3
      s2,0s2,1s2,2s2,3
      s3,0s3,1s3,2s3,3
      + +
      + + + + + + +
       
      ----------- no shift -----------> 
      ----> left-shift by C1 (1) ----> 
      ----> left-shift by C2 (2) ----> 
      ----> left-shift by C3 (3) ----> 
      + +
      + + + + + + + + + + + + + + + + + + + + + + +
      State s'
      s0,0s0,1s0,2s0,3
      s1,1s1,2s1,3s1,0
      s2,2s2,3s2,0s2,1
      s3,3s3,0s3,1s3,2
      +
      + +

      The MixColumns transformation

      +

      +The mix columns (called MixColumn in Rijndael) +transformation uses a mathematical function to transform the values of +a given column within a State, acting on the four values at one time as +if they represented a four-term polynomial. In essence, if you think of +MixColumns as a function, this could be written:

      + +

      s'i,c = MixColumns (si,c)

      + +

      +for 0<=i<=3 for some column, c. The column position doesn't change, merely the values within the column.

      + +

      Round Key generation and the AddRoundKey transformation

      +

      +The AES Cipher Key can be 128, 192, or 256 bits in length. The Cipher +Key is used to derive a different key to be applied to the block during +each round of the encryption operation. These keys are called the Round +Keys and each will be the same length as the block, i.e., Nb 32-bit words (words will be denoted W).

      +

      +The AES specification defines a key schedule by which the original Cipher Key (of length Nk 32-bit words) is used to form an Expanded Key. The Expanded Key size is equal to the block size times the number of encryption rounds plus 1, which will provide Nr+1 different keys. (Note that there are Nr encipherment rounds but Nr+1 AddRoundKey transformations.)

      +

      +Consider that AES uses a 128-bit block and either 10, 12, or 14 +iterative rounds depending upon key length. With a 128-bit key, for +example, we would need 1408 bits of key material (128x11=1408), or an +Expanded Key size of 44 32-bit words (44x32=1408). Similarly, a 192-bit +key would require 1664 bits of key material (128x13), or 52 32-bit +words, while a 256-bit key would require 1920 bits of key material +(128x15), or 60 32-bit words. The key expansion mechanism, then, starts +with the 128-, 192-, or 256-bit Cipher Key and produces a 1408-, 1664-, +or 1920-bit Expanded Key, respectively. The original Cipher Key +occupies the first portion of the Expanded Key and is used to produce +the remaining new key material.

      +

      +The result is an Expanded Key that can be thought of and used as 11, +13, or 15 separate keys, each used for one AddRoundKey operation. +These, then, are the Round Keys. The diagram below shows an example using a 192-bit Cipher Key (Nk=6), shown in magenta italics:

      + + + + +
      Expanded Key: +W0 +W1 +W2 +W3 +W4 +W5 +W6 +W7 +W8 +W9 +W10 +W11 +W12 +W13 +W14 +W15 +... +W44 +W45 +W46 +W47 +W48 +W49 +W50 +W51 +
      Round keys: +Round key 0 +Round key 1 +Round key 2 +Round key 3 +... +Round key 11 +Round key 12 +
      +

      +The AddRoundKey (called Round Key addition in Rijndael) +transformation merely applies each Round Key, in turn, to the State by +a simple bit-wise exclusive OR operation. Recall that each Round Key is +the same length as the block.

      + +

      Summary

      +

      +Ok, I hope that you've enjoyed reading this as much as I've enjoyed +writing it — and now let me guide you out of the microdetail! Recall +from the beginning of the AES overview that the cipher itself comprises +a number of rounds of just a few functions:

      +
        +
      • SubBytes takes the value of a word within a State and substitutes it with another value by a predefined S-box +
      • ShiftRows circularly shifts each row in the State by some number of predefined bytes +
      • MixColumns takes the value of a 4-word column within the State and changes the four values using a predefined mathematical function +
      • AddRoundKey XORs a key that is the same length as the block, using an Expanded Key derived from the original Cipher Key +
      + +
      + +
      Cipher (byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)])
      +begin
      +  byte state[4,Nb]
      +
      +  state = in
      +
      +  AddRoundKey(state, w)
      +
      +  for round = 1 step 1 to Nr-1
      +    SubBytes(state)
      +    ShiftRows(state)
      +    MixColumns(state)
      +    AddRoundKey(state, w+round*Nb)
      +  end for
      +
      +  SubBytes(state)
      +  ShiftRows(state)
      +  AddRoundKey(state, w+Nr*Nb)
      +
      +  out = state
      +end
      +
      +

      +

      FIGURE 17: AES pseudocode.

      +
      + +
      + +

      +As a last and final demonstration of the operation of AES, Figure 17 is +a pseudocode listing for the operation of the AES cipher. In the code:

      +
        +
      • in[] and out[] are 16-byte arrays with the plaintext +and cipher text, respectively. (According to the specification, both of +these arrays are actually 4*Nb bytes in length but Nb=4 in AES.) +
      • state[] is a 2-dimensional array containing bytes in 4 rows and 4 columns. (According to the specification, this arrays is 4 rows by Nb columns.) +
      • w[] is an array containing the key material and is 4*(Nr+1) words in length. (Again, according to the specification, the multiplier is actually Nb.) +
      • AddRoundKey(), SubBytes(), ShiftRows(), and MixColumns() are functions representing the individual transformations. +
      + +
      +

      5.10. Cisco's Stream Cipher

      +

      +Stream ciphers take advantage of the fact that:

      +

      +x XOR y XOR y = x

      +

      +One of the encryption schemes employed by Cisco routers to encrypt +passwords is a stream cipher. It uses the following fixed keystream +(thanks also to Jason Fossen for independently extending and confirming +this string):

      +

      +dsfd;kfoA,.iyewrkldJKDHSUBsgvca69834ncx

      +

      +When a password is to be encrypted, the password function chooses a +number between 0 and 15, and that becomes the offset into the +keystream. Password characters are then XORed byte-by-byte with the +keystream according to:

      +

      +Ci = Pi XOR K(offset+i)

      +

      +where K is the keystream, P is the plaintext password, and C is the ciphertext password.

      +

      +Consider the following example. Suppose we have the password abcdefgh. Converting the ASCII characters yields the hex string 0x6162636465666768.

      +

      +The keystream characters and hex code that supports an offset from 0 to 15 bytes and a password length up to 24 bytes is:

      +

      +  d s f d ; k f o A , . i y e w r k l d J K D H S U B s g v c a 6 9 8 3 4 n c x
      +0x647366643b6b666f412c2e69796577726b6c644a4b4448535542736776636136393833346e6378

      +

      +Let's say that the function decides upon a keystream offset of 6 bytes. +We then start with byte 6 of the keystream (start counting the offset +at 0) and XOR with the password:

      +

      +     0x666f412c2e697965
      +XOR 0x6162636465666768
      +     ------------------
      +     0x070D22484B0F1E0D

      +

      +The password would now be displayed in the router configuration as:

      +

      +password 7 06070D22484B0F1E0D

      +

      +where the "7" indicates the encryption type, the leading "06" indicates +the offset into the keystream, and the remaining bytes are the +encrypted password characters. (Decryption is pretty trivial so that +exercise is left to the reader. If you need some help with byte-wise +XORing, see http://www.garykessler.net/library/byte_logic_table.html.)

      + +

      +

      6. CONCLUSION... OF SORTS

      +

      +This paper has briefly described how cryptography works. The reader +must beware, however, that there are a number of ways to attack every +one of these systems; cryptanalysis and attacks on cryptosystems, +however, are well beyond the scope of this paper. In the words of +Sherlock Holmes (ok, Arthur Conan Doyle, really), "What one man can +invent, another can discover" ("The Adventure of the Dancing Men"). +

      Cryptography is a particularly interesting field because of the +amount of work that is, by necessity, done in secret. The irony is that +today, secrecy is not +the key to the goodness of a cryptographic algorithm. Regardless of the +mathematical theory behind an algorithm, the best algorithms are those +that are well-known and well-documented because they are also +well-tested and well-studied! In fact, time is the only true +test of good cryptography; any cryptographic scheme that stays in use +year after year is most likely a good one. The strength of cryptography +lies in the choice (and management) of the keys; longer keys will resist attack better than shorter keys.

      +

      +The corollary to this is that consumers should run, not walk, away from +any product that uses a proprietary cryptography scheme, ostensibly +because the algorithm's secrecy is an advantage. This observation about +not using "secret" crypto schemes has been a fundamental hallmark of +cryptography for well over 100 years; it was first stated explicitly by +Dutch linguist Auguste Kerckhoffs von Nieuwenhoff in his 1883 (yes, 1883) text titled La Cryptographie militaire, and has therefore become known as "Kerckhoffs' Principle."

      +
      + +

      7. REFERENCES AND FURTHER READING

      + + +

      +And for a purely enjoyable fiction book that combines cryptography and history, check out Neal Stephenson's Crytonomicon +(published May 1999). You will also find in it a new secure crypto +scheme based upon an ordinary deck of cards (ok, you need the +jokers...) called the Solitaire Encryption Algorithm, developed by Bruce Schneier.

      + + + +
      + +

      +Finally, I am not in the clothing business although I do have an +impressive t-shirt collection (over 350 and counting!). If you want to +proudly wear the DES (well, actually the IDEA) encryption algorithm, be +sure to see 2600 Magazine's DES Encryption Shirt, found at http://store.yahoo.com/2600hacker/desenshir.html (left). A t-shirt with Adam Back's RSA Perl code can be found at http://www.cypherspace.org/~adam/uk-shirt.html (right).

      +
      +
      + +
      +

      APPENDIX. SOME MATH NOTES

      +

      +A number of readers over time have asked for some rudimentary +background on a few of the less well-known mathematical functions +mentioned in this paper. Although this is purposely not +a mathematical treatise, some of the math functions mentioned here are +essential to grasping how modern crypto functions work. To that end, +some of the mathematical functions mentioned in this paper are defined +in greater detail below.

      + +

      A.1. The Exclusive-OR (XOR) Function

      +

      +Exclusive OR (XOR) is one of the fundamental mathematical operations +used in cryptography (and many other applications). George Boole, a +mathematician in the late 1800s, invented a new form of "algebra" that +provides the basis for building electronic computers and microprocessor +chips. Boole defined a bunch of primitive logical operations where +there are one or two inputs and a single output depending upon the +operation; the input and output are either TRUE or FALSE. The most +elemental Boolean operations are:

      +
        +
      • NOT: The output value is the inverse of the input value (i.e., the +output is TRUE if the input is false, FALSE if the input is true) +
      • AND: The output is TRUE if all inputs are true, otherwise +FALSE. (E.g., "the sky is blue AND the world is flat" is FALSE while +"the sky is blue AND security is a process" is TRUE.) +
      • OR: The output is TRUE if either or both inputs are true, +otherwise FALSE. (E.g., "the sky is blue OR the world is flat" is TRUE +and "the sky is blue OR security is a process" is TRUE.) +
      • XOR (Exclusive OR): The output is TRUE if exactly one of the +inputs is TRUE, otherwise FALSE. (E.g., "the sky is blue XOR the world +is flat" is TRUE while "the sky is blue XOR security is a process" is +FALSE.) +
      + +

      +I'll only discuss XOR for now and demonstrate its function by the use of a so-called truth tables. In computers, Boolean logic is implemented in logic gates; for design purposes, XOR has two inputs and a single output, and its logic diagram looks like this:

      + + + + + + + + + + + + + + + + + +
      XOR01
      001
      110
      + +

      So, in an XOR operation, the output will be a 1 if one input is a 1; +otherwise, the output is 0. The real significance of this is to look at +the "identity properties" of XOR. In particular, any value XORed with +itself is 0 and any value XORed with 0 is just itself. Why does this +matter? Well, if I take my plaintext and XOR it with a key, I get a +jumble of bits. If I then take that jumble and XOR it with the same +key, I return to the original plaintext.

      +

      +NOTE: Boolean truth tables usually show the inputs and output as +a single bit because they are based on single bit inputs, namely, TRUE +and FALSE. In addition, we tend to apply Boolean operations bit-by-bit. +For convenience, I have created Boolean logic tables when operating on bytes.

      + +

      A.2. The modulo Function

      +

      +The modulo function is, simply, the remainder function. It +is commonly used in programming and is critical to the operation of any +mathematical function using digital computers.

      +

      +To calculate X modulo Y (usually written X mod Y), +you merely determine the remainder after removing all multiples of Y +from X. Clearly, the value X mod Y will be in the range from 0 to Y-1.

      +

      +Some examples should clear up any remaining confusion:

      +
        +
      • 15 mod 7 = 1 +
      • 25 mod 5 = 0 +
      • 33 mod 12 = 9 +
      • 203 mod 256 = 203 +
      +

      +Modulo arithmetic is useful in crypto because it allows us to set the +size of an operation and be sure that we will never get numbers that +are too large. This is an important consideration when using digital +computers.

      + +
      +

      ABOUT THE AUTHOR

      +

      +Gary Kessler is an Associate Professor at Champlain College in Burlington, VT, where he is the director of the Computer Networking and Computer & Digital Forensics programs. He is also the president and janitor of Gary Kessler Associates, +an independent consulting and training firm specializing in computer +and network security, computer forensics, Internet access issues, and +TCP/IP networking. He has written over 60 papers for industry +publications, is co-author of ISDN, 4th. edition (McGraw-Hill, 1998), and is a contributor to Information Security Magazine. Gary's e-mail address is kumquat@sover.net and his PGP public key can be found at http://www.garykessler.net/kumquat_pubkey.html or on MIT's PGP keyserver. Some of Gary's other crypto pointers of interest on the Web can be found at his Security-related URLs list.

      +
    + +


















    + +
    \ No newline at end of file diff --git a/www/test_dir/some_text.txt b/www/test_dir/some_text.txt new file mode 100644 index 000000000..041831f7d --- /dev/null +++ b/www/test_dir/some_text.txt @@ -0,0 +1 @@ +This is some text. diff --git a/www/test_dir/test_cgi.php b/www/test_dir/test_cgi.php new file mode 100755 index 000000000..5171ff3e7 --- /dev/null +++ b/www/test_dir/test_cgi.php @@ -0,0 +1,6 @@ +#!/usr/bin/php + + +