From 425067abe69606ab7002b34c047e46a007f29895 Mon Sep 17 00:00:00 2001 From: cameronrich Date: Mon, 12 Dec 2016 19:27:38 +0000 Subject: [PATCH] * SNI added * Some non-C sample code updated. git-svn-id: svn://svn.code.sf.net/p/axtls/code/trunk@271 9a5d90b5-6617-0410-8a86-bb477d3ed2e3 --- bindings/Config.in | 105 ++++ bindings/csharp/axTLS.cs | 491 +++++++++++++++ bindings/generate_SWIG_interface.pl | 392 ++++++++++++ bindings/java/SSL.java | 137 +++++ config/makefile.conf | 134 ++++ samples/c/axssl.c | 912 ++++++++++++++++++++++++++++ samples/csharp/axssl.cs | 758 +++++++++++++++++++++++ samples/java/Makefile | 51 ++ samples/java/axssl.java | 760 +++++++++++++++++++++++ samples/lua/axssl.lua | 562 +++++++++++++++++ samples/perl/axssl.pl | 634 +++++++++++++++++++ samples/vbnet/axssl.vb | 702 +++++++++++++++++++++ ssl/asn1.c | 20 +- ssl/ssl.h | 9 +- ssl/test/ssltest.c | 11 +- ssl/tls1.c | 6 +- ssl/tls1.h | 7 +- ssl/tls1_clnt.c | 58 +- 18 files changed, 5701 insertions(+), 48 deletions(-) create mode 100644 bindings/Config.in create mode 100644 bindings/csharp/axTLS.cs create mode 100755 bindings/generate_SWIG_interface.pl create mode 100644 bindings/java/SSL.java create mode 100644 config/makefile.conf create mode 100644 samples/c/axssl.c create mode 100644 samples/csharp/axssl.cs create mode 100644 samples/java/Makefile create mode 100644 samples/java/axssl.java create mode 100755 samples/lua/axssl.lua create mode 100755 samples/perl/axssl.pl create mode 100644 samples/vbnet/axssl.vb diff --git a/bindings/Config.in b/bindings/Config.in new file mode 100644 index 000000000..443fc1a32 --- /dev/null +++ b/bindings/Config.in @@ -0,0 +1,105 @@ +# +# For a description of the syntax of this configuration file, +# see scripts/config/Kconfig-language.txt +# +menu "Language Bindings" + +config CONFIG_BINDINGS + bool "Create language bindings" + default n + help + axTLS supports language bindings in C#, VB.NET, Java and Perl. + + Select Y here if you want to build the various language bindings. + +config CONFIG_CSHARP_BINDINGS + bool "Create C# bindings" + default n + depends on CONFIG_BINDINGS + help + Build C# bindings. + + This requires .NET to be installed on Win32 platforms and mono to be + installed on all other platforms. + +config CONFIG_VBNET_BINDINGS + bool "Create VB.NET bindings" + default n + depends on CONFIG_BINDINGS + help + Build VB.NET bindings. + + This requires the .NET to be installed and is only built under Win32 + platforms. + +menu ".Net Framework" +depends on CONFIG_CSHARP_BINDINGS || CONFIG_VBNET_BINDINGS +config CONFIG_DOT_NET_FRAMEWORK_BASE + string "Location of .NET Framework" + default "c:\\WINDOWS\\Microsoft.NET\\Framework\\v2.0.50727" +endmenu + +config CONFIG_JAVA_BINDINGS + bool "Create Java bindings" + default n + depends on CONFIG_BINDINGS + help + Build Java bindings. + + Current Issues (see README): + * Needs Java 1.4 or better. + * If building under Win32 it will use the Win32 JDK. + +menu "Java Home" +depends on CONFIG_JAVA_BINDINGS +config CONFIG_JAVA_HOME + string "Location of JDK" + default "c:\\Program Files\\Java\\jdk1.5.0_06" if CONFIG_PLATFORM_WIN32 || CONFIG_PLATFORM_CYGWIN + default "/usr/lib/jvm/java-7-openjdk-amd64" if !CONFIG_PLATFORM_WIN32 && !CONFIG_PLATFORM_CYGWIN + depends on CONFIG_JAVA_BINDINGS + help + The location of Sun's JDK. +endmenu + +config CONFIG_PERL_BINDINGS + bool "Create Perl bindings" + default n + depends on CONFIG_BINDINGS + help + Build Perl bindings. + + Current Issues (see README): + * 64 bit versions don't work at present. + * libperl.so needs to be in the shared library path. + +menu "Perl Home" +depends on CONFIG_PERL_BINDINGS && CONFIG_PLATFORM_WIN32 +config CONFIG_PERL_CORE + string "Location of Perl CORE" + default "c:\\perl\\lib\\CORE" + help: + works with ActiveState + "http://www.activestate.com/Products/ActivePerl" + +config CONFIG_PERL_LIB + string "Name of Perl Library" + default "perl58.lib" +endmenu + +config CONFIG_LUA_BINDINGS + bool "Create Lua bindings" + default n + depends on CONFIG_BINDINGS && !CONFIG_PLATFORM_WIN32 + help + Build Lua bindings (see www.lua.org). + +menu "Lua Home" +depends on CONFIG_LUA_BINDINGS +config CONFIG_LUA_CORE + string "Location of Lua CORE" + default "/usr/local" + help: + If the Lua exists on another directory then this needs to be changed +endmenu + +endmenu diff --git a/bindings/csharp/axTLS.cs b/bindings/csharp/axTLS.cs new file mode 100644 index 000000000..6a2f6b063 --- /dev/null +++ b/bindings/csharp/axTLS.cs @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2007-2016, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * A wrapper around the unmanaged interface to give a semi-decent C# API + */ + +using System; +using System.Runtime.InteropServices; +using System.Net.Sockets; + +/** + * @defgroup csharp_api C# API. + * + * Ensure that the appropriate Dispose() methods are called when finished with + * various objects - otherwise memory leaks will result. + * @{ + */ +namespace axTLS +{ + /** + * @class SSL + * @ingroup csharp_api + * @brief A representation of an SSL connection. + */ + public class SSL + { + public IntPtr m_ssl; /**< A pointer to the real SSL type */ + + /** + * @brief Store the reference to an SSL context. + * @param ip [in] A reference to an SSL object. + */ + public SSL(IntPtr ip) + { + m_ssl = ip; + } + + /** + * @brief Free any used resources on this connection. + * + * A "Close Notify" message is sent on this connection (if possible). + * It is up to the application to close the socket. + */ + public void Dispose() + { + axtls.ssl_free(m_ssl); + } + + /** + * @brief Return the result of a handshake. + * @return SSL_OK if the handshake is complete and ok. + * @see ssl.h for the error code list. + */ + public int HandshakeStatus() + { + return axtls.ssl_handshake_status(m_ssl); + } + + /** + * @brief Return the SSL cipher id. + * @return The cipher id which is one of: + * - SSL_AES128_SHA (0x2f) + * - SSL_AES256_SHA (0x35) + * - SSL_AES128_SHA256 (0x3c) + * - SSL_AES256_SHA256 (0x3d) + */ + public byte GetCipherId() + { + return axtls.ssl_get_cipher_id(m_ssl); + } + + /** + * @brief Get the session id for a handshake. + * + * This will be a 32 byte sequence and is available after the first + * handshaking messages are sent. + * @return The session id as a 32 byte sequence. + * @note A SSLv23 handshake may have only 16 valid bytes. + */ + public byte[] GetSessionId() + { + IntPtr ptr = axtls.ssl_get_session_id(m_ssl); + byte sess_id_size = axtls.ssl_get_session_id_size(m_ssl); + byte[] result = new byte[sess_id_size]; + Marshal.Copy(ptr, result, 0, sess_id_size); + return result; + } + + /** + * @brief Retrieve an X.509 distinguished name component. + * + * When a handshake is complete and a certificate has been exchanged, + * then the details of the remote certificate can be retrieved. + * + * This will usually be used by a client to check that the server's + * common name matches the URL. + * + * A full handshake needs to occur for this call to work. + * + * @param component [in] one of: + * - SSL_X509_CERT_COMMON_NAME + * - SSL_X509_CERT_ORGANIZATION + * - SSL_X509_CERT_ORGANIZATIONAL_NAME + * - SSL_X509_CA_CERT_COMMON_NAME + * - SSL_X509_CA_CERT_ORGANIZATION + * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME + * @return The appropriate string (or null if not defined) + */ + public string GetCertificateDN(int component) + { + return axtls.ssl_get_cert_dn(m_ssl, component); + } + } + + /** + * @class SSLUtil + * @ingroup csharp_api + * @brief Some global helper functions. + */ + public class SSLUtil + { + + /** + * @brief Return the build mode of the axTLS project. + * @return The build mode is one of: + * - SSL_BUILD_SERVER_ONLY + * - SSL_BUILD_ENABLE_VERIFICATION + * - SSL_BUILD_ENABLE_CLIENT + * - SSL_BUILD_FULL_MODE + */ + public static int BuildMode() + { + return axtls.ssl_get_config(axtls.SSL_BUILD_MODE); + } + + /** + * @brief Return the number of chained certificates that the + * client/server supports. + * @return The number of supported server certificates. + */ + public static int MaxCerts() + { + return axtls.ssl_get_config(axtls.SSL_MAX_CERT_CFG_OFFSET); + } + + /** + * @brief Return the number of CA certificates that the client/server + * supports. + * @return The number of supported CA certificates. + */ + public static int MaxCACerts() + { + return axtls.ssl_get_config(axtls.SSL_MAX_CA_CERT_CFG_OFFSET); + } + + /** + * @brief Indicate if PEM is supported. + * @return true if PEM supported. + */ + public static bool HasPEM() + { + return axtls.ssl_get_config(axtls.SSL_HAS_PEM) > 0 ? true : false; + } + + /** + * @brief Display the text string of the error. + * @param error_code [in] The integer error code. + */ + public static void DisplayError(int error_code) + { + axtls.ssl_display_error(error_code); + } + + /** + * @brief Return the version of the axTLS project. + */ + public static string Version() + { + return axtls.ssl_version(); + } + } + + /** + * @class SSLCTX + * @ingroup csharp_api + * @brief A base object for SSLServer/SSLClient. + */ + public class SSLCTX + { + /** + * @brief A reference to the real client/server context. + */ + protected IntPtr m_ctx; + + /** + * @brief Establish a new client/server context. + * + * This function is called before any client/server SSL connections are + * made. If multiple threads are used, then each thread will have its + * own SSLCTX context. Any number of connections may be made with a + * single context. + * + * Each new connection will use the this context's private key and + * certificate chain. If a different certificate chain is required, + * then a different context needs to be be used. + * + * @param options [in] Any particular options. At present the options + * supported are: + * - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if + * the server authentication fails. The certificate can be + * authenticated later with a call to VerifyCert(). + * - SSL_CLIENT_AUTHENTICATION (server only): Enforce client + * authentication i.e. each handshake will include a "certificate + * request" message from the server. + * - SSL_DISPLAY_BYTES (full mode build only): Display the byte + * sequences during the handshake. + * - SSL_DISPLAY_STATES (full mode build only): Display the state + * changes during the handshake. + * - SSL_DISPLAY_CERTS (full mode build only): Display the + * certificates that are passed during a handshake. + * - SSL_DISPLAY_RSA (full mode build only): Display the RSA key + * details that are passed during a handshake. + * @param num_sessions [in] The number of sessions to be used for + * session caching. If this value is 0, then there is no session + * caching. + * @return A client/server context. + */ + protected SSLCTX(uint options, int num_sessions) + { + m_ctx = axtls.ssl_ctx_new(options, num_sessions); + } + + /** + * @brief Remove a client/server context. + * + * Frees any used resources used by this context. Each connection will + * be sent a "Close Notify" alert (if possible). + */ + public void Dispose() + { + axtls.ssl_ctx_free(m_ctx); + } + + /** + * @brief Read the SSL data stream. + * @param ssl [in] An SSL object reference. + * @param in_data [out] After a successful read, the decrypted data + * will be here. It will be null otherwise. + * @return The number of decrypted bytes: + * - if > 0, then the handshaking is complete and we are returning the + * number of decrypted bytes. + * - SSL_OK if the handshaking stage is successful (but not yet + * complete). + * - < 0 if an error. + * @see ssl.h for the error code list. + * @note Use in_data before doing any successive ssl calls. + */ + public int Read(SSL ssl, out byte[] in_data) + { + IntPtr ptr = IntPtr.Zero; + int ret = axtls.ssl_read(ssl.m_ssl, ref ptr); + + if (ret > axtls.SSL_OK) + { + in_data = new byte[ret]; + Marshal.Copy(ptr, in_data, 0, ret); + } + else + { + in_data = null; + } + + return ret; + } + + /** + * @brief Write to the SSL data stream. + * @param ssl [in] An SSL obect reference. + * @param out_data [in] The data to be written + * @return The number of bytes sent, or if < 0 if an error. + * @see ssl.h for the error code list. + */ + public int Write(SSL ssl, byte[] out_data) + { + return axtls.ssl_write(ssl.m_ssl, out_data, out_data.Length); + } + + /** + * @brief Write to the SSL data stream. + * @param ssl [in] An SSL obect reference. + * @param out_data [in] The data to be written + * @param out_len [in] The number of bytes to be written + * @return The number of bytes sent, or if < 0 if an error. + * @see ssl.h for the error code list. + */ + public int Write(SSL ssl, byte[] out_data, int out_len) + { + return axtls.ssl_write(ssl.m_ssl, out_data, out_len); + } + + /** + * @brief Find an ssl object based on a Socket reference. + * + * Goes through the list of SSL objects maintained in a client/server + * context to look for a socket match. + * @param s [in] A reference to a 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. + * + * This is a blocking call on the client (until the handshake + * completes). + * @param ssl [in] An SSL object reference. + * @return SSL_OK if renegotiation instantiation was ok + */ + public int Renegotiate(SSL ssl) + { + return axtls.ssl_renegotiate(ssl.m_ssl); + } + + /** + * @brief Load a file into memory that is in binary DER or ASCII PEM + * format. + * + * These are temporary objects that are used to load private keys, + * certificates etc into memory. + * @param obj_type [in] The format of the file. Can be one of: + * - SSL_OBJ_X509_CERT (no password required) + * - SSL_OBJ_X509_CACERT (no password required) + * - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported) + * - SSL_OBJ_P8 (RC4-128 encrypted data supported) + * - SSL_OBJ_P12 (RC4-128 encrypted data supported) + * + * PEM files are automatically detected (if supported). + * @param filename [in] The location of a file in DER/PEM format. + * @param password [in] The password used. Can be null if not required. + * @return SSL_OK if all ok + */ + public int ObjLoad(int obj_type, string filename, string password) + { + return axtls.ssl_obj_load(m_ctx, obj_type, filename, password); + } + + /** + * @brief Transfer binary data into the object loader. + * + * These are temporary objects that are used to load private keys, + * certificates etc into memory. + * @param obj_type [in] The format of the memory data. + * @param data [in] The binary data to be loaded. + * @param len [in] The amount of data to be loaded. + * @param password [in] The password used. Can be null if not required. + * @return SSL_OK if all ok + */ + public int ObjLoad(int obj_type, byte[] data, int len, string password) + { + return axtls.ssl_obj_memory_load(m_ctx, obj_type, + data, len, password); + } + } + + /** + * @class SSLServer + * @ingroup csharp_api + * @brief The server context. + * + * All server connections are started within a server context. + */ + public class SSLServer : SSLCTX + { + /** + * @brief Start a new server context. + * + * @see SSLCTX for details. + */ + public SSLServer(uint options, int num_sessions) : + base(options, num_sessions) {} + + /** + * @brief Establish a new SSL connection to an SSL client. + * + * It is up to the application to establish the initial socket + * connection. + * + * Call Dispose() when the connection is to be removed. + * @param s [in] A reference to a 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(); + byte sess_id_size = (byte)(session_id != null ? + session_id.Length : 0); + return new SSL(axtls.ssl_client_new(m_ctx, client_fd, session_id, + sess_id_size)); + } + } +} +/** @} */ diff --git a/bindings/generate_SWIG_interface.pl b/bindings/generate_SWIG_interface.pl new file mode 100755 index 000000000..90c4ba3be --- /dev/null +++ b/bindings/generate_SWIG_interface.pl @@ -0,0 +1,392 @@ +#!/usr/bin/perl + +# +# Copyright (c) 2007, Cameron Rich +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the axTLS project nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +#=============================================================== +# Transforms function signature into SWIG format +sub transformSignature +{ + foreach $item (@_) + { + $line =~ s/STDCALL //g; + $line =~ s/EXP_FUNC/extern/g; + + # make API Java more 'byte' friendly + $line =~ s/uint32_t/int/g; + $line =~ s/const uint8_t \* /const unsigned char \* /g; + $line =~ s/\(void\)/()/g; + if ($ARGV[0] eq "-java") + { + $line =~ s/.*ssl_read.*//g; + $line =~ s/const uint8_t \*(\w+)/const signed char $1\[\]/g; + $line =~ s/uint8_t/signed char/g; + } + elsif ($ARGV[0] eq "-perl") + { + $line =~ s/const uint8_t \*(\w+)/const unsigned char $1\[\]/g; + $line =~ s/uint8_t/unsigned char/g; + } + else # lua + { + $line =~ s/const uint8_t \*session_id/const unsigned char session_id\[\]/g; + $line =~ s/const uint8_t \*\w+/unsigned char *INPUT/g; + $line =~ s/uint8_t/unsigned char/g; + } + } + + return $line; +} + +# Parse input file +sub parseFile +{ + foreach $line (@_) + { + next if $line =~ /ssl_x509_create/; # ignore for now + + # test for a #define + if (!$skip && $line =~ m/^#define/) + { + $splitDefine = 1 if $line =~ m/\\$/; + print DATA_OUT $line; + + # check line is not split + next if $splitDefine == 1; + } + + # pick up second line of #define statement + if ($splitDefine) + { + print DATA_OUT $line; + + # check line is not split + $splitDefine = ($line =~ m/\\$/); + next; + } + + # test for function declaration + if (!$skip && $line =~ /EXP_FUNC/ && $line !~/\/\*/) + { + $line = transformSignature($line); + $splitFunctionDeclaration = $line !~ /;/; + print DATA_OUT $line; + next; + } + + if ($splitFunctionDeclaration) + { + $line = transformSignature($line); + $splitFunctionDeclaration = $line !~ /;/; + print DATA_OUT $line; + next; + } + } +} + +#=============================================================== + +# Determine which module to build from cammand-line options +use strict; +use Getopt::Std; + +my $module; +my $interfaceFile; +my $data_file; +my $skip; +my $splitLine; +my @raw_data; + +if (not defined $ARGV[0]) +{ + die "Usage: $0 [-java | -perl | -lua]\n"; +} + +if ($ARGV[0] eq "-java") +{ + print "Generating Java interface file\n"; + $module = "axtlsj"; + $interfaceFile = "java/axTLSj.i"; +} +elsif ($ARGV[0] eq "-perl") +{ + print "Generating Perl interface file\n"; + $module = "axtlsp"; + $interfaceFile = "perl/axTLSp.i"; +} +elsif ($ARGV[0] eq "-lua") +{ + print "Generating lua interface file\n"; + $module = "axtlsl"; + $interfaceFile = "lua/axTLSl.i"; +} +else +{ + die "Usage: $0 [-java | -perl | -lua]\n"; +} + +# Input file required to generate SWIG interface file. +$data_file = "../ssl/ssl.h"; + +# Open input files +open(DATA_IN, $data_file) || die("Could not open file ($data_file)!"); +@raw_data = ; + +# Open output file +open(DATA_OUT, ">$interfaceFile") || die("Cannot Open File"); + +# +# I wish I could say it was easy to generate the Perl/Java/Lua bindings, +# but each had their own set of challenges... :-(. +# +print DATA_OUT << "END"; +%module $module\n + +/* include our own header */ +%inline %{ +#include "ssl.h" +%} + +%include "typemaps.i" +/* Some SWIG magic to make the API a bit more Java friendly */ +#ifdef SWIGJAVA + +%apply long { SSL * }; +%apply long { SSL_CTX * }; +%apply long { SSLObjLoader * }; + +/* allow "unsigned char []" to become "byte[]" */ +%include "arrays_java.i" + +/* convert these pointers to use long */ +%apply signed char[] {unsigned char *}; +%apply signed char[] {signed char *}; + +/* allow ssl_get_session_id() to return "byte[]" */ +%typemap(out) unsigned char * ssl_get_session_id \"if (result) jresult = SWIG_JavaArrayOutSchar(jenv, result, ssl_get_session_id_size((SSL const *)arg1));\" + +/* allow ssl_client_new() to have a null session_id input */ +%typemap(in) const signed char session_id[] (jbyte *jarr) { + if (jarg3 == NULL) + { + jresult = (jint)ssl_client_new(arg1,arg2,NULL,0); + return jresult; + } + + if (!SWIG_JavaArrayInSchar(jenv, &jarr, &arg3, jarg3)) return 0; +} + +/* Lot's of work required for an ssl_read() due to its various custom + * requirements. + */ +%native (ssl_read) int ssl_read(SSL *ssl, jobject in_data); +%{ +JNIEXPORT jint JNICALL Java_axTLSj_axtlsjJNI_ssl_1read(JNIEnv *jenv, jclass jcls, jint jarg1, jobject jarg2) { + jint jresult = 0 ; + SSL *arg1; + unsigned char *arg2; + jbyte *jarr; + int result; + JNIEnv e = *jenv; + jclass holder_class; + jfieldID fid; + + arg1 = (SSL *)jarg1; + result = (int)ssl_read(arg1, &arg2); + + /* find the "m_buf" entry in the SSLReadHolder class */ + if (!(holder_class = e->GetObjectClass(jenv,jarg2)) || + !(fid = e->GetFieldID(jenv,holder_class, "m_buf", "[B"))) + return SSL_NOT_OK; + + if (result > SSL_OK) + { + int i; + + /* create a new byte array to hold the read data */ + jbyteArray jarray = e->NewByteArray(jenv, result); + + /* copy the bytes across to the java byte array */ + jarr = e->GetByteArrayElements(jenv, jarray, 0); + for (i = 0; i < result; i++) + jarr[i] = (jbyte)arg2[i]; + + /* clean up and set the new m_buf object */ + e->ReleaseByteArrayElements(jenv, jarray, jarr, 0); + e->SetObjectField(jenv, jarg2, fid, jarray); + } + else /* set to null */ + e->SetObjectField(jenv, jarg2, fid, NULL); + + jresult = (jint)result; + return jresult; +} +%} + +/* Big hack to get hold of a socket's file descriptor */ +%typemap (jtype) long "Object" +%typemap (jstype) long "Object" +%native (getFd) int getFd(long sock); +%{ +JNIEXPORT jint JNICALL Java_axTLSj_axtlsjJNI_getFd(JNIEnv *env, jclass jcls, jobject sock) +{ + JNIEnv e = *env; + jfieldID fid; + jobject impl; + jobject fdesc; + + /* get the SocketImpl from the Socket */ + if (!(jcls = e->GetObjectClass(env,sock)) || + !(fid = e->GetFieldID(env,jcls,"impl","Ljava/net/SocketImpl;")) || + !(impl = e->GetObjectField(env,sock,fid))) return -1; + + /* get the FileDescriptor from the SocketImpl */ + if (!(jcls = e->GetObjectClass(env,impl)) || + !(fid = e->GetFieldID(env,jcls,"fd","Ljava/io/FileDescriptor;")) || + !(fdesc = e->GetObjectField(env,impl,fid))) return -1; + + /* get the fd from the FileDescriptor */ + if (!(jcls = e->GetObjectClass(env,fdesc)) || + !(fid = e->GetFieldID(env,jcls,"fd","I"))) return -1; + + /* return the descriptor */ + return e->GetIntField(env,fdesc,fid); +} +%} + +#endif + +/* Some SWIG magic to make the API a bit more Perl friendly */ +#ifdef SWIGPERL + +/* for ssl_session_id() */ +%typemap(out) const unsigned char * { + SV *svs = newSVpv((unsigned char *)\$1, ssl_get_session_id_size((SSL const *)arg1)); + \$result = newRV(svs); + sv_2mortal(\$result); + argvi++; +} + +/* for ssl_write() */ +%typemap(in) const unsigned char out_data[] { + SV* tempsv; + if (!SvROK(\$input)) + croak("Argument \$argnum is not a reference."); + tempsv = SvRV(\$input); + if (SvTYPE(tempsv) != SVt_PV) + croak("Argument \$argnum is not an string."); + \$1 = (unsigned char *)SvPV(tempsv, PL_na); +} + +/* for ssl_read() */ +%typemap(in) unsigned char **in_data (unsigned char *buf) { + \$1 = &buf; +} + +%typemap(argout) unsigned char **in_data { + if (result > SSL_OK) { + SV *svs = newSVpv(*\$1, result); + \$result = newRV(svs); + sv_2mortal(\$result); + argvi++; + } +} + +/* for ssl_client_new() */ +%typemap(in) const unsigned char session_id[] { + /* check for a reference */ + if (SvOK(\$input) && SvROK(\$input)) { + SV* tempsv = SvRV(\$input); + if (SvTYPE(tempsv) != SVt_PV) + croak("Argument \$argnum is not an string."); + \$1 = (unsigned char *)SvPV(tempsv, PL_na); + } + else + \$1 = NULL; +} + +#endif + +/* Some SWIG magic to make the API a bit more Lua friendly */ +#ifdef SWIGLUA +SWIG_NUMBER_TYPEMAP(unsigned char); +SWIG_TYPEMAP_NUM_ARR(uchar,unsigned char); + +/* for ssl_session_id() */ +%typemap(out) const unsigned char * { + int i; + lua_newtable(L); + for (i = 0; i < ssl_get_session_id_size((SSL const *)arg1); i++){ + lua_pushnumber(L,(lua_Number)result[i]); + lua_rawseti(L,-2,i+1); /* -1 is the number, -2 is the table */ + } + SWIG_arg++; +} + +/* for ssl_read() */ +%typemap(in) unsigned char **in_data (unsigned char *buf) { + \$1 = &buf; +} + +%typemap(argout) unsigned char **in_data { + if (result > SSL_OK) { + int i; + lua_newtable(L); + for (i = 0; i < result; i++){ + lua_pushnumber(L,(lua_Number)buf2[i]); + lua_rawseti(L,-2,i+1); /* -1 is the number, -2 is the table */ + } + SWIG_arg++; + } +} + +/* for ssl_client_new() */ +%typemap(in) const unsigned char session_id[] { + if (lua_isnil(L,\$input)) + \$1 = NULL; + else + \$1 = SWIG_get_uchar_num_array_fixed(L,\$input, ssl_get_session_id((SSL const *)\$1)); +} + +#endif + +END + +# Initialise loop variables +$skip = 1; +$splitLine = 0; + +parseFile(@raw_data); + +close(DATA_IN); +close(DATA_OUT); + +#=============================================================== + diff --git a/bindings/java/SSL.java b/bindings/java/SSL.java new file mode 100644 index 000000000..e0400b601 --- /dev/null +++ b/bindings/java/SSL.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2007-2016, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * A wrapper around the unmanaged interface to give a semi-decent Java API + */ + +package axTLSj; + +import java.io.*; +import java.util.*; + +/** + * @defgroup java_api Java API. + * + * Ensure that the appropriate dispose() methods are called when finished with + * various objects - otherwise memory leaks will result. + */ + +/** + * @class SSL + * @ingroup java_api + * @brief A representation of an SSL connection. + * + */ +public class SSL +{ + public int m_ssl; /**< A pointer to the real SSL type */ + + /** + * @brief Store the reference to an SSL context. + * @param ip [in] A reference to an SSL object. + */ + public SSL(int ip) + { + m_ssl = ip; + } + + /** + * @brief Free any used resources on this connection. + * + * A "Close Notify" message is sent on this connection (if possible). It + * is up to the application to close the socket. + */ + public void dispose() + { + axtlsj.ssl_free(m_ssl); + } + + /** + * @brief Return the result of a handshake. + * @return SSL_OK if the handshake is complete and ok. + * @see ssl.h for the error code list. + */ + public int handshakeStatus() + { + return axtlsj.ssl_handshake_status(m_ssl); + } + + /** + * @brief Return the SSL cipher id. + * @return The cipher id which is one of: + * - SSL_AES128_SHA (0x2f) + * - SSL_AES256_SHA (0x35) + * - SSL_AES128_SHA256 (0x3c) + * - SSL_AES256_SHA256 (0x3d) + */ + public byte getCipherId() + { + return axtlsj.ssl_get_cipher_id(m_ssl); + } + + /** + * @brief Get the session id for a handshake. + * + * This will be a 32 byte sequence and is available after the first + * handshaking messages are sent. + * @return The session id as a 32 byte sequence. + * @note A SSLv23 handshake may have only 16 valid bytes. + */ + public byte[] getSessionId() + { + return axtlsj.ssl_get_session_id(m_ssl); + } + + /** + * @brief Retrieve an X.509 distinguished name component. + * + * When a handshake is complete and a certificate has been exchanged, + * then the details of the remote certificate can be retrieved. + * + * This will usually be used by a client to check that the server's common + * name matches the URL. + * + * A full handshake needs to occur for this call to work. + * + * @param component [in] one of: + * - SSL_X509_CERT_COMMON_NAME + * - SSL_X509_CERT_ORGANIZATION + * - SSL_X509_CERT_ORGANIZATIONAL_NAME + * - SSL_X509_CA_CERT_COMMON_NAME + * - SSL_X509_CA_CERT_ORGANIZATION + * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME + * @return The appropriate string (or null if not defined) + */ + public String getCertificateDN(int component) + { + return axtlsj.ssl_get_cert_dn(m_ssl, component); + } +} diff --git a/config/makefile.conf b/config/makefile.conf new file mode 100644 index 000000000..702abfd23 --- /dev/null +++ b/config/makefile.conf @@ -0,0 +1,134 @@ +# +# Copyright (c) 2007-2016, Cameron Rich +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the axTLS project nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# +# A standard makefile for all makefiles +# + +# All executables and libraries go here +STAGE=./_stage + +ifneq ($(MAKECMDGOALS), clean) + +# Give an initial rule +all: + +# Win32 +ifdef CONFIG_PLATFORM_WIN32 + +ifdef CONFIG_VISUAL_STUDIO_7_0 +CONFIG_VISUAL_STUDIO_7_0_BASE_UNIX:=$(shell cygpath -u $(CONFIG_VISUAL_STUDIO_7_0_BASE)) +export INCLUDE=$(shell echo "$(CONFIG_VISUAL_STUDIO_7_0_BASE)\vc7\include;$(CONFIG_VISUAL_STUDIO_7_0_BASE)\vc7\platformsdk\include") +export LIB=$(shell echo "$(CONFIG_VISUAL_STUDIO_7_0_BASE)\vc7\\platformsdk\lib;$(CONFIG_VISUAL_STUDIO_7_0_BASE)\vc7\lib") +PATH:=$(CONFIG_VISUAL_STUDIO_7_0_BASE_UNIX)/vc7/bin:$(CONFIG_VISUAL_STUDIO_7_0_BASE_UNIX)/common7/ide:$(PATH) +endif +ifdef CONFIG_VISUAL_STUDIO_8_0 +CONFIG_VISUAL_STUDIO_8_0_BASE_UNIX:=$(shell cygpath -u $(CONFIG_VISUAL_STUDIO_8_0_BASE)) +export INCLUDE=$(shell echo "$(CONFIG_VISUAL_STUDIO_8_0_BASE)\vc\include;$(CONFIG_VISUAL_STUDIO_8_0_BASE)\vc\platformsdk\include") +export LIB=$(shell echo "$(CONFIG_VISUAL_STUDIO_8_0_BASE)\vc\platformsdk\lib;$(CONFIG_VISUAL_STUDIO_8_0_BASE)\vc\lib") +PATH:=$(CONFIG_VISUAL_STUDIO_8_0_BASE_UNIX)/vc/bin:$(CONFIG_VISUAL_STUDIO_8_0_BASE_UNIX)/common7/ide:$(PATH) +endif +ifdef CONFIG_VISUAL_STUDIO_10_0 +CONFIG_VISUAL_STUDIO_10_0_BASE_UNIX:=$(shell cygpath -u $(CONFIG_VISUAL_STUDIO_10_0_BASE)) +export INCLUDE=$(shell echo "$(CONFIG_VISUAL_STUDIO_10_0_BASE)\vc\include;$(CONFIG_VISUAL_STUDIO_10_0_BASE)\..\Microsoft SDKs\Windows\v7.0A\include") +export LIB=$(shell echo "$(CONFIG_VISUAL_STUDIO_10_0_BASE)\vc\lib;$(CONFIG_VISUAL_STUDIO_10_0_BASE)\..\Microsoft SDKs\Windows\v7.0A\lib") +PATH:=$(CONFIG_VISUAL_STUDIO_10_0_BASE_UNIX)/vc/bin:$(CONFIG_VISUAL_STUDIO_10_0_BASE_UNIX)/common7/ide:$(PATH) +stuff: + @echo $(INCLUDE) +endif + +CC=cl.exe +LD=link.exe +AXTLS_INCLUDE=$(shell cygpath -w $(AXTLS_HOME)) +CFLAGS+=/nologo /W3 /D"WIN32" /D"_MBCS" /D"_CONSOLE" /D"_CRT_SECURE_NO_DEPRECATE" /FD /I"$(AXTLS_INCLUDE)crypto" /I"$(AXTLS_INCLUDE)ssl" /I"$(AXTLS_INCLUDE)config" /c +LDFLAGS=/nologo /subsystem:console /machine:I386 +LDSHARED = /dll +AR=lib /nologo + +ifdef CONFIG_DEBUG + CFLAGS += /Gm /Zi /Od /D "_DEBUG" + LDFLAGS += /debug /incremental:yes +else + CFLAGS += /O2 /D "NDEBUG" + LDFLAGS += /incremental:no +endif + +else # Not Win32 + +-include .depend + +CFLAGS += -I$(AXTLS_HOME)/config -I$(AXTLS_HOME)/ssl -I$(AXTLS_HOME)/crypto +LD=$(CC) +STRIP=$(CROSS)strip + +# Solaris +ifdef CONFIG_PLATFORM_SOLARIS +CFLAGS += -DCONFIG_PLATFORM_SOLARIS +LDFLAGS += -lsocket -lnsl -lc +LDSHARED = -G +# Linux/Cygwin +else +CFLAGS += -Wall -Wstrict-prototypes -Wshadow +LDSHARED = -shared + +# Linux +ifndef CONFIG_PLATFORM_CYGWIN +ifndef CONFIG_PLATFORM_NOMMU +CFLAGS += -fPIC + +# Cygwin +else +CFLAGS += -DCONFIG_PLATFORM_CYGWIN +LDFLAGS += -enable-auto-import +endif +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/samples/c/axssl.c b/samples/c/axssl.c new file mode 100644 index 000000000..aaf803440 --- /dev/null +++ b/samples/c/axssl.c @@ -0,0 +1,912 @@ +/* + * Copyright (c) 2007-2016, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Demonstrate the use of the axTLS library in C with a set of + * command-line parameters similar to openssl. In fact, openssl clients + * should be able to communicate with axTLS servers and visa-versa. + * + * This code has various bits enabled depending on the configuration. To enable + * the most interesting version, compile with the 'full mode' enabled. + * + * To see what options you have, run the following: + * > axssl s_server -? + * > axssl s_client -? + * + * The axtls shared library must be in the same directory or be found + * by the OS. + */ +#include +#include +#include +#include "os_port.h" +#include "ssl.h" + +/* define standard input */ +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif + +static void do_server(int argc, char *argv[]); +static void print_options(char *option); +static void print_server_options(char *option); +static void do_client(int argc, char *argv[]); +static void print_client_options(char *option); +static void display_cipher(SSL *ssl); +static void display_session_id(SSL *ssl); + +/** + * Main entry point. Doesn't do much except works out whether we are a client + * or a server. + */ +int main(int argc, char *argv[]) +{ +#ifdef WIN32 + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(2, 2); + WSAStartup(wVersionRequested, &wsaData); +#elif !defined(CONFIG_PLATFORM_SOLARIS) + signal(SIGPIPE, SIG_IGN); /* ignore pipe errors */ +#endif + + if (argc == 2 && strcmp(argv[1], "version") == 0) + { + printf("axssl %s %s\n", ssl_version(), __DATE__); + exit(0); + } + + if (argc < 2 || ( + strcmp(argv[1], "s_server") && strcmp(argv[1], "s_client"))) + print_options(argc > 1 ? argv[1] : ""); + + strcmp(argv[1], "s_server") ? + do_client(argc, argv) : do_server(argc, argv); + return 0; +} + +/** + * Implement the SSL server logic. + */ +static void do_server(int argc, char *argv[]) +{ + int i = 2; + uint16_t port = 4433; + uint32_t options = SSL_DISPLAY_CERTS; + int client_fd; + SSL_CTX *ssl_ctx; + int server_fd, res = 0; + socklen_t client_len; +#ifndef CONFIG_SSL_SKELETON_MODE + char *private_key_file = NULL; + const char *password = NULL; + char **cert; + int cert_index = 0; + int cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET); +#endif +#ifdef WIN32 + char yes = 1; +#else + int yes = 1; +#endif + struct sockaddr_in serv_addr; + struct sockaddr_in client_addr; + int quiet = 0; +#ifdef CONFIG_SSL_CERT_VERIFICATION + int ca_cert_index = 0; + int ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET); + char **ca_cert = (char **)calloc(1, sizeof(char *)*ca_cert_size); +#endif + fd_set read_set; + +#ifndef CONFIG_SSL_SKELETON_MODE + cert = (char **)calloc(1, sizeof(char *)*cert_size); +#endif + + while (i < argc) + { + if (strcmp(argv[i], "-accept") == 0) + { + if (i >= argc-1) + { + print_server_options(argv[i]); + } + + port = atoi(argv[++i]); + } +#ifndef CONFIG_SSL_SKELETON_MODE + else if (strcmp(argv[i], "-cert") == 0) + { + if (i >= argc-1 || cert_index >= cert_size) + { + print_server_options(argv[i]); + } + + cert[cert_index++] = argv[++i]; + } + else if (strcmp(argv[i], "-key") == 0) + { + if (i >= argc-1) + { + print_server_options(argv[i]); + } + + private_key_file = argv[++i]; + options |= SSL_NO_DEFAULT_KEY; + } + else if (strcmp(argv[i], "-pass") == 0) + { + if (i >= argc-1) + { + print_server_options(argv[i]); + } + + password = argv[++i]; + } +#endif + else if (strcmp(argv[i], "-quiet") == 0) + { + quiet = 1; + options &= ~SSL_DISPLAY_CERTS; + } +#ifdef CONFIG_SSL_CERT_VERIFICATION + else if (strcmp(argv[i], "-verify") == 0) + { + options |= SSL_CLIENT_AUTHENTICATION; + } + else if (strcmp(argv[i], "-CAfile") == 0) + { + if (i >= argc-1 || ca_cert_index >= ca_cert_size) + { + print_server_options(argv[i]); + } + + ca_cert[ca_cert_index++] = argv[++i]; + } +#endif +#ifdef CONFIG_SSL_FULL_MODE + else if (strcmp(argv[i], "-debug") == 0) + { + options |= SSL_DISPLAY_BYTES; + } + else if (strcmp(argv[i], "-state") == 0) + { + options |= SSL_DISPLAY_STATES; + } + else if (strcmp(argv[i], "-show-rsa") == 0) + { + options |= SSL_DISPLAY_RSA; + } +#endif + else /* don't know what this is */ + { + print_server_options(argv[i]); + } + + i++; + } + + if ((ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_SVR_SESS)) == NULL) + { + fprintf(stderr, "Error: Server context is invalid\n"); + exit(1); + } + +#ifndef CONFIG_SSL_SKELETON_MODE + if (private_key_file) + { + int obj_type = SSL_OBJ_RSA_KEY; + + /* auto-detect the key type from the file extension */ + if (strstr(private_key_file, ".p8")) + obj_type = SSL_OBJ_PKCS8; + else if (strstr(private_key_file, ".p12")) + obj_type = SSL_OBJ_PKCS12; + + if (ssl_obj_load(ssl_ctx, obj_type, private_key_file, password)) + { + fprintf(stderr, "Error: Private key '%s' is undefined.\n", + private_key_file); + exit(1); + } + } + + for (i = 0; i < cert_index; i++) + { + if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, cert[i], NULL)) + { + printf("Certificate '%s' is undefined.\n", cert[i]); + exit(1); + } + } +#endif + +#ifdef CONFIG_SSL_CERT_VERIFICATION + for (i = 0; i < ca_cert_index; i++) + { + if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, ca_cert[i], NULL)) + { + printf("Certificate '%s' is undefined.\n", ca_cert[i]); + exit(1); + } + } + + free(ca_cert); +#endif +#ifndef CONFIG_SSL_SKELETON_MODE + free(cert); +#endif + + /* Create socket for incoming connections */ + if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + perror("socket"); + return; + } + + setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + + /* Construct local address structure */ + memset(&serv_addr, 0, sizeof(serv_addr)); /* Zero out structure */ + serv_addr.sin_family = AF_INET; /* Internet address family */ + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ + serv_addr.sin_port = htons(port); /* Local port */ + + /* Bind to the local address */ + if (bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) + { + perror("bind"); + exit(1); + } + + if (listen(server_fd, 5) < 0) + { + perror("listen"); + exit(1); + } + + client_len = sizeof(client_addr); + + /************************************************************************* + * This is where the interesting stuff happens. Up until now we've + * just been setting up sockets etc. Now we do the SSL handshake. + *************************************************************************/ + for (;;) + { + SSL *ssl; + int reconnected = 0; + + if (!quiet) + { + printf("ACCEPT\n"); + TTY_FLUSH(); + } + + if ((client_fd = accept(server_fd, + (struct sockaddr *)&client_addr, &client_len)) < 0) + { + break; + } + + ssl = ssl_server_new(ssl_ctx, client_fd); + + /* now read (and display) whatever the client sends us */ + for (;;) + { + /* allow parallel reading of client and standard input */ + FD_ZERO(&read_set); + FD_SET(client_fd, &read_set); + +#ifndef WIN32 + /* win32 doesn't like mixing up stdin and sockets */ + if (isatty(STDIN_FILENO))/* but only if we are in an active shell */ + { + FD_SET(STDIN_FILENO, &read_set); + } + + if ((res = select(client_fd+1, &read_set, NULL, NULL, NULL)) > 0) + { + uint8_t buf[1024]; + + /* read standard input? */ + if (FD_ISSET(STDIN_FILENO, &read_set)) + { + if (fgets((char *)buf, sizeof(buf), stdin) == NULL) + { + res = SSL_ERROR_CONN_LOST; + } + else + { + /* small hack to check renegotiation */ + if (buf[0] == 'r' && (buf[1] == '\n' || buf[1] == '\r')) + { + res = ssl_renegotiate(ssl); + } + else /* write our ramblings to the client */ + { + res = ssl_write(ssl, buf, strlen((char *)buf)+1); + } + } + } + else /* a socket read */ +#endif + { + /* keep reading until we get something interesting */ + uint8_t *read_buf; + + if ((res = ssl_read(ssl, &read_buf)) == SSL_OK) + { + /* are we in the middle of doing a handshake? */ + if (ssl_handshake_status(ssl) != SSL_OK) + { + reconnected = 0; + } + else if (!reconnected) + { + /* we are connected/reconnected */ + if (!quiet) + { + display_session_id(ssl); + display_cipher(ssl); + } + + reconnected = 1; + } + } + + if (res > SSL_OK) /* display our interesting output */ + { + int written = 0; + while (written < res) + { + written += write(STDOUT_FILENO, read_buf+written, + res-written); + } + TTY_FLUSH(); + } + else if (res == SSL_CLOSE_NOTIFY) + { + printf("shutting down SSL\n"); + TTY_FLUSH(); + } + else if (res < SSL_OK && !quiet) + { + ssl_display_error(res); + } + } +#ifndef WIN32 + } +#endif + + if (res < SSL_OK) + { + if (!quiet) + { + printf("CONNECTION CLOSED\n"); + TTY_FLUSH(); + } + + break; + } + } + + /* client was disconnected or the handshake failed. */ + ssl_free(ssl); + SOCKET_CLOSE(client_fd); + } + + ssl_ctx_free(ssl_ctx); +} + +/** + * Implement the SSL client logic. + */ +static void do_client(int argc, char *argv[]) +{ +#ifdef CONFIG_SSL_ENABLE_CLIENT + int res, i = 2; + uint16_t port = 4433; + uint32_t options = SSL_SERVER_VERIFY_LATER|SSL_DISPLAY_CERTS; + int client_fd; + char *private_key_file = NULL; + struct sockaddr_in client_addr; + struct hostent *hostent; + int reconnect = 0; + uint32_t sin_addr; + SSL_CTX *ssl_ctx; + SSL *ssl = NULL; + int quiet = 0; + int cert_index = 0, ca_cert_index = 0; + int cert_size, ca_cert_size; + char **ca_cert, **cert; + uint8_t session_id[SSL_SESSION_ID_SIZE]; + fd_set read_set; + const char *password = NULL; + SSL_EXTENSIONS *extensions = 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]; + } + else if (strcmp(argv[i], "-servername") == 0) + { + if (i >= argc-1) + { + print_client_options(argv[i]); + } + + extensions = ssl_ext_new(); + extensions->host_name = argv[++i]; + } +#ifdef CONFIG_SSL_FULL_MODE + else if (strcmp(argv[i], "-debug") == 0) + { + options |= SSL_DISPLAY_BYTES; + } + else if (strcmp(argv[i], "-state") == 0) + { + options |= SSL_DISPLAY_STATES; + } + else if (strcmp(argv[i], "-show-rsa") == 0) + { + options |= SSL_DISPLAY_RSA; + } +#endif + else /* don't know what this is */ + { + print_client_options(argv[i]); + } + + i++; + } + + if ((ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) + { + fprintf(stderr, "Error: Client context is invalid\n"); + exit(1); + } + + if (private_key_file) + { + int obj_type = SSL_OBJ_RSA_KEY; + + /* auto-detect the key type from the file extension */ + if (strstr(private_key_file, ".p8")) + obj_type = SSL_OBJ_PKCS8; + else if (strstr(private_key_file, ".p12")) + obj_type = SSL_OBJ_PKCS12; + + if (ssl_obj_load(ssl_ctx, obj_type, private_key_file, password)) + { + fprintf(stderr, "Error: Private key '%s' is undefined.\n", + private_key_file); + exit(1); + } + } + + for (i = 0; i < cert_index; i++) + { + if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, cert[i], NULL)) + { + printf("Certificate '%s' is undefined.\n", cert[i]); + exit(1); + } + } + + for (i = 0; i < ca_cert_index; i++) + { + if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, ca_cert[i], NULL)) + { + printf("Certificate '%s' is undefined.\n", ca_cert[i]); + exit(1); + } + } + + free(cert); + free(ca_cert); + + /************************************************************************* + * This is where the interesting stuff happens. Up until now we've + * just been setting up sockets etc. Now we do the SSL handshake. + *************************************************************************/ + client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + memset(&client_addr, 0, sizeof(client_addr)); + client_addr.sin_family = AF_INET; + client_addr.sin_port = htons(port); + client_addr.sin_addr.s_addr = sin_addr; + + if (connect(client_fd, (struct sockaddr *)&client_addr, + sizeof(client_addr)) < 0) + { + perror("connect"); + exit(1); + } + + if (!quiet) + { + printf("CONNECTED\n"); + TTY_FLUSH(); + } + + /* Try session resumption? */ + if (reconnect) + { + while (reconnect--) + { + ssl = ssl_client_new(ssl_ctx, client_fd, session_id, + sizeof(session_id), extensions); + if ((res = ssl_handshake_status(ssl)) != SSL_OK) + { + if (!quiet) + { + ssl_display_error(res); + } + + ssl_free(ssl); + ssl_ext_free(extensions); + exit(1); + } + + display_session_id(ssl); + memcpy(session_id, ssl_get_session_id(ssl), SSL_SESSION_ID_SIZE); + + if (reconnect) + { + ssl_free(ssl); + ssl_ext_free(extensions); + SOCKET_CLOSE(client_fd); + + client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + connect(client_fd, (struct sockaddr *)&client_addr, + sizeof(client_addr)); + } + } + } + else + { + ssl = ssl_client_new(ssl_ctx, client_fd, NULL, 0, extensions); + } + + /* check the return status */ + if ((res = ssl_handshake_status(ssl)) != SSL_OK) + { + if (!quiet) + { + ssl_display_error(res); + } + + exit(1); + } + + if (!quiet) + { + const char *common_name = ssl_get_cert_dn(ssl, + SSL_X509_CERT_COMMON_NAME); + if (common_name) + { + printf("Common Name:\t\t\t%s\n", common_name); + } + + display_session_id(ssl); + display_cipher(ssl); + } + + for (;;) + { + uint8_t buf[1024]; + + /* 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)); + } + } + } +#ifndef WIN32 + else /* a socket read */ + { + uint8_t *read_buf; + + res = ssl_read(ssl, &read_buf); + + if (res > 0) /* display our interesting output */ + { + int written = 0; + while (written < res) + { + written += write(STDOUT_FILENO, read_buf+written, + res-written); + } + TTY_FLUSH(); + } + } + } +#endif + + if (res < 0) + { + if (!quiet) + { + ssl_display_error(res); + } + + break; /* get outta here */ + } + } + + ssl_ctx_free(ssl_ctx); + ssl_ext_free(extensions); + SOCKET_CLOSE(client_fd); +#else + print_client_options(argv[1]); +#endif +} + +/** + * We've had some sort of command-line error. Print out the basic options. + */ +static void print_options(char *option) +{ + printf("axssl: Error: '%s' is an invalid command.\n", option); + printf("usage: axssl [s_server|s_client|version] [args ...]\n"); + exit(1); +} + +/** + * We've had some sort of command-line error. Print out the server options. + */ +static void print_server_options(char *option) +{ +#ifndef CONFIG_SSL_SKELETON_MODE + int cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET); +#endif +#ifdef CONFIG_SSL_CERT_VERIFICATION + int ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET); +#endif + + printf("unknown option %s\n", option); + printf("usage: s_server [args ...]\n"); + printf(" -accept arg\t- port to accept on (default is 4433)\n"); +#ifndef CONFIG_SSL_SKELETON_MODE + printf(" -cert arg\t- certificate file to add (in addition to default)" + " to chain -\n" + "\t\t Can repeat up to %d times\n", cert_size); + printf(" -key arg\t- Private key file to use\n"); + printf(" -pass\t\t- private key file pass phrase source\n"); +#endif + printf(" -quiet\t\t- No server output\n"); +#ifdef CONFIG_SSL_CERT_VERIFICATION + printf(" -verify\t- turn on peer certificate verification\n"); + printf(" -CAfile arg\t- Certificate authority\n"); + printf("\t\t Can repeat up to %d times\n", ca_cert_size); +#endif +#ifdef CONFIG_SSL_FULL_MODE + printf(" -debug\t\t- Print more output\n"); + printf(" -state\t\t- Show state messages\n"); + printf(" -show-rsa\t- Show RSA state\n"); +#endif + exit(1); +} + +/** + * We've had some sort of command-line error. Print out the client options. + */ +static void print_client_options(char *option) +{ +#ifdef CONFIG_SSL_ENABLE_CLIENT + int cert_size = ssl_get_config(SSL_MAX_CERT_CFG_OFFSET); + int ca_cert_size = ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET); +#endif + + printf("unknown option %s\n", option); +#ifdef CONFIG_SSL_ENABLE_CLIENT + printf("usage: s_client [args ...]\n"); + printf(" -connect host:port - who to connect to (default " + "is localhost:4433)\n"); + printf(" -verify\t- turn on peer certificate verification\n"); + printf(" -cert arg\t- certificate file to use\n"); + printf("\t\t Can repeat up to %d times\n", cert_size); + printf(" -key arg\t- Private key file to use\n"); + printf(" -CAfile arg\t- Certificate authority\n"); + printf("\t\t Can repeat up to %d times\n", ca_cert_size); + printf(" -quiet\t\t- No client output\n"); + printf(" -reconnect\t- Drop and re-make the connection " + "with the same Session-ID\n"); + printf(" -pass\t\t- Private key file pass phrase source\n"); + printf(" -servername\t- Set TLS extension servername in ClientHello\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_AES128_SHA256: + printf("AES128-SHA256"); + break; + + case SSL_AES256_SHA256: + printf("AES256-SHA256"); + break; + + default: + printf("Unknown - %d", ssl_get_cipher_id(ssl)); + break; + } + + printf("\n"); + TTY_FLUSH(); +} + +/** + * Display what session id we have. + */ +static void display_session_id(SSL *ssl) +{ + int i; + const uint8_t *session_id = ssl_get_session_id(ssl); + int sess_id_size = ssl_get_session_id_size(ssl); + + if (sess_id_size > 0) + { + printf("-----BEGIN SSL SESSION PARAMETERS-----\n"); + for (i = 0; i < sess_id_size; i++) + { + printf("%02x", session_id[i]); + } + + printf("\n-----END SSL SESSION PARAMETERS-----\n"); + TTY_FLUSH(); + } +} diff --git a/samples/csharp/axssl.cs b/samples/csharp/axssl.cs new file mode 100644 index 000000000..df3c57662 --- /dev/null +++ b/samples/csharp/axssl.cs @@ -0,0 +1,758 @@ +/* + * Copyright (c) 2007-2016, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Demonstrate the use of the axTLS library in C# with a set of + * command-line parameters similar to openssl. In fact, openssl clients + * should be able to communicate with axTLS servers and visa-versa. + * + * This code has various bits enabled depending on the configuration. To enable + * the most interesting version, compile with the 'full mode' enabled. + * + * To see what options you have, run the following: + * > axssl.csharp.exe s_server -? + * > axssl.csharp.exe s_client -? + * + * The axtls shared library must be in the same directory or be found + * by the OS. + */ + +using System; +using System.Net; +using System.Net.Sockets; +using axTLS; + +public class axssl +{ + /* + * Main() + */ + public static void Main(string[] args) + { + if (args.Length == 1 && args[0] == "version") + { + Console.WriteLine("axssl.csharp " + SSLUtil.Version()); + Environment.Exit(0); + } + + axssl runner = new axssl(); + + if (args.Length < 1 || (args[0] != "s_server" && args[0] != "s_client")) + runner.print_options(args.Length > 0 ? args[0] : ""); + + int build_mode = SSLUtil.BuildMode(); + + if (args[0] == "s_server") + runner.do_server(build_mode, args); + else + runner.do_client(build_mode, args); + } + + /* + * do_server() + */ + private void do_server(int build_mode, string[] args) + { + int i = 1; + int port = 4433; + uint options = axtls.SSL_DISPLAY_CERTS; + bool quiet = false; + string password = null; + string private_key_file = null; + + /* organise the cert/ca_cert lists */ + int cert_size = SSLUtil.MaxCerts(); + int ca_cert_size = SSLUtil.MaxCACerts(); + string[] cert = new string[cert_size]; + string[] ca_cert = new string[ca_cert_size]; + int cert_index = 0; + int ca_cert_index = 0; + + while (i < args.Length) + { + if (args[i] == "-accept") + { + if (i >= args.Length-1) + { + print_server_options(build_mode, args[i]); + } + + port = Int32.Parse(args[++i]); + } + else if (args[i] == "-quiet") + { + quiet = true; + options &= ~(uint)axtls.SSL_DISPLAY_CERTS; + } + else if (build_mode >= axtls.SSL_BUILD_SERVER_ONLY) + { + if (args[i] == "-cert") + { + if (i >= args.Length-1 || cert_index >= cert_size) + { + print_server_options(build_mode, args[i]); + } + + cert[cert_index++] = args[++i]; + } + else if (args[i] == "-key") + { + if (i >= args.Length-1) + { + print_server_options(build_mode, args[i]); + } + + private_key_file = args[++i]; + options |= axtls.SSL_NO_DEFAULT_KEY; + } + else if (args[i] == "-pass") + { + if (i >= args.Length-1) + { + print_server_options(build_mode, args[i]); + } + + password = args[++i]; + } + else if (build_mode >= axtls.SSL_BUILD_ENABLE_VERIFICATION) + { + if (args[i] == "-verify") + { + options |= axtls.SSL_CLIENT_AUTHENTICATION; + } + else if (args[i] == "-CAfile") + { + if (i >= args.Length-1 || ca_cert_index >= ca_cert_size) + { + print_server_options(build_mode, args[i]); + } + + ca_cert[ca_cert_index++] = args[++i]; + } + else if (build_mode == axtls.SSL_BUILD_FULL_MODE) + { + if (args[i] == "-debug") + { + options |= axtls.SSL_DISPLAY_BYTES; + } + else if (args[i] == "-state") + { + options |= axtls.SSL_DISPLAY_STATES; + } + else if (args[i] == "-show-rsa") + { + options |= axtls.SSL_DISPLAY_RSA; + } + else + print_server_options(build_mode, args[i]); + } + else + print_server_options(build_mode, args[i]); + } + else + print_server_options(build_mode, args[i]); + } + else + print_server_options(build_mode, args[i]); + + i++; + } + + /* Create socket for incoming connections */ + IPEndPoint ep = new IPEndPoint(IPAddress.Any, port); + TcpListener server_sock = new TcpListener(ep); + server_sock.Start(); + + /********************************************************************** + * This is where the interesting stuff happens. Up until now we've + * just been setting up sockets etc. Now we do the SSL handshake. + **********************************************************************/ + SSLServer ssl_ctx = new SSLServer( + options, axtls.SSL_DEFAULT_SVR_SESS); + + if (ssl_ctx == null) + { + Console.Error.WriteLine("Error: Server context is invalid"); + Environment.Exit(1); + } + + if (private_key_file != null) + { + int obj_type = axtls.SSL_OBJ_RSA_KEY; + + if (private_key_file.EndsWith(".p8")) + obj_type = axtls.SSL_OBJ_PKCS8; + else if (private_key_file.EndsWith(".p12")) + obj_type = axtls.SSL_OBJ_PKCS12; + + if (ssl_ctx.ObjLoad(obj_type, + private_key_file, password) != axtls.SSL_OK) + { + Console.Error.WriteLine("Private key '" + private_key_file + + "' is undefined."); + Environment.Exit(1); + } + } + + for (i = 0; i < cert_index; i++) + { + if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CERT, + cert[i], null) != axtls.SSL_OK) + { + Console.WriteLine("Certificate '" + cert[i] + + "' is undefined."); + Environment.Exit(1); + } + } + + for (i = 0; i < ca_cert_index; i++) + { + if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CACERT, + ca_cert[i], null) != axtls.SSL_OK) + { + Console.WriteLine("Certificate '" + cert[i] + + "' is undefined."); + Environment.Exit(1); + } + } + + byte[] buf = null; + int res; + + for (;;) + { + if (!quiet) + { + Console.WriteLine("ACCEPT"); + } + + Socket client_sock = server_sock.AcceptSocket(); + + SSL ssl = ssl_ctx.Connect(client_sock); + + /* do the actual SSL handshake */ + while ((res = ssl_ctx.Read(ssl, out buf)) == axtls.SSL_OK) + { + /* check when the connection has been established */ + if (ssl.HandshakeStatus() == axtls.SSL_OK) + break; + + /* could do something else here */ + } + + if (res == axtls.SSL_OK) /* connection established and ok */ + { + if (!quiet) + { + display_session_id(ssl); + display_cipher(ssl); + } + + /* now read (and display) whatever the client sends us */ + for (;;) + { + /* keep reading until we get something interesting */ + while ((res = ssl_ctx.Read(ssl, out buf)) == axtls.SSL_OK) + { + /* could do something else here */ + } + + if (res < axtls.SSL_OK) + { + if (!quiet) + { + Console.WriteLine("CONNECTION CLOSED"); + } + + break; + } + + /* convert to string */ + char[] str = new char[res]; + for (i = 0; i < res; i++) + { + str[i] = (char)buf[i]; + } + + Console.Write(str); + } + } + else if (!quiet) + { + SSLUtil.DisplayError(res); + } + + /* client was disconnected or the handshake failed. */ + ssl.Dispose(); + client_sock.Close(); + } + + /* ssl_ctx.Dispose(); */ + } + + /* + * do_client() + */ + private void do_client(int build_mode, string[] args) + { + if (build_mode < axtls.SSL_BUILD_ENABLE_CLIENT) + { + print_client_options(build_mode, args[1]); + } + + int i = 1, res; + int port = 4433; + bool quiet = false; + string password = null; + int reconnect = 0; + string private_key_file = null; + string hostname = "127.0.0.1"; + + /* organise the cert/ca_cert lists */ + int cert_index = 0; + int ca_cert_index = 0; + int cert_size = SSLUtil.MaxCerts(); + int ca_cert_size = SSLUtil.MaxCACerts(); + string[] cert = new string[cert_size]; + string[] ca_cert = new string[ca_cert_size]; + + uint options = axtls.SSL_SERVER_VERIFY_LATER|axtls.SSL_DISPLAY_CERTS; + byte[] session_id = null; + + while (i < args.Length) + { + if (args[i] == "-connect") + { + string host_port; + + if (i >= args.Length-1) + { + print_client_options(build_mode, args[i]); + } + + host_port = args[++i]; + int index_colon; + + if ((index_colon = host_port.IndexOf(':')) < 0) + print_client_options(build_mode, args[i]); + + hostname = new string(host_port.ToCharArray(), + 0, index_colon); + port = Int32.Parse(new String(host_port.ToCharArray(), + index_colon+1, host_port.Length-index_colon-1)); + } + else if (args[i] == "-cert") + { + if (i >= args.Length-1 || cert_index >= cert_size) + { + print_client_options(build_mode, args[i]); + } + + cert[cert_index++] = args[++i]; + } + else if (args[i] == "-key") + { + if (i >= args.Length-1) + { + print_client_options(build_mode, args[i]); + } + + private_key_file = args[++i]; + options |= axtls.SSL_NO_DEFAULT_KEY; + } + else if (args[i] == "-CAfile") + { + if (i >= args.Length-1 || ca_cert_index >= ca_cert_size) + { + print_client_options(build_mode, args[i]); + } + + ca_cert[ca_cert_index++] = args[++i]; + } + else if (args[i] == "-verify") + { + options &= ~(uint)axtls.SSL_SERVER_VERIFY_LATER; + } + else if (args[i] == "-reconnect") + { + reconnect = 4; + } + else if (args[i] == "-quiet") + { + quiet = true; + options &= ~(uint)axtls.SSL_DISPLAY_CERTS; + } + else if (args[i] == "-pass") + { + if (i >= args.Length-1) + { + print_client_options(build_mode, args[i]); + } + + password = args[++i]; + } + else if (build_mode == axtls.SSL_BUILD_FULL_MODE) + { + if (args[i] == "-debug") + { + options |= axtls.SSL_DISPLAY_BYTES; + } + else if (args[i] == "-state") + { + options |= axtls.SSL_DISPLAY_STATES; + } + else if (args[i] == "-show-rsa") + { + options |= axtls.SSL_DISPLAY_RSA; + } + else + print_client_options(build_mode, args[i]); + } + else /* don't know what this is */ + print_client_options(build_mode, args[i]); + + i++; + } + + // IPHostEntry hostInfo = Dns.Resolve(hostname); + IPHostEntry hostInfo = Dns.GetHostEntry(hostname); + IPAddress[] addresses = hostInfo.AddressList; + IPEndPoint ep = new IPEndPoint(addresses[0], port); + Socket client_sock = new Socket(AddressFamily.InterNetwork, + SocketType.Stream, ProtocolType.Tcp); + client_sock.Connect(ep); + + if (!client_sock.Connected) + { + Console.WriteLine("could not connect"); + Environment.Exit(1); + } + + if (!quiet) + { + Console.WriteLine("CONNECTED"); + } + + /********************************************************************** + * This is where the interesting stuff happens. Up until now we've + * just been setting up sockets etc. Now we do the SSL handshake. + **********************************************************************/ + SSLClient ssl_ctx = new SSLClient(options, + axtls.SSL_DEFAULT_CLNT_SESS); + + if (ssl_ctx == null) + { + Console.Error.WriteLine("Error: Client context is invalid"); + Environment.Exit(1); + } + + if (private_key_file != null) + { + int obj_type = axtls.SSL_OBJ_RSA_KEY; + + if (private_key_file.EndsWith(".p8")) + obj_type = axtls.SSL_OBJ_PKCS8; + else if (private_key_file.EndsWith(".p12")) + obj_type = axtls.SSL_OBJ_PKCS12; + + if (ssl_ctx.ObjLoad(obj_type, + private_key_file, password) != axtls.SSL_OK) + { + Console.Error.WriteLine("Private key '" + private_key_file + + "' is undefined."); + Environment.Exit(1); + } + } + + for (i = 0; i < cert_index; i++) + { + if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CERT, + cert[i], null) != axtls.SSL_OK) + { + Console.WriteLine("Certificate '" + cert[i] + + "' is undefined."); + Environment.Exit(1); + } + } + + for (i = 0; i < ca_cert_index; i++) + { + if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CACERT, + ca_cert[i], null) != axtls.SSL_OK) + { + Console.WriteLine("Certificate '" + cert[i] + + "' is undefined."); + Environment.Exit(1); + } + } + + SSL ssl = new SSL(new IntPtr(0)); /* keep compiler happy */ + + /* Try session resumption? */ + if (reconnect > 0) + { + while (reconnect-- > 0) + { + ssl = ssl_ctx.Connect(client_sock, session_id); + + if ((res = ssl.HandshakeStatus()) != axtls.SSL_OK) + { + if (!quiet) + { + SSLUtil.DisplayError(res); + } + + ssl.Dispose(); + Environment.Exit(1); + } + + display_session_id(ssl); + session_id = ssl.GetSessionId(); + + if (reconnect > 0) + { + ssl.Dispose(); + client_sock.Close(); + + /* and reconnect */ + client_sock = new Socket(AddressFamily.InterNetwork, + SocketType.Stream, ProtocolType.Tcp); + client_sock.Connect(ep); + } + } + } + else + { + ssl = ssl_ctx.Connect(client_sock, null); + } + + /* check the return status */ + if ((res = ssl.HandshakeStatus()) != axtls.SSL_OK) + { + if (!quiet) + { + SSLUtil.DisplayError(res); + } + + Environment.Exit(1); + } + + if (!quiet) + { + string common_name = + ssl.GetCertificateDN(axtls.SSL_X509_CERT_COMMON_NAME); + + if (common_name != null) + { + Console.WriteLine("Common Name:\t\t\t" + common_name); + } + + display_session_id(ssl); + display_cipher(ssl); + } + + for (;;) + { + string user_input = Console.ReadLine(); + + if (user_input == null) + break; + + byte[] buf = new byte[user_input.Length+2]; + buf[buf.Length-2] = (byte)'\n'; /* add the carriage return */ + buf[buf.Length-1] = 0; /* null terminate */ + + for (i = 0; i < buf.Length-2; i++) + { + buf[i] = (byte)user_input[i]; + } + + if ((res = ssl_ctx.Write(ssl, buf, buf.Length)) < axtls.SSL_OK) + { + if (!quiet) + { + SSLUtil.DisplayError(res); + } + + break; + } + } + + ssl_ctx.Dispose(); + } + + /** + * We've had some sort of command-line error. Print out the basic options. + */ + private void print_options(string option) + { + Console.WriteLine("axssl: Error: '" + option + + "' is an invalid command."); + Console.WriteLine("usage: axssl.csharp [s_server|" + + "s_client|version] [args ...]"); + Environment.Exit(1); + } + + /** + * We've had some sort of command-line error. Print out the server options. + */ + private void print_server_options(int build_mode, string option) + { + int cert_size = SSLUtil.MaxCerts(); + int ca_cert_size = SSLUtil.MaxCACerts(); + + Console.WriteLine("unknown option " + option); + Console.WriteLine("usage: s_server [args ...]"); + Console.WriteLine(" -accept arg\t- port to accept on (default " + + "is 4433)"); + Console.WriteLine(" -quiet\t\t- No server output"); + + if (build_mode >= axtls.SSL_BUILD_SERVER_ONLY) + { + Console.WriteLine(" -cert arg\t- certificate file to add (in " + + "addition to default) to chain -"); + Console.WriteLine("\t\t Can repeat up to " + cert_size + " times"); + Console.WriteLine(" -key arg\t- Private key file to use"); + Console.WriteLine(" -pass\t\t- private key file pass phrase source"); + } + + if (build_mode >= axtls.SSL_BUILD_ENABLE_VERIFICATION) + { + Console.WriteLine(" -verify\t- turn on peer certificate " + + "verification"); + Console.WriteLine(" -CAfile arg\t- Certificate authority."); + Console.WriteLine("\t\t Can repeat up to " + + ca_cert_size + "times"); + } + + if (build_mode == axtls.SSL_BUILD_FULL_MODE) + { + Console.WriteLine(" -debug\t\t- Print more output"); + Console.WriteLine(" -state\t\t- Show state messages"); + Console.WriteLine(" -show-rsa\t- Show RSA state"); + } + + Environment.Exit(1); + } + + /** + * We've had some sort of command-line error. Print out the client options. + */ + private void print_client_options(int build_mode, string option) + { + int cert_size = SSLUtil.MaxCerts(); + int ca_cert_size = SSLUtil.MaxCACerts(); + + Console.WriteLine("unknown option " + option); + + if (build_mode >= axtls.SSL_BUILD_ENABLE_CLIENT) + { + Console.WriteLine("usage: s_client [args ...]"); + Console.WriteLine(" -connect host:port - who to connect to " + + "(default is localhost:4433)"); + Console.WriteLine(" -verify\t- turn on peer certificate " + + "verification"); + Console.WriteLine(" -cert arg\t- certificate file to use"); + Console.WriteLine("\t\t Can repeat up to %d times", cert_size); + Console.WriteLine(" -key arg\t- Private key file to use"); + Console.WriteLine(" -CAfile arg\t- Certificate authority."); + Console.WriteLine("\t\t Can repeat up to " + ca_cert_size + + " times"); + Console.WriteLine(" -quiet\t\t- No client output"); + Console.WriteLine(" -pass\t\t- private key file pass " + + "phrase source"); + Console.WriteLine(" -reconnect\t- Drop and re-make the " + + "connection with the same Session-ID"); + + if (build_mode == axtls.SSL_BUILD_FULL_MODE) + { + Console.WriteLine(" -debug\t\t- Print more output"); + Console.WriteLine(" -state\t\t- Show state messages"); + Console.WriteLine(" -show-rsa\t- Show RSA state"); + } + } + else + { + Console.WriteLine("Change configuration to allow this feature"); + } + + Environment.Exit(1); + } + + /** + * Display what cipher we are using + */ + private void display_cipher(SSL ssl) + { + Console.Write("CIPHER is "); + + switch (ssl.GetCipherId()) + { + case axtls.SSL_AES128_SHA: + Console.WriteLine("AES128-SHA"); + break; + + case axtls.SSL_AES256_SHA: + Console.WriteLine("AES256-SHA"); + break; + + case axtls.SSL_AES128_SHA256: + Console.WriteLine("AES128-SHA256"); + break; + + case axtls.SSL_AES256_SHA256: + Console.WriteLine("AES128-SHA256"); + break; + + default: + Console.WriteLine("Unknown - " + ssl.GetCipherId()); + break; + } + } + + /** + * Display what session id we have. + */ + private void display_session_id(SSL ssl) + { + byte[] session_id = ssl.GetSessionId(); + + if (session_id.Length > 0) + { + Console.WriteLine("-----BEGIN SSL SESSION PARAMETERS-----"); + foreach (byte b in session_id) + { + Console.Write("{0:x02}", b); + } + + Console.WriteLine("\n-----END SSL SESSION PARAMETERS-----"); + } + } +} diff --git a/samples/java/Makefile b/samples/java/Makefile new file mode 100644 index 000000000..9c1ed6da2 --- /dev/null +++ b/samples/java/Makefile @@ -0,0 +1,51 @@ +# +# Copyright (c) 2007-2016, Cameron Rich +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the axTLS project nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +include ../../config/.config +include ../../config/makefile.conf +include ../../config/makefile.java.conf + +all : sample +JAR=../../$(STAGE)/axtls.jar +CLASSES=../../bindings/java/classes +sample : $(JAR) + +$(JAR) : $(CLASSES)/axssl.class $(wildcard $(CLASSES)/axTLSj/*.class) + jar mcvf manifest.mf $@ -C $(CLASSES) axTLSj -C $(CLASSES) axssl.class + +JAVA_FILES=axssl.java +JAVA_CLASSES:=$(JAVA_FILES:%.java=$(CLASSES)/axTLSj/%.class) + +$(CLASSES)/%.class : %.java + javac -d $(CLASSES) -classpath $(CLASSES) $^ + +clean:: + -@rm -f $(TARGET) + diff --git a/samples/java/axssl.java b/samples/java/axssl.java new file mode 100644 index 000000000..e013c11b4 --- /dev/null +++ b/samples/java/axssl.java @@ -0,0 +1,760 @@ +/* + * Copyright (c) 2007-2016, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Demonstrate the use of the axTLS library in Java with a set of + * command-line parameters similar to openssl. In fact, openssl clients + * should be able to communicate with axTLS servers and visa-versa. * + * This code has various bits enabled depending on the configuration. To enable + * the most interesting version, compile with the 'full mode' enabled. + * + * To see what options you have, run the following: + * > java -jar axtls.jar s_server -? + * > java -jar axtls.jar s_client -? + * + * The axtls/axtlsj shared libraries must be in the same directory or be found + * by the OS. + */ + +import java.io.*; +import java.util.*; +import java.net.*; +import axTLSj.*; + +public class axssl +{ + /* + * Main() + */ + public static void main(String[] args) + { + if (args.length == 1 && args[0].equals("version")) + { + System.out.println("axtls.jar " + SSLUtil.version()); + System.exit(0); + } + + axssl runner = new axssl(); + + try + { + if (args.length < 1 || + (!args[0].equals("s_server") && + !args[0].equals("s_client"))) + { + runner.print_options(args.length > 0 ? args[0] : ""); + } + + int build_mode = SSLUtil.buildMode(); + + if (args[0].equals("s_server")) + runner.do_server(build_mode, args); + else + runner.do_client(build_mode, args); + } + catch (Exception e) + { + System.out.println(e); + } + } + + /* + * do_server() + */ + private void do_server(int build_mode, String[] args) + throws Exception + { + int i = 1; + int port = 4433; + int options = axtlsj.SSL_DISPLAY_CERTS; + boolean quiet = false; + String password = null; + String private_key_file = null; + + /* organise the cert/ca_cert lists */ + int cert_size = SSLUtil.maxCerts(); + int ca_cert_size = SSLUtil.maxCACerts(); + String[] cert = new String[cert_size]; + String[] ca_cert = new String[ca_cert_size]; + int cert_index = 0; + int ca_cert_index = 0; + + while (i < args.length) + { + if (args[i].equals("-accept")) + { + if (i >= args.length-1) + { + print_server_options(build_mode, args[i]); + } + + port = Integer.parseInt(args[++i]); + } + else if (args[i].equals("-quiet")) + { + quiet = true; + options &= ~(int)axtlsj.SSL_DISPLAY_CERTS; + } + else if (build_mode >= axtlsj.SSL_BUILD_SERVER_ONLY) + { + if (args[i].equals("-cert")) + { + if (i >= args.length-1 || cert_index >= cert_size) + { + print_server_options(build_mode, args[i]); + } + + cert[cert_index++] = args[++i]; + } + else if (args[i].equals("-key")) + { + if (i >= args.length-1) + { + print_server_options(build_mode, args[i]); + } + + private_key_file = args[++i]; + options |= axtlsj.SSL_NO_DEFAULT_KEY; + } + else if (args[i].equals("-pass")) + { + if (i >= args.length-1) + { + print_server_options(build_mode, args[i]); + } + + password = args[++i]; + } + else if (build_mode >= axtlsj.SSL_BUILD_ENABLE_VERIFICATION) + { + if (args[i].equals("-verify")) + { + options |= axtlsj.SSL_CLIENT_AUTHENTICATION; + } + else if (args[i].equals("-CAfile")) + { + if (i >= args.length-1 || ca_cert_index >= ca_cert_size) + { + print_server_options(build_mode, args[i]); + } + + ca_cert[ca_cert_index++] = args[++i]; + } + else if (build_mode == axtlsj.SSL_BUILD_FULL_MODE) + { + if (args[i].equals("-debug")) + { + options |= axtlsj.SSL_DISPLAY_BYTES; + } + else if (args[i].equals("-state")) + { + options |= axtlsj.SSL_DISPLAY_STATES; + } + else if (args[i].equals("-show-rsa")) + { + options |= axtlsj.SSL_DISPLAY_RSA; + } + else + print_server_options(build_mode, args[i]); + } + else + print_server_options(build_mode, args[i]); + } + else + print_server_options(build_mode, args[i]); + } + else + print_server_options(build_mode, args[i]); + + i++; + } + + /* Create socket for incoming connections */ + ServerSocket server_sock = new ServerSocket(port); + + /********************************************************************** + * This is where the interesting stuff happens. Up until now we've + * just been setting up sockets etc. Now we do the SSL handshake. + **********************************************************************/ + SSLServer ssl_ctx = new SSLServer(options, + axtlsj.SSL_DEFAULT_SVR_SESS); + + if (ssl_ctx == null) + throw new Exception("Error: Server context is invalid"); + + if (private_key_file != null) + { + int obj_type = axtlsj.SSL_OBJ_RSA_KEY; + + if (private_key_file.endsWith(".p8")) + obj_type = axtlsj.SSL_OBJ_PKCS8; + else if (private_key_file.endsWith(".p12")) + obj_type = axtlsj.SSL_OBJ_PKCS12; + + if (ssl_ctx.objLoad(obj_type, + private_key_file, password) != axtlsj.SSL_OK) + { + throw new Exception("Error: Private key '" + private_key_file + + "' is undefined."); + } + } + + for (i = 0; i < cert_index; i++) + { + if (ssl_ctx.objLoad(axtlsj.SSL_OBJ_X509_CERT, + cert[i], null) != axtlsj.SSL_OK) + { + throw new Exception("Certificate '" + cert[i] + + "' is undefined."); + } + } + + for (i = 0; i < ca_cert_index; i++) + { + if (ssl_ctx.objLoad(axtlsj.SSL_OBJ_X509_CACERT, + ca_cert[i], null) != axtlsj.SSL_OK) + { + throw new Exception("Certificate '" + ca_cert[i] + + "' is undefined."); + } + } + + int res; + SSLReadHolder rh = new SSLReadHolder(); + + for (;;) + { + if (!quiet) + { + System.out.println("ACCEPT"); + } + + Socket client_sock = server_sock.accept(); + + SSL ssl = ssl_ctx.connect(client_sock); + + while ((res = ssl_ctx.read(ssl, rh)) == axtlsj.SSL_OK) + { + /* check when the connection has been established */ + if (ssl.handshakeStatus() == axtlsj.SSL_OK) + break; + + /* could do something else here */ + } + + if (res == axtlsj.SSL_OK) /* connection established and ok */ + { + if (!quiet) + { + display_session_id(ssl); + display_cipher(ssl); + } + + /* now read (and display) whatever the client sends us */ + for (;;) + { + /* keep reading until we get something interesting */ + while ((res = ssl_ctx.read(ssl, rh)) == axtlsj.SSL_OK) + { + /* could do something else here */ + } + + if (res < axtlsj.SSL_OK) + { + if (!quiet) + { + System.out.println("CONNECTION CLOSED"); + } + + break; + } + + /* convert to String */ + byte[] buf = rh.getData(); + char[] str = new char[res]; + + for (i = 0; i < res; i++) + { + str[i] = (char)buf[i]; + } + + System.out.print(str); + } + } + else if (!quiet) + { + SSLUtil.displayError(res); + } + + /* client was disconnected or the handshake failed. */ + ssl.dispose(); + client_sock.close(); + } + + /* ssl_ctx.dispose(); */ + } + + /* + * do_client() + */ + private void do_client(int build_mode, String[] args) + throws Exception + { + if (build_mode < axtlsj.SSL_BUILD_ENABLE_CLIENT) + print_client_options(build_mode, args[1]); + + int i = 1, res; + int port = 4433; + boolean quiet = false; + String password = null; + int reconnect = 0; + String private_key_file = null; + String hostname = "127.0.0.1"; + + /* organise the cert/ca_cert lists */ + int cert_index = 0; + int ca_cert_index = 0; + int cert_size = SSLUtil.maxCerts(); + int ca_cert_size = SSLUtil.maxCACerts(); + String[] cert = new String[cert_size]; + String[] ca_cert = new String[ca_cert_size]; + + int options = axtlsj.SSL_SERVER_VERIFY_LATER|axtlsj.SSL_DISPLAY_CERTS; + byte[] session_id = null; + + while (i < args.length) + { + if (args[i].equals("-connect")) + { + String host_port; + + if (i >= args.length-1) + { + print_client_options(build_mode, args[i]); + } + + host_port = args[++i]; + int index_colon; + + if ((index_colon = host_port.indexOf(':')) < 0) + print_client_options(build_mode, args[i]); + + hostname = new String(host_port.toCharArray(), + 0, index_colon); + port = Integer.parseInt(new String(host_port.toCharArray(), + index_colon+1, host_port.length()-index_colon-1)); + } + else if (args[i].equals("-cert")) + { + if (i >= args.length-1 || cert_index >= cert_size) + { + print_client_options(build_mode, args[i]); + } + + cert[cert_index++] = args[++i]; + } + else if (args[i].equals("-CAfile")) + { + if (i >= args.length-1 || ca_cert_index >= ca_cert_size) + { + print_client_options(build_mode, args[i]); + } + + ca_cert[ca_cert_index++] = args[++i]; + } + else if (args[i].equals("-key")) + { + if (i >= args.length-1) + { + print_client_options(build_mode, args[i]); + } + + private_key_file = args[++i]; + options |= axtlsj.SSL_NO_DEFAULT_KEY; + } + else if (args[i].equals("-verify")) + { + options &= ~(int)axtlsj.SSL_SERVER_VERIFY_LATER; + } + else if (args[i].equals("-reconnect")) + { + reconnect = 4; + } + else if (args[i].equals("-quiet")) + { + quiet = true; + options &= ~(int)axtlsj.SSL_DISPLAY_CERTS; + } + else if (args[i].equals("-pass")) + { + if (i >= args.length-1) + { + print_server_options(build_mode, args[i]); + } + + password = args[++i]; + } + else if (build_mode == axtlsj.SSL_BUILD_FULL_MODE) + { + if (args[i].equals("-debug")) + { + options |= axtlsj.SSL_DISPLAY_BYTES; + } + else if (args[i].equals("-state")) + { + options |= axtlsj.SSL_DISPLAY_STATES; + } + else if (args[i].equals("-show-rsa")) + { + options |= axtlsj.SSL_DISPLAY_RSA; + } + else + print_client_options(build_mode, args[i]); + } + else /* don't know what this is */ + print_client_options(build_mode, args[i]); + + i++; + } + + Socket client_sock = new Socket(hostname, port); + + if (!client_sock.isConnected()) + { + System.out.println("could not connect"); + throw new Exception(); + } + + if (!quiet) + { + System.out.println("CONNECTED"); + } + + /********************************************************************** + * This is where the interesting stuff happens. Up until now we've + * just been setting up sockets etc. Now we do the SSL handshake. + **********************************************************************/ + SSLClient ssl_ctx = new SSLClient(options, + axtlsj.SSL_DEFAULT_CLNT_SESS); + + if (ssl_ctx == null) + { + throw new Exception("Error: Client context is invalid"); + } + + if (private_key_file != null) + { + int obj_type = axtlsj.SSL_OBJ_RSA_KEY; + + if (private_key_file.endsWith(".p8")) + obj_type = axtlsj.SSL_OBJ_PKCS8; + else if (private_key_file.endsWith(".p12")) + obj_type = axtlsj.SSL_OBJ_PKCS12; + + if (ssl_ctx.objLoad(obj_type, + private_key_file, password) != axtlsj.SSL_OK) + { + throw new Exception("Error: Private key '" + private_key_file + + "' is undefined."); + } + } + + for (i = 0; i < cert_index; i++) + { + if (ssl_ctx.objLoad(axtlsj.SSL_OBJ_X509_CERT, + cert[i], null) != axtlsj.SSL_OK) + { + throw new Exception("Certificate '" + cert[i] + + "' is undefined."); + } + } + + for (i = 0; i < ca_cert_index; i++) + { + if (ssl_ctx.objLoad(axtlsj.SSL_OBJ_X509_CACERT, + ca_cert[i], null) != axtlsj.SSL_OK) + { + throw new Exception("Certificate '" + ca_cert[i] + + "' is undefined."); + } + } + + SSL ssl = null; + + /* Try session resumption? */ + if (reconnect > 0) + { + while (reconnect-- > 0) + { + ssl = ssl_ctx.connect(client_sock, session_id); + + if ((res = ssl.handshakeStatus()) != axtlsj.SSL_OK) + { + if (!quiet) + { + SSLUtil.displayError(res); + } + + ssl.dispose(); + throw new Exception(); + } + + display_session_id(ssl); + session_id = ssl.getSessionId(); + + if (reconnect > 0) + { + ssl.dispose(); + client_sock.close(); + + /* and reconnect */ + client_sock = new Socket(hostname, port); + } + } + } + else + { + ssl = ssl_ctx.connect(client_sock, null); + } + + /* check the return status */ + if ((res = ssl.handshakeStatus()) != axtlsj.SSL_OK) + { + if (!quiet) + { + SSLUtil.displayError(res); + } + + throw new Exception(); + } + + if (!quiet) + { + String common_name = + ssl.getCertificateDN(axtlsj.SSL_X509_CERT_COMMON_NAME); + + if (common_name != null) + { + System.out.println("Common Name:\t\t\t" + common_name); + } + + display_session_id(ssl); + display_cipher(ssl); + } + + BufferedReader in = new BufferedReader( + new InputStreamReader(System.in)); + + for (;;) + { + String user_input = in.readLine(); + + if (user_input == null) + break; + + byte[] buf = new byte[user_input.length()+2]; + buf[buf.length-2] = (byte)'\n'; /* add the carriage return */ + buf[buf.length-1] = 0; /* null terminate */ + + for (i = 0; i < buf.length-2; i++) + { + buf[i] = (byte)user_input.charAt(i); + } + + if ((res = ssl_ctx.write(ssl, buf)) < axtlsj.SSL_OK) + { + if (!quiet) + { + SSLUtil.displayError(res); + } + + break; + } + } + + ssl_ctx.dispose(); + } + + /** + * We've had some sort of command-line error. Print out the basic options. + */ + private void print_options(String option) + { + System.out.println("axssl: Error: '" + option + + "' is an invalid command."); + System.out.println("usage: axtlsj.jar [s_server|s_client|version] " + + "[args ...]"); + System.exit(1); + } + + /** + * We've had some sort of command-line error. Print out the server options. + */ + private void print_server_options(int build_mode, String option) + { + int cert_size = SSLUtil.maxCerts(); + int ca_cert_size = SSLUtil.maxCACerts(); + + System.out.println("unknown option " + option); + System.out.println("usage: s_server [args ...]"); + System.out.println(" -accept arg\t- port to accept on (default " + + "is 4433)"); + System.out.println(" -quiet\t\t- No server output"); + + if (build_mode >= axtlsj.SSL_BUILD_SERVER_ONLY) + { + System.out.println(" -cert arg\t- certificate file to add (in " + + "addition to default) to chain -"); + System.out.println("\t\t Can repeat up to " + cert_size + " times"); + System.out.println(" -key arg\t- Private key file to use"); + System.out.println(" -pass\t\t- private key file pass phrase source"); + } + + if (build_mode >= axtlsj.SSL_BUILD_ENABLE_VERIFICATION) + { + System.out.println(" -verify\t- turn on peer certificate " + + "verification"); + System.out.println(" -CAfile arg\t- Certificate authority. "); + System.out.println("\t\t Can repeat up to " + + ca_cert_size + " times"); + } + + if (build_mode == axtlsj.SSL_BUILD_FULL_MODE) + { + System.out.println(" -debug\t\t- Print more output"); + System.out.println(" -state\t\t- Show state messages"); + System.out.println(" -show-rsa\t- Show RSA state"); + } + + System.exit(1); + } + + /** + * We've had some sort of command-line error. Print out the client options. + */ + private void print_client_options(int build_mode, String option) + { + int cert_size = SSLUtil.maxCerts(); + int ca_cert_size = SSLUtil.maxCACerts(); + + System.out.println("unknown option " + option); + + if (build_mode >= axtlsj.SSL_BUILD_ENABLE_CLIENT) + { + System.out.println("usage: s_client [args ...]"); + System.out.println(" -connect host:port - who to connect to " + + "(default is localhost:4433)"); + System.out.println(" -verify\t- turn on peer certificate " + + "verification"); + System.out.println(" -cert arg\t- certificate file to use"); + System.out.println(" -key arg\t- Private key file to use"); + System.out.println("\t\t Can repeat up to " + cert_size + + " times"); + System.out.println(" -CAfile arg\t- Certificate authority."); + System.out.println("\t\t Can repeat up to " + ca_cert_size + + " times"); + System.out.println(" -quiet\t\t- No client output"); + System.out.println(" -pass\t\t- private key file pass " + + "phrase source"); + System.out.println(" -reconnect\t- Drop and re-make the " + + "connection with the same Session-ID"); + + if (build_mode == axtlsj.SSL_BUILD_FULL_MODE) + { + System.out.println(" -debug\t\t- Print more output"); + System.out.println(" -state\t\t- Show state messages"); + System.out.println(" -show-rsa\t- Show RSA state"); + } + } + else + { + System.out.println("Change configuration to allow this feature"); + } + + System.exit(1); + } + + /** + * Display what cipher we are using + */ + private void display_cipher(SSL ssl) + { + System.out.print("CIPHER is "); + + byte ciph_id = ssl.getCipherId(); + + if (ciph_id == axtlsj.SSL_AES128_SHA) + System.out.println("AES128-SHA"); + else if (ciph_id == axtlsj.SSL_AES256_SHA) + System.out.println("AES256-SHA"); + else if (ciph_id == axtlsj.SSL_AES128_SHA256) + System.out.println("AES128-SHA256"); + else if (ciph_id == axtlsj.SSL_AES256_SHA256) + System.out.println("AES256-SHA256"); + else + System.out.println("Unknown - " + ssl.getCipherId()); + } + + public char toHexChar(int i) + { + if ((0 <= i) && (i <= 9 )) + return (char)('0' + i); + else + return (char)('a' + (i-10)); + } + + public void bytesToHex(byte[] data) + { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < data.length; i++ ) + { + buf.append(toHexChar((data[i]>>>4)&0x0F)); + buf.append(toHexChar(data[i]&0x0F)); + } + + System.out.println(buf); + } + + + /** + * Display what session id we have. + */ + private void display_session_id(SSL ssl) + { + byte[] session_id = ssl.getSessionId(); + + if (session_id.length > 0) + { + System.out.println("-----BEGIN SSL SESSION PARAMETERS-----"); + bytesToHex(session_id); + System.out.println("-----END SSL SESSION PARAMETERS-----"); + } + } +} diff --git a/samples/lua/axssl.lua b/samples/lua/axssl.lua new file mode 100755 index 000000000..b4f24edf0 --- /dev/null +++ b/samples/lua/axssl.lua @@ -0,0 +1,562 @@ +#!/usr/local/bin/lua + +-- +-- Copyright (c) 2007-2016, Cameron Rich +-- +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- * Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- * Neither the name of the axTLS project nor the names of its +-- contributors may be used to endorse or promote products derived +-- from this software without specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +-- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +-- TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +-- OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +-- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-- + +-- +-- Demonstrate the use of the axTLS library in Lua with a set of +-- command-line parameters similar to openssl. In fact, openssl clients +-- should be able to communicate with axTLS servers and visa-versa. +-- +-- This code has various bits enabled depending on the configuration. To enable +-- the most interesting version, compile with the 'full mode' enabled. +-- +-- To see what options you have, run the following: +-- > [lua] axssl s_server -? +-- > [lua] axssl s_client -? +-- +-- The axtls/axtlsl shared libraries must be in the same directory or be found +-- by the OS. +-- +-- +require "bit" +require("axtlsl") +local socket = require("socket") + +-- print version? +if #arg == 1 and arg[1] == "version" then + print("axssl.lua "..axtlsl.ssl_version()) + os.exit(1) +end + +-- +-- We've had some sort of command-line error. Print out the basic options. +-- +function print_options(option) + print("axssl: Error: '"..option.."' is an invalid command.") + print("usage: axssl [s_server|s_client|version] [args ...]") + os.exit(1) +end + +-- +-- We've had some sort of command-line error. Print out the server options. +-- +function print_server_options(build_mode, option) + local cert_size = axtlsl.ssl_get_config(axtlsl.SSL_MAX_CERT_CFG_OFFSET) + local ca_cert_size = axtlsl.ssl_get_config( + axtlsl.SSL_MAX_CA_CERT_CFG_OFFSET) + + print("unknown option "..option) + print("usage: s_server [args ...]") + print(" -accept\t- port to accept on (default is 4433)") + print(" -quiet\t\t- No server output") + + if build_mode >= axtlsl.SSL_BUILD_SERVER_ONLY then + print(" -cert arg\t- certificate file to add (in addition to ".. + "default) to chain -") + print("\t\t Can repeat up to "..cert_size.." times") + print(" -key arg\t- Private key file to use - default DER format") + print(" -pass\t\t- private key file pass phrase source") + end + + if build_mode >= axtlsl.SSL_BUILD_ENABLE_VERIFICATION then + print(" -verify\t- turn on peer certificate verification") + print(" -CAfile arg\t- Certificate authority - default DER format") + print("\t\t Can repeat up to "..ca_cert_size.." times") + end + + if build_mode == axtlsl.SSL_BUILD_FULL_MODE then + print(" -debug\t\t- Print more output") + print(" -state\t\t- Show state messages") + print(" -show-rsa\t- Show RSA state") + end + + os.exit(1) +end + +-- +-- We've had some sort of command-line error. Print out the client options. +-- +function print_client_options(build_mode, option) + local cert_size = axtlsl.ssl_get_config(axtlsl.SSL_MAX_CERT_CFG_OFFSET) + local ca_cert_size = axtlsl.ssl_get_config( + axtlsl.SSL_MAX_CA_CERT_CFG_OFFSET) + + print("unknown option "..option) + + if build_mode >= axtlsl.SSL_BUILD_ENABLE_CLIENT then + print("usage: s_client [args ...]") + print(" -connect host:port - who to connect to (default ".. + "is localhost:4433)") + print(" -verify\t- turn on peer certificate verification") + print(" -cert arg\t- certificate file to use - default DER format") + print(" -key arg\t- Private key file to use - default DER format") + print("\t\t Can repeat up to "..cert_size.." times") + print(" -CAfile arg\t- Certificate authority - default DER format") + print("\t\t Can repeat up to "..ca_cert_size.."times") + print(" -quiet\t\t- No client output") + print(" -pass\t\t- private key file pass phrase source") + print(" -reconnect\t- Drop and re-make the connection ".. + "with the same Session-ID") + + if build_mode == axtlsl.SSL_BUILD_FULL_MODE then + print(" -debug\t\t- Print more output") + print(" -state\t\t- Show state messages") + print(" -show-rsa\t- Show RSA state") + end + else + print("Change configuration to allow this feature") + end + + os.exit(1) +end + +-- Implement the SSL server logic. +function do_server(build_mode) + local i = 2 + local v + local port = 4433 + local options = axtlsl.SSL_DISPLAY_CERTS + local quiet = false + local password = "" + local private_key_file = nil + local cert_size = axtlsl.ssl_get_config(axtlsl.SSL_MAX_CERT_CFG_OFFSET) + local ca_cert_size = axtlsl. + ssl_get_config(axtlsl.SSL_MAX_CA_CERT_CFG_OFFSET) + local cert = {} + local ca_cert = {} + + while i <= #arg do + if arg[i] == "-accept" then + if i >= #arg then + print_server_options(build_mode, arg[i]) + end + + i = i + 1 + port = arg[i] + elseif arg[i] == "-quiet" then + quiet = true + options = bit.band(options, bit.bnot(axtlsl.SSL_DISPLAY_CERTS)) + elseif build_mode >= axtlsl.SSL_BUILD_SERVER_ONLY then + if arg[i] == "-cert" then + if i >= #arg or #cert >= cert_size then + print_server_options(build_mode, arg[i]) + end + + i = i + 1 + table.insert(cert, arg[i]) + elseif arg[i] == "-key" then + if i >= #arg then + print_server_options(build_mode, arg[i]) + end + + i = i + 1 + private_key_file = arg[i] + options = bit.bor(options, axtlsl.SSL_NO_DEFAULT_KEY) + elseif arg[i] == "-pass" then + if i >= #arg then + print_server_options(build_mode, arg[i]) + end + + i = i + 1 + password = arg[i] + elseif build_mode >= axtlsl.SSL_BUILD_ENABLE_VERIFICATION then + if arg[i] == "-verify" then + options = bit.bor(options, axtlsl.SSL_CLIENT_AUTHENTICATION) + elseif arg[i] == "-CAfile" then + if i >= #arg or #ca_cert >= ca_cert_size then + print_server_options(build_mode, arg[i]) + end + + i = i + 1 + table.insert(ca_cert, arg[i]) + elseif build_mode == axtlsl.SSL_BUILD_FULL_MODE then + if arg[i] == "-debug" then + options = bit.bor(options, axtlsl.SSL_DISPLAY_BYTES) + elseif arg[i] == "-state" then + options = bit.bor(options, axtlsl.SSL_DISPLAY_STATES) + elseif arg[i] == "-show-rsa" then + options = bit.bor(options, axtlsl.SSL_DISPLAY_RSA) + else + print_server_options(build_mode, arg[i]) + end + else + print_server_options(build_mode, arg[i]) + end + else + print_server_options(build_mode, arg[i]) + end + else + print_server_options(build_mode, arg[i]) + end + + i = i + 1 + end + + -- Create socket for incoming connections + local server_sock = socket.try(socket.bind("*", port)) + + --------------------------------------------------------------------------- + -- This is where the interesting stuff happens. Up until now we've + -- just been setting up sockets etc. Now we do the SSL handshake. + --------------------------------------------------------------------------- + local ssl_ctx = axtlsl.ssl_ctx_new(options, axtlsl.SSL_DEFAULT_SVR_SESS) + if ssl_ctx == nil then error("Error: Server context is invalid") end + + if private_key_file ~= nil then + local obj_type = axtlsl.SSL_OBJ_RSA_KEY + + if string.find(private_key_file, ".p8") then + obj_type = axtlsl.SSL_OBJ_PKCS8 + end + + if string.find(private_key_file, ".p12") then + obj_type = axtlsl.SSL_OBJ_PKCS12 + end + + if axtlsl.ssl_obj_load(ssl_ctx, obj_type, private_key_file, + password) ~= axtlsl.SSL_OK then + error("Private key '" .. private_key_file .. "' is undefined.") + end + end + + for _, v in ipairs(cert) do + if axtlsl.ssl_obj_load(ssl_ctx, axtlsl.SSL_OBJ_X509_CERT, v, "") ~= + axtlsl.SSL_OK then + error("Certificate '"..v .. "' is undefined.") + end + end + + for _, v in ipairs(ca_cert) do + if axtlsl.ssl_obj_load(ssl_ctx, axtlsl.SSL_OBJ_X509_CACERT, v, "") ~= + axtlsl.SSL_OK then + error("Certificate '"..v .."' is undefined.") + end + end + + while true do + if not quiet then print("ACCEPT") end + local client_sock = server_sock:accept(); + local ssl = axtlsl.ssl_server_new(ssl_ctx, client_sock:getfd()) + + -- do the actual SSL handshake + local connected = false + local res + local buf + + while true do + socket.select({client_sock}, nil) + res, buf = axtlsl.ssl_read(ssl) + + if res == axtlsl.SSL_OK then -- connection established and ok + if axtlsl.ssl_handshake_status(ssl) == axtlsl.SSL_OK then + if not quiet and not connected then + display_session_id(ssl) + display_cipher(ssl) + end + connected = true + end + end + + if res > axtlsl.SSL_OK then + for _, v in ipairs(buf) do + io.write(string.format("%c", v)) + end + elseif res < axtlsl.SSL_OK then + if not quiet then + axtlsl.ssl_display_error(res) + end + break + end + end + + -- client was disconnected or the handshake failed. + print("CONNECTION CLOSED") + axtlsl.ssl_free(ssl) + client_sock:close() + end + + axtlsl.ssl_ctx_free(ssl_ctx) +end + +-- +-- Implement the SSL client logic. +-- +function do_client(build_mode) + local i = 2 + local v + local port = 4433 + local options = + bit.bor(axtlsl.SSL_SERVER_VERIFY_LATER, axtlsl.SSL_DISPLAY_CERTS) + local private_key_file = nil + local reconnect = 0 + local quiet = false + local password = "" + local session_id = {} + local host = "127.0.0.1" + local cert_size = axtlsl.ssl_get_config(axtlsl.SSL_MAX_CERT_CFG_OFFSET) + local ca_cert_size = axtlsl. + ssl_get_config(axtlsl.SSL_MAX_CA_CERT_CFG_OFFSET) + local cert = {} + local ca_cert = {} + + while i <= #arg do + if arg[i] == "-connect" then + if i >= #arg then + print_client_options(build_mode, arg[i]) + end + + i = i + 1 + local t = string.find(arg[i], ":") + host = string.sub(arg[i], 1, t-1) + port = string.sub(arg[i], t+1) + elseif arg[i] == "-cert" then + if i >= #arg or #cert >= cert_size then + print_client_options(build_mode, arg[i]) + end + + i = i + 1 + table.insert(cert, arg[i]) + elseif arg[i] == "-key" then + if i >= #arg then + print_client_options(build_mode, arg[i]) + end + + i = i + 1 + private_key_file = arg[i] + options = bit.bor(options, axtlsl.SSL_NO_DEFAULT_KEY) + elseif arg[i] == "-CAfile" then + if i >= #arg or #ca_cert >= ca_cert_size then + print_client_options(build_mode, arg[i]) + end + + i = i + 1 + table.insert(ca_cert, arg[i]) + elseif arg[i] == "-verify" then + options = bit.band(options, + bit.bnot(axtlsl.SSL_SERVER_VERIFY_LATER)) + elseif arg[i] == "-reconnect" then + reconnect = 4 + elseif arg[i] == "-quiet" then + quiet = true + options = bit.band(options, bnot(axtlsl.SSL_DISPLAY_CERTS)) + elseif arg[i] == "-pass" then + if i >= #arg then + print_server_options(build_mode, arg[i]) + end + + i = i + 1 + password = arg[i] + elseif build_mode == axtlsl.SSL_BUILD_FULL_MODE then + if arg[i] == "-debug" then + options = bit.bor(options, axtlsl.SSL_DISPLAY_BYTES) + elseif arg[i] == "-state" then + options = bit.bor(axtlsl.SSL_DISPLAY_STATES) + elseif arg[i] == "-show-rsa" then + options = bit.bor(axtlsl.SSL_DISPLAY_RSA) + else -- don't know what this is + print_client_options(build_mode, arg[i]) + end + else -- don't know what this is + print_client_options(build_mode, arg[i]) + end + + i = i + 1 + end + + local client_sock = socket.try(socket.connect(host, port)) + local ssl + local res + + if not quiet then print("CONNECTED") end + + --------------------------------------------------------------------------- + -- This is where the interesting stuff happens. Up until now we've + -- just been setting up sockets etc. Now we do the SSL handshake. + --------------------------------------------------------------------------- + local ssl_ctx = axtlsl.ssl_ctx_new(options, axtlsl.SSL_DEFAULT_CLNT_SESS) + + if ssl_ctx == nil then + error("Error: Client context is invalid") + end + + if private_key_file ~= nil then + local obj_type = axtlsl.SSL_OBJ_RSA_KEY + + if string.find(private_key_file, ".p8") then + obj_type = axtlsl.SSL_OBJ_PKCS8 + end + + if string.find(private_key_file, ".p12") then + obj_type = axtlsl.SSL_OBJ_PKCS12 + end + + if axtlsl.ssl_obj_load(ssl_ctx, obj_type, private_key_file, + password) ~= axtlsl.SSL_OK then + error("Private key '"..private_key_file.."' is undefined.") + end + end + + for _, v in ipairs(cert) do + if axtlsl.ssl_obj_load(ssl_ctx, axtlsl.SSL_OBJ_X509_CERT, v, "") ~= + axtlsl.SSL_OK then + error("Certificate '"..v .. "' is undefined.") + end + end + + for _, v in ipairs(ca_cert) do + if axtlsl.ssl_obj_load(ssl_ctx, axtlsl.SSL_OBJ_X509_CACERT, v, "") ~= + axtlsl.SSL_OK then + error("Certificate '"..v .."' is undefined.") + end + end + + -- Try session resumption? + if reconnect ~= 0 then + local session_id = nil + local sess_id_size = 0 + + while reconnect > 0 do + reconnect = reconnect - 1 + ssl = axtlsl.ssl_client_new(ssl_ctx, + client_sock:getfd(), session_id, sess_id_size) + + res = axtlsl.ssl_handshake_status(ssl) + if res ~= axtlsl.SSL_OK then + if not quiet then axtlsl.ssl_display_error(res) end + axtlsl.ssl_free(ssl) + os.exit(1) + end + + display_session_id(ssl) + session_id = axtlsl.ssl_get_session_id(ssl) + sess_id_size = axtlsl.ssl_get_session_id_size(ssl) + + if reconnect > 0 then + axtlsl.ssl_free(ssl) + client_sock:close() + client_sock = socket.try(socket.connect(host, port)) + end + + end + else + ssl = axtlsl.ssl_client_new(ssl_ctx, client_sock:getfd(), nil, 0) + end + + -- check the return status + res = axtlsl.ssl_handshake_status(ssl) + if res ~= axtlsl.SSL_OK then + if not quiet then axtlsl.ssl_display_error(res) end + os.exit(1) + end + + if not quiet then + local common_name = axtlsl.ssl_get_cert_dn(ssl, + axtlsl.SSL_X509_CERT_COMMON_NAME) + + if common_name ~= nil then + print("Common Name:\t\t\t"..common_name) + end + + display_session_id(ssl) + display_cipher(ssl) + end + + while true do + local line = io.read() + if line == nil then break end + local bytes = {} + + for i = 1, #line do + bytes[i] = line.byte(line, i) + end + + bytes[#line+1] = 10 -- add carriage return, null + bytes[#line+2] = 0 + + res = axtlsl.ssl_write(ssl, bytes, #bytes) + if res < axtlsl.SSL_OK then + if not quiet then axtlsl.ssl_display_error(res) end + break + end + end + + axtlsl.ssl_ctx_free(ssl_ctx) + client_sock:close() +end + +-- +-- Display what cipher we are using +-- +function display_cipher(ssl) + io.write("CIPHER is ") + local cipher_id = axtlsl.ssl_get_cipher_id(ssl) + + if cipher_id == axtlsl.SSL_AES128_SHA then + print("AES128-SHA") + elseif cipher_id == axtlsl.SSL_AES256_SHA then + print("AES256-SHA") + elseif axtlsl.SSL_AES128_SHA256 then + print("AES128-SHA256") + elseif axtlsl.SSL_AES256_SHA256 then + print("AES256-SHA256") + else + print("Unknown - "..cipher_id) + end +end + +-- +-- Display what session id we have. +-- +function display_session_id(ssl) + local session_id = axtlsl.ssl_get_session_id(ssl) + local v + + if #session_id > 0 then + print("-----BEGIN SSL SESSION PARAMETERS-----") + for _, v in ipairs(session_id) do + io.write(string.format("%02x", v)) + end + print("\n-----END SSL SESSION PARAMETERS-----") + end +end + +-- +-- Main entry point. Doesn't do much except works out whether we are a client +-- or a server. +-- +if #arg == 0 or (arg[1] ~= "s_server" and arg[1] ~= "s_client") then + print_options(#arg > 0 and arg[1] or "") +end + +local build_mode = axtlsl.ssl_get_config(axtlsl.SSL_BUILD_MODE) +_ = arg[1] == "s_server" and do_server(build_mode) or do_client(build_mode) +os.exit(0) + diff --git a/samples/perl/axssl.pl b/samples/perl/axssl.pl new file mode 100755 index 000000000..f3b044939 --- /dev/null +++ b/samples/perl/axssl.pl @@ -0,0 +1,634 @@ +#!/usr/bin/perl -w +# +# Copyright (c) 2007-2016, Cameron Rich +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the axTLS project nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# +# Demonstrate the use of the axTLS library in Perl with a set of +# command-line parameters similar to openssl. In fact, openssl clients +# should be able to communicate with axTLS servers and visa-versa. +# +# This code has various bits enabled depending on the configuration. To enable +# the most interesting version, compile with the 'full mode' enabled. +# +# To see what options you have, run the following: +# > [perl] axssl s_server -? +# > [perl] axssl s_client -? +# +# The axtls/axtlsp shared libraries must be in the same directory or be found +# by the OS. axtlsp.pm must be in this directory or be in @INC. +# +# Under Win32, ActivePerl was used (see +# http://www.activestate.com/Products/ActivePerl/?mp=1) +# +use axtlsp; +use IO::Socket; + +# To get access to Win32 file descriptor stuff +my $is_win32 = 0; + +if ($^O eq "MSWin32") +{ + eval("use Win32API::File 0.08 qw( :ALL )"); + $is_win32 = 1; +} + +use strict; + +# +# Win32 has some problems with socket handles +# +sub get_native_sock +{ + my ($sock) = @_; + return $is_win32 ? FdGetOsFHandle($sock) : $sock; +} + +# print version? +if ($#ARGV == 0 && $ARGV[0] eq "version") +{ + printf("axssl.pl ".axtlsp::ssl_version()."\n"); + exit 0; +} + +# +# Main entry point. Doesn't do much except works out whether we are a client +# or a server. +# +print_options($#ARGV > -1 ? $ARGV[0] : "") + if ($#ARGV < 0 || ($ARGV[0] ne "s_server" && $ARGV[0] ne "s_client")); + + +# Cygwin/Win32 issue - flush our output continuously +select STDOUT; +local $|=1; + +my $build_mode = axtlsp::ssl_get_config($axtlsp::SSL_BUILD_MODE); +$ARGV[0] eq "s_server" ? do_server($build_mode) : do_client($build_mode); + +# +# Implement the SSL server logic. +# +sub do_server +{ + my ($build_mode) = @_; + my $i = 1; + my $port = 4433; + my $options = $axtlsp::SSL_DISPLAY_CERTS; + my $quiet = 0; + my $password = undef; + my $private_key_file = undef; + my $cert_size = axtlsp::ssl_get_config($axtlsp::SSL_MAX_CERT_CFG_OFFSET); + my $ca_cert_size = axtlsp::ssl_get_config( + $axtlsp::SSL_MAX_CA_CERT_CFG_OFFSET); + my @cert; + my @ca_cert; + + while ($i <= $#ARGV) + { + if ($ARGV[$i] eq "-accept") + { + print_server_options($build_mode, $ARGV[$i]) if $i >= $#ARGV; + $port = $ARGV[++$i]; + } + elsif ($ARGV[$i] eq "-quiet") + { + $quiet = 1; + $options &= ~$axtlsp::SSL_DISPLAY_CERTS; + } + elsif ($build_mode >= $axtlsp::SSL_BUILD_SERVER_ONLY) + { + if ($ARGV[$i] eq "-cert") + { + print_server_options($build_mode, $ARGV[$i]) + if $i >= $#ARGV || $#cert >= $cert_size-1; + + push @cert, $ARGV[++$i]; + } + elsif ($ARGV[$i] eq "-key") + { + print_server_options($build_mode, $ARGV[$i]) if $i >= $#ARGV; + $private_key_file = $ARGV[++$i]; + $options |= $axtlsp::SSL_NO_DEFAULT_KEY; + } + elsif ($ARGV[$i] eq "-pass") + { + print_server_options($build_mode, $ARGV[$i]) if $i >= $#ARGV; + $password = $ARGV[++$i]; + } + elsif ($build_mode >= $axtlsp::SSL_BUILD_ENABLE_VERIFICATION) + { + if ($ARGV[$i] eq "-verify") + { + $options |= $axtlsp::SSL_CLIENT_AUTHENTICATION; + } + elsif ($ARGV[$i] eq "-CAfile") + { + print_server_options($build_mode, $ARGV[$i]) + if $i >= $#ARGV || $#ca_cert >= $ca_cert_size-1; + push @ca_cert, $ARGV[++$i]; + } + elsif ($build_mode == $axtlsp::SSL_BUILD_FULL_MODE) + { + if ($ARGV[$i] eq "-debug") + { + $options |= $axtlsp::SSL_DISPLAY_BYTES; + } + elsif ($ARGV[$i] eq "-state") + { + $options |= $axtlsp::SSL_DISPLAY_STATES; + } + elsif ($ARGV[$i] eq "-show-rsa") + { + $options |= $axtlsp::SSL_DISPLAY_RSA; + } + else + { + print_server_options($build_mode, $ARGV[$i]); + } + } + else + { + print_server_options($build_mode, $ARGV[$i]); + } + } + else + { + print_server_options($build_mode, $ARGV[$i]); + } + } + else + { + print_server_options($build_mode, $ARGV[$i]); + } + + $i++; + } + + # Create socket for incoming connections + my $server_sock = IO::Socket::INET->new(Proto => 'tcp', + LocalPort => $port, + Listen => 1, + Reuse => 1) or die $!; + + ########################################################################### + # This is where the interesting stuff happens. Up until now we've + # just been setting up sockets etc. Now we do the SSL handshake. + ########################################################################### + my $ssl_ctx = axtlsp::ssl_ctx_new($options, $axtlsp::SSL_DEFAULT_SVR_SESS); + die "Error: Server context is invalid" if not defined $ssl_ctx; + + if (defined $private_key_file) + { + my $obj_type = $axtlsp::SSL_OBJ_RSA_KEY; + + $obj_type = $axtlsp::SSL_OBJ_PKCS8 if $private_key_file =~ /.p8$/; + $obj_type = $axtlsp::SSL_OBJ_PKCS12 if $private_key_file =~ /.p12$/; + + die "Private key '$private_key_file' is undefined." if + axtlsp::ssl_obj_load($ssl_ctx, $obj_type, + $private_key_file, $password); + } + + foreach (@cert) + { + die "Certificate '$_' is undefined." + if axtlsp::ssl_obj_load($ssl_ctx, $axtlsp::SSL_OBJ_X509_CERT, + $_, undef) != $axtlsp::SSL_OK; + } + + foreach (@ca_cert) + { + die "Certificate '$_' is undefined." + if axtlsp::ssl_obj_load($ssl_ctx, $axtlsp::SSL_OBJ_X509_CACERT, + $_, undef) != $axtlsp::SSL_OK; + } + + for (;;) + { + printf("ACCEPT\n") if not $quiet; + my $client_sock = $server_sock->accept; + my $native_sock = get_native_sock($client_sock->fileno); + + # This doesn't work in Win32 - need to get file descriptor from socket. + my $ssl = axtlsp::ssl_server_new($ssl_ctx, $native_sock); + + # do the actual SSL handshake + my $res; + my $buf; + my $connected = 0; + + while (1) + { + ($res, $buf) = axtlsp::ssl_read($ssl, undef); + last if $res < $axtlsp::SSL_OK; + + if ($res == $axtlsp::SSL_OK) # connection established and ok + { + if (axtlsp::ssl_handshake_status($ssl) == $axtlsp::SSL_OK) + { + if (!$quiet && !$connected) + { + display_session_id($ssl); + display_cipher($ssl); + } + + $connected = 1; + } + } + + if ($res > $axtlsp::SSL_OK) + { + printf($$buf); + } + elsif ($res < $axtlsp::SSL_OK) + { + axtlsp::ssl_display_error($res) if not $quiet; + last; + } + } + + # client was disconnected or the handshake failed. + printf("CONNECTION CLOSED\n") if not $quiet; + axtlsp::ssl_free($ssl); + $client_sock->close; + } + + axtlsp::ssl_ctx_free($ssl_ctx); +} + +# +# Implement the SSL client logic. +# +sub do_client +{ + my ($build_mode) = @_; + my $i = 1; + my $port = 4433; + my $options = $axtlsp::SSL_SERVER_VERIFY_LATER|$axtlsp::SSL_DISPLAY_CERTS; + my $private_key_file = undef; + my $reconnect = 0; + my $quiet = 0; + my $password = undef; + my @session_id; + my $host = "127.0.0.1"; + my @cert; + my @ca_cert; + my $cert_size = axtlsp::ssl_get_config( + $axtlsp::SSL_MAX_CERT_CFG_OFFSET); + my $ca_cert_size = axtlsp::ssl_get_config( + $axtlsp::SSL_MAX_CA_CERT_CFG_OFFSET); + + while ($i <= $#ARGV) + { + if ($ARGV[$i] eq "-connect") + { + print_client_options($build_mode, $ARGV[$i]) if $i >= $#ARGV; + ($host, $port) = split(':', $ARGV[++$i]); + } + elsif ($ARGV[$i] eq "-cert") + { + print_client_options($build_mode, $ARGV[$i]) + if $i >= $#ARGV || $#cert >= $cert_size-1; + + push @cert, $ARGV[++$i]; + } + elsif ($ARGV[$i] eq "-key") + { + print_client_options($build_mode, $ARGV[$i]) if $i >= $#ARGV; + $private_key_file = $ARGV[++$i]; + $options |= $axtlsp::SSL_NO_DEFAULT_KEY; + } + elsif ($ARGV[$i] eq "-CAfile") + { + print_client_options($build_mode, $ARGV[$i]) + if $i >= $#ARGV || $#ca_cert >= $ca_cert_size-1; + + push @ca_cert, $ARGV[++$i]; + } + elsif ($ARGV[$i] eq "-verify") + { + $options &= ~$axtlsp::SSL_SERVER_VERIFY_LATER; + } + elsif ($ARGV[$i] eq "-reconnect") + { + $reconnect = 4; + } + elsif ($ARGV[$i] eq "-quiet") + { + $quiet = 1; + $options &= ~$axtlsp::SSL_DISPLAY_CERTS; + } + elsif ($ARGV[$i] eq "-pass") + { + print_server_options($build_mode, $ARGV[$i]) if $i >= $#ARGV; + $password = $ARGV[++$i]; + } + elsif ($build_mode == $axtlsp::SSL_BUILD_FULL_MODE) + { + if ($ARGV[$i] eq "-debug") + { + $options |= $axtlsp::SSL_DISPLAY_BYTES; + } + elsif ($ARGV[$i] eq "-state") + { + $options |= $axtlsp::SSL_DISPLAY_STATES; + } + elsif ($ARGV[$i] eq "-show-rsa") + { + $options |= $axtlsp::SSL_DISPLAY_RSA; + } + else # don't know what this is + { + print_client_options($build_mode, $ARGV[$i]); + } + } + else # don't know what this is + { + print_client_options($build_mode, $ARGV[$i]); + } + + $i++; + } + + my $client_sock = new IO::Socket::INET ( + PeerAddr => $host, PeerPort => $port, Proto => 'tcp') + || die ("no socket: $!"); + my $ssl; + my $res; + my $native_sock = get_native_sock($client_sock->fileno); + + printf("CONNECTED\n") if not $quiet; + + ########################################################################### + # This is where the interesting stuff happens. Up until now we've + # just been setting up sockets etc. Now we do the SSL handshake. + ########################################################################### + my $ssl_ctx = axtlsp::ssl_ctx_new($options, $axtlsp::SSL_DEFAULT_CLNT_SESS); + die "Error: Client context is invalid" if not defined $ssl_ctx; + + if (defined $private_key_file) + { + my $obj_type = $axtlsp::SSL_OBJ_RSA_KEY; + + $obj_type = $axtlsp::SSL_OBJ_PKCS8 if $private_key_file =~ /.p8$/; + $obj_type = $axtlsp::SSL_OBJ_PKCS12 if $private_key_file =~ /.p12$/; + + die "Private key '$private_key_file' is undefined." if + axtlsp::ssl_obj_load($ssl_ctx, $obj_type, + $private_key_file, $password); + } + + foreach (@cert) + { + die "Certificate '$_' is undefined." + if axtlsp::ssl_obj_load($ssl_ctx, $axtlsp::SSL_OBJ_X509_CERT, + $_, undef) != $axtlsp::SSL_OK; + } + + foreach (@ca_cert) + { + die "Certificate '$_' is undefined." + if axtlsp::ssl_obj_load($ssl_ctx, $axtlsp::SSL_OBJ_X509_CACERT, + $_, undef) != $axtlsp::SSL_OK; + } + + # Try session resumption? + if ($reconnect) + { + my $session_id = undef; + my $sess_id_size = 0; + + while ($reconnect--) + { + $ssl = axtlsp::ssl_client_new($ssl_ctx, $native_sock, + $session_id, $sess_id_size); + + $res = axtlsp::ssl_handshake_status($ssl); + if ($res != $axtlsp::SSL_OK) + { + axtlsp::ssl_display_error($res) if !$quiet; + axtlsp::ssl_free($ssl); + exit 1; + } + + display_session_id($ssl); + $session_id = axtlsp::ssl_get_session_id($ssl); + + if ($reconnect) + { + axtlsp::ssl_free($ssl); + $client_sock->close; + $client_sock = new IO::Socket::INET ( + PeerAddr => $host, PeerPort => $port, Proto => 'tcp') + || die ("no socket: $!"); + + } + } + } + else + { + $ssl = axtlsp::ssl_client_new($ssl_ctx, $native_sock, undef, 0); + } + + # check the return status + $res = axtlsp::ssl_handshake_status($ssl); + if ($res != $axtlsp::SSL_OK) + { + axtlsp::ssl_display_error($res) if not $quiet; + exit 1; + } + + if (!$quiet) + { + my $common_name = axtlsp::ssl_get_cert_dn($ssl, + $axtlsp::SSL_X509_CERT_COMMON_NAME); + + printf("Common Name:\t\t\t%s\n", $common_name) if defined $common_name; + display_session_id($ssl); + display_cipher($ssl); + } + + while () + { + my $cstring = pack("a*x", $_); # add null terminator + $res = axtlsp::ssl_write($ssl, \$cstring, length($cstring)); + if ($res < $axtlsp::SSL_OK) + { + axtlsp::ssl_display_error($res) if not $quiet; + last; + } + } + + axtlsp::ssl_ctx_free($ssl_ctx); + $client_sock->close; +} + +# +# We've had some sort of command-line error. Print out the basic options. +# +sub print_options +{ + my ($option) = @_; + printf("axssl: Error: '%s' is an invalid command.\n", $option); + printf("usage: axssl [s_server|s_client|version] [args ...]\n"); + exit 1; +} + +# +# We've had some sort of command-line error. Print out the server options. +# +sub print_server_options +{ + my ($build_mode, $option) = @_; + my $cert_size = axtlsp::ssl_get_config($axtlsp::SSL_MAX_CERT_CFG_OFFSET); + my $ca_cert_size = axtlsp::ssl_get_config( + $axtlsp::SSL_MAX_CA_CERT_CFG_OFFSET); + + printf("unknown option %s\n", $option); + printf("usage: s_server [args ...]\n"); + printf(" -accept arg\t- port to accept on (default is 4433)\n"); + printf(" -quiet\t\t- No server output\n"); + + if ($build_mode >= $axtlsp::SSL_BUILD_SERVER_ONLY) + { + printf(" -cert arg\t- certificate file to add (in addition to default)". + " to chain -\n". + "\t\t Can repeat up to %d times\n", $cert_size); + printf(" -key arg\t- Private key file to use - default DER format\n"); + printf(" -pass\t\t- private key file pass phrase source\n"); + } + + if ($build_mode >= $axtlsp::SSL_BUILD_ENABLE_VERIFICATION) + { + printf(" -verify\t- turn on peer certificate verification\n"); + printf(" -CAfile arg\t- Certificate authority - default DER format\n"); + printf("\t\t Can repeat up to %d times\n", $ca_cert_size); + } + + if ($build_mode == $axtlsp::SSL_BUILD_FULL_MODE) + { + printf(" -debug\t\t- Print more output\n"); + printf(" -state\t\t- Show state messages\n"); + printf(" -show-rsa\t- Show RSA state\n"); + } + + exit 1; +} + +# +# We've had some sort of command-line error. Print out the client options. +# +sub print_client_options +{ + my ($build_mode, $option) = @_; + my $cert_size = axtlsp::ssl_get_config($axtlsp::SSL_MAX_CERT_CFG_OFFSET); + my $ca_cert_size = axtlsp::ssl_get_config( + $axtlsp::SSL_MAX_CA_CERT_CFG_OFFSET); + + printf("unknown option %s\n", $option); + + if ($build_mode >= $axtlsp::SSL_BUILD_ENABLE_CLIENT) + { + printf("usage: s_client [args ...]\n"); + printf(" -connect host:port - who to connect to (default ". + "is localhost:4433)\n"); + printf(" -verify\t- turn on peer certificate verification\n"); + printf(" -cert arg\t- certificate file to use - default DER format\n"); + printf(" -key arg\t- Private key file to use - default DER format\n"); + printf("\t\t Can repeat up to %d times\n", $cert_size); + printf(" -CAfile arg\t- Certificate authority - default DER format\n"); + printf("\t\t Can repeat up to %d times\n", $ca_cert_size); + printf(" -quiet\t\t- No client output\n"); + printf(" -pass\t\t- private key file pass phrase source\n"); + printf(" -reconnect\t- Drop and re-make the connection ". + "with the same Session-ID\n"); + + if ($build_mode == $axtlsp::SSL_BUILD_FULL_MODE) + { + printf(" -debug\t\t- Print more output\n"); + printf(" -state\t\t- Show state messages\n"); + printf(" -show-rsa\t- Show RSA state\n"); + } + } + else + { + printf("Change configuration to allow this feature\n"); + } + + exit 1; +} + +# +# Display what cipher we are using +# +sub display_cipher +{ + my ($ssl) = @_; + printf("CIPHER is "); + my $cipher_id = axtlsp::ssl_get_cipher_id($ssl); + + if ($cipher_id == $axtlsp::SSL_AES128_SHA) + { + printf("AES128-SHA"); + } + elsif ($cipher_id == $axtlsp::SSL_AES256_SHA) + { + printf("AES256-SHA"); + } + elsif ($axtlsp::SSL_AES128_SHA256) + { + printf("AES128-SHA256"); + } + elsif ($axtlsp::SSL_AES256_SHA256) + { + printf("AES256-SHA256"); + } + else + { + printf("Unknown - %d", $cipher_id); + } + + printf("\n"); +} + +# +# Display what session id we have. +# +sub display_session_id +{ + my ($ssl) = @_; + my $session_id = axtlsp::ssl_get_session_id($ssl); + if (length($$session_id) > 0) + { + printf("-----BEGIN SSL SESSION PARAMETERS-----\n"); + printf(unpack("H*", $$session_id)); + printf("\n-----END SSL SESSION PARAMETERS-----\n"); + } +} diff --git a/samples/vbnet/axssl.vb b/samples/vbnet/axssl.vb new file mode 100644 index 000000000..7e5d68277 --- /dev/null +++ b/samples/vbnet/axssl.vb @@ -0,0 +1,702 @@ +' +' Copyright (c) 2007-2016, Cameron Rich +' +' All rights reserved. +' +' Redistribution and use in source and binary forms, with or without +' modification, are permitted provided that the following conditions are met: +' +' * Redistributions of source code must retain the above copyright notice, +' this list of conditions and the following disclaimer. +' * Redistributions in binary form must reproduce the above copyright +' notice, this list of conditions and the following disclaimer in the +' documentation and/or other materials provided with the distribution. +' * Neither the name of the axTLS project nor the names of its +' contributors may be used to endorse or promote products derived +' from this software without specific prior written permission. +' +' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +' CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +' TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +' OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +' NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +' THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +' + +' +' Demonstrate the use of the axTLS library in VB.NET with a set of +' command-line parameters similar to openssl. In fact, openssl clients +' should be able to communicate with axTLS servers and visa-versa. +' +' This code has various bits enabled depending on the configuration. To enable +' the most interesting version, compile with the 'full mode' enabled. +' +' To see what options you have, run the following: +' > axssl.vbnet.exe s_server -? +' > axssl.vbnet.exe s_client -? +' +' The axtls shared library must be in the same directory or be found +' by the OS. +' + +Imports System +Imports System.Net +Imports System.Net.Sockets +Imports Microsoft.VisualBasic +Imports axTLSvb + +Public Class axssl + ' + ' do_server() + ' + Public Sub do_server(ByVal build_mode As Integer, _ + ByVal args() As String) + Dim i As Integer = 1 + Dim port As Integer = 4433 + Dim options As Integer = axtls.SSL_DISPLAY_CERTS + Dim quiet As Boolean = False + Dim password As String = Nothing + Dim private_key_file As String = Nothing + + ' organise the cert/ca_cert lists + Dim cert_size As Integer = SSLUtil.MaxCerts() + Dim ca_cert_size As Integer = SSLUtil.MaxCACerts() + Dim cert(cert_size) As String + Dim ca_cert(ca_cert_size) As String + Dim cert_index As Integer = 0 + Dim ca_cert_index As Integer = 0 + + While i < args.Length + If args(i) = "-accept" Then + If i >= args.Length-1 + print_server_options(build_mode, args(i)) + End If + + i += 1 + port = Int32.Parse(args(i)) + ElseIf args(i) = "-quiet" + quiet = True + options = options And Not axtls.SSL_DISPLAY_CERTS + ElseIf build_mode >= axtls.SSL_BUILD_SERVER_ONLY + If args(i) = "-cert" + If i >= args.Length-1 Or cert_index >= cert_size + print_server_options(build_mode, args(i)) + End If + + i += 1 + cert(cert_index) = args(i) + cert_index += 1 + ElseIf args(i) = "-key" + If i >= args.Length-1 + print_server_options(build_mode, args(i)) + End If + + i += 1 + private_key_file = args(i) + options = options Or axtls.SSL_NO_DEFAULT_KEY + ElseIf args(i) = "-pass" + If i >= args.Length-1 + print_server_options(build_mode, args(i)) + End If + + i += 1 + password = args(i) + ElseIf build_mode >= axtls.SSL_BUILD_ENABLE_VERIFICATION + If args(i) = "-verify" Then + options = options Or axtls.SSL_CLIENT_AUTHENTICATION + ElseIf args(i) = "-CAfile" + If i >= args.Length-1 Or _ + ca_cert_index >= ca_cert_size Then + print_server_options(build_mode, args(i)) + End If + + i += 1 + ca_cert(ca_cert_index) = args(i) + ca_cert_index += 1 + ElseIf build_mode = axtls.SSL_BUILD_FULL_MODE + If args(i) = "-debug" Then + options = options Or axtls.SSL_DISPLAY_BYTES + ElseIf args(i) = "-state" + options = options Or axtls.SSL_DISPLAY_STATES + ElseIf args(i) = "-show-rsa" + options = options Or axtls.SSL_DISPLAY_RSA + Else + print_server_options(build_mode, args(i)) + End If + Else + print_server_options(build_mode, args(i)) + End If + Else + print_server_options(build_mode, args(i)) + End If + End If + + i += 1 + End While + + ' Create socket for incoming connections + Dim ep As IPEndPoint = New IPEndPoint(IPAddress.Any, port) + Dim server_sock As TcpListener = New TcpListener(ep) + server_sock.Start() + + '********************************************************************* + ' This is where the interesting stuff happens. Up until now we've + ' just been setting up sockets etc. Now we do the SSL handshake. + '*********************************************************************/ + Dim ssl_ctx As SSLServer = New SSLServer(options, _ + axtls.SSL_DEFAULT_SVR_SESS) + + If ssl_ctx Is Nothing Then + Console.Error.WriteLine("Error: Server context is invalid") + Environment.Exit(1) + End If + + If private_key_file <> Nothing Then + Dim obj_type As Integer = axtls.SSL_OBJ_RSA_KEY + + If private_key_file.EndsWith(".p8") Then + obj_type = axtls.SSL_OBJ_PKCS8 + Else If (private_key_file.EndsWith(".p12")) + obj_type = axtls.SSL_OBJ_PKCS12 + End If + + If ssl_ctx.ObjLoad(obj_type, private_key_file, _ + password) <> axtls.SSL_OK Then + Console.Error.WriteLine("Error: Private key '" & _ + private_key_file & "' is undefined.") + Environment.Exit(1) + End If + End If + + For i = 0 To cert_index-1 + If ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CERT, _ + cert(i), Nothing) <> axtls.SSL_OK Then + Console.WriteLine("Certificate '" & cert(i) & _ + "' is undefined.") + Environment.Exit(1) + End If + Next + + For i = 0 To ca_cert_index-1 + If ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CACERT, _ + ca_cert(i), Nothing) <> axtls.SSL_OK Then + Console.WriteLine("Certificate '" & ca_cert(i) & _ + "' is undefined.") + Environment.Exit(1) + End If + Next + + Dim buf As Byte() = Nothing + Dim res As Integer + Dim ssl As SSL + + While 1 + If Not quiet Then + Console.WriteLine("ACCEPT") + End If + + Dim client_sock As Socket = server_sock.AcceptSocket() + + ssl = ssl_ctx.Connect(client_sock) + + ' do the actual SSL handshake + While 1 + res = ssl_ctx.Read(ssl, buf) + If res <> axtls.SSL_OK Then + Exit While + End If + + ' check when the connection has been established + If ssl.HandshakeStatus() = axtls.SSL_OK + Exit While + End If + + ' could do something else here + End While + + If res = axtls.SSL_OK Then ' connection established and ok + If Not quiet + display_session_id(ssl) + display_cipher(ssl) + End If + + ' now read (and display) whatever the client sends us + While 1 + ' keep reading until we get something interesting + While 1 + res = ssl_ctx.Read(ssl, buf) + If res <> axtls.SSL_OK Then + Exit While + End If + + ' could do something else here + End While + + If res < axtls.SSL_OK + If Not quiet + Console.WriteLine("CONNECTION CLOSED") + End If + + Exit While + End If + + ' convert to String + Dim str(res) As Char + For i = 0 To res-1 + str(i) = Chr(buf(i)) + Next + + Console.Write(str) + End While + ElseIf Not quiet + SSLUtil.DisplayError(res) + End If + + ' client was disconnected or the handshake failed. */ + ssl.Dispose() + client_sock.Close() + End While + + ssl_ctx.Dispose() + End Sub + + ' + ' do_client() + ' + Public Sub do_client(ByVal build_mode As Integer, _ + ByVal args() As String) + + If build_mode < axtls.SSL_BUILD_ENABLE_CLIENT Then + print_client_options(build_mode, args(1)) + End If + + Dim i As Integer = 1 + Dim res As Integer + Dim port As Integer = 4433 + Dim quiet As Boolean = False + Dim password As String = Nothing + Dim reconnect As Integer = 0 + Dim private_key_file As String = Nothing + Dim hostname As String = "127.0.0.1" + + ' organise the cert/ca_cert lists + Dim ssl As SSL = Nothing + Dim cert_size As Integer = SSLUtil.MaxCerts() + Dim ca_cert_size As Integer = SSLUtil.MaxCACerts() + Dim cert(cert_size) As String + Dim ca_cert(ca_cert_size) As String + Dim cert_index As Integer = 0 + Dim ca_cert_index As Integer = 0 + + Dim options As Integer = _ + axtls.SSL_SERVER_VERIFY_LATER Or axtls.SSL_DISPLAY_CERTS + Dim session_id As Byte() = Nothing + + While i < args.Length + If args(i) = "-connect" Then + Dim host_port As String + + If i >= args.Length-1 + print_client_options(build_mode, args(i)) + End If + + i += 1 + host_port = args(i) + + Dim index_colon As Integer = host_port.IndexOf(":"C) + If index_colon < 0 Then + print_client_options(build_mode, args(i)) + End If + + hostname = New String(host_port.ToCharArray(), _ + 0, index_colon) + port = Int32.Parse(New String(host_port.ToCharArray(), _ + index_colon+1, host_port.Length-index_colon-1)) + ElseIf args(i) = "-cert" + If i >= args.Length-1 Or cert_index >= cert_size Then + print_client_options(build_mode, args(i)) + End If + + i += 1 + cert(cert_index) = args(i) + cert_index += 1 + ElseIf args(i) = "-key" + If i >= args.Length-1 + print_client_options(build_mode, args(i)) + End If + + i += 1 + private_key_file = args(i) + options = options Or axtls.SSL_NO_DEFAULT_KEY + ElseIf args(i) = "-CAfile" + If i >= args.Length-1 Or ca_cert_index >= ca_cert_size + print_client_options(build_mode, args(i)) + End If + + i += 1 + ca_cert(ca_cert_index) = args(i) + ca_cert_index += 1 + ElseIf args(i) = "-verify" + options = options And Not axtls.SSL_SERVER_VERIFY_LATER + ElseIf args(i) = "-reconnect" + reconnect = 4 + ElseIf args(i) = "-quiet" + quiet = True + options = options And Not axtls.SSL_DISPLAY_CERTS + ElseIf args(i) = "-pass" + If i >= args.Length-1 + print_client_options(build_mode, args(i)) + End If + + i += 1 + password = args(i) + ElseIf build_mode = axtls.SSL_BUILD_FULL_MODE + If args(i) = "-debug" Then + options = options Or axtls.SSL_DISPLAY_BYTES + ElseIf args(i) = "-state" + options = options Or axtls.SSL_DISPLAY_STATES + ElseIf args(i) = "-show-rsa" + options = options Or axtls.SSL_DISPLAY_RSA + Else + print_client_options(build_mode, args(i)) + End If + Else ' don't know what this is + print_client_options(build_mode, args(i)) + End If + + i += 1 + End While + + 'Dim hostInfo As IPHostEntry = Dns.Resolve(hostname) + Dim hostInfo As IPHostEntry = Dns.GetHostEntry(hostname) + Dim addresses As IPAddress() = hostInfo.AddressList + Dim ep As IPEndPoint = New IPEndPoint(addresses(0), port) + Dim client_sock As Socket = New Socket(AddressFamily.InterNetwork, _ + SocketType.Stream, ProtocolType.Tcp) + client_sock.Connect(ep) + + If Not client_sock.Connected Then + Console.WriteLine("could not connect") + Environment.Exit(1) + End If + + If Not quiet Then + Console.WriteLine("CONNECTED") + End If + + '********************************************************************* + ' This is where the interesting stuff happens. Up until now we've + ' just been setting up sockets etc. Now we do the SSL handshake. + '*********************************************************************/ + Dim ssl_ctx As SSLClient = New SSLClient(options, _ + axtls.SSL_DEFAULT_CLNT_SESS) + + If ssl_ctx Is Nothing Then + Console.Error.WriteLine("Error: Client context is invalid") + Environment.Exit(1) + End If + + If private_key_file <> Nothing Then + Dim obj_type As Integer = axtls.SSL_OBJ_RSA_KEY + + If private_key_file.EndsWith(".p8") Then + obj_type = axtls.SSL_OBJ_PKCS8 + Else If (private_key_file.EndsWith(".p12")) + obj_type = axtls.SSL_OBJ_PKCS12 + End If + + If ssl_ctx.ObjLoad(obj_type, private_key_file, _ + password) <> axtls.SSL_OK Then + Console.Error.WriteLine("Error: Private key '" & _ + private_key_file & "' is undefined.") + Environment.Exit(1) + End If + End If + + For i = 0 To cert_index-1 + If ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CERT, _ + cert(i), Nothing) <> axtls.SSL_OK Then + Console.WriteLine("Certificate '" & cert(i) & _ + "' is undefined.") + Environment.Exit(1) + End If + Next + + For i = 0 To ca_cert_index-1 + If ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CACERT, _ + ca_cert(i), Nothing) <> axtls.SSL_OK Then + Console.WriteLine("Certificate '" & ca_cert(i) & _ + "' is undefined.") + Environment.Exit(1) + End If + Next + + ' Try session resumption? + If reconnect > 0 Then + While reconnect > 0 + reconnect -= 1 + ssl = ssl_ctx.Connect(client_sock, session_id) + + res = ssl.HandshakeStatus() + If res <> axtls.SSL_OK Then + If Not quiet Then + SSLUtil.DisplayError(res) + End If + + ssl.Dispose() + Environment.Exit(1) + End If + + display_session_id(ssl) + session_id = ssl.GetSessionId() + + If reconnect > 0 Then + ssl.Dispose() + client_sock.Close() + + ' and reconnect + client_sock = New Socket(AddressFamily.InterNetwork, _ + SocketType.Stream, ProtocolType.Tcp) + client_sock.Connect(ep) + End If + End While + Else + ssl = ssl_ctx.Connect(client_sock, Nothing) + End If + + ' check the return status + res = ssl.HandshakeStatus() + If res <> axtls.SSL_OK Then + If Not quiet Then + SSLUtil.DisplayError(res) + End If + + Environment.Exit(1) + End If + + If Not quiet Then + Dim common_name As String = _ + ssl.GetCertificateDN(axtls.SSL_X509_CERT_COMMON_NAME) + + If common_name <> Nothing + Console.WriteLine("Common Name:" & _ + ControlChars.Tab & ControlChars.Tab & _ + ControlChars.Tab & common_name) + End If + + display_session_id(ssl) + display_cipher(ssl) + End If + + While (1) + Dim user_input As String = Console.ReadLine() + + If user_input = Nothing Then + Exit While + End If + + Dim buf(user_input.Length+1) As Byte + buf(buf.Length-2) = Asc(ControlChars.Lf) ' add the carriage return + buf(buf.Length-1) = 0 ' null terminate + + For i = 0 To user_input.Length-1 + buf(i) = Asc(user_input.Chars(i)) + Next + + res = ssl_ctx.Write(ssl, buf, buf.Length) + If res < axtls.SSL_OK Then + If Not quiet Then + SSLUtil.DisplayError(res) + End If + + Exit While + End If + End While + + ssl_ctx.Dispose() + End Sub + + ' + ' Display what cipher we are using + ' + Private Sub display_cipher(ByVal ssl As SSL) + Console.Write("CIPHER is ") + + Select ssl.GetCipherId() + Case axtls.SSL_AES128_SHA + Console.WriteLine("AES128-SHA") + + Case axtls.SSL_AES256_SHA + Console.WriteLine("AES256-SHA") + + Case axtls.SSL_AES128_SHA256 + Console.WriteLine("AES128-SHA256") + + Case axtls.SSL_AES256_SHA256 + Console.WriteLine("AES256-SHA256") + + Case Else + Console.WriteLine("Unknown - " & ssl.GetCipherId()) + End Select + End Sub + + ' + ' Display what session id we have. + ' + Private Sub display_session_id(ByVal ssl As SSL) + Dim session_id As Byte() = ssl.GetSessionId() + + If session_id.Length > 0 Then + Console.WriteLine("-----BEGIN SSL SESSION PARAMETERS-----") + Dim b As Byte + For Each b In session_id + Console.Write("{0:x02}", b) + Next + + Console.WriteLine() + Console.WriteLine("-----END SSL SESSION PARAMETERS-----") + End If + End Sub + + ' + ' We've had some sort of command-line error. Print out the basic options. + ' + Public Sub print_options(ByVal options As String) + Console.WriteLine("axssl: Error: '" & options & _ + "' is an invalid command.") + Console.WriteLine("usage: axssl.vbnet [s_server|s_client|" & _ + "version] [args ...]") + Environment.Exit(1) + End Sub + + ' + ' We've had some sort of command-line error. Print out the server options. + ' + Private Sub print_server_options(ByVal build_mode As Integer, _ + ByVal options As String) + Dim cert_size As Integer = SSLUtil.MaxCerts() + Dim ca_cert_size As Integer = SSLUtil.MaxCACerts() + + Console.WriteLine("unknown option " & options) + Console.WriteLine("usage: s_server [args ...]") + Console.WriteLine(" -accept arg" & ControlChars.Tab & _ + "- port to accept on (default is 4433)") + Console.WriteLine(" -quiet" & ControlChars.Tab & ControlChars.Tab & _ + "- No server output") + If build_mode >= axtls.SSL_BUILD_SERVER_ONLY + Console.WriteLine(" -cert arg" & ControlChars.Tab & _ + "- certificate file to add (in addition to default) to chain -") + Console.WriteLine(ControlChars.Tab & ControlChars.Tab & _ + " Can repeat up to " & cert_size & " times") + Console.WriteLine(" -key arg" & ControlChars.Tab & _ + "- Private key file to use") + Console.WriteLine(" -pass" & ControlChars.Tab & ControlChars.Tab & _ + "- private key file pass phrase source") + End If + + If build_mode >= axtls.SSL_BUILD_ENABLE_VERIFICATION + Console.WriteLine(" -verify" & ControlChars.Tab & _ + "- turn on peer certificate verification") + Console.WriteLine(" -CAfile arg" & ControlChars.Tab & _ + "- Certificate authority") + Console.WriteLine(ControlChars.Tab & ControlChars.Tab & _ + " Can repeat up to " & ca_cert_size & " times") + End If + + If build_mode = axtls.SSL_BUILD_FULL_MODE + Console.WriteLine(" -debug" & _ + ControlChars.Tab & ControlChars.Tab & _ + "- Print more output") + Console.WriteLine(" -state" & _ + ControlChars.Tab & ControlChars.Tab & _ + "- Show state messages") + Console.WriteLine(" -show-rsa" & _ + ControlChars.Tab & "- Show RSA state") + End If + + Environment.Exit(1) + End Sub + + ' + ' We've had some sort of command-line error. Print out the client options. + ' + Private Sub print_client_options(ByVal build_mode As Integer, _ + ByVal options As String) + Dim cert_size As Integer = SSLUtil.MaxCerts() + Dim ca_cert_size As Integer = SSLUtil.MaxCACerts() + + Console.WriteLine("unknown option " & options) + + If build_mode >= axtls.SSL_BUILD_ENABLE_CLIENT Then + Console.WriteLine("usage: s_client [args ...]") + Console.WriteLine(" -connect host:port - who to connect to " & _ + "(default is localhost:4433)") + Console.WriteLine(" -verify" & ControlChars.Tab & _ + "- turn on peer certificate verification") + Console.WriteLine(" -cert arg" & ControlChars.Tab & _ + "- certificate file to use") + Console.WriteLine(ControlChars.Tab & ControlChars.Tab & _ + " Can repeat up to " & cert_size & " times") + Console.WriteLine(" -key arg" & ControlChars.Tab & _ + "- Private key file to use") + Console.WriteLine(" -CAfile arg" & ControlChars.Tab & _ + "- Certificate authority") + Console.WriteLine(ControlChars.Tab & ControlChars.Tab & _ + " Can repeat up to " & ca_cert_size & " times") + Console.WriteLine(" -quiet" & _ + ControlChars.Tab & ControlChars.Tab & "- No client output") + Console.WriteLine(" -pass" & ControlChars.Tab & _ + ControlChars.Tab & _ + "- private key file pass phrase source") + Console.WriteLine(" -reconnect" & ControlChars.Tab & _ + "- Drop and re-make the " & _ + "connection with the same Session-ID") + + If build_mode = axtls.SSL_BUILD_FULL_MODE Then + Console.WriteLine(" -debug" & _ + ControlChars.Tab & ControlChars.Tab & _ + "- Print more output") + Console.WriteLine(" -state" & _ + ControlChars.Tab & ControlChars.Tab & _ + "- Show state messages") + Console.WriteLine(" -show-rsa" & ControlChars.Tab & _ + "- Show RSA state") + End If + Else + Console.WriteLine("Change configuration to allow this feature") + End If + + Environment.Exit(1) + End Sub + +End Class + +Public Module MyMain + Function Main(ByVal args() As String) As Integer + Dim runner As axssl = New axssl() + + If args.Length = 1 And args(0) = "version" Then + Console.WriteLine("axssl.vbnet " & SSLUtil.Version()) + Environment.Exit(0) + End If + + If args.Length < 1 + runner.print_options("") + ElseIf args(0) <> "s_server" And args(0) <> "s_client" + runner.print_options(args(0)) + End If + + Dim build_mode As Integer = SSLUtil.BuildMode() + + If args(0) = "s_server" Then + runner.do_server(build_mode, args) + Else + runner.do_client(build_mode, args) + End If + End Function +End Module diff --git a/ssl/asn1.c b/ssl/asn1.c index 0a139bb51..8faefe23a 100644 --- a/ssl/asn1.c +++ b/ssl/asn1.c @@ -243,13 +243,16 @@ static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t) 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 */ + 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'); + tm.tm_hour = (buf[t_offset+6] - '0')*10 + (buf[t_offset+7] - '0'); + tm.tm_min = (buf[t_offset+8] - '0')*10 + (buf[t_offset+9] - '0'); + tm.tm_sec = (buf[t_offset+10] - '0')*10 + (buf[t_offset+11] - '0'); *t = mktime(&tm); *offset += len; ret = X509_OK; @@ -274,13 +277,14 @@ static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t) } else { - tm.tm_year = abs_year - 1900; - tm.tm_mon = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0') - 1; - tm.tm_mday = (buf[t_offset+6] - '0')*10 + (buf[t_offset+7] - '0'); - tm.tm_hour = (buf[t_offset+8] - '0')*10 + (buf[t_offset+9] - '0'); - tm.tm_min = (buf[t_offset+10] - '0')*10 + (buf[t_offset+11] - '0'); - tm.tm_sec = (buf[t_offset+12] - '0')*10 + (buf[t_offset+13] - '0'); - *t = mktime(&tm); + tm.tm_year = abs_year - 1900; + tm.tm_mon = (buf[t_offset+4] - '0')*10 + + (buf[t_offset+5] - '0') - 1; + tm.tm_mday = (buf[t_offset+6] - '0')*10 + (buf[t_offset+7] - '0'); + tm.tm_hour = (buf[t_offset+8] - '0')*10 + (buf[t_offset+9] - '0'); + tm.tm_min = (buf[t_offset+10] - '0')*10 + (buf[t_offset+11] - '0'); + tm.tm_sec = (buf[t_offset+12] - '0')*10 + (buf[t_offset+13] - '0'); + *t = mktime(&tm); } *offset += len; diff --git a/ssl/ssl.h b/ssl/ssl.h index 09d205a8d..71f92f0f5 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -231,7 +231,7 @@ EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx); * @return ssl_ext Pointer to SSL_EXTENSIONS structure * */ -EXP_FUNC SSL_EXTENSIONS * STDCALL ssl_ext_new(); +EXP_FUNC SSL_EXTENSIONS * STDCALL ssl_ext_new(void); /** * @brief Set the host name for SNI extension @@ -281,7 +281,8 @@ EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd); * can be null if no session resumption is being used or required. This option * is not used in skeleton mode. * @param sess_id_size The size of the session id (max 32) - * @param ssl_ext pointer to a structure with the activated SSL extensions and their values + * @param ssl_ext pointer to a structure with the activated SSL extensions + * and their values * @return An SSL object reference. Use ssl_handshake_status() to check * if a handshake succeeded. */ @@ -373,8 +374,8 @@ EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl); * @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) + * - SSL_AES128_SHA256 (0x3c) + * - SSL_AES256_SHA256 (0x3d) */ EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl); diff --git a/ssl/test/ssltest.c b/ssl/test/ssltest.c index 98ba3e192..b7a2c9b8b 100644 --- a/ssl/test/ssltest.c +++ b/ssl/test/ssltest.c @@ -1587,7 +1587,7 @@ static int SSL_client_test( #endif } - usleep(200000); /* allow server to start */ + usleep(500000); /* allow server to start */ if (*ssl_ctx == NULL) { @@ -1649,7 +1649,8 @@ static int SSL_client_test( goto client_test_exit; } - ssl = ssl_client_new(*ssl_ctx, client_fd, session_id, sizeof(session_id)); + ssl = ssl_client_new(*ssl_ctx, client_fd, + session_id, sizeof(session_id), NULL); /* check the return status */ if ((ret = ssl_handshake_status(ssl))) @@ -1938,7 +1939,7 @@ static void do_basic(void) "../ssl/test/axTLS.ca_x509.cer", NULL)) goto error; - ssl_clnt = ssl_client_new(ssl_clnt_ctx, client_fd, NULL, 0); + ssl_clnt = ssl_client_new(ssl_clnt_ctx, client_fd, NULL, 0, NULL); /* check the return status */ if (ssl_handshake_status(ssl_clnt) < 0) @@ -2062,7 +2063,7 @@ static void do_unblocked(void) "../ssl/test/axTLS.ca_x509.cer", NULL)) goto error; - ssl_clnt = ssl_client_new(ssl_clnt_ctx, client_fd, NULL, 0); + ssl_clnt = ssl_client_new(ssl_clnt_ctx, client_fd, NULL, 0, NULL); while (ssl_handshake_status(ssl_clnt) != SSL_OK) { @@ -2182,7 +2183,7 @@ void do_multi_clnt(multi_t *multi_data) goto client_test_exit; usleep(200000); - ssl = ssl_client_new(multi_data->ssl_clnt_ctx, client_fd, NULL, 0); + ssl = ssl_client_new(multi_data->ssl_clnt_ctx, client_fd, NULL, 0, NULL); if ((res = ssl_handshake_status(ssl))) { diff --git a/ssl/tls1.c b/ssl/tls1.c index 7b84ef277..b8a813bc5 100644 --- a/ssl/tls1.c +++ b/ssl/tls1.c @@ -158,11 +158,13 @@ EXP_FUNC SSL_EXTENSIONS * STDCALL ssl_ext_new() */ EXP_FUNC void STDCALL ssl_ext_free(SSL_EXTENSIONS *ssl_ext) { - if(ssl_ext == NULL ) { + if (ssl_ext == NULL ) + { return; } - if(ssl_ext->host_name != NULL) { + if (ssl_ext->host_name != NULL) + { free(ssl_ext->host_name); } free(ssl_ext); diff --git a/ssl/tls1.h b/ssl/tls1.h index 6565625ae..9f4926876 100644 --- a/ssl/tls1.h +++ b/ssl/tls1.h @@ -173,9 +173,12 @@ typedef struct uint8_t key_block_generated; } DISPOSABLE_CTX; -typedef struct { +typedef struct +{ char *host_name; /* Needed for the SNI support */ - uint16_t max_fragment_size; /* Needed for the Max Fragment Size Extension. Allowed values: 2^9, 2^10 .. 2^14 */ + /* Needed for the Max Fragment Size Extension. + Allowed values: 2^9, 2^10 .. 2^14 */ + uint16_t max_fragment_size; } SSL_EXTENSIONS; struct _SSL diff --git a/ssl/tls1_clnt.c b/ssl/tls1_clnt.c index fab26676a..f670e704f 100644 --- a/ssl/tls1_clnt.c +++ b/ssl/tls1_clnt.c @@ -195,9 +195,8 @@ static int send_client_hello(SSL *ssl) time_t tm = time(NULL); uint8_t *tm_ptr = &buf[6]; /* time will go here */ int i, offset, ext_offset; - uint16_t ext_len; /* extensions total length */ + int ext_len = 0; - ext_len = 0; buf[0] = HS_CLIENT_HELLO; buf[1] = 0; @@ -257,39 +256,44 @@ static int send_client_hello(SSL *ssl) ext_len += sizeof(g_sig_alg); } - if (ssl->extensions != NULL) { + if (ssl->extensions != NULL) + { /* send the host name if specified */ - if (ssl->extensions->host_name != NULL) { - unsigned int host_len = strlen(ssl->extensions->host_name); - - buf[offset++] = 0; - buf[offset++] = SSL_EXT_SERVER_NAME; /* server_name(0) (65535) */ - buf[offset++] = 0; - buf[offset++] = host_len + 5; /* server_name length */ - buf[offset++] = 0; - buf[offset++] = host_len + 3; /* server_list length */ - buf[offset++] = 0; /* host_name(0) (255) */ - buf[offset++] = 0; - buf[offset++] = host_len; /* host_name length */ - strncpy((char*) &buf[offset], ssl->extensions->host_name, host_len); - offset += host_len; - ext_len += host_len + 9; + if (ssl->extensions->host_name != NULL) + { + size_t host_len = strlen(ssl->extensions->host_name); + buf[offset++] = 0; + buf[offset++] = SSL_EXT_SERVER_NAME; /* server_name(0) (65535) */ + buf[offset++] = 0; + buf[offset++] = host_len + 5; /* server_name length */ + buf[offset++] = 0; + buf[offset++] = host_len + 3; /* server_list length */ + buf[offset++] = 0; /* host_name(0) (255) */ + buf[offset++] = 0; + buf[offset++] = host_len; /* host_name length */ + strncpy((char*) &buf[offset], ssl->extensions->host_name, host_len); + offset += host_len; + ext_len += host_len + 9; } - if (ssl->extensions->max_fragment_size) { - buf[offset++] = 0; - buf[offset++] = SSL_EXT_MAX_FRAGMENT_SIZE; + if (ssl->extensions->max_fragment_size) + { + buf[offset++] = 0; + buf[offset++] = SSL_EXT_MAX_FRAGMENT_SIZE; - buf[offset++] = 0; // size of data - buf[offset++] = 2; + buf[offset++] = 0; // size of data + buf[offset++] = 2; - buf[offset++] = (uint8_t)((ssl->extensions->max_fragment_size >> 8) & 0xff); - buf[offset++] = (uint8_t)(ssl->extensions->max_fragment_size & 0xff); - ext_len += 6; + buf[offset++] = (uint8_t) + ((ssl->extensions->max_fragment_size >> 8) & 0xff); + buf[offset++] = (uint8_t) + (ssl->extensions->max_fragment_size & 0xff); + ext_len += 6; } } - if(ext_len > 0) { + if (ext_len > 0) + { // update the extensions length value buf[ext_offset] = (uint8_t) ((ext_len >> 8) & 0xff); buf[ext_offset + 1] = (uint8_t) (ext_len & 0xff);