summaryrefslogtreecommitdiffstats
path: root/lib/libssl/src/demos
diff options
context:
space:
mode:
authorbeck <beck@openbsd.org>2002-05-15 02:29:01 +0000
committerbeck <beck@openbsd.org>2002-05-15 02:29:01 +0000
commitda347917d3d3e5d3ece379d298f4e183b4828151 (patch)
tree4667bec6fb5a5191ed165d4bf727adbb97475bcb /lib/libssl/src/demos
parentOpenSSL 0.9.7 (diff)
downloadwireguard-openbsd-da347917d3d3e5d3ece379d298f4e183b4828151.tar.xz
wireguard-openbsd-da347917d3d3e5d3ece379d298f4e183b4828151.zip
OpenSSL 0.9.7 stable 2002 05 08 merge
Diffstat (limited to 'lib/libssl/src/demos')
-rw-r--r--lib/libssl/src/demos/asn1/README.ASN17
-rw-r--r--lib/libssl/src/demos/asn1/ocsp.c366
-rw-r--r--lib/libssl/src/demos/b64.c4
-rw-r--r--lib/libssl/src/demos/easy_tls/Makefile123
-rw-r--r--lib/libssl/src/demos/easy_tls/README65
-rw-r--r--lib/libssl/src/demos/easy_tls/cacerts.pem18
-rw-r--r--lib/libssl/src/demos/easy_tls/cert.pem31
-rw-r--r--lib/libssl/src/demos/easy_tls/easy-tls.c1235
-rw-r--r--lib/libssl/src/demos/easy_tls/easy-tls.h57
-rw-r--r--lib/libssl/src/demos/easy_tls/test.c244
-rw-r--r--lib/libssl/src/demos/easy_tls/test.h11
-rw-r--r--lib/libssl/src/demos/maurice/example1.c8
-rw-r--r--lib/libssl/src/demos/maurice/example3.c6
-rw-r--r--lib/libssl/src/demos/maurice/loadkeys.c9
-rw-r--r--lib/libssl/src/demos/pkcs12/README3
-rw-r--r--lib/libssl/src/demos/pkcs12/pkread.c61
-rw-r--r--lib/libssl/src/demos/pkcs12/pkwrite.c46
-rw-r--r--lib/libssl/src/demos/sign/sign.c4
-rw-r--r--lib/libssl/src/demos/ssl/cli.cpp4
-rw-r--r--lib/libssl/src/demos/ssl/inetdsrv.cpp4
-rw-r--r--lib/libssl/src/demos/ssl/serv.cpp4
-rw-r--r--lib/libssl/src/demos/state_machine/Makefile9
-rw-r--r--lib/libssl/src/demos/state_machine/state_machine.c416
-rw-r--r--lib/libssl/src/demos/tunala/A-client.pem84
-rw-r--r--lib/libssl/src/demos/tunala/A-server.pem84
-rw-r--r--lib/libssl/src/demos/tunala/CA.pem24
-rw-r--r--lib/libssl/src/demos/tunala/INSTALL107
-rw-r--r--lib/libssl/src/demos/tunala/Makefile41
-rw-r--r--lib/libssl/src/demos/tunala/Makefile.am7
-rw-r--r--lib/libssl/src/demos/tunala/README233
-rw-r--r--lib/libssl/src/demos/tunala/autogunk.sh25
-rw-r--r--lib/libssl/src/demos/tunala/autoungunk.sh18
-rw-r--r--lib/libssl/src/demos/tunala/breakage.c66
-rw-r--r--lib/libssl/src/demos/tunala/buffer.c205
-rw-r--r--lib/libssl/src/demos/tunala/cb.c133
-rw-r--r--lib/libssl/src/demos/tunala/configure.in28
-rw-r--r--lib/libssl/src/demos/tunala/ip.c146
-rw-r--r--lib/libssl/src/demos/tunala/sm.c151
-rw-r--r--lib/libssl/src/demos/tunala/tunala.c1093
-rw-r--r--lib/libssl/src/demos/tunala/tunala.h214
-rw-r--r--lib/libssl/src/demos/x509/README3
-rw-r--r--lib/libssl/src/demos/x509/mkcert.c168
-rw-r--r--lib/libssl/src/demos/x509/mkreq.c157
43 files changed, 5698 insertions, 24 deletions
diff --git a/lib/libssl/src/demos/asn1/README.ASN1 b/lib/libssl/src/demos/asn1/README.ASN1
new file mode 100644
index 00000000000..ac497be184a
--- /dev/null
+++ b/lib/libssl/src/demos/asn1/README.ASN1
@@ -0,0 +1,7 @@
+This is a demo of the new ASN1 code. Its an OCSP ASN1 module. Doesn't
+do much yet other than demonstrate what the new ASN1 modules might look
+like.
+
+It wont even compile yet: the new code isn't in place.
+
+
diff --git a/lib/libssl/src/demos/asn1/ocsp.c b/lib/libssl/src/demos/asn1/ocsp.c
new file mode 100644
index 00000000000..0199fe10040
--- /dev/null
+++ b/lib/libssl/src/demos/asn1/ocsp.c
@@ -0,0 +1,366 @@
+/* ocsp.c */
+/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
+ * project 2000.
+ */
+/* ====================================================================
+ * Copyright (c) 2000 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509v3.h>
+
+
+
+
+/* Example of new ASN1 code, OCSP request
+
+ OCSPRequest ::= SEQUENCE {
+ tbsRequest TBSRequest,
+ optionalSignature [0] EXPLICIT Signature OPTIONAL }
+
+ TBSRequest ::= SEQUENCE {
+ version [0] EXPLICIT Version DEFAULT v1,
+ requestorName [1] EXPLICIT GeneralName OPTIONAL,
+ requestList SEQUENCE OF Request,
+ requestExtensions [2] EXPLICIT Extensions OPTIONAL }
+
+ Signature ::= SEQUENCE {
+ signatureAlgorithm AlgorithmIdentifier,
+ signature BIT STRING,
+ certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+
+ Version ::= INTEGER { v1(0) }
+
+ Request ::= SEQUENCE {
+ reqCert CertID,
+ singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
+
+ CertID ::= SEQUENCE {
+ hashAlgorithm AlgorithmIdentifier,
+ issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ issuerKeyHash OCTET STRING, -- Hash of Issuers public key
+ serialNumber CertificateSerialNumber }
+
+ OCSPResponse ::= SEQUENCE {
+ responseStatus OCSPResponseStatus,
+ responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
+
+ OCSPResponseStatus ::= ENUMERATED {
+ successful (0), --Response has valid confirmations
+ malformedRequest (1), --Illegal confirmation request
+ internalError (2), --Internal error in issuer
+ tryLater (3), --Try again later
+ --(4) is not used
+ sigRequired (5), --Must sign the request
+ unauthorized (6) --Request unauthorized
+ }
+
+ ResponseBytes ::= SEQUENCE {
+ responseType OBJECT IDENTIFIER,
+ response OCTET STRING }
+
+ BasicOCSPResponse ::= SEQUENCE {
+ tbsResponseData ResponseData,
+ signatureAlgorithm AlgorithmIdentifier,
+ signature BIT STRING,
+ certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+
+ ResponseData ::= SEQUENCE {
+ version [0] EXPLICIT Version DEFAULT v1,
+ responderID ResponderID,
+ producedAt GeneralizedTime,
+ responses SEQUENCE OF SingleResponse,
+ responseExtensions [1] EXPLICIT Extensions OPTIONAL }
+
+ ResponderID ::= CHOICE {
+ byName [1] Name, --EXPLICIT
+ byKey [2] KeyHash }
+
+ KeyHash ::= OCTET STRING --SHA-1 hash of responder's public key
+ --(excluding the tag and length fields)
+
+ SingleResponse ::= SEQUENCE {
+ certID CertID,
+ certStatus CertStatus,
+ thisUpdate GeneralizedTime,
+ nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
+ singleExtensions [1] EXPLICIT Extensions OPTIONAL }
+
+ CertStatus ::= CHOICE {
+ good [0] IMPLICIT NULL,
+ revoked [1] IMPLICIT RevokedInfo,
+ unknown [2] IMPLICIT UnknownInfo }
+
+ RevokedInfo ::= SEQUENCE {
+ revocationTime GeneralizedTime,
+ revocationReason [0] EXPLICIT CRLReason OPTIONAL }
+
+ UnknownInfo ::= NULL -- this can be replaced with an enumeration
+
+ ArchiveCutoff ::= GeneralizedTime
+
+ AcceptableResponses ::= SEQUENCE OF OBJECT IDENTIFIER
+
+ ServiceLocator ::= SEQUENCE {
+ issuer Name,
+ locator AuthorityInfoAccessSyntax }
+
+ -- Object Identifiers
+
+ id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
+ id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp }
+ id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 }
+ id-pkix-ocsp-nonce OBJECT IDENTIFIER ::= { id-pkix-ocsp 2 }
+ id-pkix-ocsp-crl OBJECT IDENTIFIER ::= { id-pkix-ocsp 3 }
+ id-pkix-ocsp-response OBJECT IDENTIFIER ::= { id-pkix-ocsp 4 }
+ id-pkix-ocsp-nocheck OBJECT IDENTIFIER ::= { id-pkix-ocsp 5 }
+ id-pkix-ocsp-archive-cutoff OBJECT IDENTIFIER ::= { id-pkix-ocsp 6 }
+ id-pkix-ocsp-service-locator OBJECT IDENTIFIER ::= { id-pkix-ocsp 7 }
+
+*/
+
+/* Request Structures */
+
+DECLARE_STACK_OF(Request)
+
+typedef struct {
+ ASN1_INTEGER *version;
+ GENERAL_NAME *requestorName;
+ STACK_OF(Request) *requestList;
+ STACK_OF(X509_EXTENSION) *requestExtensions;
+} TBSRequest;
+
+typedef struct {
+ X509_ALGOR *signatureAlgorithm;
+ ASN1_BIT_STRING *signature;
+ STACK_OF(X509) *certs;
+} Signature;
+
+typedef struct {
+ TBSRequest *tbsRequest;
+ Signature *optionalSignature;
+} OCSPRequest;
+
+typedef struct {
+ X509_ALGOR *hashAlgorithm;
+ ASN1_OCTET_STRING *issuerNameHash;
+ ASN1_OCTET_STRING *issuerKeyHash;
+ ASN1_INTEGER *certificateSerialNumber;
+} CertID;
+
+typedef struct {
+ CertID *reqCert;
+ STACK_OF(X509_EXTENSION) *singleRequestExtensions;
+} Request;
+
+/* Response structures */
+
+typedef struct {
+ ASN1_OBJECT *responseType;
+ ASN1_OCTET_STRING *response;
+} ResponseBytes;
+
+typedef struct {
+ ASN1_ENUMERATED *responseStatus;
+ ResponseBytes *responseBytes;
+} OCSPResponse;
+
+typedef struct {
+ int type;
+ union {
+ X509_NAME *byName;
+ ASN1_OCTET_STRING *byKey;
+ }d;
+} ResponderID;
+
+typedef struct {
+ ASN1_INTEGER *version;
+ ResponderID *responderID;
+ ASN1_GENERALIZEDTIME *producedAt;
+ STACK_OF(SingleResponse) *responses;
+ STACK_OF(X509_EXTENSION) *responseExtensions;
+} ResponseData;
+
+typedef struct {
+ ResponseData *tbsResponseData;
+ X509_ALGOR *signatureAlgorithm;
+ ASN1_BIT_STRING *signature;
+ STACK_OF(X509) *certs;
+} BasicOCSPResponse;
+
+typedef struct {
+ ASN1_GENERALIZEDTIME *revocationTime;
+ ASN1_ENUMERATED * revocationReason;
+} RevokedInfo;
+
+typedef struct {
+ int type;
+ union {
+ ASN1_NULL *good;
+ RevokedInfo *revoked;
+ ASN1_NULL *unknown;
+ } d;
+} CertStatus;
+
+typedef struct {
+ CertID *certID;
+ CertStatus *certStatus;
+ ASN1_GENERALIZEDTIME *thisUpdate;
+ ASN1_GENERALIZEDTIME *nextUpdate;
+ STACK_OF(X509_EXTENSION) *singleExtensions;
+} SingleResponse;
+
+
+typedef struct {
+ X509_NAME *issuer;
+ STACK_OF(ACCESS_DESCRIPTION) *locator;
+} ServiceLocator;
+
+
+/* Now the ASN1 templates */
+
+IMPLEMENT_COMPAT_ASN1(X509);
+IMPLEMENT_COMPAT_ASN1(X509_ALGOR);
+//IMPLEMENT_COMPAT_ASN1(X509_EXTENSION);
+IMPLEMENT_COMPAT_ASN1(GENERAL_NAME);
+IMPLEMENT_COMPAT_ASN1(X509_NAME);
+
+ASN1_SEQUENCE(X509_EXTENSION) = {
+ ASN1_SIMPLE(X509_EXTENSION, object, ASN1_OBJECT),
+ ASN1_OPT(X509_EXTENSION, critical, ASN1_BOOLEAN),
+ ASN1_SIMPLE(X509_EXTENSION, value, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(X509_EXTENSION);
+
+
+ASN1_SEQUENCE(Signature) = {
+ ASN1_SIMPLE(Signature, signatureAlgorithm, X509_ALGOR),
+ ASN1_SIMPLE(Signature, signature, ASN1_BIT_STRING),
+ ASN1_SEQUENCE_OF(Signature, certs, X509)
+} ASN1_SEQUENCE_END(Signature);
+
+ASN1_SEQUENCE(CertID) = {
+ ASN1_SIMPLE(CertID, hashAlgorithm, X509_ALGOR),
+ ASN1_SIMPLE(CertID, issuerNameHash, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(CertID, issuerKeyHash, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(CertID, certificateSerialNumber, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(CertID);
+
+ASN1_SEQUENCE(Request) = {
+ ASN1_SIMPLE(Request, reqCert, CertID),
+ ASN1_EXP_SEQUENCE_OF_OPT(Request, singleRequestExtensions, X509_EXTENSION, 0)
+} ASN1_SEQUENCE_END(Request);
+
+ASN1_SEQUENCE(TBSRequest) = {
+ ASN1_EXP_OPT(TBSRequest, version, ASN1_INTEGER, 0),
+ ASN1_EXP_OPT(TBSRequest, requestorName, GENERAL_NAME, 1),
+ ASN1_SEQUENCE_OF(TBSRequest, requestList, Request),
+ ASN1_EXP_SEQUENCE_OF_OPT(TBSRequest, requestExtensions, X509_EXTENSION, 2)
+} ASN1_SEQUENCE_END(TBSRequest);
+
+ASN1_SEQUENCE(OCSPRequest) = {
+ ASN1_SIMPLE(OCSPRequest, tbsRequest, TBSRequest),
+ ASN1_EXP_OPT(OCSPRequest, optionalSignature, Signature, 0)
+} ASN1_SEQUENCE_END(OCSPRequest);
+
+
+/* Response templates */
+
+ASN1_SEQUENCE(ResponseBytes) = {
+ ASN1_SIMPLE(ResponseBytes, responseType, ASN1_OBJECT),
+ ASN1_SIMPLE(ResponseBytes, response, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(ResponseBytes);
+
+ASN1_SEQUENCE(OCSPResponse) = {
+ ASN1_SIMPLE(OCSPResponse, responseStatus, ASN1_ENUMERATED),
+ ASN1_EXP_OPT(OCSPResponse, responseBytes, ResponseBytes, 0)
+} ASN1_SEQUENCE_END(OCSPResponse);
+
+ASN1_CHOICE(ResponderID) = {
+ ASN1_EXP(ResponderID, d.byName, X509_NAME, 1),
+ ASN1_IMP(ResponderID, d.byKey, ASN1_OCTET_STRING, 2)
+} ASN1_CHOICE_END(ResponderID);
+
+ASN1_SEQUENCE(RevokedInfo) = {
+ ASN1_SIMPLE(RevokedInfo, revocationTime, ASN1_GENERALIZEDTIME),
+ ASN1_EXP_OPT(RevokedInfo, revocationReason, ASN1_ENUMERATED, 0)
+} ASN1_SEQUENCE_END(RevokedInfo);
+
+ASN1_CHOICE(CertStatus) = {
+ ASN1_IMP(CertStatus, d.good, ASN1_NULL, 0),
+ ASN1_IMP(CertStatus, d.revoked, RevokedInfo, 1),
+ ASN1_IMP(CertStatus, d.unknown, ASN1_NULL, 2)
+} ASN1_CHOICE_END(CertStatus);
+
+ASN1_SEQUENCE(SingleResponse) = {
+ ASN1_SIMPLE(SingleResponse, certID, CertID),
+ ASN1_SIMPLE(SingleResponse, certStatus, CertStatus),
+ ASN1_SIMPLE(SingleResponse, thisUpdate, ASN1_GENERALIZEDTIME),
+ ASN1_EXP_OPT(SingleResponse, nextUpdate, ASN1_GENERALIZEDTIME, 0),
+ ASN1_EXP_SEQUENCE_OF_OPT(SingleResponse, singleExtensions, X509_EXTENSION, 1)
+} ASN1_SEQUENCE_END(SingleResponse);
+
+ASN1_SEQUENCE(ResponseData) = {
+ ASN1_EXP_OPT(ResponseData, version, ASN1_INTEGER, 0),
+ ASN1_SIMPLE(ResponseData, responderID, ResponderID),
+ ASN1_SIMPLE(ResponseData, producedAt, ASN1_GENERALIZEDTIME),
+ ASN1_SEQUENCE_OF(ResponseData, responses, SingleResponse),
+ ASN1_EXP_SEQUENCE_OF_OPT(ResponseData, responseExtensions, X509_EXTENSION, 1)
+} ASN1_SEQUENCE_END(ResponseData);
+
+ASN1_SEQUENCE(BasicOCSPResponse) = {
+ ASN1_SIMPLE(BasicOCSPResponse, tbsResponseData, ResponseData),
+ ASN1_SIMPLE(BasicOCSPResponse, signatureAlgorithm, X509_ALGOR),
+ ASN1_SIMPLE(BasicOCSPResponse, signature, ASN1_BIT_STRING),
+ ASN1_EXP_SEQUENCE_OF_OPT(BasicOCSPResponse, certs, X509, 0)
+} ASN1_SEQUENCE_END(BasicOCSPResponse);
+
diff --git a/lib/libssl/src/demos/b64.c b/lib/libssl/src/demos/b64.c
index 8e248e7e728..113da89baf4 100644
--- a/lib/libssl/src/demos/b64.c
+++ b/lib/libssl/src/demos/b64.c
@@ -91,8 +91,8 @@ char **argv;
EVP_CIPHER *cipher=NULL,*c;
char *inf=NULL,*outf=NULL;
BIO *in=NULL,*out=NULL,*b64=NULL,*benc=NULL,*rbio=NULL,*wbio=NULL;
-#define PROG_NAME_SIZE 16
- char pname[PROG_NAME_SIZE];
+#define PROG_NAME_SIZE 39
+ char pname[PROG_NAME_SIZE+1];
apps_startup();
diff --git a/lib/libssl/src/demos/easy_tls/Makefile b/lib/libssl/src/demos/easy_tls/Makefile
new file mode 100644
index 00000000000..fd3c246ef4e
--- /dev/null
+++ b/lib/libssl/src/demos/easy_tls/Makefile
@@ -0,0 +1,123 @@
+# Makefile for easy-tls example application (rudimentary client and server)
+# $Id: Makefile,v 1.1 2002/05/15 02:29:18 beck Exp $
+
+SOLARIS_CFLAGS=-Wall -pedantic -g -O2
+SOLARIS_LIBS=-lxnet
+
+LINUX_CFLAGS=-Wall -pedantic -g -O2
+LINUX_LIBS=
+
+
+auto-all:
+ case `uname -s` in \
+ SunOS) echo Using SunOS configuration; \
+ make SYSCFLAGS="$(SOLARIS_CFLAGS)" SYSLIBS="$(SOLARIS_LIBS)" all;; \
+ Linux) echo Using Linux configuration; \
+ make SYSCFLAGS="$(LINUX_CFLAGS)" SYSLIBS="$(LINUX_LIBS)" all;; \
+ *) echo "unknown system"; exit 1;; \
+ esac
+
+all: test TAGS
+
+# For adapting this Makefile to a different system, only the following
+# definitions should need customizing:
+
+OPENSSLDIR=../..
+CC=gcc
+
+SYSCFLAGS=whatever
+SYSLIBS=whatever
+
+
+#############################################################################
+#
+# SSLeay/OpenSSL imports
+#
+# OPENSSLDIR (set above) can be either the directory where OpenSSL is
+# installed or the directory where it was compiled.
+
+# We rely on having a new OpenSSL release where include files
+# have names like <openssl/ssl.h> (not just <ssl.h>).
+OPENSSLINCLUDES=-I$(OPENSSLDIR)/include
+
+# libcrypto.a and libssl.a are directly in $(OPENSSLDIR) if this is
+# the compile directory, or in $(OPENSSLDIR)/lib if we use an installed
+# library. With the following definition, we can handle either case.
+OPENSSLLIBS=-L$(OPENSSLDIR) -L$(OPENSSLDIR)/lib -lssl -lcrypto
+
+
+#############################################################################
+#
+# Stuff for handling the source files
+#
+
+SOURCES=easy-tls.c test.c
+HEADERS=easy-tls.h test.h
+DOCSandEXAMPLESetc=Makefile cert.pem cacerts.pem
+EVERYTHING=$(SOURCES) $(HEADERS) $(DOCSandEXAMPLESetc)
+
+ls: ls-l
+ls-l:
+ ls -l $(EVERYTHING)
+# For RCS:
+tag:
+ -rcs -n_`date +%y%m%d`: $(EVERYTHING)
+ rcs -nMYTAG $(EVERYTHING)
+ rcs -nMYTAG: $(EVERYTHING)
+diff:
+ -rcsdiff -rMYTAG -u $(EVERYTHING)
+today:
+ -rcsdiff -r_`date +%y%m%d` -u $(EVERYTHING)
+ident:
+ for a in $(EVERYTHING); do ident $$a; done
+
+# Distribution .tar:
+easy-tls.tar.gz: $(EVERYTHING)
+ tar cvf - $(EVERYTHING) | \
+ gzip -9 > easy-tls.tar.gz
+
+# Working .tar:
+tls.tgz: $(EVERYTHING)
+ tar cfv - `find . -type f -a ! -name '*.tgz' -a ! -name '*.tar.gz'` | \
+ gzip -9 > tls.tgz
+
+# For emacs:
+etags: TAGS
+TAGS: $(SOURCES) $(HEADERS)
+ -etags $(SOURCES) $(HEADERS)
+
+
+#############################################################################
+#
+# Compilation
+#
+# The following definitions are system dependent (and hence defined
+# at the beginning of this Makefile, where they are more easily found):
+
+### CC=gcc
+### SYSCFLAGS=-Wall -pedantic -g -O2
+### SYSLIBS=-lxnet
+
+EXTRACFLAGS=-DTLS_APP=\"test.h\"
+# EXTRACFLAGS=-DTLS_APP=\"test.h\" -DDEBUG_TLS
+
+#
+# The rest shouldn't need to be touched.
+#
+LDFLAGS=$(SYSLIBS) $(OPENSSLLIBS)
+INCLUDES=$(OPENSSLINCLUDES)
+CFLAGS=$(SYSCFLAGS) $(EXTRACFLAGS) $(INCLUDES)
+
+OBJS=easy-tls.o test.o
+
+clean:
+ @rm -f test
+ @rm -f TAGS
+ @rm -f *.o
+ @rm -f core
+
+test: $(OBJS)
+ $(CC) $(OBJS) $(LDFLAGS) -o test
+
+test.o: $(HEADERS)
+easy-tls.o: $(HEADERS)
diff --git a/lib/libssl/src/demos/easy_tls/README b/lib/libssl/src/demos/easy_tls/README
new file mode 100644
index 00000000000..816a58009c8
--- /dev/null
+++ b/lib/libssl/src/demos/easy_tls/README
@@ -0,0 +1,65 @@
+easy_tls - generic SSL/TLS proxy
+========
+
+(... and example for non-blocking SSL/TLS I/O multiplexing.)
+
+
+ easy_tls.c, easy_tls.h:
+
+ Small generic SSL/TLS proxy library: With a few function calls,
+ an application socket will be replaced by a pipe handled by a
+ separate SSL/TLS proxy process. This allows easily adding
+ SSL/TLS support to many programs not originally designed for it.
+
+ [Actually easy_tls.c is not a proper library: Customization
+ requires defining preprocessor macros while compiling it.
+ This is quite confusing, so I'll probably change it.]
+
+ These files may be used under the OpenSSL license.
+
+
+
+ test.c, test.h, Makefile, cert.pem, cacerts.pem:
+
+ Rudimentary example program using the easy_tls library, and
+ example key and certificates for it. Usage examples:
+
+ $ ./test 8443 # create server listening at port 8443
+ $ ./test 127.0.0.1 8443 # create client, connect to port 8443
+ # at IP address 127.0.0.1
+
+ 'test' will not automatically do SSL/TLS, or even read or write
+ data -- it must be told to do so on input lines starting
+ with a command letter. 'W' means write a line, 'R' means
+ read a line, 'C' means close the connection, 'T' means
+ start an SSL/TLS proxy. E.g. (user input tagged with '*'):
+
+ * R
+ <<< 220 mail.example.net
+ * WSTARTTLS
+ >>> STARTTLS
+ * R
+ <<< 220 Ready to start TLS
+ * T
+ test_process_init(fd = 3, client_p = 1, apparg = (nil))
+ +++ `E:self signed certificate in certificate chain'
+ +++ `<... certificate info ...>'
+ * WHELO localhost
+ >>> HELO localhost
+ R
+ <<< 250 mail.example.net
+
+ You can even do SSL/TLS over SSL/TLS over SSL/TLS ... by using
+ 'T' multiple times. I have no idea why you would want to though.
+
+
+This code is rather old. When I find time I will update anything that
+should be changed, and improve code comments. To compile the sample
+program 'test' on platforms other then Linux or Solaris, you will have
+to edit the Makefile.
+
+As noted above, easy_tls.c will be changed to become a library one
+day, which means that future revisions will not be fully compatible to
+the current version.
+
+Bodo Möller <bodo@openssl.org>
diff --git a/lib/libssl/src/demos/easy_tls/cacerts.pem b/lib/libssl/src/demos/easy_tls/cacerts.pem
new file mode 100644
index 00000000000..0b1c91f95ee
--- /dev/null
+++ b/lib/libssl/src/demos/easy_tls/cacerts.pem
@@ -0,0 +1,18 @@
+$Id: cacerts.pem,v 1.1 2002/05/15 02:29:18 beck Exp $
+
+issuer= /C=AU/ST=Queensland/O=CryptSoft Pty Ltd/CN=Test PCA (1024 bit)
+subject=/C=AU/ST=Queensland/O=CryptSoft Pty Ltd/CN=Test CA (1024 bit)
+-----BEGIN CERTIFICATE-----
+MIICJjCCAY8CAQAwDQYJKoZIhvcNAQEEBQAwXDELMAkGA1UEBhMCQVUxEzARBgNV
+BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRwwGgYD
+VQQDExNUZXN0IFBDQSAoMTAyNCBiaXQpMB4XDTk3MDYwOTEzNTc0M1oXDTAxMDYw
+OTEzNTc0M1owWzELMAkGA1UEBhMCQVUxEzARBgNVBAgTClF1ZWVuc2xhbmQxGjAY
+BgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRswGQYDVQQDExJUZXN0IENBICgxMDI0
+IGJpdCkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKO7o8t116VP6cgybTsZ
+DCZhr95nYlZuya3aCi1IKoztqwWnjbmDFIriOqGFPrZQ+moMETC9D59iRW/dFXSv
+1F65ka/XY2hLh9exCCo7XuUcDs53Qp3bI3AmMqHjgzE8oO3ajyJAzJkTTOUecQU2
+mw/gI4tMM0LqWMQS7luTy4+xAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAM7achv3v
+hLQJcv/65eGEpBXM40ZDVoFQFFJWaY5p883HTqLB1x4FdzsXHH0QKBTcKpWwqyu4
+YDm3fb8oDugw72bCzfyZK/zVZPR/hVlqI/fvU109Qoc+7oPvIXWky71HfcK6ZBCA
+q30KIqGM/uoM60INq97qjDmCJapagcNBGQs=
+-----END CERTIFICATE-----
diff --git a/lib/libssl/src/demos/easy_tls/cert.pem b/lib/libssl/src/demos/easy_tls/cert.pem
new file mode 100644
index 00000000000..d4d19d9ad1f
--- /dev/null
+++ b/lib/libssl/src/demos/easy_tls/cert.pem
@@ -0,0 +1,31 @@
+$Id: cert.pem,v 1.1 2002/05/15 02:29:18 beck Exp $
+
+Example certificate and key.
+
+-----BEGIN CERTIFICATE-----
+MIIB1jCCAT8CAQEwDQYJKoZIhvcNAQEEBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV
+BAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
+ZDAeFw05OTA1MDEwMTI2MzVaFw05OTA1MzEwMTI2MzVaMCIxCzAJBgNVBAYTAkRF
+MRMwEQYDVQQDEwpUZXN0c2VydmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
+gQD6I3oDKiexwwlkzjar69AIFnVUaG85LtCege2R+CtIDlkQYw68/8MbT3ou0pdF
+AcL9IGiYY3Y0SHM9PqF00RO1MCtNpqTnF3ScLpbmggGjKilmWYn2ai7emdjMjXVL
+tzWW2xGgIGATWQN32KgfJng4jXi1UjEiyLhkw0Zf1I/ggwIDAQABMA0GCSqGSIb3
+DQEBBAUAA4GBAMgM+sbAk8DfjSfa+Rf2gcGXmbrvZAzKzC+5RU3kaq/NyxIXAGco
+9dZjozzWfN/xuGup5boFk+KrP+xdgsaqGHsyzlgEoqz4ekqLjQeVbnoj339hVFU9
+MhPi6JULPxjXKumjfX2LLNkikW5puz8Df3UiX0EiaJvd7EwP8J75tiUT
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQD6I3oDKiexwwlkzjar69AIFnVUaG85LtCege2R+CtIDlkQYw68
+/8MbT3ou0pdFAcL9IGiYY3Y0SHM9PqF00RO1MCtNpqTnF3ScLpbmggGjKilmWYn2
+ai7emdjMjXVLtzWW2xGgIGATWQN32KgfJng4jXi1UjEiyLhkw0Zf1I/ggwIDAQAB
+AoGANST8c1etf1MU19oIO5aqaE19OCXIG7oakNLCCtVTPMfvnE+vffBJH7BPIUuU
+4BBzwRv1nQrkvk72TPjVjOAu81B1SStKQueun2flVuYxp9NyupNWCBley4QdohlP
+I92ml2tzTSPmNIoA6jdGyNzFcGchapRRmejsC39F1RUbHQECQQD9KX81Wt8ZOrri
+dWiEXja1L3X8Bkb9vvUjVMQDTJJPxBJjehC6eurgE6PP6SJD5p/f3RHPCcLr8tSM
+D4P/OpKhAkEA/PFNlhIZUDKK6aTvG2mn7qQ5phbadOoyN1Js3ttWG5OMOZ6b/QlC
+Wvp84h44506BIlv+Tg2YAI0AdBUrf7oEowJAM4joAVd/ROaEtqbJ4PBA2L9RmD06
+5FqkEk4mHLnQqvYx/BgUIbH18ClvVlqSBBqFfw/EmU3WZSuogt6Bs0ocIQJBAOxB
+AoPiYcxbeQ5kZIVJOXaX49SzUdaUDNVJYrEBUzsspHQJJo/Avz606kJVkjbSR6Ft
+JWmIHuqcyMikIV4KxFsCQQCU2evoVjVsqkkbHi7W28f73PGBsyu0KIwlK7nu4h08
+Daf7TAI+A6jW/WRUsJ6dFhUYi7/Jvkcdrlnbgm2fxziX
+-----END RSA PRIVATE KEY-----
diff --git a/lib/libssl/src/demos/easy_tls/easy-tls.c b/lib/libssl/src/demos/easy_tls/easy-tls.c
new file mode 100644
index 00000000000..9fa0ef9a6be
--- /dev/null
+++ b/lib/libssl/src/demos/easy_tls/easy-tls.c
@@ -0,0 +1,1235 @@
+/* -*- Mode: C; c-file-style: "bsd" -*- */
+/*
+ * easy-tls.c -- generic TLS proxy.
+ * $Id: easy-tls.c,v 1.1 2002/05/15 02:29:18 beck Exp $
+ */
+/*
+ (c) Copyright 1999 Bodo Moeller. All rights reserved.
+
+ This is free software; you can redistributed and/or modify it
+ unter the terms of either
+ - the GNU General Public License as published by the
+ Free Software Foundation, version 1, or (at your option)
+ any later version,
+ or
+ - the following license:
+*/
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that each of the following
+ * conditions is met:
+ *
+ * 1. Redistributions qualify as "freeware" or "Open Source Software" under
+ * one of the following terms:
+ *
+ * (a) Redistributions are made at no charge beyond the reasonable cost of
+ * materials and delivery.
+ *
+ * (b) Redistributions are accompanied by a copy of the Source Code
+ * or by an irrevocable offer to provide a copy of the Source Code
+ * for up to three years at the cost of materials and delivery.
+ * Such redistributions must allow further use, modification, and
+ * redistribution of the Source Code under substantially the same
+ * terms as this license.
+ *
+ * 2. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 3. 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.
+ *
+ * 4. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by Bodo Moeller."
+ * (If available, substitute umlauted o for oe.)
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Bodo Moeller."
+ *
+ * THIS SOFTWARE IS PROVIDED BY BODO MOELLER ``AS IS'' AND ANY
+ * EXPRESSED 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 BODO MOELLER OR
+ * HIS 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.
+ */
+/*
+ * Attribution for OpenSSL library:
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ * This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)
+ */
+
+static char const rcsid[] =
+"$Id: easy-tls.c,v 1.1 2002/05/15 02:29:18 beck Exp $";
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include <openssl/crypto.h>
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/opensslv.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#ifndef NO_RSA
+ #include <openssl/rsa.h>
+#endif
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x00904000L /* 0.9.4-dev */
+# error "This program needs OpenSSL 0.9.4 or later."
+#endif
+
+#include "easy-tls.h" /* include after <openssl/ssl.h> if both are needed */
+
+#if TLS_INFO_SIZE > PIPE_BUF
+# if PIPE_BUF < 512
+# error "PIPE_BUF < 512" /* non-POSIX */
+# endif
+# error "TLS_INFO_SIZE > PIPE_BUF"
+#endif
+
+/*****************************************************************************/
+
+#ifdef TLS_APP
+# include TLS_APP
+#endif
+
+/* Applications can define:
+ * TLS_APP_PROCESS_INIT -- void ...(int fd, int client_p, void *apparg)
+ * TLS_CUMULATE_ERRORS
+ * TLS_ERROR_BUFSIZ
+ * TLS_APP_ERRFLUSH -- void ...(int child_p, char *, size_t, void *apparg)
+ */
+
+#ifndef TLS_APP_PROCESS_INIT
+# define TLS_APP_PROCESS_INIT(fd, client_p, apparg) ((void) 0)
+#endif
+
+#ifndef TLS_ERROR_BUFSIZ
+# define TLS_ERROR_BUFSIZ (10*160)
+#endif
+#if TLS_ERROR_BUFSIZ < 2 /* {'\n',0} */
+# error "TLS_ERROR_BUFSIZE is too small."
+#endif
+
+#ifndef TLS_APP_ERRFLUSH
+# define TLS_APP_ERRFLUSH tls_app_errflush
+static void
+tls_app_errflush(int child_p, char *errbuf, size_t num, void *apparg)
+{
+ fputs(errbuf, stderr);
+}
+#endif
+
+/*****************************************************************************/
+
+#ifdef DEBUG_TLS
+# define DEBUG_MSG(x) fprintf(stderr," %s\n",x)
+# define DEBUG_MSG2(x,y) fprintf(stderr, " %s: %d\n",x,y)
+static int tls_loop_count = 0;
+static int tls_select_count = 0;
+#else
+# define DEBUG_MSG(x) (void)0
+# define DEBUG_MSG2(x,y) (void)0
+#endif
+
+static void tls_rand_seed_uniquely(void);
+static void tls_proxy(int clear_fd, int tls_fd, int info_fd, SSL_CTX *ctx, int client_p);
+static int tls_socket_nonblocking(int fd);
+
+static int tls_child_p = 0;
+static void *tls_child_apparg;
+
+
+struct tls_start_proxy_args
+tls_start_proxy_defaultargs(void)
+{
+ struct tls_start_proxy_args ret;
+
+ ret.fd = -1;
+ ret.client_p = -1;
+ ret.ctx = NULL;
+ ret.pid = NULL;
+ ret.infofd = NULL;
+
+ return ret;
+}
+
+/* Slice in TLS proxy process at fd.
+ * Return value:
+ * 0 ok (*pid is set to child's PID if pid != NULL),
+ * < 0 look at errno
+ * > 0 other error
+ * (return value encodes place of error)
+ *
+ */
+int
+tls_start_proxy(struct tls_start_proxy_args a, void *apparg)
+{
+ int fds[2] = {-1, -1};
+ int infofds[2] = {-1, -1};
+ int r, getfd, getfl;
+ int ret;
+
+ DEBUG_MSG2("tls_start_proxy fd", a.fd);
+ DEBUG_MSG2("tls_start_proxy client_p", a.client_p);
+
+ if (a.fd == -1 || a.client_p == -1 || a.ctx == NULL)
+ return 1;
+
+ if (a.pid != NULL) {
+ *a.pid = 0;
+ }
+ if (a.infofd != NULL) {
+ *a.infofd = -1;
+ }
+
+ r = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+ if (r == -1)
+ return -1;
+ if (a.fd >= FD_SETSIZE || fds[0] >= FD_SETSIZE) {
+ ret = 2;
+ goto err;
+ }
+ if (a.infofd != NULL) {
+ r = pipe(infofds);
+ if (r == -1) {
+ ret = -3;
+ goto err;
+ }
+ }
+
+ r = fork();
+ if (r == -1) {
+ ret = -4;
+ goto err;
+ }
+ if (r == 0) {
+ DEBUG_MSG("fork");
+ tls_child_p = 1;
+ tls_child_apparg = apparg;
+ close(fds[1]);
+ if (infofds[0] != -1)
+ close(infofds[0]);
+ TLS_APP_PROCESS_INIT(a.fd, a.client_p, apparg);
+ DEBUG_MSG("TLS_APP_PROCESS_INIT");
+ tls_proxy(fds[0], a.fd, infofds[1], a.ctx, a.client_p);
+ exit(0);
+ }
+ if (a.pid != NULL)
+ *a.pid = r;
+ if (infofds[1] != -1) {
+ close(infofds[1]);
+ infofds[1] = -1;
+ }
+ /* install fds[1] in place of fd: */
+ close(fds[0]);
+ fds[0] = -1;
+ getfd = fcntl(a.fd, F_GETFD);
+ getfl = fcntl(a.fd, F_GETFL);
+ r = dup2(fds[1], a.fd);
+ close(fds[1]);
+ fds[1] = -1;
+ if (r == -1) {
+ ret = -5;
+ goto err;
+ }
+ if (getfd != 1)
+ fcntl(a.fd, F_SETFD, getfd);
+ if (getfl & O_NONBLOCK)
+ (void)tls_socket_nonblocking(a.fd);
+ if (a.infofd != NULL)
+ *a.infofd = infofds[0];
+ return 0;
+
+ err:
+ if (fds[0] != -1)
+ close(fds[0]);
+ if (fds[1] != -1)
+ close(fds[1]);
+ if (infofds[0] != -1)
+ close(infofds[0]);
+ if (infofds[1] != -1)
+ close(infofds[1]);
+ return ret;
+}
+
+/*****************************************************************************/
+
+static char errbuf[TLS_ERROR_BUFSIZ];
+static size_t errbuf_i = 0;
+
+static void
+tls_errflush(void *apparg)
+{
+ if (errbuf_i == 0)
+ return;
+
+ assert(errbuf_i < sizeof errbuf);
+ assert(errbuf[errbuf_i] == 0);
+ if (errbuf_i == sizeof errbuf - 1) {
+ /* make sure we have a newline, even if string has been truncated */
+ errbuf[errbuf_i - 1] = '\n';
+ }
+
+ /* TLS_APP_ERRFLUSH may modify the string as needed,
+ * e.g. substitute other characters for \n for convenience */
+ TLS_APP_ERRFLUSH(tls_child_p, errbuf, errbuf_i, apparg);
+
+ errbuf_i = 0;
+}
+
+static void
+tls_errprintf(int flush, void *apparg, const char *fmt, ...)
+{
+ va_list args;
+ int r;
+
+ if (errbuf_i < sizeof errbuf - 1) {
+ size_t n;
+
+ va_start(args, fmt);
+ n = (sizeof errbuf) - errbuf_i;
+ r = vsnprintf(errbuf + errbuf_i, n, fmt, args);
+ if (r >= n)
+ r = n - 1;
+ if (r >= 0) {
+ errbuf_i += r;
+ } else {
+ errbuf_i = sizeof errbuf - 1;
+ errbuf[errbuf_i] = '\0';
+ }
+ assert(errbuf_i < sizeof errbuf);
+ assert(errbuf[errbuf_i] == 0);
+ }
+#ifndef TLS_CUMULATE_ERRORS
+ tls_errflush(apparg);
+#else
+ if (flush)
+ tls_errflush(apparg);
+#endif
+}
+
+/* app_prefix.. are for additional information provided by caller.
+ * If OpenSSL error queue is empty, print default_text ("???" if NULL).
+ */
+static char *
+tls_openssl_errors(const char *app_prefix_1, const char *app_prefix_2, const char *default_text, void *apparg)
+{
+ static char reasons[255];
+ size_t reasons_i;
+ unsigned long err;
+ const char *file;
+ int line;
+ const char *data;
+ int flags;
+ char *errstring;
+ int printed_something = 0;
+
+ reasons_i = 0;
+
+ assert(app_prefix_1 != NULL);
+ assert(app_prefix_2 != NULL);
+
+ if (default_text == NULL)
+ default_text = "?""?""?";
+
+ while ((err = ERR_get_error_line_data(&file,&line,&data,&flags)) != 0) {
+ if (reasons_i < sizeof reasons) {
+ size_t n;
+ int r;
+
+ n = (sizeof reasons) - reasons_i;
+ r = snprintf(reasons + reasons_i, n, "%s%s", (reasons_i > 0 ? ", " : ""), ERR_reason_error_string(err));
+ if (r >= n)
+ r = n - 1;
+ if (r >= 0) {
+ reasons_i += r;
+ } else {
+ reasons_i = sizeof reasons;
+ }
+ assert(reasons_i <= sizeof reasons);
+ }
+
+ errstring = ERR_error_string(err, NULL);
+ assert(errstring != NULL);
+ tls_errprintf(0, apparg, "OpenSSL error%s%s: %s:%s:%d:%s\n", app_prefix_1, app_prefix_2, errstring, file, line, (flags & ERR_TXT_STRING) ? data : "");
+ printed_something = 1;
+ }
+
+ if (!printed_something) {
+ assert(reasons_i == 0);
+ snprintf(reasons, sizeof reasons, "%s", default_text);
+ tls_errprintf(0, apparg, "OpenSSL error%s%s: %s\n", app_prefix_1, app_prefix_2, default_text);
+ }
+
+#ifdef TLS_CUMULATE_ERRORS
+ tls_errflush(apparg);
+#endif
+ assert(errbuf_i == 0);
+
+ return reasons;
+}
+
+/*****************************************************************************/
+
+static int tls_init_done = 0;
+
+static int
+tls_init(void *apparg)
+{
+ if (tls_init_done)
+ return 0;
+
+ SSL_load_error_strings();
+ if (!SSL_library_init() /* aka SSLeay_add_ssl_algorithms() */ ) {
+ tls_errprintf(1, apparg, "SSL_library_init failed.\n");
+ return -1;
+ }
+ tls_init_done = 1;
+ tls_rand_seed();
+ return 0;
+}
+
+/*****************************************************************************/
+
+static void
+tls_rand_seed_uniquely(void)
+{
+ struct {
+ pid_t pid;
+ time_t time;
+ void *stack;
+ } data;
+
+ data.pid = getpid();
+ data.time = time(NULL);
+ data.stack = (void *)&data;
+
+ RAND_seed((const void *)&data, sizeof data);
+}
+
+void
+tls_rand_seed(void)
+{
+ struct {
+ struct utsname uname;
+ int uname_1;
+ int uname_2;
+ uid_t uid;
+ uid_t euid;
+ gid_t gid;
+ gid_t egid;
+ } data;
+
+ data.uname_1 = uname(&data.uname);
+ data.uname_2 = errno; /* Let's hope that uname fails randomly :-) */
+
+ data.uid = getuid();
+ data.euid = geteuid();
+ data.gid = getgid();
+ data.egid = getegid();
+
+ RAND_seed((const void *)&data, sizeof data);
+ tls_rand_seed_uniquely();
+}
+
+static int tls_rand_seeded_p = 0;
+
+#define my_MIN_SEED_BYTES 256 /* struct stat can be larger than 128 */
+int
+tls_rand_seed_from_file(const char *filename, size_t n, void *apparg)
+{
+ /* Seed OpenSSL's random number generator from file.
+ Try to read n bytes if n > 0, whole file if n == 0. */
+
+ int r;
+
+ if (tls_init(apparg) == -1)
+ return -1;
+ tls_rand_seed();
+
+ r = RAND_load_file(filename, (n > 0 && n < LONG_MAX) ? (long)n : LONG_MAX);
+ /* r is the number of bytes filled into the random number generator,
+ * which are taken from "stat(filename, ...)" in addition to the
+ * file contents.
+ */
+ assert(1 < my_MIN_SEED_BYTES);
+ /* We need to detect at least those cases when the file does not exist
+ * at all. With current versions of OpenSSL, this should do it: */
+ if (n == 0)
+ n = my_MIN_SEED_BYTES;
+ if (r < n) {
+ tls_errprintf(1, apparg, "rand_seed_from_file: could not read %d bytes from %s.\n", n, filename);
+ return -1;
+ } else {
+ tls_rand_seeded_p = 1;
+ return 0;
+ }
+}
+
+void
+tls_rand_seed_from_memory(const void *buf, size_t n)
+{
+ size_t i = 0;
+
+ while (i < n) {
+ size_t rest = n - i;
+ int chunk = rest < INT_MAX ? (int)rest : INT_MAX;
+ RAND_seed((const char *)buf + i, chunk);
+ i += chunk;
+ }
+ tls_rand_seeded_p = 1;
+}
+
+
+/*****************************************************************************/
+
+struct tls_x509_name_string {
+ char str[100];
+};
+
+static void
+tls_get_x509_subject_name_oneline(X509 *cert, struct tls_x509_name_string *namestring)
+{
+ X509_NAME *name;
+
+ if (cert == NULL) {
+ namestring->str[0] = '\0';
+ return;
+ }
+
+ name = X509_get_subject_name(cert); /* does not increment any reference counter */
+
+ assert(sizeof namestring->str >= 4); /* "?" or "...", plus 0 */
+
+ if (name == NULL) {
+ namestring->str[0] = '?';
+ namestring->str[1] = 0;
+ } else {
+ size_t len;
+
+ X509_NAME_oneline(name, namestring->str, sizeof namestring->str);
+ len = strlen(namestring->str);
+ assert(namestring->str[len] == 0);
+ assert(len < sizeof namestring->str);
+
+ if (len+1 == sizeof namestring->str) {
+ /* (Probably something was cut off.)
+ * Does not really work -- X509_NAME_oneline truncates after
+ * name components, we cannot tell from the result whether
+ * anything is missing. */
+
+ assert(namestring->str[len] == 0);
+ namestring->str[--len] = '.';
+ namestring->str[--len] = '.';
+ namestring->str[--len] = '.';
+ }
+ }
+}
+
+/*****************************************************************************/
+
+/* to hinder OpenSSL from asking for passphrases */
+static int
+no_passphrase_callback(char *buf, int num, int w, void *arg)
+{
+ return -1;
+}
+
+static int
+verify_dont_fail_cb(X509_STORE_CTX *c, void *unused_arg)
+{
+ int i;
+
+ i = X509_verify_cert(c); /* sets c->error */
+#if OPENSSL_VERSION_NUMBER >= 0x00905000L /* don't allow unverified
+ * certificates -- they could
+ * survive session reuse, but
+ * OpenSSL < 0.9.5-dev does not
+ * preserve their verify_result */
+ if (i == 0)
+ return 1;
+ else
+#endif
+ return i;
+}
+
+static DH *tls_dhe1024 = NULL; /* generating these takes a while, so do it just once */
+
+void
+tls_set_dhe1024(int i, void *apparg)
+{
+ DSA *dsaparams;
+ DH *dhparams;
+ const char *seed[] = { ";-) :-( :-) :-( ",
+ ";-) :-( :-) :-( ",
+ "Random String no. 12",
+ ";-) :-( :-) :-( ",
+ "hackers have even mo", /* from jargon file */
+ };
+ unsigned char seedbuf[20];
+
+ tls_init(apparg);
+ if (i >= 0) {
+ i %= sizeof seed / sizeof seed[0];
+ assert(strlen(seed[i]) == 20);
+ memcpy(seedbuf, seed[i], 20);
+ dsaparams = DSA_generate_parameters(1024, seedbuf, 20, NULL, NULL, 0, NULL);
+ } else {
+ /* random parameters (may take a while) */
+ dsaparams = DSA_generate_parameters(1024, NULL, 0, NULL, NULL, 0, NULL);
+ }
+
+ if (dsaparams == NULL) {
+ tls_openssl_errors("", "", NULL, apparg);
+ return;
+ }
+ dhparams = DSA_dup_DH(dsaparams);
+ DSA_free(dsaparams);
+ if (dhparams == NULL) {
+ tls_openssl_errors("", "", NULL, apparg);
+ return;
+ }
+ if (tls_dhe1024 != NULL)
+ DH_free(tls_dhe1024);
+ tls_dhe1024 = dhparams;
+}
+
+struct tls_create_ctx_args
+tls_create_ctx_defaultargs(void)
+{
+ struct tls_create_ctx_args ret;
+
+ ret.client_p = 0;
+ ret.certificate_file = NULL;
+ ret.key_file = NULL;
+ ret.ca_file = NULL;
+ ret.verify_depth = -1;
+ ret.fail_unless_verified = 0;
+ ret.export_p = 0;
+
+ return ret;
+}
+
+SSL_CTX *
+tls_create_ctx(struct tls_create_ctx_args a, void *apparg)
+{
+ int r;
+ static long context_num = 0;
+ SSL_CTX *ret;
+ const char *err_pref_1 = "", *err_pref_2 = "";
+
+ if (tls_init(apparg) == -1)
+ return NULL;
+
+ ret = SSL_CTX_new((a.client_p? SSLv23_client_method:SSLv23_server_method)());
+
+ if (ret == NULL)
+ goto err;
+
+ SSL_CTX_set_default_passwd_cb(ret, no_passphrase_callback);
+ SSL_CTX_set_mode(ret, SSL_MODE_ENABLE_PARTIAL_WRITE);
+
+ if ((a.certificate_file != NULL) || (a.key_file != NULL)) {
+ if (a.key_file == NULL) {
+ tls_errprintf(1, apparg, "Need a key file.\n");
+ goto err_return;
+ }
+ if (a.certificate_file == NULL) {
+ tls_errprintf(1, apparg, "Need a certificate chain file.\n");
+ goto err_return;
+ }
+
+ if (!SSL_CTX_use_PrivateKey_file(ret, a.key_file, SSL_FILETYPE_PEM))
+ goto err;
+ if (!tls_rand_seeded_p) {
+ /* particularly paranoid people may not like this --
+ * so provide your own random seeding before calling this */
+ if (tls_rand_seed_from_file(a.key_file, 0, apparg) == -1)
+ goto err_return;
+ }
+ if (!SSL_CTX_use_certificate_chain_file(ret, a.certificate_file))
+ goto err;
+ if (!SSL_CTX_check_private_key(ret)) {
+ tls_errprintf(1, apparg, "Private key \"%s\" does not match certificate \"%s\".\n", a.key_file, a.certificate_file);
+ goto err_peek;
+ }
+ }
+
+ if ((a.ca_file != NULL) || (a.verify_depth > 0)) {
+ context_num++;
+ r = SSL_CTX_set_session_id_context(ret, (const void *)&context_num, (unsigned int)sizeof context_num);
+ if (!r)
+ goto err;
+
+ SSL_CTX_set_verify(ret, SSL_VERIFY_PEER | (a.fail_unless_verified ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0), 0);
+ if (!a.fail_unless_verified)
+ SSL_CTX_set_cert_verify_callback(ret, verify_dont_fail_cb, NULL);
+
+ if (a.verify_depth > 0)
+ SSL_CTX_set_verify_depth(ret, a.verify_depth);
+
+ if (a.ca_file != NULL) {
+ r = SSL_CTX_load_verify_locations(ret, a.ca_file, NULL /* no CA-directory */); /* does not report failure if file does not exist ... */
+ if (!r) {
+ err_pref_1 = " while processing certificate file ";
+ err_pref_2 = a.ca_file;
+ goto err;
+ }
+
+ if (!a.client_p) {
+ /* SSL_load_client_CA_file is a misnomer, it just creates a list of CNs. */
+ SSL_CTX_set_client_CA_list(ret, SSL_load_client_CA_file(a.ca_file));
+ /* SSL_CTX_set_client_CA_list does not have a return value;
+ * it does not really need one, but make sure
+ * (we really test if SSL_load_client_CA_file worked) */
+ if (SSL_CTX_get_client_CA_list(ret) == NULL) {
+ tls_errprintf(1, apparg, "Could not set client CA list from \"%s\".\n", a.ca_file);
+ goto err_peek;
+ }
+ }
+ }
+ }
+
+ if (!a.client_p) {
+ if (tls_dhe1024 == NULL) {
+ int i;
+
+ RAND_bytes((unsigned char *) &i, sizeof i);
+ /* make sure that i is non-negative -- pick one of the provided
+ * seeds */
+ if (i < 0)
+ i = -i;
+ if (i < 0)
+ i = 0;
+ tls_set_dhe1024(i, apparg);
+ if (tls_dhe1024 == NULL)
+ goto err_return;
+ }
+
+ if (!SSL_CTX_set_tmp_dh(ret, tls_dhe1024))
+ goto err;
+
+ /* avoid small subgroup attacks: */
+ SSL_CTX_set_options(ret, SSL_OP_SINGLE_DH_USE);
+ }
+
+#ifndef NO_RSA
+ if (!a.client_p && a.export_p) {
+ RSA *tmpkey;
+
+ tmpkey = RSA_generate_key(512, RSA_F4, 0, NULL);
+ if (tmpkey == NULL)
+ goto err;
+ if (!SSL_CTX_set_tmp_rsa(ret, tmpkey)) {
+ RSA_free(tmpkey);
+ goto err;
+ }
+ RSA_free(tmpkey); /* SSL_CTX_set_tmp_rsa uses a duplicate. */
+ }
+#endif
+
+ return ret;
+
+ err_peek:
+ if (!ERR_peek_error())
+ goto err_return;
+ err:
+ tls_openssl_errors(err_pref_1, err_pref_2, NULL, apparg);
+ err_return:
+ if (ret != NULL)
+ SSL_CTX_free(ret);
+ return NULL;
+}
+
+
+/*****************************************************************************/
+
+static int
+tls_socket_nonblocking(int fd)
+{
+ int v, r;
+
+ v = fcntl(fd, F_GETFL, 0);
+ if (v == -1) {
+ if (errno == EINVAL)
+ return 0; /* already shut down -- ignore */
+ return -1;
+ }
+ r = fcntl(fd, F_SETFL, v | O_NONBLOCK);
+ if (r == -1) {
+ if (errno == EINVAL)
+ return 0; /* already shut down -- ignore */
+ return -1;
+ }
+ return 0;
+}
+
+static int
+max(int a, int b)
+{
+ return a > b ? a : b;
+}
+
+static void
+tls_sockets_select(int read_select_1, int read_select_2, int write_select_1, int write_select_2, int seconds /* timeout, -1 means no timeout */)
+{
+ int maxfd, n;
+ fd_set reads, writes;
+ struct timeval timeout;
+ struct timeval *timeout_p;
+
+ assert(read_select_1 >= -1 && read_select_2 >= -1 && write_select_1 >= -1 && write_select_2 >= -1);
+ assert(read_select_1 < FD_SETSIZE && read_select_2 < FD_SETSIZE -1 && write_select_1 < FD_SETSIZE -1 && write_select_2 < FD_SETSIZE -1);
+
+ maxfd = max(max(read_select_1, read_select_2), max(write_select_1, write_select_2));
+ assert(maxfd >= 0);
+
+ FD_ZERO(&reads);
+ FD_ZERO(&writes);
+
+ for(n = 0; n < 4; ++n) {
+ int i = n % 2;
+ int w = n >= 2;
+ /* loop over all (i, w) in {0,1}x{0,1} */
+ int fd;
+
+ if (i == 0 && w == 0)
+ fd = read_select_1;
+ else if (i == 1 && w == 0)
+ fd = read_select_2;
+ else if (i == 0 && w == 1)
+ fd = write_select_1;
+ else {
+ assert(i == 1 && w == 1);
+ fd = write_select_2;
+ }
+
+ if (fd >= 0) {
+ if (w == 0)
+ FD_SET(fd, &reads);
+ else /* w == 1 */
+ FD_SET(fd, &writes);
+ }
+ }
+
+ if (seconds >= 0) {
+ timeout.tv_sec = seconds;
+ timeout.tv_usec = 0;
+ timeout_p = &timeout;
+ } else
+ timeout_p = NULL;
+
+ DEBUG_MSG2("select no.", ++tls_select_count);
+ select(maxfd + 1, &reads, &writes, (fd_set *) NULL, timeout_p);
+ DEBUG_MSG("cont.");
+}
+
+/*****************************************************************************/
+
+#define TUNNELBUFSIZE (16*1024)
+struct tunnelbuf {
+ char buf[TUNNELBUFSIZE];
+ size_t len;
+ size_t offset;
+};
+
+static int tls_connect_attempt(SSL *, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref);
+
+static int tls_accept_attempt(SSL *, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref);
+
+static int tls_write_attempt(SSL *, struct tunnelbuf *, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref);
+
+static int tls_read_attempt(SSL *, struct tunnelbuf *, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref);
+
+static int write_attempt(int fd, struct tunnelbuf *, int *select, int *closed, int *progress);
+
+static int read_attempt(int fd, struct tunnelbuf *, int *select, int *closed, int *progress);
+
+static void write_info(SSL *ssl, int *info_fd)
+{
+ if (*info_fd != -1) {
+ long v;
+ int v_ok;
+ struct tls_x509_name_string peer;
+ char infobuf[TLS_INFO_SIZE];
+ int r;
+
+ DEBUG_MSG("write_info");
+ v = SSL_get_verify_result(ssl);
+ v_ok = (v == X509_V_OK) ? 'A' : 'E'; /* Auth./Error */
+ {
+ X509 *peercert;
+
+ peercert = SSL_get_peer_certificate(ssl);
+ tls_get_x509_subject_name_oneline(peercert, &peer);
+ if (peercert != NULL)
+ X509_free(peercert);
+ }
+ if (peer.str[0] == '\0')
+ v_ok = '0'; /* no cert at all */
+ else
+ if (strchr(peer.str, '\n')) {
+ /* should not happen, but make sure */
+ *strchr(peer.str, '\n') = '\0';
+ }
+ r = snprintf(infobuf, sizeof infobuf, "%c:%s\n%s\n", v_ok, X509_verify_cert_error_string(v), peer.str);
+ DEBUG_MSG2("snprintf", r);
+ if (r == -1 || r >= sizeof infobuf)
+ r = sizeof infobuf - 1;
+ write(*info_fd, infobuf, r);
+ close (*info_fd);
+ *info_fd = -1;
+ }
+}
+
+
+/* tls_proxy expects that all fds are closed after return */
+static void
+tls_proxy(int clear_fd, int tls_fd, int info_fd, SSL_CTX *ctx, int client_p)
+{
+ struct tunnelbuf clear_to_tls, tls_to_clear;
+ SSL *ssl;
+ BIO *rbio, *wbio;
+ int closed, in_handshake;
+ const char *err_pref_1 = "", *err_pref_2 = "";
+ const char *err_def = NULL;
+
+ assert(clear_fd != -1);
+ assert(tls_fd != -1);
+ assert(clear_fd < FD_SETSIZE);
+ assert(tls_fd < FD_SETSIZE);
+ /* info_fd may be -1 */
+ assert(ctx != NULL);
+
+ tls_rand_seed_uniquely();
+
+ tls_socket_nonblocking(clear_fd);
+ DEBUG_MSG2("clear_fd", clear_fd);
+ tls_socket_nonblocking(tls_fd);
+ DEBUG_MSG2("tls_fd", tls_fd);
+
+ ssl = SSL_new(ctx);
+ if (ssl == NULL)
+ goto err;
+ DEBUG_MSG("SSL_new");
+ if (!SSL_set_fd(ssl, tls_fd))
+ goto err;
+ rbio = SSL_get_rbio(ssl);
+ wbio = SSL_get_wbio(ssl); /* should be the same, but who cares */
+ assert(rbio != NULL);
+ assert(wbio != NULL);
+ if (client_p)
+ SSL_set_connect_state(ssl);
+ else
+ SSL_set_accept_state(ssl);
+
+ closed = 0;
+ in_handshake = 1;
+ tls_to_clear.len = 0;
+ tls_to_clear.offset = 0;
+ clear_to_tls.len = 0;
+ clear_to_tls.offset = 0;
+
+ err_def = "I/O error";
+
+ /* loop finishes as soon as we detect that one side closed;
+ * when all (program and OS) buffers have enough space,
+ * the data from the last succesful read in each direction is transferred
+ * before close */
+ do {
+ int clear_read_select = 0, clear_write_select = 0,
+ tls_read_select = 0, tls_write_select = 0,
+ progress = 0;
+ int r;
+ unsigned long num_read = BIO_number_read(rbio),
+ num_written = BIO_number_written(wbio);
+
+ DEBUG_MSG2("loop iteration", ++tls_loop_count);
+
+ if (in_handshake) {
+ DEBUG_MSG("in_handshake");
+ if (client_p)
+ r = tls_connect_attempt(ssl, &tls_write_select, &tls_read_select, &closed, &progress, &err_pref_1);
+ else
+ r = tls_accept_attempt(ssl, &tls_write_select, &tls_read_select, &closed, &progress, &err_pref_1);
+ if (r != 0) {
+ write_info(ssl, &info_fd);
+ goto err;
+ }
+ if (closed)
+ goto err_return;
+ if (!SSL_in_init(ssl)) {
+ in_handshake = 0;
+ write_info(ssl, &info_fd);
+ }
+ }
+
+ if (clear_to_tls.len != 0 && !in_handshake) {
+ assert(!closed);
+
+ r = tls_write_attempt(ssl, &clear_to_tls, &tls_write_select, &tls_read_select, &closed, &progress, &err_pref_1);
+ if (r != 0)
+ goto err;
+ if (closed) {
+ assert(progress);
+ tls_to_clear.offset = 0;
+ tls_to_clear.len = 0;
+ }
+ }
+
+ if (tls_to_clear.len != 0) {
+ assert(!closed);
+
+ r = write_attempt(clear_fd, &tls_to_clear, &clear_write_select, &closed, &progress);
+ if (r != 0)
+ goto err_return;
+ if (closed) {
+ assert(progress);
+ clear_to_tls.offset = 0;
+ clear_to_tls.len = 0;
+ }
+ }
+
+ if (!closed) {
+ if (clear_to_tls.offset + clear_to_tls.len < sizeof clear_to_tls.buf) {
+ r = read_attempt(clear_fd, &clear_to_tls, &clear_read_select, &closed, &progress);
+ if (r != 0)
+ goto err_return;
+ if (closed) {
+ r = SSL_shutdown(ssl);
+ DEBUG_MSG2("SSL_shutdown", r);
+ }
+ }
+ }
+
+ if (!closed && !in_handshake) {
+ if (tls_to_clear.offset + tls_to_clear.len < sizeof tls_to_clear.buf) {
+ r = tls_read_attempt(ssl, &tls_to_clear, &tls_write_select, &tls_read_select, &closed, &progress, &err_pref_1);
+ if (r != 0)
+ goto err;
+ if (closed) {
+ r = SSL_shutdown(ssl);
+ DEBUG_MSG2("SSL_shutdown", r);
+ }
+ }
+ }
+
+ if (!progress) {
+ DEBUG_MSG("!progress?");
+ if (num_read != BIO_number_read(rbio) || num_written != BIO_number_written(wbio))
+ progress = 1;
+
+ if (!progress) {
+ DEBUG_MSG("!progress");
+ assert(clear_read_select || tls_read_select || clear_write_select || tls_write_select);
+ tls_sockets_select(clear_read_select ? clear_fd : -1, tls_read_select ? tls_fd : -1, clear_write_select ? clear_fd : -1, tls_write_select ? tls_fd : -1, -1);
+ }
+ }
+ } while (!closed);
+ return;
+
+ err:
+ tls_openssl_errors(err_pref_1, err_pref_2, err_def, tls_child_apparg);
+ err_return:
+ return;
+}
+
+
+static int
+tls_get_error(SSL *ssl, int r, int *write_select, int *read_select, int *closed, int *progress)
+{
+ int err = SSL_get_error(ssl, r);
+
+ if (err == SSL_ERROR_NONE) {
+ assert(r > 0);
+ *progress = 1;
+ return 0;
+ }
+
+ assert(r <= 0);
+
+ switch (err) {
+ case SSL_ERROR_ZERO_RETURN:
+ assert(r == 0);
+ *closed = 1;
+ *progress = 1;
+ return 0;
+
+ case SSL_ERROR_WANT_WRITE:
+ *write_select = 1;
+ return 0;
+
+ case SSL_ERROR_WANT_READ:
+ *read_select = 1;
+ return 0;
+ }
+
+ return -1;
+}
+
+static int
+tls_connect_attempt(SSL *ssl, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref)
+{
+ int n, r;
+
+ DEBUG_MSG("tls_connect_attempt");
+ n = SSL_connect(ssl);
+ DEBUG_MSG2("SSL_connect",n);
+ r = tls_get_error(ssl, n, write_select, read_select, closed, progress);
+ if (r == -1)
+ *err_pref = " during SSL_connect";
+ return r;
+}
+
+static int
+tls_accept_attempt(SSL *ssl, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref)
+{
+ int n, r;
+
+ DEBUG_MSG("tls_accept_attempt");
+ n = SSL_accept(ssl);
+ DEBUG_MSG2("SSL_accept",n);
+ r = tls_get_error(ssl, n, write_select, read_select, closed, progress);
+ if (r == -1)
+ *err_pref = " during SSL_accept";
+ return r;
+}
+
+static int
+tls_write_attempt(SSL *ssl, struct tunnelbuf *buf, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref)
+{
+ int n, r;
+
+ DEBUG_MSG("tls_write_attempt");
+ n = SSL_write(ssl, buf->buf + buf->offset, buf->len);
+ DEBUG_MSG2("SSL_write",n);
+ r = tls_get_error(ssl, n, write_select, read_select, closed, progress);
+ if (n > 0) {
+ buf->len -= n;
+ assert(buf->len >= 0);
+ if (buf->len == 0)
+ buf->offset = 0;
+ else
+ buf->offset += n;
+ }
+ if (r == -1)
+ *err_pref = " during SSL_write";
+ return r;
+}
+
+static int
+tls_read_attempt(SSL *ssl, struct tunnelbuf *buf, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref)
+{
+ int n, r;
+ size_t total;
+
+ DEBUG_MSG("tls_read_attempt");
+ total = buf->offset + buf->len;
+ assert(total < sizeof buf->buf);
+ n = SSL_read(ssl, buf->buf + total, (sizeof buf->buf) - total);
+ DEBUG_MSG2("SSL_read",n);
+ r = tls_get_error(ssl, n, write_select, read_select, closed, progress);
+ if (n > 0) {
+ buf->len += n;
+ assert(buf->offset + buf->len <= sizeof buf->buf);
+ }
+ if (r == -1)
+ *err_pref = " during SSL_read";
+ return r;
+}
+
+static int
+get_error(int r, int *select, int *closed, int *progress)
+{
+ if (r >= 0) {
+ *progress = 1;
+ if (r == 0)
+ *closed = 1;
+ return 0;
+ } else {
+ assert(r == -1);
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ *select = 1;
+ return 0;
+ } else if (errno == EPIPE) {
+ *progress = 1;
+ *closed = 1;
+ return 0;
+ } else
+ return -1;
+ }
+}
+
+static int write_attempt(int fd, struct tunnelbuf *buf, int *select, int *closed, int *progress)
+{
+ int n, r;
+
+ DEBUG_MSG("write_attempt");
+ n = write(fd, buf->buf + buf->offset, buf->len);
+ DEBUG_MSG2("write",n);
+ r = get_error(n, select, closed, progress);
+ if (n > 0) {
+ buf->len -= n;
+ assert(buf->len >= 0);
+ if (buf->len == 0)
+ buf->offset = 0;
+ else
+ buf->offset += n;
+ }
+ if (r == -1)
+ tls_errprintf(1, tls_child_apparg, "write error: %s\n", strerror(errno));
+ return r;
+}
+
+static int
+read_attempt(int fd, struct tunnelbuf *buf, int *select, int *closed, int *progress)
+{
+ int n, r;
+ size_t total;
+
+ DEBUG_MSG("read_attempt");
+ total = buf->offset + buf->len;
+ assert(total < sizeof buf->buf);
+ n = read(fd, buf->buf + total, (sizeof buf->buf) - total);
+ DEBUG_MSG2("read",n);
+ r = get_error(n, select, closed, progress);
+ if (n > 0) {
+ buf->len += n;
+ assert(buf->offset + buf->len <= sizeof buf->buf);
+ }
+ if (r == -1)
+ tls_errprintf(1, tls_child_apparg, "read error: %s\n", strerror(errno));
+ return r;
+}
diff --git a/lib/libssl/src/demos/easy_tls/easy-tls.h b/lib/libssl/src/demos/easy_tls/easy-tls.h
new file mode 100644
index 00000000000..0cfbd8fe7b8
--- /dev/null
+++ b/lib/libssl/src/demos/easy_tls/easy-tls.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; c-file-style: "bsd" -*- */
+/*
+ * easy-tls.h -- generic TLS proxy.
+ * $Id: easy-tls.h,v 1.1 2002/05/15 02:29:18 beck Exp $
+ */
+/*
+ * (c) Copyright 1999 Bodo Moeller. All rights reserved.
+ */
+
+#ifndef HEADER_TLS_H
+#define HEADER_TLS_H
+
+#ifndef HEADER_SSL_H
+typedef struct ssl_ctx_st SSL_CTX;
+#endif
+
+#define TLS_INFO_SIZE 512 /* max. # of bytes written to infofd */
+
+void tls_set_dhe1024(int i, void* apparg);
+/* Generate DHE parameters:
+ * i >= 0 deterministic (i selects seed), i < 0 random (may take a while).
+ * tls_create_ctx calls this with random non-negative i if the application
+ * has never called it.*/
+
+void tls_rand_seed(void);
+int tls_rand_seed_from_file(const char *filename, size_t n, void *apparg);
+void tls_rand_seed_from_memory(const void *buf, size_t n);
+
+struct tls_create_ctx_args
+{
+ int client_p;
+ const char *certificate_file;
+ const char *key_file;
+ const char *ca_file;
+ int verify_depth;
+ int fail_unless_verified;
+ int export_p;
+};
+struct tls_create_ctx_args tls_create_ctx_defaultargs(void);
+/* struct tls_create_ctx_args is similar to a conventional argument list,
+ * but it can provide default values and allows for future extension. */
+SSL_CTX *tls_create_ctx(struct tls_create_ctx_args, void *apparg);
+
+struct tls_start_proxy_args
+{
+ int fd;
+ int client_p;
+ SSL_CTX *ctx;
+ pid_t *pid;
+ int *infofd;
+};
+struct tls_start_proxy_args tls_start_proxy_defaultargs(void);
+/* tls_start_proxy return value *MUST* be checked!
+ * 0 means ok, otherwise we've probably run out of some resources. */
+int tls_start_proxy(struct tls_start_proxy_args, void *apparg);
+
+#endif
diff --git a/lib/libssl/src/demos/easy_tls/test.c b/lib/libssl/src/demos/easy_tls/test.c
new file mode 100644
index 00000000000..4ce676ca93e
--- /dev/null
+++ b/lib/libssl/src/demos/easy_tls/test.c
@@ -0,0 +1,244 @@
+/* test.c */
+/* $Id: test.c,v 1.1 2002/05/15 02:29:18 beck Exp $ */
+
+#define L_PORT 9999
+#define C_PORT 443
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "test.h"
+#include "easy-tls.h"
+
+void
+test_process_init(int fd, int client_p, void *apparg)
+{
+ fprintf(stderr, "test_process_init(fd = %d, client_p = %d, apparg = %p)\n", fd, client_p, apparg);
+}
+
+void
+test_errflush(int child_p, char *errbuf, size_t num, void *apparg)
+{
+ fputs(errbuf, stderr);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int s, fd, r;
+ FILE *conn_in;
+ FILE *conn_out;
+ char buf[256];
+ SSL_CTX *ctx;
+ int client_p = 0;
+ int port;
+ int tls = 0;
+ char infobuf[TLS_INFO_SIZE + 1];
+
+ if (argc > 1 && argv[1][0] == '-') {
+ fputs("Usage: test [port] -- server\n"
+ " test num.num.num.num [port] -- client\n",
+ stderr);
+ exit(1);
+ }
+
+ if (argc > 1) {
+ if (strchr(argv[1], '.')) {
+ client_p = 1;
+ }
+ }
+
+ fputs(client_p ? "Client\n" : "Server\n", stderr);
+
+ {
+ struct tls_create_ctx_args a = tls_create_ctx_defaultargs();
+ a.client_p = client_p;
+ a.certificate_file = "cert.pem";
+ a.key_file = "cert.pem";
+ a.ca_file = "cacerts.pem";
+
+ ctx = tls_create_ctx(a, NULL);
+ if (ctx == NULL)
+ exit(1);
+ }
+
+ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (s == -1) {
+ perror("socket");
+ exit(1);
+ }
+
+ if (client_p) {
+ struct sockaddr_in addr;
+ size_t addr_len = sizeof addr;
+
+ addr.sin_family = AF_INET;
+ assert(argc > 1);
+ if (argc > 2)
+ sscanf(argv[2], "%d", &port);
+ else
+ port = C_PORT;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = inet_addr(argv[1]);
+
+ r = connect(s, &addr, addr_len);
+ if (r != 0) {
+ perror("connect");
+ exit(1);
+ }
+ fd = s;
+ fprintf(stderr, "Connect (fd = %d).\n", fd);
+ } else {
+ /* server */
+ {
+ int i = 1;
+
+ r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof i);
+ if (r == -1) {
+ perror("setsockopt");
+ exit(1);
+ }
+ }
+
+ {
+ struct sockaddr_in addr;
+ size_t addr_len = sizeof addr;
+
+ if (argc > 1)
+ sscanf(argv[1], "%d", &port);
+ else
+ port = L_PORT;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ r = bind(s, &addr, addr_len);
+ if (r != 0) {
+ perror("bind");
+ exit(1);
+ }
+ }
+
+ r = listen(s, 1);
+ if (r == -1) {
+ perror("listen");
+ exit(1);
+ }
+
+ fprintf(stderr, "Listening at port %i.\n", port);
+
+ fd = accept(s, NULL, 0);
+ if (fd == -1) {
+ perror("accept");
+ exit(1);
+ }
+
+ fprintf(stderr, "Accept (fd = %d).\n", fd);
+ }
+
+ conn_in = fdopen(fd, "r");
+ if (conn_in == NULL) {
+ perror("fdopen");
+ exit(1);
+ }
+ conn_out = fdopen(fd, "w");
+ if (conn_out == NULL) {
+ perror("fdopen");
+ exit(1);
+ }
+
+ setvbuf(conn_in, NULL, _IOLBF, 256);
+ setvbuf(conn_out, NULL, _IOLBF, 256);
+
+ while (fgets(buf, sizeof buf, stdin) != NULL) {
+ if (buf[0] == 'W') {
+ fprintf(conn_out, "%.*s\r\n", (int)(strlen(buf + 1) - 1), buf + 1);
+ fprintf(stderr, ">>> %.*s\n", (int)(strlen(buf + 1) - 1), buf + 1);
+ } else if (buf[0] == 'C') {
+ fprintf(stderr, "Closing.\n");
+ fclose(conn_in);
+ fclose(conn_out);
+ exit(0);
+ } else if (buf[0] == 'R') {
+ int lines = 0;
+
+ sscanf(buf + 1, "%d", &lines);
+ do {
+ if (fgets(buf, sizeof buf, conn_in) == NULL) {
+ if (ferror(conn_in)) {
+ fprintf(stderr, "ERROR\n");
+ exit(1);
+ }
+ fprintf(stderr, "CLOSED\n");
+ return 0;
+ }
+ fprintf(stderr, "<<< %s", buf);
+ } while (--lines > 0);
+ } else if (buf[0] == 'T') {
+ int infofd;
+
+ tls++;
+ {
+ struct tls_start_proxy_args a = tls_start_proxy_defaultargs();
+ a.fd = fd;
+ a.client_p = client_p;
+ a.ctx = ctx;
+ a.infofd = &infofd;
+ r = tls_start_proxy(a, NULL);
+ }
+ assert(r != 1);
+ if (r != 0) {
+ fprintf(stderr, "tls_start_proxy failed: %d\n", r);
+ switch (r) {
+ case -1:
+ fputs("socketpair", stderr); break;
+ case 2:
+ fputs("FD_SETSIZE exceeded", stderr); break;
+ case -3:
+ fputs("pipe", stderr); break;
+ case -4:
+ fputs("fork", stderr); break;
+ case -5:
+ fputs("dup2", stderr); break;
+ default:
+ fputs("?", stderr);
+ }
+ if (r < 0)
+ perror("");
+ else
+ fputc('\n', stderr);
+ exit(1);
+ }
+
+ r = read(infofd, infobuf, sizeof infobuf - 1);
+ if (r > 0) {
+ const char *info = infobuf;
+ const char *eol;
+
+ infobuf[r] = '\0';
+ while ((eol = strchr(info, '\n')) != NULL) {
+ fprintf(stderr, "+++ `%.*s'\n", eol - info, info);
+ info = eol+1;
+ }
+ close (infofd);
+ }
+ } else {
+ fprintf(stderr, "W... write line to network\n"
+ "R[n] read line (n lines) from network\n"
+ "C close\n"
+ "T start %sTLS proxy\n", tls ? "another " : "");
+ }
+ }
+ return 0;
+}
diff --git a/lib/libssl/src/demos/easy_tls/test.h b/lib/libssl/src/demos/easy_tls/test.h
new file mode 100644
index 00000000000..c580169464b
--- /dev/null
+++ b/lib/libssl/src/demos/easy_tls/test.h
@@ -0,0 +1,11 @@
+/* test.h */
+/* $Id: test.h,v 1.1 2002/05/15 02:29:18 beck Exp $ */
+
+
+void test_process_init(int fd, int client_p, void *apparg);
+#define TLS_APP_PROCESS_INIT test_process_init
+
+#undef TLS_CUMULATE_ERRORS
+
+void test_errflush(int child_p, char *errbuf, size_t num, void *apparg);
+#define TLS_APP_ERRFLUSH test_errflush
diff --git a/lib/libssl/src/demos/maurice/example1.c b/lib/libssl/src/demos/maurice/example1.c
index 0e70523a336..1ef82999006 100644
--- a/lib/libssl/src/demos/maurice/example1.c
+++ b/lib/libssl/src/demos/maurice/example1.c
@@ -72,7 +72,7 @@ void main_encrypt(void)
pubKey[0] = ReadPublicKey(PUBFILE);
- if(!pubKey)
+ if(!pubKey[0])
{
fprintf(stderr,"Error: can't load public key");
exit(1);
@@ -126,11 +126,11 @@ void main_encrypt(void)
void main_decrypt(void)
{
- char buf[512];
+ char buf[520];
char ebuf[512];
unsigned int buflen;
EVP_CIPHER_CTX ectx;
- unsigned char iv[8];
+ unsigned char iv[EVP_MAX_IV_LENGTH];
unsigned char *encryptKey;
unsigned int ekeylen;
EVP_PKEY *privateKey;
@@ -164,7 +164,6 @@ void main_decrypt(void)
read(STDIN, encryptKey, ekeylen);
read(STDIN, iv, sizeof(iv));
-
EVP_OpenInit(&ectx,
EVP_des_ede3_cbc(),
encryptKey,
@@ -185,7 +184,6 @@ void main_decrypt(void)
}
EVP_OpenUpdate(&ectx, buf, &buflen, ebuf, readlen);
-
write(STDOUT, buf, buflen);
}
diff --git a/lib/libssl/src/demos/maurice/example3.c b/lib/libssl/src/demos/maurice/example3.c
index c8462a47c37..03d8a20f62b 100644
--- a/lib/libssl/src/demos/maurice/example3.c
+++ b/lib/libssl/src/demos/maurice/example3.c
@@ -57,7 +57,8 @@ void do_cipher(char *pw, int operation)
EVP_BytesToKey(ALG, EVP_md5(), "salu", pw, strlen(pw), 1, key, iv);
- EVP_CipherInit(&ectx, ALG, key, iv, operation);
+ EVP_CIPHER_CTX_init(&ectx);
+ EVP_CipherInit_ex(&ectx, ALG, NULL, key, iv, operation);
while(1)
{
@@ -79,7 +80,8 @@ void do_cipher(char *pw, int operation)
write(STDOUT, ebuf, ebuflen);
}
- EVP_CipherFinal(&ectx, ebuf, &ebuflen);
+ EVP_CipherFinal_ex(&ectx, ebuf, &ebuflen);
+ EVP_CIPHER_CTX_cleanup(&ectx);
write(STDOUT, ebuf, ebuflen);
}
diff --git a/lib/libssl/src/demos/maurice/loadkeys.c b/lib/libssl/src/demos/maurice/loadkeys.c
index 0f3464753af..82fd22a9503 100644
--- a/lib/libssl/src/demos/maurice/loadkeys.c
+++ b/lib/libssl/src/demos/maurice/loadkeys.c
@@ -31,9 +31,7 @@ EVP_PKEY * ReadPublicKey(const char *certfile)
if (!fp)
return NULL;
- x509 = (X509 *)PEM_ASN1_read ((char *(*)())d2i_X509,
- PEM_STRING_X509,
- fp, NULL, NULL);
+ x509 = PEM_read_X509(fp, NULL, 0, NULL);
if (x509 == NULL)
{
@@ -61,10 +59,7 @@ EVP_PKEY *ReadPrivateKey(const char *keyfile)
if (!fp)
return NULL;
- pkey = (EVP_PKEY*)PEM_ASN1_read ((char *(*)())d2i_PrivateKey,
- PEM_STRING_EVP_PKEY,
- fp,
- NULL, NULL);
+ pkey = PEM_read_PrivateKey(fp, NULL, 0, NULL);
fclose (fp);
diff --git a/lib/libssl/src/demos/pkcs12/README b/lib/libssl/src/demos/pkcs12/README
new file mode 100644
index 00000000000..c87434b04f6
--- /dev/null
+++ b/lib/libssl/src/demos/pkcs12/README
@@ -0,0 +1,3 @@
+PKCS#12 demo applications
+
+Written by Steve Henson.
diff --git a/lib/libssl/src/demos/pkcs12/pkread.c b/lib/libssl/src/demos/pkcs12/pkread.c
new file mode 100644
index 00000000000..8e1b6863121
--- /dev/null
+++ b/lib/libssl/src/demos/pkcs12/pkread.c
@@ -0,0 +1,61 @@
+/* pkread.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/pkcs12.h>
+
+/* Simple PKCS#12 file reader */
+
+int main(int argc, char **argv)
+{
+ FILE *fp;
+ EVP_PKEY *pkey;
+ X509 *cert;
+ STACK_OF(X509) *ca = NULL;
+ PKCS12 *p12;
+ int i;
+ if (argc != 4) {
+ fprintf(stderr, "Usage: pkread p12file password opfile\n");
+ exit (1);
+ }
+ SSLeay_add_all_algorithms();
+ ERR_load_crypto_strings();
+ if (!(fp = fopen(argv[1], "rb"))) {
+ fprintf(stderr, "Error opening file %s\n", argv[1]);
+ exit(1);
+ }
+ p12 = d2i_PKCS12_fp(fp, NULL);
+ fclose (fp);
+ if (!p12) {
+ fprintf(stderr, "Error reading PKCS#12 file\n");
+ ERR_print_errors_fp(stderr);
+ exit (1);
+ }
+ if (!PKCS12_parse(p12, argv[2], &pkey, &cert, &ca)) {
+ fprintf(stderr, "Error parsing PKCS#12 file\n");
+ ERR_print_errors_fp(stderr);
+ exit (1);
+ }
+ PKCS12_free(p12);
+ if (!(fp = fopen(argv[3], "w"))) {
+ fprintf(stderr, "Error opening file %s\n", argv[1]);
+ exit(1);
+ }
+ if (pkey) {
+ fprintf(fp, "***Private Key***\n");
+ PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
+ }
+ if (cert) {
+ fprintf(fp, "***User Certificate***\n");
+ PEM_write_X509_AUX(fp, cert);
+ }
+ if (ca && sk_num(ca)) {
+ fprintf(fp, "***Other Certificates***\n");
+ for (i = 0; i < sk_X509_num(ca); i++)
+ PEM_write_X509_AUX(fp, sk_X509_value(ca, i));
+ }
+ fclose(fp);
+ return 0;
+}
diff --git a/lib/libssl/src/demos/pkcs12/pkwrite.c b/lib/libssl/src/demos/pkcs12/pkwrite.c
new file mode 100644
index 00000000000..15f839d1eba
--- /dev/null
+++ b/lib/libssl/src/demos/pkcs12/pkwrite.c
@@ -0,0 +1,46 @@
+/* pkwrite.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/pkcs12.h>
+
+/* Simple PKCS#12 file creator */
+
+int main(int argc, char **argv)
+{
+ FILE *fp;
+ EVP_PKEY *pkey;
+ X509 *cert;
+ PKCS12 *p12;
+ if (argc != 5) {
+ fprintf(stderr, "Usage: pkwrite infile password name p12file\n");
+ exit(1);
+ }
+ SSLeay_add_all_algorithms();
+ ERR_load_crypto_strings();
+ if (!(fp = fopen(argv[1], "r"))) {
+ fprintf(stderr, "Error opening file %s\n", argv[1]);
+ exit(1);
+ }
+ cert = PEM_read_X509(fp, NULL, NULL, NULL);
+ rewind(fp);
+ pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
+ fclose(fp);
+ p12 = PKCS12_create(argv[2], argv[3], pkey, cert, NULL, 0,0,0,0,0);
+ if(!p12) {
+ fprintf(stderr, "Error creating PKCS#12 structure\n");
+ ERR_print_errors_fp(stderr);
+ exit(1);
+ }
+ if (!(fp = fopen(argv[4], "wb"))) {
+ fprintf(stderr, "Error opening file %s\n", argv[1]);
+ ERR_print_errors_fp(stderr);
+ exit(1);
+ }
+ i2d_PKCS12_fp(fp, p12);
+ PKCS12_free(p12);
+ fclose(fp);
+ return 0;
+}
diff --git a/lib/libssl/src/demos/sign/sign.c b/lib/libssl/src/demos/sign/sign.c
index 0fdf0de387d..a6c66e17c3c 100644
--- a/lib/libssl/src/demos/sign/sign.c
+++ b/lib/libssl/src/demos/sign/sign.c
@@ -96,7 +96,7 @@ int main ()
fp = fopen (keyfile, "r");
if (fp == NULL) exit (1);
- pkey = PEM_read_PrivateKey(fp, NULL, NULL);
+ pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
fclose (fp);
if (pkey == NULL) {
@@ -122,7 +122,7 @@ int main ()
fp = fopen (certfile, "r");
if (fp == NULL) exit (1);
- x509 = PEM_read_X509(fp, NULL, NULL);
+ x509 = PEM_read_X509(fp, NULL, NULL, NULL);
fclose (fp);
if (x509 == NULL) {
diff --git a/lib/libssl/src/demos/ssl/cli.cpp b/lib/libssl/src/demos/ssl/cli.cpp
index daea2bd9c7a..49cba5da0c8 100644
--- a/lib/libssl/src/demos/ssl/cli.cpp
+++ b/lib/libssl/src/demos/ssl/cli.cpp
@@ -79,12 +79,12 @@ void main ()
str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0);
CHK_NULL(str);
printf ("\t subject: %s\n", str);
- Free (str);
+ OPENSSL_free (str);
str = X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0);
CHK_NULL(str);
printf ("\t issuer: %s\n", str);
- Free (str);
+ OPENSSL_free (str);
/* We could do all sorts of certificate verification stuff here before
deallocating the certificate. */
diff --git a/lib/libssl/src/demos/ssl/inetdsrv.cpp b/lib/libssl/src/demos/ssl/inetdsrv.cpp
index 5b092272106..efd70d2771b 100644
--- a/lib/libssl/src/demos/ssl/inetdsrv.cpp
+++ b/lib/libssl/src/demos/ssl/inetdsrv.cpp
@@ -65,12 +65,12 @@ void main ()
str = X509_NAME_oneline (X509_get_subject_name (client_cert));
CHK_NULL(str);
fprintf (log, "\t subject: %s\n", str);
- Free (str);
+ OPENSSL_free (str);
str = X509_NAME_oneline (X509_get_issuer_name (client_cert));
CHK_NULL(str);
fprintf (log, "\t issuer: %s\n", str);
- Free (str);
+ OPENSSL_free (str);
/* We could do all sorts of certificate verification stuff here before
deallocating the certificate. */
diff --git a/lib/libssl/src/demos/ssl/serv.cpp b/lib/libssl/src/demos/ssl/serv.cpp
index aec610d0189..b142c758d2c 100644
--- a/lib/libssl/src/demos/ssl/serv.cpp
+++ b/lib/libssl/src/demos/ssl/serv.cpp
@@ -121,12 +121,12 @@ void main ()
str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
CHK_NULL(str);
printf ("\t subject: %s\n", str);
- Free (str);
+ OPENSSL_free (str);
str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0);
CHK_NULL(str);
printf ("\t issuer: %s\n", str);
- Free (str);
+ OPENSSL_free (str);
/* We could do all sorts of certificate verification stuff here before
deallocating the certificate. */
diff --git a/lib/libssl/src/demos/state_machine/Makefile b/lib/libssl/src/demos/state_machine/Makefile
new file mode 100644
index 00000000000..c7a114540de
--- /dev/null
+++ b/lib/libssl/src/demos/state_machine/Makefile
@@ -0,0 +1,9 @@
+CFLAGS=-I../../include -Wall -Werror -g
+
+all: state_machine
+
+state_machine: state_machine.o
+ $(CC) -o state_machine state_machine.o -L../.. -lssl -lcrypto
+
+test: state_machine
+ ./state_machine 10000 ../../apps/server.pem ../../apps/server.pem
diff --git a/lib/libssl/src/demos/state_machine/state_machine.c b/lib/libssl/src/demos/state_machine/state_machine.c
new file mode 100644
index 00000000000..fef3f3e3d1f
--- /dev/null
+++ b/lib/libssl/src/demos/state_machine/state_machine.c
@@ -0,0 +1,416 @@
+/* ====================================================================
+ * Copyright (c) 2000 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/*
+ * Nuron, a leader in hardware encryption technology, generously
+ * sponsored the development of this demo by Ben Laurie.
+ *
+ * See http://www.nuron.com/.
+ */
+
+/*
+ * the aim of this demo is to provide a fully working state-machine
+ * style SSL implementation, i.e. one where the main loop acquires
+ * some data, then converts it from or to SSL by feeding it into the
+ * SSL state machine. It then does any I/O required by the state machine
+ * and loops.
+ *
+ * In order to keep things as simple as possible, this implementation
+ * listens on a TCP socket, which it expects to get an SSL connection
+ * on (for example, from s_client) and from then on writes decrypted
+ * data to stdout and encrypts anything arriving on stdin. Verbose
+ * commentary is written to stderr.
+ *
+ * This implementation acts as a server, but it can also be done for a client. */
+
+#include <openssl/ssl.h>
+#include <assert.h>
+#include <unistd.h>
+#include <string.h>
+#include <openssl/err.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+/* die_unless is intended to work like assert, except that it happens
+ always, even if NDEBUG is defined. Use assert as a stopgap. */
+
+#define die_unless(x) assert(x)
+
+typedef struct
+ {
+ SSL_CTX *pCtx;
+ BIO *pbioRead;
+ BIO *pbioWrite;
+ SSL *pSSL;
+ } SSLStateMachine;
+
+void SSLStateMachine_print_error(SSLStateMachine *pMachine,const char *szErr)
+ {
+ unsigned long l;
+
+ fprintf(stderr,"%s\n",szErr);
+ while((l=ERR_get_error()))
+ {
+ char buf[1024];
+
+ ERR_error_string_n(l,buf,sizeof buf);
+ fprintf(stderr,"Error %lx: %s\n",l,buf);
+ }
+ }
+
+SSLStateMachine *SSLStateMachine_new(const char *szCertificateFile,
+ const char *szKeyFile)
+ {
+ SSLStateMachine *pMachine=malloc(sizeof *pMachine);
+ int n;
+
+ die_unless(pMachine);
+
+ pMachine->pCtx=SSL_CTX_new(SSLv23_server_method());
+ die_unless(pMachine->pCtx);
+
+ n=SSL_CTX_use_certificate_file(pMachine->pCtx,szCertificateFile,
+ SSL_FILETYPE_PEM);
+ die_unless(n > 0);
+
+ n=SSL_CTX_use_PrivateKey_file(pMachine->pCtx,szKeyFile,SSL_FILETYPE_PEM);
+ die_unless(n > 0);
+
+ pMachine->pSSL=SSL_new(pMachine->pCtx);
+ die_unless(pMachine->pSSL);
+
+ pMachine->pbioRead=BIO_new(BIO_s_mem());
+
+ pMachine->pbioWrite=BIO_new(BIO_s_mem());
+
+ SSL_set_bio(pMachine->pSSL,pMachine->pbioRead,pMachine->pbioWrite);
+
+ SSL_set_accept_state(pMachine->pSSL);
+
+ return pMachine;
+ }
+
+void SSLStateMachine_read_inject(SSLStateMachine *pMachine,
+ const unsigned char *aucBuf,int nBuf)
+ {
+ int n=BIO_write(pMachine->pbioRead,aucBuf,nBuf);
+ /* If it turns out this assert fails, then buffer the data here
+ * and just feed it in in churn instead. Seems to me that it
+ * should be guaranteed to succeed, though.
+ */
+ assert(n == nBuf);
+ fprintf(stderr,"%d bytes of encrypted data fed to state machine\n",n);
+ }
+
+int SSLStateMachine_read_extract(SSLStateMachine *pMachine,
+ unsigned char *aucBuf,int nBuf)
+ {
+ int n;
+
+ if(!SSL_is_init_finished(pMachine->pSSL))
+ {
+ fprintf(stderr,"Doing SSL_accept\n");
+ n=SSL_accept(pMachine->pSSL);
+ if(n == 0)
+ fprintf(stderr,"SSL_accept returned zero\n");
+ if(n < 0)
+ {
+ int err;
+
+ if((err=SSL_get_error(pMachine->pSSL,n)) == SSL_ERROR_WANT_READ)
+ {
+ fprintf(stderr,"SSL_accept wants more data\n");
+ return 0;
+ }
+
+ SSLStateMachine_print_error(pMachine,"SSL_accept error");
+ exit(7);
+ }
+ return 0;
+ }
+
+ n=SSL_read(pMachine->pSSL,aucBuf,nBuf);
+ if(n < 0)
+ {
+ int err=SSL_get_error(pMachine->pSSL,n);
+
+ if(err == SSL_ERROR_WANT_READ)
+ {
+ fprintf(stderr,"SSL_read wants more data\n");
+ return 0;
+ }
+
+ SSLStateMachine_print_error(pMachine,"SSL_read error");
+ exit(8);
+ }
+
+ fprintf(stderr,"%d bytes of decrypted data read from state machine\n",n);
+ return n;
+ }
+
+int SSLStateMachine_write_can_extract(SSLStateMachine *pMachine)
+ {
+ int n=BIO_pending(pMachine->pbioWrite);
+ if(n)
+ fprintf(stderr,"There is encrypted data available to write\n");
+ else
+ fprintf(stderr,"There is no encrypted data available to write\n");
+
+ return n;
+ }
+
+int SSLStateMachine_write_extract(SSLStateMachine *pMachine,
+ unsigned char *aucBuf,int nBuf)
+ {
+ int n;
+
+ n=BIO_read(pMachine->pbioWrite,aucBuf,nBuf);
+ fprintf(stderr,"%d bytes of encrypted data read from state machine\n",n);
+ return n;
+ }
+
+void SSLStateMachine_write_inject(SSLStateMachine *pMachine,
+ const unsigned char *aucBuf,int nBuf)
+ {
+ int n=SSL_write(pMachine->pSSL,aucBuf,nBuf);
+ /* If it turns out this assert fails, then buffer the data here
+ * and just feed it in in churn instead. Seems to me that it
+ * should be guaranteed to succeed, though.
+ */
+ assert(n == nBuf);
+ fprintf(stderr,"%d bytes of unencrypted data fed to state machine\n",n);
+ }
+
+int OpenSocket(int nPort)
+ {
+ int nSocket;
+ struct sockaddr_in saServer;
+ struct sockaddr_in saClient;
+ int one=1;
+ int nSize;
+ int nFD;
+ int nLen;
+
+ nSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
+ if(nSocket < 0)
+ {
+ perror("socket");
+ exit(1);
+ }
+
+ if(setsockopt(nSocket,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof one) < 0)
+ {
+ perror("setsockopt");
+ exit(2);
+ }
+
+ memset(&saServer,0,sizeof saServer);
+ saServer.sin_family=AF_INET;
+ saServer.sin_port=htons(nPort);
+ nSize=sizeof saServer;
+ if(bind(nSocket,(struct sockaddr *)&saServer,nSize) < 0)
+ {
+ perror("bind");
+ exit(3);
+ }
+
+ if(listen(nSocket,512) < 0)
+ {
+ perror("listen");
+ exit(4);
+ }
+
+ nLen=sizeof saClient;
+ nFD=accept(nSocket,(struct sockaddr *)&saClient,&nLen);
+ if(nFD < 0)
+ {
+ perror("accept");
+ exit(5);
+ }
+
+ fprintf(stderr,"Incoming accepted on port %d\n",nPort);
+
+ return nFD;
+ }
+
+int main(int argc,char **argv)
+ {
+ SSLStateMachine *pMachine;
+ int nPort;
+ int nFD;
+ const char *szCertificateFile;
+ const char *szKeyFile;
+ char rbuf[1];
+ int nrbuf=0;
+
+ if(argc != 4)
+ {
+ fprintf(stderr,"%s <port> <certificate file> <key file>\n",argv[0]);
+ exit(6);
+ }
+
+ nPort=atoi(argv[1]);
+ szCertificateFile=argv[2];
+ szKeyFile=argv[3];
+
+ SSL_library_init();
+ OpenSSL_add_ssl_algorithms();
+ SSL_load_error_strings();
+ ERR_load_crypto_strings();
+
+ nFD=OpenSocket(nPort);
+
+ pMachine=SSLStateMachine_new(szCertificateFile,szKeyFile);
+
+ for( ; ; )
+ {
+ fd_set rfds,wfds;
+ unsigned char buf[1024];
+ int n;
+
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+
+ /* Select socket for input */
+ FD_SET(nFD,&rfds);
+
+ /* check whether there's decrypted data */
+ if(!nrbuf)
+ nrbuf=SSLStateMachine_read_extract(pMachine,rbuf,1);
+
+ /* if there's decrypted data, check whether we can write it */
+ if(nrbuf)
+ FD_SET(1,&wfds);
+
+ /* Select socket for output */
+ if(SSLStateMachine_write_can_extract(pMachine))
+ FD_SET(nFD,&wfds);
+
+ /* Select stdin for input */
+ FD_SET(0,&rfds);
+
+ /* Wait for something to do something */
+ n=select(nFD+1,&rfds,&wfds,NULL,NULL);
+ assert(n > 0);
+
+ /* Socket is ready for input */
+ if(FD_ISSET(nFD,&rfds))
+ {
+ n=read(nFD,buf,sizeof buf);
+ if(n == 0)
+ {
+ fprintf(stderr,"Got EOF on socket\n");
+ exit(0);
+ }
+ assert(n > 0);
+
+ SSLStateMachine_read_inject(pMachine,buf,n);
+ }
+
+ /* stdout is ready for output (and hence we have some to send it) */
+ if(FD_ISSET(1,&wfds))
+ {
+ assert(nrbuf == 1);
+ buf[0]=rbuf[0];
+ nrbuf=0;
+
+ n=SSLStateMachine_read_extract(pMachine,buf+1,sizeof buf-1);
+ if(n < 0)
+ {
+ SSLStateMachine_print_error(pMachine,"read extract failed");
+ break;
+ }
+ assert(n >= 0);
+ ++n;
+ if(n > 0) /* FIXME: has to be true now */
+ {
+ int w;
+
+ w=write(1,buf,n);
+ /* FIXME: we should push back any unwritten data */
+ assert(w == n);
+ }
+ }
+
+ /* Socket is ready for output (and therefore we have output to send) */
+ if(FD_ISSET(nFD,&wfds))
+ {
+ int w;
+
+ n=SSLStateMachine_write_extract(pMachine,buf,sizeof buf);
+ assert(n > 0);
+
+ w=write(nFD,buf,n);
+ /* FIXME: we should push back any unwritten data */
+ assert(w == n);
+ }
+
+ /* Stdin is ready for input */
+ if(FD_ISSET(0,&rfds))
+ {
+ n=read(0,buf,sizeof buf);
+ if(n == 0)
+ {
+ fprintf(stderr,"Got EOF on stdin\n");
+ exit(0);
+ }
+ assert(n > 0);
+
+ SSLStateMachine_write_inject(pMachine,buf,n);
+ }
+ }
+ /* not reached */
+ return 0;
+ }
diff --git a/lib/libssl/src/demos/tunala/A-client.pem b/lib/libssl/src/demos/tunala/A-client.pem
new file mode 100644
index 00000000000..a4caf6ef8a8
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/A-client.pem
@@ -0,0 +1,84 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: md5WithRSAEncryption
+ Issuer: C=NZ, L=Wellington, O=Really Irresponsible Authorisation Authority (RIAA), OU=Cert-stamping, CN=Jackov al-Trades/Email=none@fake.domain
+ Validity
+ Not Before: Jan 16 05:19:30 2002 GMT
+ Not After : Jan 14 05:19:30 2012 GMT
+ Subject: C=NZ, L=Auckland, O=Mordor, OU=SSL grunt things, CN=tunala-client/Email=client@fake.domain
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (1024 bit)
+ Modulus (1024 bit):
+ 00:b0:d3:56:5c:c8:7f:fb:f4:95:9d:04:84:4f:82:
+ b7:a2:75:5c:81:48:8c:56:5d:52:ee:38:e1:5c:c8:
+ 9a:70:8e:72:f2:00:1c:17:ef:df:b7:06:59:82:04:
+ f1:f6:49:11:12:a6:4d:cb:1e:ed:ac:59:1c:4a:d0:
+ 3d:de:e6:f2:8d:cd:39:c2:0f:e0:46:2f:db:cb:9f:
+ 47:f7:56:e7:f8:16:5f:68:71:fb:3a:e3:ab:d2:e5:
+ 05:b7:da:65:61:fe:6d:30:e4:12:a8:b5:c1:71:24:
+ 6b:aa:80:05:41:17:a0:8b:6e:8b:e6:04:cf:85:7b:
+ 2a:ac:a1:79:7d:f4:96:6e:77
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ F8:43:CB:4F:4D:4F:BC:6E:52:1A:FD:F9:7B:E1:12:3F:A7:A3:BA:93
+ X509v3 Authority Key Identifier:
+ keyid:49:FB:45:72:12:C4:CC:E1:45:A1:D3:08:9E:95:C4:2C:6D:55:3F:17
+ DirName:/C=NZ/L=Wellington/O=Really Irresponsible Authorisation Authority (RIAA)/OU=Cert-stamping/CN=Jackov al-Trades/Email=none@fake.domain
+ serial:00
+
+ Signature Algorithm: md5WithRSAEncryption
+ 8f:5f:0e:43:da:9d:61:43:7e:03:38:9a:e6:50:9d:42:e8:95:
+ 34:49:75:ec:04:8d:5c:85:99:94:70:a0:e7:1f:1e:a0:8b:0f:
+ d6:e2:cb:f7:35:d9:96:72:bd:a6:e9:8d:4e:b1:e2:ac:97:7f:
+ 2f:70:01:9d:aa:04:bc:d4:01:2b:63:77:a5:de:63:3c:a8:f5:
+ f2:72:af:ec:11:12:c0:d4:70:cf:71:a6:fb:e9:1d:b3:27:07:
+ aa:f2:b1:f3:87:d6:ab:8b:ce:c2:08:1b:3c:f9:ba:ff:77:71:
+ 86:09:ef:9e:4e:04:06:63:44:e9:93:20:90:c7:2d:50:c6:50:
+ f8:66
+-----BEGIN CERTIFICATE-----
+MIID9TCCA16gAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox
+EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp
+YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy
+dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3
+DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMjAxMTYwNTE5MzBaFw0xMjAxMTQw
+NTE5MzBaMIGHMQswCQYDVQQGEwJOWjERMA8GA1UEBxMIQXVja2xhbmQxDzANBgNV
+BAoTBk1vcmRvcjEZMBcGA1UECxMQU1NMIGdydW50IHRoaW5nczEWMBQGA1UEAxMN
+dHVuYWxhLWNsaWVudDEhMB8GCSqGSIb3DQEJARYSY2xpZW50QGZha2UuZG9tYWlu
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCw01ZcyH/79JWdBIRPgreidVyB
+SIxWXVLuOOFcyJpwjnLyABwX79+3BlmCBPH2SRESpk3LHu2sWRxK0D3e5vKNzTnC
+D+BGL9vLn0f3Vuf4Fl9ocfs646vS5QW32mVh/m0w5BKotcFxJGuqgAVBF6CLbovm
+BM+FeyqsoXl99JZudwIDAQABo4IBQDCCATwwCQYDVR0TBAIwADAsBglghkgBhvhC
+AQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFPhD
+y09NT7xuUhr9+XvhEj+no7qTMIHhBgNVHSMEgdkwgdaAFEn7RXISxMzhRaHTCJ6V
+xCxtVT8XoYG6pIG3MIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3Rv
+bjE8MDoGA1UEChMzUmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBB
+dXRob3JpdHkgKFJJQUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQD
+ExBKYWNrb3YgYWwtVHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9t
+YWluggEAMA0GCSqGSIb3DQEBBAUAA4GBAI9fDkPanWFDfgM4muZQnULolTRJdewE
+jVyFmZRwoOcfHqCLD9biy/c12ZZyvabpjU6x4qyXfy9wAZ2qBLzUAStjd6XeYzyo
+9fJyr+wREsDUcM9xpvvpHbMnB6rysfOH1quLzsIIGzz5uv93cYYJ755OBAZjROmT
+IJDHLVDGUPhm
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQCw01ZcyH/79JWdBIRPgreidVyBSIxWXVLuOOFcyJpwjnLyABwX
+79+3BlmCBPH2SRESpk3LHu2sWRxK0D3e5vKNzTnCD+BGL9vLn0f3Vuf4Fl9ocfs6
+46vS5QW32mVh/m0w5BKotcFxJGuqgAVBF6CLbovmBM+FeyqsoXl99JZudwIDAQAB
+AoGAU4chbqbPvkclPYzaq2yGLlneHrwUft+KwzlfS6L/QVgo+CQRIUWQmjaHpaGM
+YtjVFcg1S1QK1bUqZjTEZT0XKhfbYmqW8yYTfbcDEbnY7esoYlvIlW8qRlPRlTBE
+utKrtZafmVhLgoNawYGD0aLZofPqpYjbGUlrC7nrem2vNJECQQDVLD3Qb+OlEMET
+73ApnJhYsK3e+G2LTrtjrS8y5zS4+Xv61XUqvdV7ogzRl0tpvSAmMOItVyoYadkB
+S3xSIWX9AkEA1Fm1FhkQSZwGG5rf4c6gMN71jJ6JE3/kocdVa0sUjRevIupo4XQ2
+Vkykxi84MRP8cfHqyjewq7Ozv3op2MGWgwJBAKemsb66IJjzAkaBav7u70nhOf0/
++Dc1Zl7QF2y7NVW8sGrnccx5m+ot2lMD4AV6/kvK6jaqdKrapBZGnbGiHqkCQQDI
+T1r33mqz1R8Z2S2Jtzz6/McKf930a/dC+GLGVEutkILf39lRmytKmv/wB0jtWtoO
+rlJ5sLDSNzC+1cE1u997AkEAu3IrtGmLKiuS6kDj6W47m+iiTIsuSJtTJb1SbUaK
+fIoBNFxbvJYW6rUU9+PxpMRaEhzh5s24/jBOE+mlb17mRQ==
+-----END RSA PRIVATE KEY-----
diff --git a/lib/libssl/src/demos/tunala/A-server.pem b/lib/libssl/src/demos/tunala/A-server.pem
new file mode 100644
index 00000000000..e9f37b1895b
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/A-server.pem
@@ -0,0 +1,84 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: md5WithRSAEncryption
+ Issuer: C=NZ, L=Wellington, O=Really Irresponsible Authorisation Authority (RIAA), OU=Cert-stamping, CN=Jackov al-Trades/Email=none@fake.domain
+ Validity
+ Not Before: Jan 16 05:14:06 2002 GMT
+ Not After : Jan 14 05:14:06 2012 GMT
+ Subject: C=NZ, L=Wellington, O=Middle Earth, OU=SSL dev things, CN=tunala-server/Email=server@fake.domain
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (1024 bit)
+ Modulus (1024 bit):
+ 00:a9:3e:62:87:97:13:6b:de:8f:bc:1d:0a:3f:65:
+ 0c:f9:76:a3:53:ce:97:30:27:0d:c6:df:72:1f:8d:
+ 5a:ce:58:23:6a:65:e5:e3:72:1a:8d:7f:fe:90:01:
+ ea:42:f1:9f:6e:7b:0a:bd:eb:52:15:7b:f4:3d:9c:
+ 4e:db:74:29:2b:d1:81:9d:b9:9e:18:2b:87:e1:da:
+ 50:20:3c:59:6c:c9:83:3e:2c:11:0b:78:1e:03:f4:
+ 56:3a:db:95:6a:75:33:85:a9:7b:cc:3c:4a:67:96:
+ f2:24:b2:a0:cb:2e:cc:52:18:16:6f:44:d9:29:64:
+ 07:2e:fb:56:cc:7c:dc:a2:d7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 70:AC:7A:B5:6E:97:C2:82:AF:11:9E:32:CB:8D:48:49:93:B7:DC:22
+ X509v3 Authority Key Identifier:
+ keyid:49:FB:45:72:12:C4:CC:E1:45:A1:D3:08:9E:95:C4:2C:6D:55:3F:17
+ DirName:/C=NZ/L=Wellington/O=Really Irresponsible Authorisation Authority (RIAA)/OU=Cert-stamping/CN=Jackov al-Trades/Email=none@fake.domain
+ serial:00
+
+ Signature Algorithm: md5WithRSAEncryption
+ 2e:cb:a3:cd:6d:a8:9d:d1:dc:e5:f0:e0:27:7e:4b:5a:90:a8:
+ 85:43:f0:05:f7:04:43:d7:5f:d1:a5:8f:5c:58:eb:fc:da:c6:
+ 7c:e0:0b:2b:98:72:95:f6:79:48:96:7a:fa:0c:6b:09:ec:c6:
+ 8c:91:74:45:9f:8f:0f:16:78:e3:66:14:fa:1e:f4:f0:23:ec:
+ cd:a9:52:77:20:4d:c5:05:2c:52:b6:7b:f3:42:33:fd:90:1f:
+ 3e:88:6f:9b:23:61:c8:80:3b:e6:57:84:2e:f7:26:c7:35:ed:
+ 00:8b:08:30:9b:aa:21:83:b6:6d:b8:7c:8a:9b:2a:ef:79:3d:
+ 96:31
+-----BEGIN CERTIFICATE-----
+MIID+zCCA2SgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox
+EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp
+YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy
+dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3
+DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMjAxMTYwNTE0MDZaFw0xMjAxMTQw
+NTE0MDZaMIGNMQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjEVMBMG
+A1UEChMMTWlkZGxlIEVhcnRoMRcwFQYDVQQLEw5TU0wgZGV2IHRoaW5nczEWMBQG
+A1UEAxMNdHVuYWxhLXNlcnZlcjEhMB8GCSqGSIb3DQEJARYSc2VydmVyQGZha2Uu
+ZG9tYWluMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpPmKHlxNr3o+8HQo/
+ZQz5dqNTzpcwJw3G33IfjVrOWCNqZeXjchqNf/6QAepC8Z9uewq961IVe/Q9nE7b
+dCkr0YGduZ4YK4fh2lAgPFlsyYM+LBELeB4D9FY625VqdTOFqXvMPEpnlvIksqDL
+LsxSGBZvRNkpZAcu+1bMfNyi1wIDAQABo4IBQDCCATwwCQYDVR0TBAIwADAsBglg
+hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O
+BBYEFHCserVul8KCrxGeMsuNSEmTt9wiMIHhBgNVHSMEgdkwgdaAFEn7RXISxMzh
+RaHTCJ6VxCxtVT8XoYG6pIG3MIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2Vs
+bGluZ3RvbjE8MDoGA1UEChMzUmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNh
+dGlvbiBBdXRob3JpdHkgKFJJQUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkw
+FwYDVQQDExBKYWNrb3YgYWwtVHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZh
+a2UuZG9tYWluggEAMA0GCSqGSIb3DQEBBAUAA4GBAC7Lo81tqJ3R3OXw4Cd+S1qQ
+qIVD8AX3BEPXX9Glj1xY6/zaxnzgCyuYcpX2eUiWevoMawnsxoyRdEWfjw8WeONm
+FPoe9PAj7M2pUncgTcUFLFK2e/NCM/2QHz6Ib5sjYciAO+ZXhC73Jsc17QCLCDCb
+qiGDtm24fIqbKu95PZYx
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCpPmKHlxNr3o+8HQo/ZQz5dqNTzpcwJw3G33IfjVrOWCNqZeXj
+chqNf/6QAepC8Z9uewq961IVe/Q9nE7bdCkr0YGduZ4YK4fh2lAgPFlsyYM+LBEL
+eB4D9FY625VqdTOFqXvMPEpnlvIksqDLLsxSGBZvRNkpZAcu+1bMfNyi1wIDAQAB
+AoGANCwqHZhiAU/TyW6+WPqivEhpYw19p/dyFMuPF9DwnEmpaUROUQY8z0AUznn4
+qHhp6Jn/nrprTHowucl0ucweYIYVxZoUiUDFpxdFUbzMdFvo6HcyV1Pe4Rt81HaY
+KYWrTZ6PaPtN65hLms8NhPEdGcGAFlY1owYv4QNGq2bU1JECQQDd32LM0NSfyGmK
+4ziajqGcvzK9NO2XyV/nJsGlJZNgMh2zm1t7yR28l/6Q2uyU49cCN+2aYULZCAfs
+taNvxBspAkEAw0alNub+xj2AVQvaxOB1sGfKzsJjHCzKIxUXn/tJi3j0+2asmkBZ
+Umx1MWr9jKQBnCMciCRUbnMEZiElOxCN/wJAfAeQl6Z19gx206lJzzzEo3dOye54
+k02DSxijT8q9pBzf9bN3ZK987BybtiZr8p+bZiYVsSOF1wViSLURdD1QYQJAIaMU
+qH1n24wShBPTrmAfxbBLTgxL+Dl65Eoo1KT7iSvfv0JzbuqwuDL4iPeuD0DdCiE+
+M/FWHeRwGIuTFzaFzwJBANKwx0jZS/h093w9g0Clw6UzeA1P5VcAt9y+qMC9hO3c
+4KXwIxQAt9yRaFLpiIR9do5bjjKNnMguf3aO/XRSDQM=
+-----END RSA PRIVATE KEY-----
diff --git a/lib/libssl/src/demos/tunala/CA.pem b/lib/libssl/src/demos/tunala/CA.pem
new file mode 100644
index 00000000000..7a55b5463ef
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/CA.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID9zCCA2CgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox
+EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp
+YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy
+dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3
+DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMjAxMTYwNTA5NTlaFw0xMjAxMTQw
+NTA5NTlaMIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoG
+A1UEChMzUmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3Jp
+dHkgKFJJQUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNr
+b3YgYWwtVHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluMIGf
+MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7QdDfFIrJn3X24hKmpkyk3TG0Ivxd
+K2wWmDPXq1wjr8lUTwrA6hM5Ba9N36jLieWpXhviLOWu9DBza5GmtgCuXloATKTC
+94xOdKHlciTVujG3wDlLDB5e710Kar84nnj6VueL1RyZ0bmP5PANa4mbGW9Tqc7J
+CkBTTW2y9d0SgQIDAQABo4IBFTCCAREwHQYDVR0OBBYEFEn7RXISxMzhRaHTCJ6V
+xCxtVT8XMIHhBgNVHSMEgdkwgdaAFEn7RXISxMzhRaHTCJ6VxCxtVT8XoYG6pIG3
+MIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoGA1UEChMz
+UmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3JpdHkgKFJJ
+QUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNrb3YgYWwt
+VHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluggEAMAwGA1Ud
+EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAYQo95V/NY+eKxYxkhibZiUQygph+
+gTfgbDG20MsnH6+8//w5ArHauFCgDrf0P2VyACgq+N4pBTWFGaAaLwbjKy9HCe2E
+j9C91tO1CqDS4MJkDB5AP13FTkK6fP1ZCiTQranOAp3DlGWTTWsFVyW5kVfQ9diS
+ZOyJZ9Fit5XM2X0=
+-----END CERTIFICATE-----
diff --git a/lib/libssl/src/demos/tunala/INSTALL b/lib/libssl/src/demos/tunala/INSTALL
new file mode 100644
index 00000000000..a65bbeb8d11
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/INSTALL
@@ -0,0 +1,107 @@
+There are two ways to build this code;
+
+(1) Manually
+
+(2) Using all-singing all-dancing (all-confusing) autotools, ie. autoconf,
+automake, and their little friends (autoheader, etc).
+
+=================
+Building Manually
+=================
+
+There is a basic "Makefile" in this directory that gets moved out of the way and
+ignored when building with autoconf et al. This Makefile is suitable for
+building tunala on Linux using gcc. Any other platform probably requires some
+tweaking. Here are the various bits you might need to do if you want to build
+this way and the default Makefile isn't sufficient;
+
+* Compiler: Edit the "CC" definition in Makefile
+
+* Headers, features: tunala.h controls what happens in the non-autoconf world.
+ It, by default, assumes the system has *everything* (except autoconf's
+ "config.h") so if a target system is missing something it must define the
+ appropriate "NO_***" symbols in CFLAGS. These include;
+
+ - NO_HAVE_UNISTD_H, NO_HAVE_FCNTL_H, NO_HAVE_LIMITS_H
+ Indicates the compiling system doesn't have (or need) these header files.
+ - NO_HAVE_STRSTR, NO_HAVE_STRTOUL
+ Indicates the compiling system doesn't have these functions. Replacements
+ are compiled and used in breakage.c
+ - NO_HAVE_SELECT, NO_HAVE_SOCKET
+ Pointless symbols - these indicate select() and/or socket() are missing in
+ which case the program won't compile anyway.
+
+ If you want to specify any of these, add them with "-D" prefixed to each in
+ the CFLAGS definition in Makefile.
+
+* Compilation flags: edit DEBUG_FLAGS and/or CFLAGS directly to control the
+ flags passed to the compiler. This can also be used to change the degree of
+ optimisation.
+
+* Linker flags: some systems (eg. Solaris) require extra linker flags such as;
+ -ldl, -lsocket, -lnsl, etc. If unsure, bring up the man page for whichever
+ function is "undefined" when the linker fails - that usually indicates what
+ you need to add. Make changes to the LINK_FLAGS symbol.
+
+* Linker command: if a different linker syntax or even a different program is
+ required to link, edit the linker line directly in the "tunala:" target
+ definition - it currently assumes the "CC" (compiler) program is used to link.
+
+======================
+Building Automagically
+======================
+
+Automagic building is handled courtesy of autoconf, automake, etc. There are in
+fact two steps required to build, and only the first has to be done on a system
+with these tools installed (and if I was prepared to bloat out the CVS
+repository, I could store these extra files, but I'm not).
+
+First step: "autogunk.sh"
+-------------------------
+
+The "./autogunk.sh" script will call all the necessary autotool commands to
+create missing files and run automake and autoconf. The result is that a
+"./configure" script should be generated and a "Makefile.in" generated from the
+supplied "Makefile.am". NB: This script also moves the "manual" Makefile (see
+above) out of the way and calls it "Makefile.plain" - the "ungunk" script
+reverses this to leave the directory it was previously.
+
+Once "ungunk" has been run, the resulting directory should be able to build on
+other systems without autoconf, automake, or libtool. Which is what the second
+step describes;
+
+Second step: "./configure"
+--------------------------
+
+The second step is to run the generated "./configure" script to create a
+config.h header for your system and to generate a "Makefile" (generated from
+"Makefile.in") tweaked to compile on your system. This is the standard sort of
+thing you see in GNU packages, for example, and the standard tricks also work.
+Eg. to override "configure"'s choice of compiler, set the CC environment
+variable prior to running configure, eg.
+
+ CC=gcc ./configure
+
+would cause "gcc" to be used even if there is an otherwise preferable (to
+autoconf) native compiler on your system.
+
+After this run "make" and it should build the "tunala" executable.
+
+Notes
+-----
+
+- Some versions of autoconf (or automake?) generate a Makefile syntax that gives
+ trouble to some "make" programs on some systems (eg. OpenBSD). If this
+ happens, either build 'Manually' (see above) or use "gmake" instead of "make".
+ I don't like this either but like even less the idea of sifting into all the
+ script magic crud that's involved.
+
+- On a solaris system I tried, the "configure" script specified some broken
+ compiler flags in the resulting Makefile that don't even get echoed to
+ stdout/err when the error happens (evil!). If this happens, go into the
+ generated Makefile, find the two affected targets ("%.o:" and "%.lo"), and
+ remove the offending hidden option in the $(COMPILE) line all the sludge after
+ the two first lines of script (ie. after the "echo" and the "COMPILE" lines).
+ NB: This will probably only function if "--disable-shared" was used, otherwise
+ who knows what would result ...
+
diff --git a/lib/libssl/src/demos/tunala/Makefile b/lib/libssl/src/demos/tunala/Makefile
new file mode 100644
index 00000000000..bef1704a3ca
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/Makefile
@@ -0,0 +1,41 @@
+# Edit these to suit
+#
+# Oh yeah, and please read the README too.
+
+
+SSL_HOMEDIR=../..
+SSL_INCLUDEDIR=$(SSL_HOMEDIR)/include
+SSL_LIBDIR=$(SSL_HOMEDIR)
+
+RM=rm -f
+CC=gcc
+DEBUG_FLAGS=-g -ggdb3 -Wall -Wshadow
+INCLUDE_FLAGS=-I$(SSL_INCLUDEDIR)
+CFLAGS=$(DEBUG_FLAGS) $(INCLUDE_FLAGS) -DNO_CONFIG_H
+COMPILE=$(CC) $(CFLAGS) -c
+
+# Edit, particularly the "-ldl" if not building with "dlfcn" support
+LINK_FLAGS=-L$(SSL_LIBDIR) -lssl -lcrypto -ldl
+
+SRCS=buffer.c cb.c ip.c sm.c tunala.c breakage.c
+OBJS=buffer.o cb.o ip.o sm.o tunala.o breakage.o
+
+TARGETS=tunala
+
+default: $(TARGETS)
+
+clean:
+ $(RM) $(OBJS) $(TARGETS) *.bak core
+
+.c.o:
+ $(COMPILE) $<
+
+tunala: $(OBJS)
+ $(CC) -o tunala $(OBJS) $(LINK_FLAGS)
+
+# Extra dependencies, should really use makedepend
+buffer.o: buffer.c tunala.h
+cb.o: cb.c tunala.h
+ip.o: ip.c tunala.h
+sm.o: sm.c tunala.h
+tunala.o: tunala.c tunala.h
diff --git a/lib/libssl/src/demos/tunala/Makefile.am b/lib/libssl/src/demos/tunala/Makefile.am
new file mode 100644
index 00000000000..706c7806c9d
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/Makefile.am
@@ -0,0 +1,7 @@
+# Our includes come from the OpenSSL build-tree we're in
+INCLUDES = -I$(top_builddir)/../../include
+
+bin_PROGRAMS = tunala
+
+tunala_SOURCES = tunala.c buffer.c cb.c ip.c sm.c breakage.c
+tunala_LDADD = -L$(top_builddir)/../.. -lssl -lcrypto
diff --git a/lib/libssl/src/demos/tunala/README b/lib/libssl/src/demos/tunala/README
new file mode 100644
index 00000000000..15690088f33
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/README
@@ -0,0 +1,233 @@
+This is intended to be an example of a state-machine driven SSL application. It
+acts as an SSL tunneler (functioning as either the server or client half,
+depending on command-line arguments). *PLEASE* read the comments in tunala.h
+before you treat this stuff as anything more than a curiosity - YOU HAVE BEEN
+WARNED!! There, that's the draconian bit out of the way ...
+
+
+Why "tunala"??
+--------------
+
+I thought I asked you to read tunala.h?? :-)
+
+
+Show me
+-------
+
+If you want to simply see it running, skip to the end and see some example
+command-line arguments to demonstrate with.
+
+
+Where to look and what to do?
+-----------------------------
+
+The code is split up roughly coinciding with the detaching of an "abstract" SSL
+state machine (which is the purpose of all this) and its surrounding application
+specifics. This is primarily to make it possible for me to know when I could cut
+corners and when I needed to be rigorous (or at least maintain the pretense as
+such :-).
+
+Network stuff:
+
+Basically, the network part of all this is what is supposed to be abstracted out
+of the way. The intention is to illustrate one way to stick OpenSSL's mechanisms
+inside a little memory-driven sandbox and operate it like a pure state-machine.
+So, the network code is inside both ip.c (general utility functions and gory
+IPv4 details) and tunala.c itself, which takes care of application specifics
+like the main select() loop. The connectivity between the specifics of this
+application (TCP/IP tunneling and the associated network code) and the
+underlying abstract SSL state machine stuff is through the use of the "buffer_t"
+type, declared in tunala.h and implemented in buffer.c.
+
+State machine:
+
+Which leaves us, generally speaking, with the abstract "state machine" code left
+over and this is sitting inside sm.c, with declarations inside tunala.h. As can
+be seen by the definition of the state_machine_t structure and the associated
+functions to manipulate it, there are the 3 OpenSSL "handles" plus 4 buffer_t
+structures dealing with IO on both the encrypted and unencrypted sides ("dirty"
+and "clean" respectively). The "SSL" handle is what facilitates the reading and
+writing of the unencrypted (tunneled) data. The two "BIO" handles act as the
+read and write channels for encrypted tunnel traffic - in other applications
+these are often socket BIOs so that the OpenSSL framework operates with the
+network layer directly. In this example, those two BIOs are memory BIOs
+(BIO_s_mem()) so that the sending and receiving of the tunnel traffic stays
+within the state-machine, and we can handle where this gets send to (or read
+from) ourselves.
+
+
+Why?
+----
+
+If you take a look at the "state_machine_t" section of tunala.h and the code in
+sm.c, you will notice that nothing related to the concept of 'transport' is
+involved. The binding to TCP/IP networking occurs in tunala.c, specifically
+within the "tunala_item_t" structure that associates a state_machine_t object
+with 4 file-descriptors. The way to best see where the bridge between the
+outside world (TCP/IP reads, writes, select()s, file-descriptors, etc) and the
+state machine is, is to examine the "tunala_item_io()" function in tunala.c.
+This is currently around lines 641-732 but of course could be subject to change.
+
+
+And...?
+-------
+
+Well, although that function is around 90 lines of code, it could easily have
+been a lot less only I was trying to address an easily missed "gotcha" (item (2)
+below). The main() code that drives the select/accept/IO loop initialises new
+tunala_item_t structures when connections arrive, and works out which
+file-descriptors go where depending on whether we're an SSL client or server
+(client --> accepted connection is clean and proxied is dirty, server -->
+accepted connection is dirty and proxied is clean). What that tunala_item_io()
+function is attempting to do is 2 things;
+
+ (1) Perform all reads and writes on the network directly into the
+ state_machine_t's buffers (based on a previous select() result), and only
+ then allow the abstact state_machine_t to "churn()" using those buffers.
+ This will cause the SSL machine to consume as much input data from the two
+ "IN" buffers as possible, and generate as much output data into the two
+ "OUT" buffers as possible. Back up in the main() function, the next main
+ loop loop will examine these output buffers and select() for writability
+ on the corresponding sockets if the buffers are non-empty.
+
+ (2) Handle the complicated tunneling-specific issue of cascading "close"s.
+ This is the reason for most of the complexity in the logic - if one side
+ of the tunnel is closed, you can't simply close the other side and throw
+ away the whole thing - (a) there may still be outgoing data on the other
+ side of the tunnel that hasn't been sent yet, (b) the close (or things
+ happening during the close) may cause more data to be generated that needs
+ sending on the other side. Of course, this logic is complicated yet futher
+ by the fact that it's different depending on which side closes first :-)
+ state_machine_close_clean() will indicate to the state machine that the
+ unencrypted side of the tunnel has closed, so any existing outgoing data
+ needs to be flushed, and the SSL stream needs to be closed down using the
+ appropriate shutdown sequence. state_machine_close_dirty() is simpler
+ because it indicates that the SSL stream has been disconnected, so all
+ that remains before closing the other side is to flush out anything that
+ remains and wait for it to all be sent.
+
+Anyway, with those things in mind, the code should be a little easier to follow
+in terms of "what is *this* bit supposed to achieve??!!".
+
+
+How might this help?
+--------------------
+
+Well, the reason I wrote this is that there seemed to be rather a flood of
+questions of late on the openssl-dev and openssl-users lists about getting this
+whole IO logic thing sorted out, particularly by those who were trying to either
+use non-blocking IO, or wanted SSL in an environment where "something else" was
+handling the network already and they needed to operate in memory only. This
+code is loosely based on some other stuff I've been working on, although that
+stuff is far more complete, far more dependant on a whole slew of other
+network/framework code I don't want to incorporate here, and far harder to look
+at for 5 minutes and follow where everything is going. I will be trying over
+time to suck in a few things from that into this demo in the hopes it might be
+more useful, and maybe to even make this demo usable as a utility of its own.
+Possible things include:
+
+ * controlling multiple processes/threads - this can be used to combat
+ latencies and get passed file-descriptor limits on some systems, and it uses
+ a "controller" process/thread that maintains IPC links with the
+ processes/threads doing the real work.
+
+ * cert verification rules - having some say over which certs get in or out :-)
+
+ * control over SSL protocols and cipher suites
+
+ * A few other things you can already do in s_client and s_server :-)
+
+ * Support (and control over) session resuming, particularly when functioning
+ as an SSL client.
+
+If you have a particular environment where this model might work to let you "do
+SSL" without having OpenSSL be aware of the transport, then you should find you
+could use the state_machine_t structure (or your own variant thereof) and hook
+it up to your transport stuff in much the way tunala.c matches it up with those
+4 file-descriptors. The state_machine_churn(), state_machine_close_clean(), and
+state_machine_close_dirty() functions are the main things to understand - after
+that's done, you just have to ensure you're feeding and bleeding the 4
+state_machine buffers in a logical fashion. This state_machine loop handles not
+only handshakes and normal streaming, but also renegotiates - there's no special
+handling required beyond keeping an eye on those 4 buffers and keeping them in
+sync with your outer "loop" logic. Ie. if one of the OUT buffers is not empty,
+you need to find an opportunity to try and forward its data on. If one of the IN
+buffers is not full, you should keep an eye out for data arriving that should be
+placed there.
+
+This approach could hopefully also allow you to run the SSL protocol in very
+different environments. As an example, you could support encrypted event-driven
+IPC where threads/processes pass messages to each other inside an SSL layer;
+each IPC-message's payload would be in fact the "dirty" content, and the "clean"
+payload coming out of the tunnel at each end would be the real intended message.
+Likewise, this could *easily* be made to work across unix domain sockets, or
+even entirely different network/comms protocols.
+
+This is also a quick and easy way to do VPN if you (and the remote network's
+gateway) support virtual network devices that are encapsulted in a single
+network connection, perhaps PPP going through an SSL tunnel?
+
+
+Suggestions
+-----------
+
+Please let me know if you find this useful, or if there's anything wrong or
+simply too confusing about it. Patches are also welcome, but please attach a
+description of what it changes and why, and "diff -urN" format is preferred.
+Mail to geoff@openssl.org should do the trick.
+
+
+Example
+-------
+
+Here is an example of how to use "tunala" ...
+
+First, it's assumed that OpenSSL has already built, and that you are building
+inside the ./demos/tunala/ directory. If not - please correct the paths and
+flags inside the Makefile. Likewise, if you want to tweak the building, it's
+best to try and do so in the makefile (eg. removing the debug flags and adding
+optimisation flags).
+
+Secondly, this code has mostly only been tested on Linux. However, some
+autoconf/etc support has been added and the code has been compiled on openbsd
+and solaris using that.
+
+Thirdly, if you are Win32, you probably need to do some *major* rewriting of
+ip.c to stand a hope in hell. Good luck, and please mail me the diff if you do
+this, otherwise I will take a look at another time. It can certainly be done,
+but it's very non-POSIXy.
+
+See the INSTALL document for details on building.
+
+Now, if you don't have an executable "tunala" compiled, go back to "First,...".
+Rinse and repeat.
+
+Inside one console, try typing;
+
+(i) ./tunala -listen localhost:8080 -proxy localhost:8081 -cacert CA.pem \
+ -cert A-client.pem -out_totals -v_peer -v_strict
+
+In another console, type;
+
+(ii) ./tunala -listen localhost:8081 -proxy localhost:23 -cacert CA.pem \
+ -cert A-server.pem -server 1 -out_totals -v_peer -v_strict
+
+Now if you open another console and "telnet localhost 8080", you should be
+tunneled through to the telnet service on your local machine (if it's running -
+you could change it to port "22" and tunnel ssh instead if you so desired). When
+you logout of the telnet session, the tunnel should cleanly shutdown and show
+you some traffic stats in both consoles. Feel free to experiment. :-)
+
+Notes:
+
+ - the format for the "-listen" argument can skip the host part (eg. "-listen
+ 8080" is fine). If you do, the listening socket will listen on all interfaces
+ so you can connect from other machines for example. Using the "localhost"
+ form listens only on 127.0.0.1 so you can only connect locally (unless, of
+ course, you've set up weird stuff with your networking in which case probably
+ none of the above applies).
+
+ - ./tunala -? gives you a list of other command-line options, but tunala.c is
+ also a good place to look :-)
+
+
diff --git a/lib/libssl/src/demos/tunala/autogunk.sh b/lib/libssl/src/demos/tunala/autogunk.sh
new file mode 100644
index 00000000000..c9783c6261c
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/autogunk.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# This script tries to follow the "GNU way" w.r.t. the autobits.
+# This does of course generate a number of irritating files.
+# Try to get over it (I am getting there myself).
+
+# This should generate any missing crud, and then run autoconf which should turn
+# configure.in into a "./configure" script and "Makefile.am" into a
+# "Makefile.in". Then running "./configure" should turn "Makefile.in" into
+# "Makefile" and should generate the config.h containing your systems various
+# settings. I know ... what a hassle ...
+
+# Also, sometimes these autobits things generate bizarre output (looking like
+# errors). So I direct everything "elsewhere" ...
+
+(aclocal
+autoheader
+libtoolize --copy --force
+automake --foreign --add-missing --copy
+autoconf) 1> /dev/null 2>&1
+
+# Move the "no-autotools" Makefile out of the way
+if test ! -f Makefile.plain; then
+ mv Makefile Makefile.plain
+fi
diff --git a/lib/libssl/src/demos/tunala/autoungunk.sh b/lib/libssl/src/demos/tunala/autoungunk.sh
new file mode 100644
index 00000000000..14d10790fd8
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/autoungunk.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# This script tries to clean up as much as is possible from whatever diabolical
+# mess has been left in the directory thanks to autoconf, automake, and their
+# friends.
+
+if test -f Makefile; then
+ make distclean
+ rm -f Makefile
+fi
+
+if test -f Makefile.plain; then
+ mv Makefile.plain Makefile
+fi
+
+rm -f aclocal.m4 config.* configure install-sh \
+ missing mkinstalldirs stamp-h.* Makefile.in \
+ ltconfig ltmain.sh
diff --git a/lib/libssl/src/demos/tunala/breakage.c b/lib/libssl/src/demos/tunala/breakage.c
new file mode 100644
index 00000000000..dcdd64b0ef1
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/breakage.c
@@ -0,0 +1,66 @@
+#include "tunala.h"
+
+int int_strtoul(const char *str, unsigned long *val)
+{
+#ifdef HAVE_STRTOUL
+ char *tmp;
+ unsigned long ret = strtoul(str, &tmp, 10);
+ if((str == tmp) || (*tmp != '\0'))
+ /* The value didn't parse cleanly */
+ return 0;
+ if(ret == ULONG_MAX)
+ /* We hit a limit */
+ return 0;
+ *val = ret;
+ return 1;
+#else
+ char buf[2];
+ unsigned long ret = 0;
+ buf[1] = '\0';
+ if(str == '\0')
+ /* An empty string ... */
+ return 0;
+ while(*str != '\0') {
+ /* We have to multiply 'ret' by 10 before absorbing the next
+ * digit. If this will overflow, catch it now. */
+ if(ret && (((ULONG_MAX + 10) / ret) < 10))
+ return 0;
+ ret *= 10;
+ if(!isdigit(*str))
+ return 0;
+ buf[0] = *str;
+ ret += atoi(buf);
+ str++;
+ }
+ *val = ret;
+ return 1;
+#endif
+}
+
+#ifndef HAVE_STRSTR
+char *int_strstr(const char *haystack, const char *needle)
+{
+ const char *sub_haystack = haystack, *sub_needle = needle;
+ unsigned int offset = 0;
+ if(!needle)
+ return haystack;
+ if(!haystack)
+ return NULL;
+ while((*sub_haystack != '\0') && (*sub_needle != '\0')) {
+ if(sub_haystack[offset] == sub_needle) {
+ /* sub_haystack is still a candidate */
+ offset++;
+ sub_needle++;
+ } else {
+ /* sub_haystack is no longer a possibility */
+ sub_haystack++;
+ offset = 0;
+ sub_needle = needle;
+ }
+ }
+ if(*sub_haystack == '\0')
+ /* Found nothing */
+ return NULL;
+ return sub_haystack;
+}
+#endif
diff --git a/lib/libssl/src/demos/tunala/buffer.c b/lib/libssl/src/demos/tunala/buffer.c
new file mode 100644
index 00000000000..c5cd004209a
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/buffer.c
@@ -0,0 +1,205 @@
+#include "tunala.h"
+
+#ifndef NO_BUFFER
+
+void buffer_init(buffer_t *buf)
+{
+ buf->used = 0;
+ buf->total_in = buf->total_out = 0;
+}
+
+void buffer_close(buffer_t *buf)
+{
+ /* Our data is static - nothing needs "release", just reset it */
+ buf->used = 0;
+}
+
+/* Code these simple ones in compact form */
+unsigned int buffer_used(buffer_t *buf) {
+ return buf->used; }
+unsigned int buffer_unused(buffer_t *buf) {
+ return (MAX_DATA_SIZE - buf->used); }
+int buffer_full(buffer_t *buf) {
+ return (buf->used == MAX_DATA_SIZE ? 1 : 0); }
+int buffer_notfull(buffer_t *buf) {
+ return (buf->used < MAX_DATA_SIZE ? 1 : 0); }
+int buffer_empty(buffer_t *buf) {
+ return (buf->used == 0 ? 1 : 0); }
+int buffer_notempty(buffer_t *buf) {
+ return (buf->used > 0 ? 1 : 0); }
+unsigned long buffer_total_in(buffer_t *buf) {
+ return buf->total_in; }
+unsigned long buffer_total_out(buffer_t *buf) {
+ return buf->total_out; }
+
+/* These 3 static (internal) functions don't adjust the "total" variables as
+ * it's not sure when they're called how it should be interpreted. Only the
+ * higher-level "buffer_[to|from]_[fd|SSL|BIO]" functions should alter these
+ * values. */
+#if 0 /* To avoid "unused" warnings */
+static unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr,
+ unsigned int size)
+{
+ unsigned int added = MAX_DATA_SIZE - buf->used;
+ if(added > size)
+ added = size;
+ if(added == 0)
+ return 0;
+ memcpy(buf->data + buf->used, ptr, added);
+ buf->used += added;
+ buf->total_in += added;
+ return added;
+}
+
+static unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap)
+{
+ unsigned int moved, tomove = from->used;
+ if((int)tomove > cap)
+ tomove = cap;
+ if(tomove == 0)
+ return 0;
+ moved = buffer_adddata(to, from->data, tomove);
+ if(moved == 0)
+ return 0;
+ buffer_takedata(from, NULL, moved);
+ return moved;
+}
+#endif
+
+static unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr,
+ unsigned int size)
+{
+ unsigned int taken = buf->used;
+ if(taken > size)
+ taken = size;
+ if(taken == 0)
+ return 0;
+ if(ptr)
+ memcpy(ptr, buf->data, taken);
+ buf->used -= taken;
+ /* Do we have to scroll? */
+ if(buf->used > 0)
+ memmove(buf->data, buf->data + taken, buf->used);
+ return taken;
+}
+
+#ifndef NO_IP
+
+int buffer_from_fd(buffer_t *buf, int fd)
+{
+ int toread = buffer_unused(buf);
+ if(toread == 0)
+ /* Shouldn't be called in this case! */
+ abort();
+ toread = read(fd, buf->data + buf->used, toread);
+ if(toread > 0) {
+ buf->used += toread;
+ buf->total_in += toread;
+ }
+ return toread;
+}
+
+int buffer_to_fd(buffer_t *buf, int fd)
+{
+ int towrite = buffer_used(buf);
+ if(towrite == 0)
+ /* Shouldn't be called in this case! */
+ abort();
+ towrite = write(fd, buf->data, towrite);
+ if(towrite > 0) {
+ buffer_takedata(buf, NULL, towrite);
+ buf->total_out += towrite;
+ }
+ return towrite;
+}
+
+#endif /* !defined(NO_IP) */
+
+#ifndef NO_OPENSSL
+
+static void int_ssl_check(SSL *s, int ret)
+{
+ int e = SSL_get_error(s, ret);
+ switch(e) {
+ /* These seem to be harmless and already "dealt with" by our
+ * non-blocking environment. NB: "ZERO_RETURN" is the clean
+ * "error" indicating a successfully closed SSL tunnel. We let
+ * this happen because our IO loop should not appear to have
+ * broken on this condition - and outside the IO loop, the
+ * "shutdown" state is checked. */
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_ZERO_RETURN:
+ return;
+ /* These seem to be indications of a genuine error that should
+ * result in the SSL tunnel being regarded as "dead". */
+ case SSL_ERROR_SYSCALL:
+ case SSL_ERROR_SSL:
+ SSL_set_app_data(s, (char *)1);
+ return;
+ default:
+ break;
+ }
+ /* For any other errors that (a) exist, and (b) crop up - we need to
+ * interpret what to do with them - so "politely inform" the caller that
+ * the code needs updating here. */
+ abort();
+}
+
+void buffer_from_SSL(buffer_t *buf, SSL *ssl)
+{
+ int ret;
+ if(!ssl || buffer_full(buf))
+ return;
+ ret = SSL_read(ssl, buf->data + buf->used, buffer_unused(buf));
+ if(ret > 0) {
+ buf->used += ret;
+ buf->total_in += ret;
+ }
+ if(ret < 0)
+ int_ssl_check(ssl, ret);
+}
+
+void buffer_to_SSL(buffer_t *buf, SSL *ssl)
+{
+ int ret;
+ if(!ssl || buffer_empty(buf))
+ return;
+ ret = SSL_write(ssl, buf->data, buf->used);
+ if(ret > 0) {
+ buffer_takedata(buf, NULL, ret);
+ buf->total_out += ret;
+ }
+ if(ret < 0)
+ int_ssl_check(ssl, ret);
+}
+
+void buffer_from_BIO(buffer_t *buf, BIO *bio)
+{
+ int ret;
+ if(!bio || buffer_full(buf))
+ return;
+ ret = BIO_read(bio, buf->data + buf->used, buffer_unused(buf));
+ if(ret > 0) {
+ buf->used += ret;
+ buf->total_in += ret;
+ }
+}
+
+void buffer_to_BIO(buffer_t *buf, BIO *bio)
+{
+ int ret;
+ if(!bio || buffer_empty(buf))
+ return;
+ ret = BIO_write(bio, buf->data, buf->used);
+ if(ret > 0) {
+ buffer_takedata(buf, NULL, ret);
+ buf->total_out += ret;
+ }
+}
+
+#endif /* !defined(NO_OPENSSL) */
+
+#endif /* !defined(NO_BUFFER) */
diff --git a/lib/libssl/src/demos/tunala/cb.c b/lib/libssl/src/demos/tunala/cb.c
new file mode 100644
index 00000000000..cd32f74c70a
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/cb.c
@@ -0,0 +1,133 @@
+#include "tunala.h"
+
+#ifndef NO_OPENSSL
+
+/* For callbacks generating output, here are their file-descriptors. */
+static FILE *fp_cb_ssl_info = NULL;
+static FILE *fp_cb_ssl_verify = NULL;
+/* Output level:
+ * 0 = nothing,
+ * 1 = minimal, just errors,
+ * 2 = minimal, all steps,
+ * 3 = detail, all steps */
+static unsigned int cb_ssl_verify_level = 1;
+
+/* Other static rubbish (to mirror s_cb.c where required) */
+static int int_verify_depth = 10;
+
+/* This function is largely borrowed from the one used in OpenSSL's "s_client"
+ * and "s_server" utilities. */
+void cb_ssl_info(const SSL *s, int where, int ret)
+{
+ const char *str1, *str2;
+ int w;
+
+ if(!fp_cb_ssl_info)
+ return;
+
+ w = where & ~SSL_ST_MASK;
+ str1 = (w & SSL_ST_CONNECT ? "SSL_connect" : (w & SSL_ST_ACCEPT ?
+ "SSL_accept" : "undefined")),
+ str2 = SSL_state_string_long(s);
+
+ if (where & SSL_CB_LOOP)
+ fprintf(fp_cb_ssl_info, "(%s) %s\n", str1, str2);
+ else if (where & SSL_CB_EXIT) {
+ if (ret == 0)
+ fprintf(fp_cb_ssl_info, "(%s) failed in %s\n", str1, str2);
+/* In a non-blocking model, we get a few of these "error"s simply because we're
+ * calling "reads" and "writes" on the state-machine that are virtual NOPs
+ * simply to avoid wasting the time seeing if we *should* call them. Removing
+ * this case makes the "-out_state" output a lot easier on the eye. */
+#if 0
+ else if (ret < 0)
+ fprintf(fp_cb_ssl_info, "%s:error in %s\n", str1, str2);
+#endif
+ }
+}
+
+void cb_ssl_info_set_output(FILE *fp)
+{
+ fp_cb_ssl_info = fp;
+}
+
+static const char *int_reason_no_issuer = "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT";
+static const char *int_reason_not_yet = "X509_V_ERR_CERT_NOT_YET_VALID";
+static const char *int_reason_before = "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD";
+static const char *int_reason_expired = "X509_V_ERR_CERT_HAS_EXPIRED";
+static const char *int_reason_after = "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD";
+
+/* Stolen wholesale from apps/s_cb.c :-) And since then, mutilated ... */
+int cb_ssl_verify(int ok, X509_STORE_CTX *ctx)
+{
+ char buf1[256]; /* Used for the subject name */
+ char buf2[256]; /* Used for the issuer name */
+ const char *reason = NULL; /* Error reason (if any) */
+ X509 *err_cert;
+ int err, depth;
+
+ if(!fp_cb_ssl_verify || (cb_ssl_verify_level == 0))
+ return ok;
+ err_cert = X509_STORE_CTX_get_current_cert(ctx);
+ err = X509_STORE_CTX_get_error(ctx);
+ depth = X509_STORE_CTX_get_error_depth(ctx);
+
+ buf1[0] = buf2[0] = '\0';
+ /* Fill buf1 */
+ X509_NAME_oneline(X509_get_subject_name(err_cert), buf1, 256);
+ /* Fill buf2 */
+ X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf2, 256);
+ switch (ctx->error) {
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ reason = int_reason_no_issuer;
+ break;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ reason = int_reason_not_yet;
+ break;
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ reason = int_reason_before;
+ break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ reason = int_reason_expired;
+ break;
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ reason = int_reason_after;
+ break;
+ }
+
+ if((cb_ssl_verify_level == 1) && ok)
+ return ok;
+ fprintf(fp_cb_ssl_verify, "chain-depth=%d, ", depth);
+ if(reason)
+ fprintf(fp_cb_ssl_verify, "error=%s\n", reason);
+ else
+ fprintf(fp_cb_ssl_verify, "error=%d\n", err);
+ if(cb_ssl_verify_level < 3)
+ return ok;
+ fprintf(fp_cb_ssl_verify, "--> subject = %s\n", buf1);
+ fprintf(fp_cb_ssl_verify, "--> issuer = %s\n", buf2);
+ if(!ok)
+ fprintf(fp_cb_ssl_verify,"--> verify error:num=%d:%s\n",err,
+ X509_verify_cert_error_string(err));
+ fprintf(fp_cb_ssl_verify, "--> verify return:%d\n",ok);
+ return ok;
+}
+
+void cb_ssl_verify_set_output(FILE *fp)
+{
+ fp_cb_ssl_verify = fp;
+}
+
+void cb_ssl_verify_set_depth(unsigned int verify_depth)
+{
+ int_verify_depth = verify_depth;
+}
+
+void cb_ssl_verify_set_level(unsigned int level)
+{
+ if(level < 4)
+ cb_ssl_verify_level = level;
+}
+
+#endif /* !defined(NO_OPENSSL) */
+
diff --git a/lib/libssl/src/demos/tunala/configure.in b/lib/libssl/src/demos/tunala/configure.in
new file mode 100644
index 00000000000..b2a6ffc756b
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/configure.in
@@ -0,0 +1,28 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(tunala.c)
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE(tunala, 0.0.1-dev)
+
+dnl Checks for programs. (Though skip libtool)
+AC_PROG_CC
+dnl AC_PROG_LIBTOOL
+dnl AM_PROG_LIBTOOL
+
+dnl Checks for libraries.
+AC_CHECK_LIB(dl, dlopen)
+AC_CHECK_LIB(socket, socket)
+AC_CHECK_LIB(nsl, gethostbyname)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(strstr strtoul)
+AC_CHECK_FUNCS(select socket)
+AC_CHECK_FUNCS(dlopen)
+
+AC_OUTPUT(Makefile)
diff --git a/lib/libssl/src/demos/tunala/ip.c b/lib/libssl/src/demos/tunala/ip.c
new file mode 100644
index 00000000000..96ef4e65360
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/ip.c
@@ -0,0 +1,146 @@
+#include "tunala.h"
+
+#ifndef NO_IP
+
+#define IP_LISTENER_BACKLOG 511 /* So if it gets masked by 256 or some other
+ such value it'll still be respectable */
+
+/* Any IP-related initialisations. For now, this means blocking SIGPIPE */
+int ip_initialise(void)
+{
+ struct sigaction sa;
+
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ if(sigaction(SIGPIPE, &sa, NULL) != 0)
+ return 0;
+ return 1;
+}
+
+int ip_create_listener_split(const char *ip, unsigned short port)
+{
+ struct sockaddr_in in_addr;
+ int fd = -1;
+ int reuseVal = 1;
+
+ /* Create the socket */
+ if((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
+ goto err;
+ /* Set the SO_REUSEADDR flag - servers act weird without it */
+ if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)(&reuseVal),
+ sizeof(reuseVal)) != 0)
+ goto err;
+ /* Prepare the listen address stuff */
+ in_addr.sin_family = AF_INET;
+ memcpy(&in_addr.sin_addr.s_addr, ip, 4);
+ in_addr.sin_port = htons(port);
+ /* Bind to the required port/address/interface */
+ if(bind(fd, (struct sockaddr *)&in_addr, sizeof(struct sockaddr_in)) != 0)
+ goto err;
+ /* Start "listening" */
+ if(listen(fd, IP_LISTENER_BACKLOG) != 0)
+ goto err;
+ return fd;
+err:
+ if(fd != -1)
+ close(fd);
+ return -1;
+}
+
+int ip_create_connection_split(const char *ip, unsigned short port)
+{
+ struct sockaddr_in in_addr;
+ int flags, fd = -1;
+
+ /* Create the socket */
+ if((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
+ goto err;
+ /* Make it non-blocking */
+ if(((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
+ (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0))
+ goto err;
+ /* Prepare the connection address stuff */
+ in_addr.sin_family = AF_INET;
+ memcpy(&in_addr.sin_addr.s_addr, ip, 4);
+ in_addr.sin_port = htons(port);
+ /* Start a connect (non-blocking, in all likelihood) */
+ if((connect(fd, (struct sockaddr *)&in_addr,
+ sizeof(struct sockaddr_in)) != 0) &&
+ (errno != EINPROGRESS))
+ goto err;
+ return fd;
+err:
+ if(fd != -1)
+ close(fd);
+ return -1;
+}
+
+static char all_local_ip[] = {0x00,0x00,0x00,0x00};
+
+int ip_parse_address(const char *address, const char **parsed_ip,
+ unsigned short *parsed_port, int accept_all_ip)
+{
+ char buf[256];
+ struct hostent *lookup;
+ unsigned long port;
+ const char *ptr = strstr(address, ":");
+ const char *ip = all_local_ip;
+
+ if(!ptr) {
+ /* We assume we're listening on all local interfaces and have
+ * only specified a port. */
+ if(!accept_all_ip)
+ return 0;
+ ptr = address;
+ goto determine_port;
+ }
+ if((ptr - address) > 255)
+ return 0;
+ memset(buf, 0, 256);
+ memcpy(buf, address, ptr - address);
+ ptr++;
+ if((lookup = gethostbyname(buf)) == NULL) {
+ /* Spit a message to differentiate between lookup failures and
+ * bad strings. */
+ fprintf(stderr, "hostname lookup for '%s' failed\n", buf);
+ return 0;
+ }
+ ip = lookup->h_addr_list[0];
+determine_port:
+ if(strlen(ptr) < 1)
+ return 0;
+ if(!int_strtoul(ptr, &port) || (port > 65535))
+ return 0;
+ *parsed_ip = ip;
+ *parsed_port = (unsigned short)port;
+ return 1;
+}
+
+int ip_create_listener(const char *address)
+{
+ const char *ip;
+ unsigned short port;
+
+ if(!ip_parse_address(address, &ip, &port, 1))
+ return -1;
+ return ip_create_listener_split(ip, port);
+}
+
+int ip_create_connection(const char *address)
+{
+ const char *ip;
+ unsigned short port;
+
+ if(!ip_parse_address(address, &ip, &port, 0))
+ return -1;
+ return ip_create_connection_split(ip, port);
+}
+
+int ip_accept_connection(int listen_fd)
+{
+ return accept(listen_fd, NULL, NULL);
+}
+
+#endif /* !defined(NO_IP) */
+
diff --git a/lib/libssl/src/demos/tunala/sm.c b/lib/libssl/src/demos/tunala/sm.c
new file mode 100644
index 00000000000..25359e67ef4
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/sm.c
@@ -0,0 +1,151 @@
+#include "tunala.h"
+
+#ifndef NO_TUNALA
+
+void state_machine_init(state_machine_t *machine)
+{
+ machine->ssl = NULL;
+ machine->bio_intossl = machine->bio_fromssl = NULL;
+ buffer_init(&machine->clean_in);
+ buffer_init(&machine->clean_out);
+ buffer_init(&machine->dirty_in);
+ buffer_init(&machine->dirty_out);
+}
+
+void state_machine_close(state_machine_t *machine)
+{
+ if(machine->ssl)
+ SSL_free(machine->ssl);
+/* SSL_free seems to decrement the reference counts already so doing this goes
+ * kaboom. */
+#if 0
+ if(machine->bio_intossl)
+ BIO_free(machine->bio_intossl);
+ if(machine->bio_fromssl)
+ BIO_free(machine->bio_fromssl);
+#endif
+ buffer_close(&machine->clean_in);
+ buffer_close(&machine->clean_out);
+ buffer_close(&machine->dirty_in);
+ buffer_close(&machine->dirty_out);
+ state_machine_init(machine);
+}
+
+buffer_t *state_machine_get_buffer(state_machine_t *machine, sm_buffer_t type)
+{
+ switch(type) {
+ case SM_CLEAN_IN:
+ return &machine->clean_in;
+ case SM_CLEAN_OUT:
+ return &machine->clean_out;
+ case SM_DIRTY_IN:
+ return &machine->dirty_in;
+ case SM_DIRTY_OUT:
+ return &machine->dirty_out;
+ default:
+ break;
+ }
+ /* Should never get here */
+ abort();
+ return NULL;
+}
+
+SSL *state_machine_get_SSL(state_machine_t *machine)
+{
+ return machine->ssl;
+}
+
+int state_machine_set_SSL(state_machine_t *machine, SSL *ssl, int is_server)
+{
+ if(machine->ssl)
+ /* Shouldn't ever be set twice */
+ abort();
+ machine->ssl = ssl;
+ /* Create the BIOs to handle the dirty side of the SSL */
+ if((machine->bio_intossl = BIO_new(BIO_s_mem())) == NULL)
+ abort();
+ if((machine->bio_fromssl = BIO_new(BIO_s_mem())) == NULL)
+ abort();
+ /* Hook up the BIOs on the dirty side of the SSL */
+ SSL_set_bio(machine->ssl, machine->bio_intossl, machine->bio_fromssl);
+ if(is_server)
+ SSL_set_accept_state(machine->ssl);
+ else
+ SSL_set_connect_state(machine->ssl);
+ /* If we're the first one to generate traffic - do it now otherwise we
+ * go into the next select empty-handed and our peer will not send data
+ * but will similarly wait for us. */
+ return state_machine_churn(machine);
+}
+
+/* Performs the data-IO loop and returns zero if the machine should close */
+int state_machine_churn(state_machine_t *machine)
+{
+ unsigned int loop;
+ if(machine->ssl == NULL) {
+ if(buffer_empty(&machine->clean_out))
+ /* Time to close this state-machine altogether */
+ return 0;
+ else
+ /* Still buffered data on the clean side to go out */
+ return 1;
+ }
+ /* Do this loop twice to cover any dependencies about which precise
+ * order of reads and writes is required. */
+ for(loop = 0; loop < 2; loop++) {
+ buffer_to_SSL(&machine->clean_in, machine->ssl);
+ buffer_to_BIO(&machine->dirty_in, machine->bio_intossl);
+ buffer_from_SSL(&machine->clean_out, machine->ssl);
+ buffer_from_BIO(&machine->dirty_out, machine->bio_fromssl);
+ }
+ /* We close on the SSL side if the info callback noticed some problems
+ * or an SSL shutdown was underway and shutdown traffic had all been
+ * sent. */
+ if(SSL_get_app_data(machine->ssl) || (SSL_get_shutdown(machine->ssl) &&
+ buffer_empty(&machine->dirty_out))) {
+ /* Great, we can seal off the dirty side completely */
+ if(!state_machine_close_dirty(machine))
+ return 0;
+ }
+ /* Either the SSL is alive and well, or the closing process still has
+ * outgoing data waiting to be sent */
+ return 1;
+}
+
+/* Called when the clean side of the SSL has lost its connection */
+int state_machine_close_clean(state_machine_t *machine)
+{
+ /* Well, first thing to do is null out the clean-side buffers - they're
+ * no use any more. */
+ buffer_close(&machine->clean_in);
+ buffer_close(&machine->clean_out);
+ /* And start an SSL shutdown */
+ if(machine->ssl)
+ SSL_shutdown(machine->ssl);
+ /* This is an "event", so flush the SSL of any generated traffic */
+ state_machine_churn(machine);
+ if(buffer_empty(&machine->dirty_in) &&
+ buffer_empty(&machine->dirty_out))
+ return 0;
+ return 1;
+}
+
+/* Called when the dirty side of the SSL has lost its connection. This is pretty
+ * terminal as all that can be left to do is send any buffered output on the
+ * clean side - after that, we're done. */
+int state_machine_close_dirty(state_machine_t *machine)
+{
+ buffer_close(&machine->dirty_in);
+ buffer_close(&machine->dirty_out);
+ buffer_close(&machine->clean_in);
+ if(machine->ssl)
+ SSL_free(machine->ssl);
+ machine->ssl = NULL;
+ machine->bio_intossl = machine->bio_fromssl = NULL;
+ if(buffer_empty(&machine->clean_out))
+ return 0;
+ return 1;
+}
+
+#endif /* !defined(NO_TUNALA) */
+
diff --git a/lib/libssl/src/demos/tunala/tunala.c b/lib/libssl/src/demos/tunala/tunala.c
new file mode 100644
index 00000000000..e802a6209ff
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/tunala.c
@@ -0,0 +1,1093 @@
+#if defined(NO_BUFFER) || defined(NO_IP) || defined(NO_OPENSSL)
+#error "Badness, NO_BUFFER, NO_IP or NO_OPENSSL is defined, turn them *off*"
+#endif
+
+/* Include our bits'n'pieces */
+#include "tunala.h"
+
+
+/********************************************/
+/* Our local types that specify our "world" */
+/********************************************/
+
+/* These represent running "tunnels". Eg. if you wanted to do SSL in a
+ * "message-passing" scanario, the "int" file-descriptors might be replaced by
+ * thread or process IDs, and the "select" code might be replaced by message
+ * handling code. Whatever. */
+typedef struct _tunala_item_t {
+ /* The underlying SSL state machine. This is a data-only processing unit
+ * and we communicate with it by talking to its four "buffers". */
+ state_machine_t sm;
+ /* The file-descriptors for the "dirty" (encrypted) side of the SSL
+ * setup. In actuality, this is typically a socket and both values are
+ * identical. */
+ int dirty_read, dirty_send;
+ /* The file-descriptors for the "clean" (unencrypted) side of the SSL
+ * setup. These could be stdin/stdout, a socket (both values the same),
+ * or whatever you like. */
+ int clean_read, clean_send;
+} tunala_item_t;
+
+/* This structure is used as the data for running the main loop. Namely, in a
+ * network format such as this, it is stuff for select() - but as pointed out,
+ * when moving the real-world to somewhere else, this might be replaced by
+ * something entirely different. It's basically the stuff that controls when
+ * it's time to do some "work". */
+typedef struct _select_sets_t {
+ int max; /* As required as the first argument to select() */
+ fd_set reads, sends, excepts; /* As passed to select() */
+} select_sets_t;
+typedef struct _tunala_selector_t {
+ select_sets_t last_selected; /* Results of the last select() */
+ select_sets_t next_select; /* What we'll next select on */
+} tunala_selector_t;
+
+/* This structure is *everything*. We do it to avoid the use of globals so that,
+ * for example, it would be easier to shift things around between async-IO,
+ * thread-based, or multi-fork()ed (or combinations thereof). */
+typedef struct _tunala_world_t {
+ /* The file-descriptor we "listen" on for new connections */
+ int listen_fd;
+ /* The array of tunnels */
+ tunala_item_t *tunnels;
+ /* the number of tunnels in use and allocated, respectively */
+ unsigned int tunnels_used, tunnels_size;
+ /* Our outside "loop" context stuff */
+ tunala_selector_t selector;
+ /* Our SSL_CTX, which is configured as the SSL client or server and has
+ * the various cert-settings and callbacks configured. */
+ SSL_CTX *ssl_ctx;
+ /* Simple flag with complex logic :-) Indicates whether we're an SSL
+ * server or an SSL client. */
+ int server_mode;
+} tunala_world_t;
+
+/*****************************/
+/* Internal static functions */
+/*****************************/
+
+static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id,
+ const char *CAfile, const char *cert, const char *key,
+ const char *dcert, const char *dkey, const char *cipher_list,
+ const char *dh_file, const char *dh_special, int ctx_options,
+ int out_state, int out_verify, int verify_mode,
+ unsigned int verify_depth);
+static void selector_init(tunala_selector_t *selector);
+static void selector_add_listener(tunala_selector_t *selector, int fd);
+static void selector_add_tunala(tunala_selector_t *selector, tunala_item_t *t);
+static int selector_select(tunala_selector_t *selector);
+/* This returns -1 for error, 0 for no new connections, or 1 for success, in
+ * which case *newfd is populated. */
+static int selector_get_listener(tunala_selector_t *selector, int fd, int *newfd);
+static int tunala_world_new_item(tunala_world_t *world, int fd,
+ const char *ip, unsigned short port, int flipped);
+static void tunala_world_del_item(tunala_world_t *world, unsigned int idx);
+static int tunala_item_io(tunala_selector_t *selector, tunala_item_t *item);
+
+/*********************************************/
+/* MAIN FUNCTION (and its utility functions) */
+/*********************************************/
+
+static const char *def_proxyhost = "127.0.0.1:443";
+static const char *def_listenhost = "127.0.0.1:8080";
+static int def_max_tunnels = 50;
+static const char *def_cacert = NULL;
+static const char *def_cert = NULL;
+static const char *def_key = NULL;
+static const char *def_dcert = NULL;
+static const char *def_dkey = NULL;
+static const char *def_engine_id = NULL;
+static int def_server_mode = 0;
+static int def_flipped = 0;
+static const char *def_cipher_list = NULL;
+static const char *def_dh_file = NULL;
+static const char *def_dh_special = NULL;
+static int def_ctx_options = 0;
+static int def_verify_mode = 0;
+static unsigned int def_verify_depth = 10;
+static int def_out_state = 0;
+static unsigned int def_out_verify = 0;
+static int def_out_totals = 0;
+static int def_out_conns = 0;
+
+static const char *helpstring =
+"\n'Tunala' (A tunneler with a New Zealand accent)\n"
+"Usage: tunala [options], where options are from;\n"
+" -listen [host:]<port> (default = 127.0.0.1:8080)\n"
+" -proxy <host>:<port> (default = 127.0.0.1:443)\n"
+" -maxtunnels <num> (default = 50)\n"
+" -cacert <path|NULL> (default = NULL)\n"
+" -cert <path|NULL> (default = NULL)\n"
+" -key <path|NULL> (default = whatever '-cert' is)\n"
+" -dcert <path|NULL> (usually for DSA, default = NULL)\n"
+" -dkey <path|NULL> (usually for DSA, default = whatever '-dcert' is)\n"
+" -engine <id|NULL> (default = NULL)\n"
+" -server <0|1> (default = 0, ie. an SSL client)\n"
+" -flipped <0|1> (makes SSL servers be network clients, and vice versa)\n"
+" -cipher <list> (specifies cipher list to use)\n"
+" -dh_file <path> (a PEM file containing DH parameters to use)\n"
+" -dh_special <NULL|generate|standard> (see below: def=NULL)\n"
+" -no_ssl2 (disable SSLv2)\n"
+" -no_ssl3 (disable SSLv3)\n"
+" -no_tls1 (disable TLSv1)\n"
+" -v_peer (verify the peer certificate)\n"
+" -v_strict (do not continue if peer doesn't authenticate)\n"
+" -v_once (no verification in renegotiates)\n"
+" -v_depth <num> (limit certificate chain depth, default = 10)\n"
+" -out_conns (prints client connections and disconnections)\n"
+" -out_state (prints SSL handshake states)\n"
+" -out_verify <0|1|2|3> (prints certificate verification states: def=1)\n"
+" -out_totals (prints out byte-totals when a tunnel closes)\n"
+" -<h|help|?> (displays this help screen)\n"
+"Notes:\n"
+"(1) It is recommended to specify a cert+key when operating as an SSL server.\n"
+" If you only specify '-cert', the same file must contain a matching\n"
+" private key.\n"
+"(2) Either dh_file or dh_special can be used to specify where DH parameters\n"
+" will be obtained from (or '-dh_special NULL' for the default choice) but\n"
+" you cannot specify both. For dh_special, 'generate' will create new DH\n"
+" parameters on startup, and 'standard' will use embedded parameters\n"
+" instead.\n"
+"(3) Normally an ssl client connects to an ssl server - so that an 'ssl client\n"
+" tunala' listens for 'clean' client connections and proxies ssl, and an\n"
+" 'ssl server tunala' listens for ssl connections and proxies 'clean'. With\n"
+" '-flipped 1', this behaviour is reversed so that an 'ssl server tunala'\n"
+" listens for clean client connections and proxies ssl (but participating\n"
+" as an ssl *server* in the SSL/TLS protocol), and an 'ssl client tunala'\n"
+" listens for ssl connections (participating as an ssl *client* in the\n"
+" SSL/TLS protocol) and proxies 'clean' to the end destination. This can\n"
+" be useful for allowing network access to 'servers' where only the server\n"
+" needs to authenticate the client (ie. the other way is not required).\n"
+" Even with client and server authentication, this 'technique' mitigates\n"
+" some DoS (denial-of-service) potential as it will be the network client\n"
+" having to perform the first private key operation rather than the other\n"
+" way round.\n"
+"(4) The 'technique' used by setting '-flipped 1' is probably compatible with\n"
+" absolutely nothing except another complimentary instance of 'tunala'\n"
+" running with '-flipped 1'. :-)\n";
+
+/* Default DH parameters for use with "-dh_special standard" ... stolen striaght
+ * from s_server. */
+static unsigned char dh512_p[]={
+ 0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75,
+ 0x6F,0x4C,0xCA,0x92,0xDD,0x4B,0xE5,0x33,0xB8,0x04,0xFB,0x0F,
+ 0xED,0x94,0xEF,0x9C,0x8A,0x44,0x03,0xED,0x57,0x46,0x50,0xD3,
+ 0x69,0x99,0xDB,0x29,0xD7,0x76,0x27,0x6B,0xA2,0xD3,0xD4,0x12,
+ 0xE2,0x18,0xF4,0xDD,0x1E,0x08,0x4C,0xF6,0xD8,0x00,0x3E,0x7C,
+ 0x47,0x74,0xE8,0x33,
+ };
+static unsigned char dh512_g[]={
+ 0x02,
+ };
+
+/* And the function that parses the above "standard" parameters, again, straight
+ * out of s_server. */
+static DH *get_dh512(void)
+ {
+ DH *dh=NULL;
+
+ if ((dh=DH_new()) == NULL) return(NULL);
+ dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
+ dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ return(NULL);
+ return(dh);
+ }
+
+/* Various help/error messages used by main() */
+static int usage(const char *errstr, int isunknownarg)
+{
+ if(isunknownarg)
+ fprintf(stderr, "Error: unknown argument '%s'\n", errstr);
+ else
+ fprintf(stderr, "Error: %s\n", errstr);
+ fprintf(stderr, "%s\n", helpstring);
+ return 1;
+}
+
+static int err_str0(const char *str0)
+{
+ fprintf(stderr, "%s\n", str0);
+ return 1;
+}
+
+static int err_str1(const char *fmt, const char *str1)
+{
+ fprintf(stderr, fmt, str1);
+ fprintf(stderr, "\n");
+ return 1;
+}
+
+static int parse_max_tunnels(const char *s, unsigned int *maxtunnels)
+{
+ unsigned long l;
+ if(!int_strtoul(s, &l) || (l < 1) || (l > 1024)) {
+ fprintf(stderr, "Error, '%s' is an invalid value for "
+ "maxtunnels\n", s);
+ return 0;
+ }
+ *maxtunnels = (unsigned int)l;
+ return 1;
+}
+
+static int parse_server_mode(const char *s, int *servermode)
+{
+ unsigned long l;
+ if(!int_strtoul(s, &l) || (l > 1)) {
+ fprintf(stderr, "Error, '%s' is an invalid value for the "
+ "server mode\n", s);
+ return 0;
+ }
+ *servermode = (int)l;
+ return 1;
+}
+
+static int parse_dh_special(const char *s, const char **dh_special)
+{
+ if((strcmp(s, "NULL") == 0) || (strcmp(s, "generate") == 0) ||
+ (strcmp(s, "standard") == 0)) {
+ *dh_special = s;
+ return 1;
+ }
+ fprintf(stderr, "Error, '%s' is an invalid value for 'dh_special'\n", s);
+ return 0;
+}
+
+static int parse_verify_level(const char *s, unsigned int *verify_level)
+{
+ unsigned long l;
+ if(!int_strtoul(s, &l) || (l > 3)) {
+ fprintf(stderr, "Error, '%s' is an invalid value for "
+ "out_verify\n", s);
+ return 0;
+ }
+ *verify_level = (unsigned int)l;
+ return 1;
+}
+
+static int parse_verify_depth(const char *s, unsigned int *verify_depth)
+{
+ unsigned long l;
+ if(!int_strtoul(s, &l) || (l < 1) || (l > 50)) {
+ fprintf(stderr, "Error, '%s' is an invalid value for "
+ "verify_depth\n", s);
+ return 0;
+ }
+ *verify_depth = (unsigned int)l;
+ return 1;
+}
+
+/* Some fprintf format strings used when tunnels close */
+static const char *io_stats_dirty =
+" SSL traffic; %8lu bytes in, %8lu bytes out\n";
+static const char *io_stats_clean =
+" clear traffic; %8lu bytes in, %8lu bytes out\n";
+
+int main(int argc, char *argv[])
+{
+ unsigned int loop;
+ int newfd;
+ tunala_world_t world;
+ tunala_item_t *t_item;
+ const char *proxy_ip;
+ unsigned short proxy_port;
+ /* Overridables */
+ const char *proxyhost = def_proxyhost;
+ const char *listenhost = def_listenhost;
+ unsigned int max_tunnels = def_max_tunnels;
+ const char *cacert = def_cacert;
+ const char *cert = def_cert;
+ const char *key = def_key;
+ const char *dcert = def_dcert;
+ const char *dkey = def_dkey;
+ const char *engine_id = def_engine_id;
+ int server_mode = def_server_mode;
+ int flipped = def_flipped;
+ const char *cipher_list = def_cipher_list;
+ const char *dh_file = def_dh_file;
+ const char *dh_special = def_dh_special;
+ int ctx_options = def_ctx_options;
+ int verify_mode = def_verify_mode;
+ unsigned int verify_depth = def_verify_depth;
+ int out_state = def_out_state;
+ unsigned int out_verify = def_out_verify;
+ int out_totals = def_out_totals;
+ int out_conns = def_out_conns;
+
+/* Parse command-line arguments */
+next_arg:
+ argc--; argv++;
+ if(argc > 0) {
+ if(strcmp(*argv, "-listen") == 0) {
+ if(argc < 2)
+ return usage("-listen requires an argument", 0);
+ argc--; argv++;
+ listenhost = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-proxy") == 0) {
+ if(argc < 2)
+ return usage("-proxy requires an argument", 0);
+ argc--; argv++;
+ proxyhost = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-maxtunnels") == 0) {
+ if(argc < 2)
+ return usage("-maxtunnels requires an argument", 0);
+ argc--; argv++;
+ if(!parse_max_tunnels(*argv, &max_tunnels))
+ return 1;
+ goto next_arg;
+ } else if(strcmp(*argv, "-cacert") == 0) {
+ if(argc < 2)
+ return usage("-cacert requires an argument", 0);
+ argc--; argv++;
+ if(strcmp(*argv, "NULL") == 0)
+ cacert = NULL;
+ else
+ cacert = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-cert") == 0) {
+ if(argc < 2)
+ return usage("-cert requires an argument", 0);
+ argc--; argv++;
+ if(strcmp(*argv, "NULL") == 0)
+ cert = NULL;
+ else
+ cert = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-key") == 0) {
+ if(argc < 2)
+ return usage("-key requires an argument", 0);
+ argc--; argv++;
+ if(strcmp(*argv, "NULL") == 0)
+ key = NULL;
+ else
+ key = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-dcert") == 0) {
+ if(argc < 2)
+ return usage("-dcert requires an argument", 0);
+ argc--; argv++;
+ if(strcmp(*argv, "NULL") == 0)
+ dcert = NULL;
+ else
+ dcert = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-dkey") == 0) {
+ if(argc < 2)
+ return usage("-dkey requires an argument", 0);
+ argc--; argv++;
+ if(strcmp(*argv, "NULL") == 0)
+ dkey = NULL;
+ else
+ dkey = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-engine") == 0) {
+ if(argc < 2)
+ return usage("-engine requires an argument", 0);
+ argc--; argv++;
+ engine_id = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-server") == 0) {
+ if(argc < 2)
+ return usage("-server requires an argument", 0);
+ argc--; argv++;
+ if(!parse_server_mode(*argv, &server_mode))
+ return 1;
+ goto next_arg;
+ } else if(strcmp(*argv, "-flipped") == 0) {
+ if(argc < 2)
+ return usage("-flipped requires an argument", 0);
+ argc--; argv++;
+ if(!parse_server_mode(*argv, &flipped))
+ return 1;
+ goto next_arg;
+ } else if(strcmp(*argv, "-cipher") == 0) {
+ if(argc < 2)
+ return usage("-cipher requires an argument", 0);
+ argc--; argv++;
+ cipher_list = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-dh_file") == 0) {
+ if(argc < 2)
+ return usage("-dh_file requires an argument", 0);
+ if(dh_special)
+ return usage("cannot mix -dh_file with "
+ "-dh_special", 0);
+ argc--; argv++;
+ dh_file = *argv;
+ goto next_arg;
+ } else if(strcmp(*argv, "-dh_special") == 0) {
+ if(argc < 2)
+ return usage("-dh_special requires an argument", 0);
+ if(dh_file)
+ return usage("cannot mix -dh_file with "
+ "-dh_special", 0);
+ argc--; argv++;
+ if(!parse_dh_special(*argv, &dh_special))
+ return 1;
+ goto next_arg;
+ } else if(strcmp(*argv, "-no_ssl2") == 0) {
+ ctx_options |= SSL_OP_NO_SSLv2;
+ goto next_arg;
+ } else if(strcmp(*argv, "-no_ssl3") == 0) {
+ ctx_options |= SSL_OP_NO_SSLv3;
+ goto next_arg;
+ } else if(strcmp(*argv, "-no_tls1") == 0) {
+ ctx_options |= SSL_OP_NO_TLSv1;
+ goto next_arg;
+ } else if(strcmp(*argv, "-v_peer") == 0) {
+ verify_mode |= SSL_VERIFY_PEER;
+ goto next_arg;
+ } else if(strcmp(*argv, "-v_strict") == 0) {
+ verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ goto next_arg;
+ } else if(strcmp(*argv, "-v_once") == 0) {
+ verify_mode |= SSL_VERIFY_CLIENT_ONCE;
+ goto next_arg;
+ } else if(strcmp(*argv, "-v_depth") == 0) {
+ if(argc < 2)
+ return usage("-v_depth requires an argument", 0);
+ argc--; argv++;
+ if(!parse_verify_depth(*argv, &verify_depth))
+ return 1;
+ goto next_arg;
+ } else if(strcmp(*argv, "-out_state") == 0) {
+ out_state = 1;
+ goto next_arg;
+ } else if(strcmp(*argv, "-out_verify") == 0) {
+ if(argc < 2)
+ return usage("-out_verify requires an argument", 0);
+ argc--; argv++;
+ if(!parse_verify_level(*argv, &out_verify))
+ return 1;
+ goto next_arg;
+ } else if(strcmp(*argv, "-out_totals") == 0) {
+ out_totals = 1;
+ goto next_arg;
+ } else if(strcmp(*argv, "-out_conns") == 0) {
+ out_conns = 1;
+ goto next_arg;
+ } else if((strcmp(*argv, "-h") == 0) ||
+ (strcmp(*argv, "-help") == 0) ||
+ (strcmp(*argv, "-?") == 0)) {
+ fprintf(stderr, "%s\n", helpstring);
+ return 0;
+ } else
+ return usage(*argv, 1);
+ }
+ /* Run any sanity checks we want here */
+ if(!cert && !dcert && server_mode)
+ fprintf(stderr, "WARNING: you are running an SSL server without "
+ "a certificate - this may not work!\n");
+
+ /* Initialise network stuff */
+ if(!ip_initialise())
+ return err_str0("ip_initialise failed");
+ /* Create the SSL_CTX */
+ if((world.ssl_ctx = initialise_ssl_ctx(server_mode, engine_id,
+ cacert, cert, key, dcert, dkey, cipher_list, dh_file,
+ dh_special, ctx_options, out_state, out_verify,
+ verify_mode, verify_depth)) == NULL)
+ return err_str1("initialise_ssl_ctx(engine_id=%s) failed",
+ (engine_id == NULL) ? "NULL" : engine_id);
+ if(engine_id)
+ fprintf(stderr, "Info, engine '%s' initialised\n", engine_id);
+ /* Create the listener */
+ if((world.listen_fd = ip_create_listener(listenhost)) == -1)
+ return err_str1("ip_create_listener(%s) failed", listenhost);
+ fprintf(stderr, "Info, listening on '%s'\n", listenhost);
+ if(!ip_parse_address(proxyhost, &proxy_ip, &proxy_port, 0))
+ return err_str1("ip_parse_address(%s) failed", proxyhost);
+ fprintf(stderr, "Info, proxying to '%s' (%d.%d.%d.%d:%d)\n", proxyhost,
+ (int)proxy_ip[0], (int)proxy_ip[1],
+ (int)proxy_ip[2], (int)proxy_ip[3], (int)proxy_port);
+ fprintf(stderr, "Info, set maxtunnels to %d\n", (int)max_tunnels);
+ fprintf(stderr, "Info, set to operate as an SSL %s\n",
+ (server_mode ? "server" : "client"));
+ /* Initialise the rest of the stuff */
+ world.tunnels_used = world.tunnels_size = 0;
+ world.tunnels = NULL;
+ world.server_mode = server_mode;
+ selector_init(&world.selector);
+
+/* We're ready to loop */
+main_loop:
+ /* Should we listen for *new* tunnels? */
+ if(world.tunnels_used < max_tunnels)
+ selector_add_listener(&world.selector, world.listen_fd);
+ /* We should add in our existing tunnels */
+ for(loop = 0; loop < world.tunnels_used; loop++)
+ selector_add_tunala(&world.selector, world.tunnels + loop);
+ /* Now do the select */
+ switch(selector_select(&world.selector)) {
+ case -1:
+ fprintf(stderr, "selector_select returned a badness error.\n");
+ goto shouldnt_happen;
+ case 0:
+ fprintf(stderr, "Warn, selector_select returned 0 - signal?""?\n");
+ goto main_loop;
+ default:
+ break;
+ }
+ /* Accept new connection if we should and can */
+ if((world.tunnels_used < max_tunnels) && (selector_get_listener(
+ &world.selector, world.listen_fd,
+ &newfd) == 1)) {
+ /* We have a new connection */
+ if(!tunala_world_new_item(&world, newfd, proxy_ip,
+ proxy_port, flipped))
+ fprintf(stderr, "tunala_world_new_item failed\n");
+ else if(out_conns)
+ fprintf(stderr, "Info, new tunnel opened, now up to "
+ "%d\n", world.tunnels_used);
+ }
+ /* Give each tunnel its moment, note the while loop is because it makes
+ * the logic easier than with "for" to deal with an array that may shift
+ * because of deletes. */
+ loop = 0;
+ t_item = world.tunnels;
+ while(loop < world.tunnels_used) {
+ if(!tunala_item_io(&world.selector, t_item)) {
+ /* We're closing whether for reasons of an error or a
+ * natural close. Don't increment loop or t_item because
+ * the next item is moving to us! */
+ if(!out_totals)
+ goto skip_totals;
+ fprintf(stderr, "Tunnel closing, traffic stats follow\n");
+ /* Display the encrypted (over the network) stats */
+ fprintf(stderr, io_stats_dirty,
+ buffer_total_in(state_machine_get_buffer(
+ &t_item->sm,SM_DIRTY_IN)),
+ buffer_total_out(state_machine_get_buffer(
+ &t_item->sm,SM_DIRTY_OUT)));
+ /* Display the local (tunnelled) stats. NB: Data we
+ * *receive* is data sent *out* of the state_machine on
+ * its 'clean' side. Hence the apparent back-to-front
+ * OUT/IN mixup here :-) */
+ fprintf(stderr, io_stats_clean,
+ buffer_total_out(state_machine_get_buffer(
+ &t_item->sm,SM_CLEAN_OUT)),
+ buffer_total_in(state_machine_get_buffer(
+ &t_item->sm,SM_CLEAN_IN)));
+skip_totals:
+ tunala_world_del_item(&world, loop);
+ if(out_conns)
+ fprintf(stderr, "Info, tunnel closed, down to %d\n",
+ world.tunnels_used);
+ }
+ else {
+ /* Move to the next item */
+ loop++;
+ t_item++;
+ }
+ }
+ goto main_loop;
+ /* Should never get here */
+shouldnt_happen:
+ abort();
+ return 1;
+}
+
+/****************/
+/* OpenSSL bits */
+/****************/
+
+static int ctx_set_cert(SSL_CTX *ctx, const char *cert, const char *key)
+{
+ FILE *fp = NULL;
+ X509 *x509 = NULL;
+ EVP_PKEY *pkey = NULL;
+ int toret = 0; /* Assume an error */
+
+ /* cert */
+ if(cert) {
+ if((fp = fopen(cert, "r")) == NULL) {
+ fprintf(stderr, "Error opening cert file '%s'\n", cert);
+ goto err;
+ }
+ if(!PEM_read_X509(fp, &x509, NULL, NULL)) {
+ fprintf(stderr, "Error reading PEM cert from '%s'\n",
+ cert);
+ goto err;
+ }
+ if(!SSL_CTX_use_certificate(ctx, x509)) {
+ fprintf(stderr, "Error, cert in '%s' can not be used\n",
+ cert);
+ goto err;
+ }
+ /* Clear the FILE* for reuse in the "key" code */
+ fclose(fp);
+ fp = NULL;
+ fprintf(stderr, "Info, operating with cert in '%s'\n", cert);
+ /* If a cert was given without matching key, we assume the same
+ * file contains the required key. */
+ if(!key)
+ key = cert;
+ } else {
+ if(key)
+ fprintf(stderr, "Error, can't specify a key without a "
+ "corresponding certificate\n");
+ else
+ fprintf(stderr, "Error, ctx_set_cert called with "
+ "NULLs!\n");
+ goto err;
+ }
+ /* key */
+ if(key) {
+ if((fp = fopen(key, "r")) == NULL) {
+ fprintf(stderr, "Error opening key file '%s'\n", key);
+ goto err;
+ }
+ if(!PEM_read_PrivateKey(fp, &pkey, NULL, NULL)) {
+ fprintf(stderr, "Error reading PEM key from '%s'\n",
+ key);
+ goto err;
+ }
+ if(!SSL_CTX_use_PrivateKey(ctx, pkey)) {
+ fprintf(stderr, "Error, key in '%s' can not be used\n",
+ key);
+ goto err;
+ }
+ fprintf(stderr, "Info, operating with key in '%s'\n", key);
+ } else
+ fprintf(stderr, "Info, operating without a cert or key\n");
+ /* Success */
+ toret = 1; err:
+ if(x509)
+ X509_free(x509);
+ if(pkey)
+ EVP_PKEY_free(pkey);
+ if(fp)
+ fclose(fp);
+ return toret;
+}
+
+static int ctx_set_dh(SSL_CTX *ctx, const char *dh_file, const char *dh_special)
+{
+ DH *dh = NULL;
+ FILE *fp = NULL;
+
+ if(dh_special) {
+ if(strcmp(dh_special, "NULL") == 0)
+ return 1;
+ if(strcmp(dh_special, "standard") == 0) {
+ if((dh = get_dh512()) == NULL) {
+ fprintf(stderr, "Error, can't parse 'standard'"
+ " DH parameters\n");
+ return 0;
+ }
+ fprintf(stderr, "Info, using 'standard' DH parameters\n");
+ goto do_it;
+ }
+ if(strcmp(dh_special, "generate") != 0)
+ /* This shouldn't happen - screening values is handled
+ * in main(). */
+ abort();
+ fprintf(stderr, "Info, generating DH parameters ... ");
+ fflush(stderr);
+ if((dh = DH_generate_parameters(512, DH_GENERATOR_5,
+ NULL, NULL)) == NULL) {
+ fprintf(stderr, "error!\n");
+ return 0;
+ }
+ fprintf(stderr, "complete\n");
+ goto do_it;
+ }
+ /* So, we're loading dh_file */
+ if((fp = fopen(dh_file, "r")) == NULL) {
+ fprintf(stderr, "Error, couldn't open '%s' for DH parameters\n",
+ dh_file);
+ return 0;
+ }
+ dh = PEM_read_DHparams(fp, NULL, NULL, NULL);
+ fclose(fp);
+ if(dh == NULL) {
+ fprintf(stderr, "Error, could not parse DH parameters from '%s'\n",
+ dh_file);
+ return 0;
+ }
+ fprintf(stderr, "Info, using DH parameters from file '%s'\n", dh_file);
+do_it:
+ SSL_CTX_set_tmp_dh(ctx, dh);
+ DH_free(dh);
+ return 1;
+}
+
+static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id,
+ const char *CAfile, const char *cert, const char *key,
+ const char *dcert, const char *dkey, const char *cipher_list,
+ const char *dh_file, const char *dh_special, int ctx_options,
+ int out_state, int out_verify, int verify_mode,
+ unsigned int verify_depth)
+{
+ SSL_CTX *ctx = NULL, *ret = NULL;
+ SSL_METHOD *meth;
+ ENGINE *e = NULL;
+
+ OpenSSL_add_ssl_algorithms();
+ SSL_load_error_strings();
+
+ meth = (server_mode ? SSLv23_server_method() : SSLv23_client_method());
+ if(meth == NULL)
+ goto err;
+ if(engine_id) {
+ ENGINE_load_builtin_engines();
+ if((e = ENGINE_by_id(engine_id)) == NULL) {
+ fprintf(stderr, "Error obtaining '%s' engine, openssl "
+ "errors follow\n", engine_id);
+ goto err;
+ }
+ if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
+ fprintf(stderr, "Error assigning '%s' engine, openssl "
+ "errors follow\n", engine_id);
+ goto err;
+ }
+ ENGINE_free(e);
+ }
+ if((ctx = SSL_CTX_new(meth)) == NULL)
+ goto err;
+ /* cacert */
+ if(CAfile) {
+ if(!X509_STORE_load_locations(SSL_CTX_get_cert_store(ctx),
+ CAfile, NULL)) {
+ fprintf(stderr, "Error loading CA cert(s) in '%s'\n",
+ CAfile);
+ goto err;
+ }
+ fprintf(stderr, "Info, operating with CA cert(s) in '%s'\n",
+ CAfile);
+ } else
+ fprintf(stderr, "Info, operating without a CA cert(-list)\n");
+ if(!SSL_CTX_set_default_verify_paths(ctx)) {
+ fprintf(stderr, "Error setting default verify paths\n");
+ goto err;
+ }
+
+ /* cert and key */
+ if((cert || key) && !ctx_set_cert(ctx, cert, key))
+ goto err;
+ /* dcert and dkey */
+ if((dcert || dkey) && !ctx_set_cert(ctx, dcert, dkey))
+ goto err;
+
+ /* cipher_list */
+ if(cipher_list) {
+ if(!SSL_CTX_set_cipher_list(ctx, cipher_list)) {
+ fprintf(stderr, "Error setting cipher list '%s'\n",
+ cipher_list);
+ goto err;
+ }
+ fprintf(stderr, "Info, set cipher list '%s'\n", cipher_list);
+ } else
+ fprintf(stderr, "Info, operating with default cipher list\n");
+
+ /* dh_file & dh_special */
+ if((dh_file || dh_special) && !ctx_set_dh(ctx, dh_file, dh_special))
+ goto err;
+
+ /* ctx_options */
+ SSL_CTX_set_options(ctx, ctx_options);
+
+ /* out_state (output of SSL handshake states to screen). */
+ if(out_state)
+ cb_ssl_info_set_output(stderr);
+
+ /* out_verify */
+ if(out_verify > 0) {
+ cb_ssl_verify_set_output(stderr);
+ cb_ssl_verify_set_level(out_verify);
+ }
+
+ /* verify_depth */
+ cb_ssl_verify_set_depth(verify_depth);
+
+ /* Success! (includes setting verify_mode) */
+ SSL_CTX_set_info_callback(ctx, cb_ssl_info);
+ SSL_CTX_set_verify(ctx, verify_mode, cb_ssl_verify);
+ ret = ctx;
+err:
+ if(!ret) {
+ ERR_print_errors_fp(stderr);
+ if(ctx)
+ SSL_CTX_free(ctx);
+ }
+ return ret;
+}
+
+/*****************/
+/* Selector bits */
+/*****************/
+
+static void selector_sets_init(select_sets_t *s)
+{
+ s->max = 0;
+ FD_ZERO(&s->reads);
+ FD_ZERO(&s->sends);
+ FD_ZERO(&s->excepts);
+}
+static void selector_init(tunala_selector_t *selector)
+{
+ selector_sets_init(&selector->last_selected);
+ selector_sets_init(&selector->next_select);
+}
+
+#define SEL_EXCEPTS 0x00
+#define SEL_READS 0x01
+#define SEL_SENDS 0x02
+static void selector_add_raw_fd(tunala_selector_t *s, int fd, int flags)
+{
+ FD_SET(fd, &s->next_select.excepts);
+ if(flags & SEL_READS)
+ FD_SET(fd, &s->next_select.reads);
+ if(flags & SEL_SENDS)
+ FD_SET(fd, &s->next_select.sends);
+ /* Adjust "max" */
+ if(s->next_select.max < (fd + 1))
+ s->next_select.max = fd + 1;
+}
+
+static void selector_add_listener(tunala_selector_t *selector, int fd)
+{
+ selector_add_raw_fd(selector, fd, SEL_READS);
+}
+
+static void selector_add_tunala(tunala_selector_t *s, tunala_item_t *t)
+{
+ /* Set clean read if sm.clean_in is not full */
+ if(t->clean_read != -1) {
+ selector_add_raw_fd(s, t->clean_read,
+ (buffer_full(state_machine_get_buffer(&t->sm,
+ SM_CLEAN_IN)) ? SEL_EXCEPTS : SEL_READS));
+ }
+ /* Set clean send if sm.clean_out is not empty */
+ if(t->clean_send != -1) {
+ selector_add_raw_fd(s, t->clean_send,
+ (buffer_empty(state_machine_get_buffer(&t->sm,
+ SM_CLEAN_OUT)) ? SEL_EXCEPTS : SEL_SENDS));
+ }
+ /* Set dirty read if sm.dirty_in is not full */
+ if(t->dirty_read != -1) {
+ selector_add_raw_fd(s, t->dirty_read,
+ (buffer_full(state_machine_get_buffer(&t->sm,
+ SM_DIRTY_IN)) ? SEL_EXCEPTS : SEL_READS));
+ }
+ /* Set dirty send if sm.dirty_out is not empty */
+ if(t->dirty_send != -1) {
+ selector_add_raw_fd(s, t->dirty_send,
+ (buffer_empty(state_machine_get_buffer(&t->sm,
+ SM_DIRTY_OUT)) ? SEL_EXCEPTS : SEL_SENDS));
+ }
+}
+
+static int selector_select(tunala_selector_t *selector)
+{
+ memcpy(&selector->last_selected, &selector->next_select,
+ sizeof(select_sets_t));
+ selector_sets_init(&selector->next_select);
+ return select(selector->last_selected.max,
+ &selector->last_selected.reads,
+ &selector->last_selected.sends,
+ &selector->last_selected.excepts, NULL);
+}
+
+/* This returns -1 for error, 0 for no new connections, or 1 for success, in
+ * which case *newfd is populated. */
+static int selector_get_listener(tunala_selector_t *selector, int fd, int *newfd)
+{
+ if(FD_ISSET(fd, &selector->last_selected.excepts))
+ return -1;
+ if(!FD_ISSET(fd, &selector->last_selected.reads))
+ return 0;
+ if((*newfd = ip_accept_connection(fd)) == -1)
+ return -1;
+ return 1;
+}
+
+/************************/
+/* "Tunala" world stuff */
+/************************/
+
+static int tunala_world_make_room(tunala_world_t *world)
+{
+ unsigned int newsize;
+ tunala_item_t *newarray;
+
+ if(world->tunnels_used < world->tunnels_size)
+ return 1;
+ newsize = (world->tunnels_size == 0 ? 16 :
+ ((world->tunnels_size * 3) / 2));
+ if((newarray = malloc(newsize * sizeof(tunala_item_t))) == NULL)
+ return 0;
+ memset(newarray, 0, newsize * sizeof(tunala_item_t));
+ if(world->tunnels_used > 0)
+ memcpy(newarray, world->tunnels,
+ world->tunnels_used * sizeof(tunala_item_t));
+ if(world->tunnels_size > 0)
+ free(world->tunnels);
+ /* migrate */
+ world->tunnels = newarray;
+ world->tunnels_size = newsize;
+ return 1;
+}
+
+static int tunala_world_new_item(tunala_world_t *world, int fd,
+ const char *ip, unsigned short port, int flipped)
+{
+ tunala_item_t *item;
+ int newfd;
+ SSL *new_ssl = NULL;
+
+ if(!tunala_world_make_room(world))
+ return 0;
+ if((new_ssl = SSL_new(world->ssl_ctx)) == NULL) {
+ fprintf(stderr, "Error creating new SSL\n");
+ ERR_print_errors_fp(stderr);
+ return 0;
+ }
+ item = world->tunnels + (world->tunnels_used++);
+ state_machine_init(&item->sm);
+ item->clean_read = item->clean_send =
+ item->dirty_read = item->dirty_send = -1;
+ if((newfd = ip_create_connection_split(ip, port)) == -1)
+ goto err;
+ /* Which way round? If we're a server, "fd" is the dirty side and the
+ * connection we open is the clean one. For a client, it's the other way
+ * around. Unless, of course, we're "flipped" in which case everything
+ * gets reversed. :-) */
+ if((world->server_mode && !flipped) ||
+ (!world->server_mode && flipped)) {
+ item->dirty_read = item->dirty_send = fd;
+ item->clean_read = item->clean_send = newfd;
+ } else {
+ item->clean_read = item->clean_send = fd;
+ item->dirty_read = item->dirty_send = newfd;
+ }
+ /* We use the SSL's "app_data" to indicate a call-back induced "kill" */
+ SSL_set_app_data(new_ssl, NULL);
+ if(!state_machine_set_SSL(&item->sm, new_ssl, world->server_mode))
+ goto err;
+ return 1;
+err:
+ tunala_world_del_item(world, world->tunnels_used - 1);
+ return 0;
+
+}
+
+static void tunala_world_del_item(tunala_world_t *world, unsigned int idx)
+{
+ tunala_item_t *item = world->tunnels + idx;
+ if(item->clean_read != -1)
+ close(item->clean_read);
+ if(item->clean_send != item->clean_read)
+ close(item->clean_send);
+ item->clean_read = item->clean_send = -1;
+ if(item->dirty_read != -1)
+ close(item->dirty_read);
+ if(item->dirty_send != item->dirty_read)
+ close(item->dirty_send);
+ item->dirty_read = item->dirty_send = -1;
+ state_machine_close(&item->sm);
+ /* OK, now we fix the item array */
+ if(idx + 1 < world->tunnels_used)
+ /* We need to scroll entries to the left */
+ memmove(world->tunnels + idx,
+ world->tunnels + (idx + 1),
+ (world->tunnels_used - (idx + 1)) *
+ sizeof(tunala_item_t));
+ world->tunnels_used--;
+}
+
+static int tunala_item_io(tunala_selector_t *selector, tunala_item_t *item)
+{
+ int c_r, c_s, d_r, d_s; /* Four boolean flags */
+
+ /* Take ourselves out of the gene-pool if there was an except */
+ if((item->clean_read != -1) && FD_ISSET(item->clean_read,
+ &selector->last_selected.excepts))
+ return 0;
+ if((item->clean_send != -1) && FD_ISSET(item->clean_send,
+ &selector->last_selected.excepts))
+ return 0;
+ if((item->dirty_read != -1) && FD_ISSET(item->dirty_read,
+ &selector->last_selected.excepts))
+ return 0;
+ if((item->dirty_send != -1) && FD_ISSET(item->dirty_send,
+ &selector->last_selected.excepts))
+ return 0;
+ /* Grab our 4 IO flags */
+ c_r = c_s = d_r = d_s = 0;
+ if(item->clean_read != -1)
+ c_r = FD_ISSET(item->clean_read, &selector->last_selected.reads);
+ if(item->clean_send != -1)
+ c_s = FD_ISSET(item->clean_send, &selector->last_selected.sends);
+ if(item->dirty_read != -1)
+ d_r = FD_ISSET(item->dirty_read, &selector->last_selected.reads);
+ if(item->dirty_send != -1)
+ d_s = FD_ISSET(item->dirty_send, &selector->last_selected.sends);
+ /* If no IO has happened for us, skip needless data looping */
+ if(!c_r && !c_s && !d_r && !d_s)
+ return 1;
+ if(c_r)
+ c_r = (buffer_from_fd(state_machine_get_buffer(&item->sm,
+ SM_CLEAN_IN), item->clean_read) <= 0);
+ if(c_s)
+ c_s = (buffer_to_fd(state_machine_get_buffer(&item->sm,
+ SM_CLEAN_OUT), item->clean_send) <= 0);
+ if(d_r)
+ d_r = (buffer_from_fd(state_machine_get_buffer(&item->sm,
+ SM_DIRTY_IN), item->dirty_read) <= 0);
+ if(d_s)
+ d_s = (buffer_to_fd(state_machine_get_buffer(&item->sm,
+ SM_DIRTY_OUT), item->dirty_send) <= 0);
+ /* If any of the flags is non-zero, that means they need closing */
+ if(c_r) {
+ close(item->clean_read);
+ if(item->clean_send == item->clean_read)
+ item->clean_send = -1;
+ item->clean_read = -1;
+ }
+ if(c_s && (item->clean_send != -1)) {
+ close(item->clean_send);
+ if(item->clean_send == item->clean_read)
+ item->clean_read = -1;
+ item->clean_send = -1;
+ }
+ if(d_r) {
+ close(item->dirty_read);
+ if(item->dirty_send == item->dirty_read)
+ item->dirty_send = -1;
+ item->dirty_read = -1;
+ }
+ if(d_s && (item->dirty_send != -1)) {
+ close(item->dirty_send);
+ if(item->dirty_send == item->dirty_read)
+ item->dirty_read = -1;
+ item->dirty_send = -1;
+ }
+ /* This function name is attributed to the term donated by David
+ * Schwartz on openssl-dev, message-ID:
+ * <NCBBLIEPOCNJOAEKBEAKEEDGLIAA.davids@webmaster.com>. :-) */
+ if(!state_machine_churn(&item->sm))
+ /* If the SSL closes, it will also zero-out the _in buffers
+ * and will in future process just outgoing data. As and
+ * when the outgoing data has gone, it will return zero
+ * here to tell us to bail out. */
+ return 0;
+ /* Otherwise, we return zero if both sides are dead. */
+ if(((item->clean_read == -1) || (item->clean_send == -1)) &&
+ ((item->dirty_read == -1) || (item->dirty_send == -1)))
+ return 0;
+ /* If only one side closed, notify the SSL of this so it can take
+ * appropriate action. */
+ if((item->clean_read == -1) || (item->clean_send == -1)) {
+ if(!state_machine_close_clean(&item->sm))
+ return 0;
+ }
+ if((item->dirty_read == -1) || (item->dirty_send == -1)) {
+ if(!state_machine_close_dirty(&item->sm))
+ return 0;
+ }
+ return 1;
+}
+
diff --git a/lib/libssl/src/demos/tunala/tunala.h b/lib/libssl/src/demos/tunala/tunala.h
new file mode 100644
index 00000000000..b4c8ec78d8a
--- /dev/null
+++ b/lib/libssl/src/demos/tunala/tunala.h
@@ -0,0 +1,214 @@
+/* Tunala ("Tunneler with a New Zealand accent")
+ *
+ * Written by Geoff Thorpe, but endorsed/supported by noone. Please use this is
+ * if it's useful or informative to you, but it's only here as a scratchpad for
+ * ideas about how you might (or might not) program with OpenSSL. If you deploy
+ * this is in a mission-critical environment, and have not read, understood,
+ * audited, and modified this code to your satisfaction, and the result is that
+ * all hell breaks loose and you are looking for a new employer, then it proves
+ * nothing except perhaps that Darwinism is alive and well. Let's just say, *I*
+ * don't use this in a mission-critical environment, so it would be stupid for
+ * anyone to assume that it is solid and/or tested enough when even its author
+ * doesn't place that much trust in it. You have been warned.
+ *
+ * With thanks to Cryptographic Appliances, Inc.
+ */
+
+#ifndef _TUNALA_H
+#define _TUNALA_H
+
+/* pull in autoconf fluff */
+#ifndef NO_CONFIG_H
+#include "config.h"
+#else
+/* We don't have autoconf, we have to set all of these unless a tweaked Makefile
+ * tells us not to ... */
+/* headers */
+#ifndef NO_HAVE_SELECT
+#define HAVE_SELECT
+#endif
+#ifndef NO_HAVE_SOCKET
+#define HAVE_SOCKET
+#endif
+#ifndef NO_HAVE_UNISTD_H
+#define HAVE_UNISTD_H
+#endif
+#ifndef NO_HAVE_FCNTL_H
+#define HAVE_FCNTL_H
+#endif
+#ifndef NO_HAVE_LIMITS_H
+#define HAVE_LIMITS_H
+#endif
+/* features */
+#ifndef NO_HAVE_STRSTR
+#define HAVE_STRSTR
+#endif
+#ifndef NO_HAVE_STRTOUL
+#define HAVE_STRTOUL
+#endif
+#endif
+
+#if !defined(HAVE_SELECT) || !defined(HAVE_SOCKET)
+#error "can't build without some network basics like select() and socket()"
+#endif
+
+#include <stdlib.h>
+#ifndef NO_SYSTEM_H
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#include <netdb.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#endif /* !defined(NO_SYSTEM_H) */
+
+#ifndef NO_OPENSSL
+#include <openssl/err.h>
+#include <openssl/engine.h>
+#include <openssl/ssl.h>
+#endif /* !defined(NO_OPENSSL) */
+
+#ifndef OPENSSL_NO_BUFFER
+/* This is the generic "buffer" type that is used when feeding the
+ * state-machine. It's basically a FIFO with respect to the "adddata" &
+ * "takedata" type functions that operate on it. */
+#define MAX_DATA_SIZE 16384
+typedef struct _buffer_t {
+ unsigned char data[MAX_DATA_SIZE];
+ unsigned int used;
+ /* Statistical values - counts the total number of bytes read in and
+ * read out (respectively) since "buffer_init()" */
+ unsigned long total_in, total_out;
+} buffer_t;
+
+/* Initialise a buffer structure before use */
+void buffer_init(buffer_t *buf);
+/* Cleanup a buffer structure - presently not needed, but if buffer_t is
+ * converted to using dynamic allocation, this would be required - so should be
+ * called to protect against an explosion of memory leaks later if the change is
+ * made. */
+void buffer_close(buffer_t *buf);
+
+/* Basic functions to manipulate buffers */
+
+unsigned int buffer_used(buffer_t *buf); /* How much data in the buffer */
+unsigned int buffer_unused(buffer_t *buf); /* How much space in the buffer */
+int buffer_full(buffer_t *buf); /* Boolean, is it full? */
+int buffer_notfull(buffer_t *buf); /* Boolean, is it not full? */
+int buffer_empty(buffer_t *buf); /* Boolean, is it empty? */
+int buffer_notempty(buffer_t *buf); /* Boolean, is it not empty? */
+unsigned long buffer_total_in(buffer_t *buf); /* Total bytes written to buffer */
+unsigned long buffer_total_out(buffer_t *buf); /* Total bytes read from buffer */
+
+#if 0 /* Currently used only within buffer.c - better to expose only
+ * higher-level functions anyway */
+/* Add data to the tail of the buffer, returns the amount that was actually
+ * added (so, you need to check if return value is less than size) */
+unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr,
+ unsigned int size);
+
+/* Take data from the front of the buffer (and scroll the rest forward). If
+ * "ptr" is NULL, this just removes data off the front of the buffer. Return
+ * value is the amount actually removed (can be less than size if the buffer has
+ * too little data). */
+unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr,
+ unsigned int size);
+
+/* Flushes as much data as possible out of the "from" buffer into the "to"
+ * buffer. Return value is the amount moved. The amount moved can be restricted
+ * to a maximum by specifying "cap" - setting it to -1 means no limit. */
+unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap);
+#endif
+
+#ifndef NO_IP
+/* Read or write between a file-descriptor and a buffer */
+int buffer_from_fd(buffer_t *buf, int fd);
+int buffer_to_fd(buffer_t *buf, int fd);
+#endif /* !defined(NO_IP) */
+
+#ifndef NO_OPENSSL
+/* Read or write between an SSL or BIO and a buffer */
+void buffer_from_SSL(buffer_t *buf, SSL *ssl);
+void buffer_to_SSL(buffer_t *buf, SSL *ssl);
+void buffer_from_BIO(buffer_t *buf, BIO *bio);
+void buffer_to_BIO(buffer_t *buf, BIO *bio);
+
+/* Callbacks */
+void cb_ssl_info(const SSL *s, int where, int ret);
+void cb_ssl_info_set_output(FILE *fp); /* Called if output should be sent too */
+int cb_ssl_verify(int ok, X509_STORE_CTX *ctx);
+void cb_ssl_verify_set_output(FILE *fp);
+void cb_ssl_verify_set_depth(unsigned int verify_depth);
+void cb_ssl_verify_set_level(unsigned int level);
+#endif /* !defined(NO_OPENSSL) */
+#endif /* !defined(OPENSSL_NO_BUFFER) */
+
+#ifndef NO_TUNALA
+#ifdef OPENSSL_NO_BUFFER
+#error "TUNALA section of tunala.h requires BUFFER support"
+#endif
+typedef struct _state_machine_t {
+ SSL *ssl;
+ BIO *bio_intossl;
+ BIO *bio_fromssl;
+ buffer_t clean_in, clean_out;
+ buffer_t dirty_in, dirty_out;
+} state_machine_t;
+typedef enum {
+ SM_CLEAN_IN, SM_CLEAN_OUT,
+ SM_DIRTY_IN, SM_DIRTY_OUT
+} sm_buffer_t;
+void state_machine_init(state_machine_t *machine);
+void state_machine_close(state_machine_t *machine);
+buffer_t *state_machine_get_buffer(state_machine_t *machine, sm_buffer_t type);
+SSL *state_machine_get_SSL(state_machine_t *machine);
+int state_machine_set_SSL(state_machine_t *machine, SSL *ssl, int is_server);
+/* Performs the data-IO loop and returns zero if the machine should close */
+int state_machine_churn(state_machine_t *machine);
+/* Is used to handle closing conditions - namely when one side of the tunnel has
+ * closed but the other should finish flushing. */
+int state_machine_close_clean(state_machine_t *machine);
+int state_machine_close_dirty(state_machine_t *machine);
+#endif /* !defined(NO_TUNALA) */
+
+#ifndef NO_IP
+/* Initialise anything related to the networking. This includes blocking pesky
+ * SIGPIPE signals. */
+int ip_initialise(void);
+/* ip is the 4-byte ip address (eg. 127.0.0.1 is {0x7F,0x00,0x00,0x01}), port is
+ * the port to listen on (host byte order), and the return value is the
+ * file-descriptor or -1 on error. */
+int ip_create_listener_split(const char *ip, unsigned short port);
+/* Same semantics as above. */
+int ip_create_connection_split(const char *ip, unsigned short port);
+/* Converts a string into the ip/port before calling the above */
+int ip_create_listener(const char *address);
+int ip_create_connection(const char *address);
+/* Just does a string conversion on its own. NB: If accept_all_ip is non-zero,
+ * then the address string could be just a port. Ie. it's suitable for a
+ * listening address but not a connecting address. */
+int ip_parse_address(const char *address, const char **parsed_ip,
+ unsigned short *port, int accept_all_ip);
+/* Accepts an incoming connection through the listener. Assumes selects and
+ * what-not have deemed it an appropriate thing to do. */
+int ip_accept_connection(int listen_fd);
+#endif /* !defined(NO_IP) */
+
+/* These functions wrap up things that can be portability hassles. */
+int int_strtoul(const char *str, unsigned long *val);
+#ifdef HAVE_STRSTR
+#define int_strstr strstr
+#else
+char *int_strstr(const char *haystack, const char *needle);
+#endif
+
+#endif /* !defined(_TUNALA_H) */
diff --git a/lib/libssl/src/demos/x509/README b/lib/libssl/src/demos/x509/README
new file mode 100644
index 00000000000..88f9d6c46e8
--- /dev/null
+++ b/lib/libssl/src/demos/x509/README
@@ -0,0 +1,3 @@
+This directory contains examples of how to contruct
+various X509 structures. Certificates, certificate requests
+and CRLs.
diff --git a/lib/libssl/src/demos/x509/mkcert.c b/lib/libssl/src/demos/x509/mkcert.c
new file mode 100644
index 00000000000..4709e18e7c9
--- /dev/null
+++ b/lib/libssl/src/demos/x509/mkcert.c
@@ -0,0 +1,168 @@
+/* Certificate creation. Demonstrates some certificate related
+ * operations.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <openssl/pem.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include <openssl/engine.h>
+
+int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days);
+int add_ext(X509 *cert, int nid, char *value);
+
+int main(int argc, char **argv)
+ {
+ BIO *bio_err;
+ X509 *x509=NULL;
+ EVP_PKEY *pkey=NULL;
+
+ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+
+ bio_err=BIO_new_fp(stderr, BIO_NOCLOSE);
+
+ mkcert(&x509,&pkey,512,0,365);
+
+ RSA_print_fp(stdout,pkey->pkey.rsa,0);
+ X509_print_fp(stdout,x509);
+
+ PEM_write_PrivateKey(stdout,pkey,NULL,NULL,0,NULL, NULL);
+ PEM_write_X509(stdout,x509);
+
+ X509_free(x509);
+ EVP_PKEY_free(pkey);
+
+ ENGINE_cleanup();
+ CRYPTO_cleanup_all_ex_data();
+
+ CRYPTO_mem_leaks(bio_err);
+ BIO_free(bio_err);
+ return(0);
+ }
+
+static void callback(int p, int n, void *arg)
+ {
+ char c='B';
+
+ if (p == 0) c='.';
+ if (p == 1) c='+';
+ if (p == 2) c='*';
+ if (p == 3) c='\n';
+ fputc(c,stderr);
+ }
+
+int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days)
+ {
+ X509 *x;
+ EVP_PKEY *pk;
+ RSA *rsa;
+ X509_NAME *name=NULL;
+
+ if ((pkeyp == NULL) || (*pkeyp == NULL))
+ {
+ if ((pk=EVP_PKEY_new()) == NULL)
+ {
+ abort();
+ return(0);
+ }
+ }
+ else
+ pk= *pkeyp;
+
+ if ((x509p == NULL) || (*x509p == NULL))
+ {
+ if ((x=X509_new()) == NULL)
+ goto err;
+ }
+ else
+ x= *x509p;
+
+ rsa=RSA_generate_key(bits,RSA_F4,callback,NULL);
+ if (!EVP_PKEY_assign_RSA(pk,rsa))
+ {
+ abort();
+ goto err;
+ }
+ rsa=NULL;
+
+ X509_set_version(x,3);
+ ASN1_INTEGER_set(X509_get_serialNumber(x),serial);
+ X509_gmtime_adj(X509_get_notBefore(x),0);
+ X509_gmtime_adj(X509_get_notAfter(x),(long)60*60*24*days);
+ X509_set_pubkey(x,pk);
+
+ name=X509_get_subject_name(x);
+
+ /* This function creates and adds the entry, working out the
+ * correct string type and performing checks on its length.
+ * Normally we'd check the return value for errors...
+ */
+ X509_NAME_add_entry_by_txt(name,"C",
+ MBSTRING_ASC, "UK", -1, -1, 0);
+ X509_NAME_add_entry_by_txt(name,"CN",
+ MBSTRING_ASC, "OpenSSL Group", -1, -1, 0);
+
+ /* Its self signed so set the issuer name to be the same as the
+ * subject.
+ */
+ X509_set_issuer_name(x,name);
+
+ /* Add various extensions: standard extensions */
+ add_ext(x, NID_basic_constraints, "critical,CA:TRUE");
+ add_ext(x, NID_key_usage, "critical,keyCertSign,cRLSign");
+
+ add_ext(x, NID_subject_key_identifier, "hash");
+
+ /* Some Netscape specific extensions */
+ add_ext(x, NID_netscape_cert_type, "sslCA");
+
+ add_ext(x, NID_netscape_comment, "example comment extension");
+
+
+#ifdef CUSTOM_EXT
+ /* Maybe even add our own extension based on existing */
+ {
+ int nid;
+ nid = OBJ_create("1.2.3.4", "MyAlias", "My Test Alias Extension");
+ X509V3_EXT_add_alias(nid, NID_netscape_comment);
+ add_ext(x, nid, "example comment alias");
+ }
+#endif
+
+ if (!X509_sign(x,pk,EVP_md5()))
+ goto err;
+
+ *x509p=x;
+ *pkeyp=pk;
+ return(1);
+err:
+ return(0);
+ }
+
+/* Add extension using V3 code: we can set the config file as NULL
+ * because we wont reference any other sections.
+ */
+
+int add_ext(X509 *cert, int nid, char *value)
+ {
+ X509_EXTENSION *ex;
+ X509V3_CTX ctx;
+ /* This sets the 'context' of the extensions. */
+ /* No configuration database */
+ X509V3_set_ctx_nodb(&ctx);
+ /* Issuer and subject certs: both the target since it is self signed,
+ * no request and no CRL
+ */
+ X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
+ ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
+ if (!ex)
+ return 0;
+
+ X509_add_ext(cert,ex,-1);
+ X509_EXTENSION_free(ex);
+ return 1;
+ }
+
diff --git a/lib/libssl/src/demos/x509/mkreq.c b/lib/libssl/src/demos/x509/mkreq.c
new file mode 100644
index 00000000000..d69dcc392b9
--- /dev/null
+++ b/lib/libssl/src/demos/x509/mkreq.c
@@ -0,0 +1,157 @@
+/* Certificate request creation. Demonstrates some request related
+ * operations.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <openssl/pem.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include <openssl/engine.h>
+
+int mkreq(X509_REQ **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days);
+int add_ext(STACK_OF(X509_REQUEST) *sk, int nid, char *value);
+
+int main(int argc, char **argv)
+ {
+ BIO *bio_err;
+ X509_REQ *req=NULL;
+ EVP_PKEY *pkey=NULL;
+
+ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+
+ bio_err=BIO_new_fp(stderr, BIO_NOCLOSE);
+
+ mkreq(&req,&pkey,512,0,365);
+
+ RSA_print_fp(stdout,pkey->pkey.rsa,0);
+ X509_REQ_print_fp(stdout,req);
+
+ PEM_write_X509_REQ(stdout,req);
+
+ X509_REQ_free(req);
+ EVP_PKEY_free(pkey);
+
+ ENGINE_cleanup();
+ CRYPTO_cleanup_all_ex_data();
+
+ CRYPTO_mem_leaks(bio_err);
+ BIO_free(bio_err);
+ return(0);
+ }
+
+static void callback(int p, int n, void *arg)
+ {
+ char c='B';
+
+ if (p == 0) c='.';
+ if (p == 1) c='+';
+ if (p == 2) c='*';
+ if (p == 3) c='\n';
+ fputc(c,stderr);
+ }
+
+int mkreq(X509_REQ **req, EVP_PKEY **pkeyp, int bits, int serial, int days)
+ {
+ X509_REQ *x;
+ EVP_PKEY *pk;
+ RSA *rsa;
+ X509_NAME *name=NULL;
+ STACK_OF(X509_EXTENSION) *exts = NULL;
+
+ if ((pk=EVP_PKEY_new()) == NULL)
+ goto err;
+
+ if ((x=X509_REQ_new()) == NULL)
+ goto err;
+
+ rsa=RSA_generate_key(bits,RSA_F4,callback,NULL);
+ if (!EVP_PKEY_assign_RSA(pk,rsa))
+ goto err;
+
+ rsa=NULL;
+
+ X509_REQ_set_pubkey(x,pk);
+
+ name=X509_REQ_get_subject_name(x);
+
+ /* This function creates and adds the entry, working out the
+ * correct string type and performing checks on its length.
+ * Normally we'd check the return value for errors...
+ */
+ X509_NAME_add_entry_by_txt(name,"C",
+ MBSTRING_ASC, "UK", -1, -1, 0);
+ X509_NAME_add_entry_by_txt(name,"CN",
+ MBSTRING_ASC, "OpenSSL Group", -1, -1, 0);
+
+#ifdef REQUEST_EXTENSIONS
+ /* Certificate requests can contain extensions, which can be used
+ * to indicate the extensions the requestor would like added to
+ * their certificate. CAs might ignore them however or even choke
+ * if they are present.
+ */
+
+ /* For request extensions they are all packed in a single attribute.
+ * We save them in a STACK and add them all at once later...
+ */
+
+ exts = sk_X509_EXTENSION_new_null();
+ /* Standard extenions */
+
+ add_ext(exts, NID_key_usage, "critical,digitalSignature,keyEncipherment");
+
+ /* This is a typical use for request extensions: requesting a value for
+ * subject alternative name.
+ */
+
+ add_ext(exts, NID_subject_alt_name, "email:steve@openssl.org");
+
+ /* Some Netscape specific extensions */
+ add_ext(exts, NID_netscape_cert_type, "client,email");
+
+
+
+#ifdef CUSTOM_EXT
+ /* Maybe even add our own extension based on existing */
+ {
+ int nid;
+ nid = OBJ_create("1.2.3.4", "MyAlias", "My Test Alias Extension");
+ X509V3_EXT_add_alias(nid, NID_netscape_comment);
+ add_ext(x, nid, "example comment alias");
+ }
+#endif
+
+ /* Now we've created the extensions we add them to the request */
+
+ X509_REQ_add_extensions(x, exts);
+
+ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+
+#endif
+
+ if (!X509_REQ_sign(x,pk,EVP_md5()))
+ goto err;
+
+ *req=x;
+ *pkeyp=pk;
+ return(1);
+err:
+ return(0);
+ }
+
+/* Add extension using V3 code: we can set the config file as NULL
+ * because we wont reference any other sections.
+ */
+
+int add_ext(STACK_OF(X509_REQUEST) *sk, int nid, char *value)
+ {
+ X509_EXTENSION *ex;
+ ex = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
+ if (!ex)
+ return 0;
+ sk_X509_EXTENSION_push(sk, ex);
+
+ return 1;
+ }
+