1 /* ====================================================================
2 * Copyright (c) 2000 The OpenSSL Project. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * 3. All advertising materials mentioning features or use of this
17 * software must display the following acknowledgment:
18 * "This product includes software developed by the OpenSSL Project
19 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission. For written permission, please contact
24 * openssl-core@openssl.org.
26 * 5. Products derived from this software may not be called "OpenSSL"
27 * nor may "OpenSSL" appear in their names without prior written
28 * permission of the OpenSSL Project.
30 * 6. Redistributions of any form whatsoever must retain the following
32 * "This product includes software developed by the OpenSSL Project
33 * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
36 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46 * OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
49 * This product includes cryptographic software written by Eric Young
50 * (eay@cryptsoft.com). This product includes software written by Tim
51 * Hudson (tjh@cryptsoft.com).
56 * Nuron, a leader in hardware encryption technology, generously
57 * sponsored the development of this demo by Ben Laurie.
59 * See http://www.nuron.com/.
63 * the aim of this demo is to provide a fully working state-machine
64 * style SSL implementation, i.e. one where the main loop acquires
65 * some data, then converts it from or to SSL by feeding it into the
66 * SSL state machine. It then does any I/O required by the state machine
69 * In order to keep things as simple as possible, this implementation
70 * listens on a TCP socket, which it expects to get an SSL connection
71 * on (for example, from s_client) and from then on writes decrypted
72 * data to stdout and encrypts anything arriving on stdin. Verbose
73 * commentary is written to stderr.
75 * This implementation acts as a server, but it can also be done for a client. */
77 #include <openssl/ssl.h>
81 #include <openssl/err.h>
82 #include <sys/types.h>
83 #include <sys/socket.h>
84 #include <netinet/in.h>
87 * die_unless is intended to work like assert, except that it happens always,
88 * even if NDEBUG is defined. Use assert as a stopgap.
91 #define die_unless(x) assert(x)
100 void SSLStateMachine_print_error(SSLStateMachine
* pMachine
,
105 fprintf(stderr
, "%s\n", szErr
);
106 while ((l
= ERR_get_error())) {
109 ERR_error_string_n(l
, buf
, sizeof buf
);
110 fprintf(stderr
, "Error %lx: %s\n", l
, buf
);
114 SSLStateMachine
*SSLStateMachine_new(const char *szCertificateFile
,
115 const char *szKeyFile
)
117 SSLStateMachine
*pMachine
= malloc(sizeof *pMachine
);
120 die_unless(pMachine
);
122 pMachine
->pCtx
= SSL_CTX_new(SSLv23_server_method());
123 die_unless(pMachine
->pCtx
);
125 n
= SSL_CTX_use_certificate_file(pMachine
->pCtx
, szCertificateFile
,
129 n
= SSL_CTX_use_PrivateKey_file(pMachine
->pCtx
, szKeyFile
,
133 pMachine
->pSSL
= SSL_new(pMachine
->pCtx
);
134 die_unless(pMachine
->pSSL
);
136 pMachine
->pbioRead
= BIO_new(BIO_s_mem());
138 pMachine
->pbioWrite
= BIO_new(BIO_s_mem());
140 SSL_set_bio(pMachine
->pSSL
, pMachine
->pbioRead
, pMachine
->pbioWrite
);
142 SSL_set_accept_state(pMachine
->pSSL
);
147 void SSLStateMachine_read_inject(SSLStateMachine
* pMachine
,
148 const unsigned char *aucBuf
, int nBuf
)
150 int n
= BIO_write(pMachine
->pbioRead
, aucBuf
, nBuf
);
152 * If it turns out this assert fails, then buffer the data here and just
153 * feed it in in churn instead. Seems to me that it should be guaranteed
154 * to succeed, though.
157 fprintf(stderr
, "%d bytes of encrypted data fed to state machine\n", n
);
160 int SSLStateMachine_read_extract(SSLStateMachine
* pMachine
,
161 unsigned char *aucBuf
, int nBuf
)
165 if (!SSL_is_init_finished(pMachine
->pSSL
)) {
166 fprintf(stderr
, "Doing SSL_accept\n");
167 n
= SSL_accept(pMachine
->pSSL
);
169 fprintf(stderr
, "SSL_accept returned zero\n");
174 SSL_get_error(pMachine
->pSSL
, n
)) == SSL_ERROR_WANT_READ
) {
175 fprintf(stderr
, "SSL_accept wants more data\n");
179 SSLStateMachine_print_error(pMachine
, "SSL_accept error");
185 n
= SSL_read(pMachine
->pSSL
, aucBuf
, nBuf
);
187 int err
= SSL_get_error(pMachine
->pSSL
, n
);
189 if (err
== SSL_ERROR_WANT_READ
) {
190 fprintf(stderr
, "SSL_read wants more data\n");
194 SSLStateMachine_print_error(pMachine
, "SSL_read error");
198 fprintf(stderr
, "%d bytes of decrypted data read from state machine\n",
203 int SSLStateMachine_write_can_extract(SSLStateMachine
* pMachine
)
205 int n
= BIO_pending(pMachine
->pbioWrite
);
207 fprintf(stderr
, "There is encrypted data available to write\n");
209 fprintf(stderr
, "There is no encrypted data available to write\n");
214 int SSLStateMachine_write_extract(SSLStateMachine
* pMachine
,
215 unsigned char *aucBuf
, int nBuf
)
219 n
= BIO_read(pMachine
->pbioWrite
, aucBuf
, nBuf
);
220 fprintf(stderr
, "%d bytes of encrypted data read from state machine\n",
225 void SSLStateMachine_write_inject(SSLStateMachine
* pMachine
,
226 const unsigned char *aucBuf
, int nBuf
)
228 int n
= SSL_write(pMachine
->pSSL
, aucBuf
, nBuf
);
230 * If it turns out this assert fails, then buffer the data here and just
231 * feed it in in churn instead. Seems to me that it should be guaranteed
232 * to succeed, though.
235 fprintf(stderr
, "%d bytes of unencrypted data fed to state machine\n", n
);
238 int OpenSocket(int nPort
)
241 struct sockaddr_in saServer
;
242 struct sockaddr_in saClient
;
248 nSocket
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
255 (nSocket
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&one
, sizeof one
) < 0) {
256 perror("setsockopt");
260 memset(&saServer
, 0, sizeof saServer
);
261 saServer
.sin_family
= AF_INET
;
262 saServer
.sin_port
= htons(nPort
);
263 nSize
= sizeof saServer
;
264 if (bind(nSocket
, (struct sockaddr
*)&saServer
, nSize
) < 0) {
269 if (listen(nSocket
, 512) < 0) {
274 nLen
= sizeof saClient
;
275 nFD
= accept(nSocket
, (struct sockaddr
*)&saClient
, &nLen
);
281 fprintf(stderr
, "Incoming accepted on port %d\n", nPort
);
286 int main(int argc
, char **argv
)
288 SSLStateMachine
*pMachine
;
291 const char *szCertificateFile
;
292 const char *szKeyFile
;
297 fprintf(stderr
, "%s <port> <certificate file> <key file>\n", argv
[0]);
301 nPort
= atoi(argv
[1]);
302 szCertificateFile
= argv
[2];
306 OpenSSL_add_ssl_algorithms();
307 SSL_load_error_strings();
308 ERR_load_crypto_strings();
310 nFD
= OpenSocket(nPort
);
312 pMachine
= SSLStateMachine_new(szCertificateFile
, szKeyFile
);
316 unsigned char buf
[1024];
322 /* Select socket for input */
325 /* check whether there's decrypted data */
327 nrbuf
= SSLStateMachine_read_extract(pMachine
, rbuf
, 1);
329 /* if there's decrypted data, check whether we can write it */
333 /* Select socket for output */
334 if (SSLStateMachine_write_can_extract(pMachine
))
337 /* Select stdin for input */
340 /* Wait for something to do something */
341 n
= select(nFD
+ 1, &rfds
, &wfds
, NULL
, NULL
);
344 /* Socket is ready for input */
345 if (FD_ISSET(nFD
, &rfds
)) {
346 n
= read(nFD
, buf
, sizeof buf
);
348 fprintf(stderr
, "Got EOF on socket\n");
353 SSLStateMachine_read_inject(pMachine
, buf
, n
);
356 /* stdout is ready for output (and hence we have some to send it) */
357 if (FD_ISSET(1, &wfds
)) {
362 n
= SSLStateMachine_read_extract(pMachine
, buf
+ 1,
365 SSLStateMachine_print_error(pMachine
, "read extract failed");
370 if (n
> 0) { /* FIXME: has to be true now */
373 w
= write(1, buf
, n
);
374 /* FIXME: we should push back any unwritten data */
380 * Socket is ready for output (and therefore we have output to send)
382 if (FD_ISSET(nFD
, &wfds
)) {
385 n
= SSLStateMachine_write_extract(pMachine
, buf
, sizeof buf
);
388 w
= write(nFD
, buf
, n
);
389 /* FIXME: we should push back any unwritten data */
393 /* Stdin is ready for input */
394 if (FD_ISSET(0, &rfds
)) {
395 n
= read(0, buf
, sizeof buf
);
397 fprintf(stderr
, "Got EOF on stdin\n");
402 SSLStateMachine_write_inject(pMachine
, buf
, n
);