summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Laurie <ben@openssl.org>2000-08-30 18:14:28 +0000
committerBen Laurie <ben@openssl.org>2000-08-30 18:14:28 +0000
commit7049ef5f90b5ebf89eea3e8b58d940c2485aacd8 (patch)
tree4b7c4d10abb7afe83e909b90f5e2c05c1e887fc3
parent7df1c720f60ad3813cc88607c4520da031e41e88 (diff)
Add demo state machine.
-rw-r--r--CHANGES5
-rw-r--r--demos/state_machine/Makefile9
-rw-r--r--demos/state_machine/state_machine.c369
3 files changed, 383 insertions, 0 deletions
diff --git a/CHANGES b/CHANGES
index 9c3a1e3fd6..bc77ece719 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,11 @@
Changes between 0.9.5a and 0.9.6 [xx XXX 2000]
+ *) A demo state-machine implementation was sponsored by
+ Nuron (http://www.nuron.com/) and is now available in
+ demos/state_machine.
+ [Ben Laurie]
+
*) New options added to the 'dgst' utility for signature
generation and verification.
[Steve Henson]
diff --git a/demos/state_machine/Makefile b/demos/state_machine/Makefile
new file mode 100644
index 0000000000..c7a114540d
--- /dev/null
+++ b/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/demos/state_machine/state_machine.c b/demos/state_machine/state_machine.c
new file mode 100644
index 0000000000..b66d059266
--- /dev/null
+++ b/demos/state_machine/state_machine.c
@@ -0,0 +1,369 @@
+/* ====================================================================
+ * 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>
+
+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;
+
+ assert(pMachine);
+
+ pMachine->pCtx=SSL_CTX_new(SSLv23_server_method());
+ assert(pMachine->pCtx);
+
+ n=SSL_CTX_use_certificate_file(pMachine->pCtx,szCertificateFile,
+ SSL_FILETYPE_PEM);
+ assert(n > 0);
+
+ n=SSL_CTX_use_PrivateKey_file(pMachine->pCtx,szKeyFile,SSL_FILETYPE_PEM);
+ assert(n > 0);
+
+ pMachine->pSSL=SSL_new(pMachine->pCtx);
+ assert(pMachine->pSSL);
+
+ pMachine->pbioRead=BIO_new(BIO_s_mem());
+ /* Set EOF to return 0 (-1 is the default) */
+ BIO_ctrl(pMachine->pbioRead,BIO_C_SET_BUF_MEM_EOF_RETURN,0,NULL);
+
+ 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)
+ SSLStateMachine_print_error(pMachine,"SSL_accept failed");
+ if(n == 0)
+ fprintf(stderr,"SSL_accept returned zero\n");
+ assert(n >= 0);
+ return 0;
+ }
+
+ n=SSL_read(pMachine->pSSL,aucBuf,nBuf);
+ 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;
+ }
+
+void main(int argc,char **argv)
+ {
+ SSLStateMachine *pMachine;
+ int nPort;
+ int nFD;
+ const char *szCertificateFile;
+ const char *szKeyFile;
+
+ 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);
+
+ /* 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);
+ }
+
+ /* FIXME: we should only extract if stdout is ready */
+ n=SSLStateMachine_read_extract(pMachine,buf,n);
+ if(n < 0)
+ {
+ SSLStateMachine_print_error(pMachine,"read extract failed");
+ break;
+ }
+ assert(n >= 0);
+ if(n > 0)
+ {
+ 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);
+ }
+ }
+ }