/* ==================================================================== * 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 #include #include #include #include #include #include #include /* 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 \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; } n-center>span { display: block; overflow: hidden; margin: 13px auto 0; text-align: center; } .markdown-body span.align-center span img { margin: 0 auto; text-align: center; } .markdown-body span.align-right { display: block; overflow: hidden; clear: both; } .markdown-body span.align-right>span { display: block; overflow: hidden; margin: 13px 0 0; text-align: right; } .markdown-body span.align-right span img { margin: 0; text-align: right; } .markdown-body span.float-left { display: block; margin-right: 13px; overflow: hidden; float: left; } .markdown-body span.float-left span { margin: 13px 0 0; } .markdown-body span.float-right { display: block; margin-left: 13px; overflow: hidden; float: right; } .markdown-body span.float-right>span { display: block; overflow: hidden; margin: 13px auto 0; text-align: right; } .markdown-body code, .markdown-body tt { margin: 0 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; } .markdown-body code { white-space: nowrap; } .markdown-body pre>code { margin: 0; padding: 0; white-space: pre; border: none; background: transparent; } .markdown-body .highlight pre, .markdown-body pre { background-color: #f8f8f8; border: 1px solid #ccc; font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-radius: 3px; } .markdown-body pre code, .markdown-body pre tt { margin: 0; padding: 0; background-color: transparent; border: none; } pre { line-height: 125%; } td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } .highlight .hll { background-color: #ffffcc } .highlight { background: #ffffff; } .highlight .c { color: #888 } /* Comment */ .highlight .err { color: #A61717; background-color: #E3D2D2 } /* Error */ .highlight .k { color: #080; font-weight: bold } /* Keyword */ .highlight .ch { color: #888 } /* Comment.Hashbang */ .highlight .cm { color: #888 } /* Comment.Multiline */ .highlight .cp { color: #C00; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888 } /* Comment.Single */ .highlight .cs { color: #C00; font-weight: bold; background-color: #FFF0F0 } /* Comment.Special */ .highlight .gd { color: #000; background-color: #FDD } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ .highlight .gr { color: #A00 } /* Generic.Error */ .highlight .gh { color: #333 } /* Generic.Heading */ .highlight .gi { color: #000; background-color: #DFD } /* Generic.Inserted */ .highlight .go { color: #888 } /* Generic.Output */ .highlight .gp { color: #555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666 } /* Generic.Subheading */ .highlight .gt { color: #A00 } /* Generic.Traceback */ .highlight .kc { color: #080; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #080; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #080; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #080 } /* Keyword.Pseudo */ .highlight .kr { color: #080; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #00D; font-weight: bold } /* Literal.Number */ .highlight .s { color: #D20; background-color: #FFF0F0 } /* Literal.String */ .highlight .na { color: #369 } /* Name.Attribute */ .highlight .nb { color: #038 } /* Name.Builtin */ .highlight .nc { color: #B06; font-weight: bold } /* Name.Class */ .highlight .no { color: #036; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555 } /* Name.Decorator */ .highlight .ne { color: #B06; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #06B; font-weight: bold } /* Name.Function */ .highlight .nl { color: #369; font-style: italic } /* Name.Label */ .highlight .nn { color: #B06; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #369; font-weight: bold } /* Name.Property */ .highlight .nt { color: #B06; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #369 } /* Name.Variable */ .highlight .ow { color: #080 } /* Operator.Word */ .highlight .w { color: #BBB } /* Text.Whitespace */ .highlight .mb { color: #00D; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #00D; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #00D; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #00D; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #00D; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #D20; background-color: #FFF0F0 } /* Literal.String.Affix */ .highlight .sb { color: #D20; background-color: #FFF0F0 } /* Literal.String.Backtick */ .highlight .sc { color: #D20; background-color: #FFF0F0 } /* Literal.String.Char */ .highlight .dl { color: #D20; background-color: #FFF0F0 } /* Literal.String.Delimiter */ .highlight .sd { color: #D20; background-color: #FFF0F0 } /* Literal.String.Doc */ .highlight .s2 { color: #D20; background-color: #FFF0F0 } /* Literal.String.Double */ .highlight .se { color: #04D; background-color: #FFF0F0 } /* Literal.String.Escape */ .highlight .sh { color: #D20; background-color: #FFF0F0 } /* Literal.String.Heredoc */ .highlight .si { color: #33B; background-color: #FFF0F0 } /* Literal.String.Interpol */ .highlight .sx { color: #2B2; background-color: #F0FFF0 } /* Literal.String.Other */ .highlight .sr { color: #080; background-color: #FFF0FF } /* Literal.String.Regex */ .highlight .s1 { color: #D20; background-color: #FFF0F0 } /* Literal.String.Single */ .highlight .ss { color: #A60; background-color: #FFF0F0 } /* Literal.String.Symbol */ .highlight .bp { color: #038 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #06B; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #369 } /* Name.Variable.Class */ .highlight .vg { color: #D70 } /* Name.Variable.Global */ .highlight .vi { color: #33B } /* Name.Variable.Instance */ .highlight .vm { color: #369 } /* Name.Variable.Magic */ .highlight .il { color: #00D; font-weight: bold } /* Literal.Number.Integer.Long */