~ubuntu-branches/ubuntu/hardy/openssl/hardy-security

« back to all changes in this revision

Viewing changes to demos/state_machine/state_machine.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Martin
  • Date: 2004-05-24 17:02:29 UTC
  • Revision ID: james.westby@ubuntu.com-20040524170229-ixlo08bbbly0xied
Tags: upstream-0.9.7d
ImportĀ upstreamĀ versionĀ 0.9.7d

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ====================================================================
 
2
 * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions
 
6
 * are met:
 
7
 *
 
8
 * 1. Redistributions of source code must retain the above copyright
 
9
 *    notice, this list of conditions and the following disclaimer. 
 
10
 *
 
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
 
14
 *    distribution.
 
15
 *
 
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/)"
 
20
 *
 
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.
 
25
 *
 
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.
 
29
 *
 
30
 * 6. Redistributions of any form whatsoever must retain the following
 
31
 *    acknowledgment:
 
32
 *    "This product includes software developed by the OpenSSL Project
 
33
 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 
34
 *
 
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
 * ====================================================================
 
48
 *
 
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).
 
52
 *
 
53
 */
 
54
 
 
55
/*
 
56
 * Nuron, a leader in hardware encryption technology, generously
 
57
 * sponsored the development of this demo by Ben Laurie.
 
58
 *
 
59
 * See http://www.nuron.com/.
 
60
 */
 
61
 
 
62
/*
 
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
 
67
 * and loops.
 
68
 *
 
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.
 
74
 *
 
75
 * This implementation acts as a server, but it can also be done for a client.  */
 
76
 
 
77
#include <openssl/ssl.h>
 
78
#include <assert.h>
 
79
#include <unistd.h>
 
80
#include <string.h>
 
81
#include <openssl/err.h>
 
82
#include <sys/types.h>
 
83
#include <sys/socket.h>
 
84
#include <netinet/in.h>
 
85
 
 
86
/* die_unless is intended to work like assert, except that it happens
 
87
   always, even if NDEBUG is defined. Use assert as a stopgap. */
 
88
 
 
89
#define die_unless(x)   assert(x)
 
90
 
 
91
typedef struct
 
92
    {
 
93
    SSL_CTX *pCtx;
 
94
    BIO *pbioRead;
 
95
    BIO *pbioWrite;
 
96
    SSL *pSSL;
 
97
    } SSLStateMachine;
 
98
 
 
99
void SSLStateMachine_print_error(SSLStateMachine *pMachine,const char *szErr)
 
100
    {
 
101
    unsigned long l;
 
102
 
 
103
    fprintf(stderr,"%s\n",szErr);
 
104
    while((l=ERR_get_error()))
 
105
        {
 
106
        char buf[1024];
 
107
 
 
108
        ERR_error_string_n(l,buf,sizeof buf);
 
109
        fprintf(stderr,"Error %lx: %s\n",l,buf);
 
110
        }
 
111
    }
 
112
 
 
113
SSLStateMachine *SSLStateMachine_new(const char *szCertificateFile,
 
114
                                     const char *szKeyFile)
 
115
    {
 
116
    SSLStateMachine *pMachine=malloc(sizeof *pMachine);
 
117
    int n;
 
118
 
 
119
    die_unless(pMachine);
 
120
 
 
121
    pMachine->pCtx=SSL_CTX_new(SSLv23_server_method());
 
122
    die_unless(pMachine->pCtx);
 
123
 
 
124
    n=SSL_CTX_use_certificate_file(pMachine->pCtx,szCertificateFile,
 
125
                                   SSL_FILETYPE_PEM);
 
126
    die_unless(n > 0);
 
127
 
 
128
    n=SSL_CTX_use_PrivateKey_file(pMachine->pCtx,szKeyFile,SSL_FILETYPE_PEM);
 
129
    die_unless(n > 0);
 
130
 
 
131
    pMachine->pSSL=SSL_new(pMachine->pCtx);
 
132
    die_unless(pMachine->pSSL);
 
133
 
 
134
    pMachine->pbioRead=BIO_new(BIO_s_mem());
 
135
 
 
136
    pMachine->pbioWrite=BIO_new(BIO_s_mem());
 
137
 
 
138
    SSL_set_bio(pMachine->pSSL,pMachine->pbioRead,pMachine->pbioWrite);
 
139
 
 
140
    SSL_set_accept_state(pMachine->pSSL);
 
141
 
 
142
    return pMachine;
 
143
    }
 
144
 
 
145
void SSLStateMachine_read_inject(SSLStateMachine *pMachine,
 
146
                                 const unsigned char *aucBuf,int nBuf)
 
147
    {
 
148
    int n=BIO_write(pMachine->pbioRead,aucBuf,nBuf);
 
149
    /* If it turns out this assert fails, then buffer the data here
 
150
     * and just feed it in in churn instead. Seems to me that it
 
151
     * should be guaranteed to succeed, though.
 
152
     */
 
153
    assert(n == nBuf);
 
154
    fprintf(stderr,"%d bytes of encrypted data fed to state machine\n",n);
 
155
    }
 
156
 
 
157
int SSLStateMachine_read_extract(SSLStateMachine *pMachine,
 
158
                                 unsigned char *aucBuf,int nBuf)
 
159
    {
 
160
    int n;
 
161
 
 
162
    if(!SSL_is_init_finished(pMachine->pSSL))
 
163
        {
 
164
        fprintf(stderr,"Doing SSL_accept\n");
 
165
        n=SSL_accept(pMachine->pSSL);
 
166
        if(n == 0)
 
167
            fprintf(stderr,"SSL_accept returned zero\n");
 
168
        if(n < 0)
 
169
            {
 
170
            int err;
 
171
 
 
172
            if((err=SSL_get_error(pMachine->pSSL,n)) == SSL_ERROR_WANT_READ)
 
173
                {
 
174
                fprintf(stderr,"SSL_accept wants more data\n");
 
175
                return 0;
 
176
                }
 
177
 
 
178
            SSLStateMachine_print_error(pMachine,"SSL_accept error");
 
179
            exit(7);
 
180
            }
 
181
        return 0;
 
182
        }
 
183
 
 
184
    n=SSL_read(pMachine->pSSL,aucBuf,nBuf);
 
185
    if(n < 0)
 
186
        {
 
187
        int err=SSL_get_error(pMachine->pSSL,n);
 
188
 
 
189
        if(err == SSL_ERROR_WANT_READ)
 
190
            {
 
191
            fprintf(stderr,"SSL_read wants more data\n");
 
192
            return 0;
 
193
            }
 
194
 
 
195
        SSLStateMachine_print_error(pMachine,"SSL_read error");
 
196
        exit(8);
 
197
        }
 
198
 
 
199
    fprintf(stderr,"%d bytes of decrypted data read from state machine\n",n);
 
200
    return n;
 
201
    }
 
202
 
 
203
int SSLStateMachine_write_can_extract(SSLStateMachine *pMachine)
 
204
    {
 
205
    int n=BIO_pending(pMachine->pbioWrite);
 
206
    if(n)
 
207
        fprintf(stderr,"There is encrypted data available to write\n");
 
208
    else
 
209
        fprintf(stderr,"There is no encrypted data available to write\n");
 
210
 
 
211
    return n;
 
212
    }
 
213
 
 
214
int SSLStateMachine_write_extract(SSLStateMachine *pMachine,
 
215
                                  unsigned char *aucBuf,int nBuf)
 
216
    {
 
217
    int n;
 
218
 
 
219
    n=BIO_read(pMachine->pbioWrite,aucBuf,nBuf);
 
220
    fprintf(stderr,"%d bytes of encrypted data read from state machine\n",n);
 
221
    return n;
 
222
    }
 
223
 
 
224
void SSLStateMachine_write_inject(SSLStateMachine *pMachine,
 
225
                                  const unsigned char *aucBuf,int nBuf)
 
226
    {
 
227
    int n=SSL_write(pMachine->pSSL,aucBuf,nBuf);
 
228
    /* If it turns out this assert fails, then buffer the data here
 
229
     * and just feed it in in churn instead. Seems to me that it
 
230
     * should be guaranteed to succeed, though.
 
231
     */
 
232
    assert(n == nBuf);
 
233
    fprintf(stderr,"%d bytes of unencrypted data fed to state machine\n",n);
 
234
    }
 
235
 
 
236
int OpenSocket(int nPort)
 
237
    {
 
238
    int nSocket;
 
239
    struct sockaddr_in saServer;
 
240
    struct sockaddr_in saClient;
 
241
    int one=1;
 
242
    int nSize;
 
243
    int nFD;
 
244
    int nLen;
 
245
 
 
246
    nSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
 
247
    if(nSocket < 0)
 
248
        {
 
249
        perror("socket");
 
250
        exit(1);
 
251
        }
 
252
 
 
253
    if(setsockopt(nSocket,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof one) < 0)
 
254
        {
 
255
        perror("setsockopt");
 
256
        exit(2);
 
257
        }
 
258
 
 
259
    memset(&saServer,0,sizeof saServer);
 
260
    saServer.sin_family=AF_INET;
 
261
    saServer.sin_port=htons(nPort);
 
262
    nSize=sizeof saServer;
 
263
    if(bind(nSocket,(struct sockaddr *)&saServer,nSize) < 0)
 
264
        {
 
265
        perror("bind");
 
266
        exit(3);
 
267
        }
 
268
 
 
269
    if(listen(nSocket,512) < 0)
 
270
        {
 
271
        perror("listen");
 
272
        exit(4);
 
273
        }
 
274
 
 
275
    nLen=sizeof saClient;
 
276
    nFD=accept(nSocket,(struct sockaddr *)&saClient,&nLen);
 
277
    if(nFD < 0)
 
278
        {
 
279
        perror("accept");
 
280
        exit(5);
 
281
        }
 
282
 
 
283
    fprintf(stderr,"Incoming accepted on port %d\n",nPort);
 
284
 
 
285
    return nFD;
 
286
    }
 
287
 
 
288
int main(int argc,char **argv)
 
289
    {
 
290
    SSLStateMachine *pMachine;
 
291
    int nPort;
 
292
    int nFD;
 
293
    const char *szCertificateFile;
 
294
    const char *szKeyFile;
 
295
    char rbuf[1];
 
296
    int nrbuf=0;
 
297
 
 
298
    if(argc != 4)
 
299
        {
 
300
        fprintf(stderr,"%s <port> <certificate file> <key file>\n",argv[0]);
 
301
        exit(6);
 
302
        }
 
303
 
 
304
    nPort=atoi(argv[1]);
 
305
    szCertificateFile=argv[2];
 
306
    szKeyFile=argv[3];
 
307
 
 
308
    SSL_library_init();
 
309
    OpenSSL_add_ssl_algorithms();
 
310
    SSL_load_error_strings();
 
311
    ERR_load_crypto_strings();
 
312
 
 
313
    nFD=OpenSocket(nPort);
 
314
 
 
315
    pMachine=SSLStateMachine_new(szCertificateFile,szKeyFile);
 
316
 
 
317
    for( ; ; )
 
318
        {
 
319
        fd_set rfds,wfds;
 
320
        unsigned char buf[1024];
 
321
        int n;
 
322
 
 
323
        FD_ZERO(&rfds);
 
324
        FD_ZERO(&wfds);
 
325
 
 
326
        /* Select socket for input */
 
327
        FD_SET(nFD,&rfds);
 
328
 
 
329
        /* check whether there's decrypted data */
 
330
        if(!nrbuf)
 
331
            nrbuf=SSLStateMachine_read_extract(pMachine,rbuf,1);
 
332
 
 
333
        /* if there's decrypted data, check whether we can write it */
 
334
        if(nrbuf)
 
335
            FD_SET(1,&wfds);
 
336
 
 
337
        /* Select socket for output */
 
338
        if(SSLStateMachine_write_can_extract(pMachine))
 
339
            FD_SET(nFD,&wfds);
 
340
 
 
341
        /* Select stdin for input */
 
342
        FD_SET(0,&rfds);
 
343
 
 
344
        /* Wait for something to do something */
 
345
        n=select(nFD+1,&rfds,&wfds,NULL,NULL);
 
346
        assert(n > 0);
 
347
 
 
348
        /* Socket is ready for input */
 
349
        if(FD_ISSET(nFD,&rfds))
 
350
            {
 
351
            n=read(nFD,buf,sizeof buf);
 
352
            if(n == 0)
 
353
                {
 
354
                fprintf(stderr,"Got EOF on socket\n");
 
355
                exit(0);
 
356
                }
 
357
            assert(n > 0);
 
358
 
 
359
            SSLStateMachine_read_inject(pMachine,buf,n);
 
360
            }
 
361
 
 
362
        /* stdout is ready for output (and hence we have some to send it) */
 
363
        if(FD_ISSET(1,&wfds))
 
364
            {
 
365
            assert(nrbuf == 1);
 
366
            buf[0]=rbuf[0];
 
367
            nrbuf=0;
 
368
 
 
369
            n=SSLStateMachine_read_extract(pMachine,buf+1,sizeof buf-1);
 
370
            if(n < 0)
 
371
                {
 
372
                SSLStateMachine_print_error(pMachine,"read extract failed");
 
373
                break;
 
374
                }
 
375
            assert(n >= 0);
 
376
            ++n;
 
377
            if(n > 0) /* FIXME: has to be true now */
 
378
                {
 
379
                int w;
 
380
                
 
381
                w=write(1,buf,n);
 
382
                /* FIXME: we should push back any unwritten data */
 
383
                assert(w == n);
 
384
                }
 
385
            }
 
386
 
 
387
        /* Socket is ready for output (and therefore we have output to send) */
 
388
        if(FD_ISSET(nFD,&wfds))
 
389
            {
 
390
            int w;
 
391
 
 
392
            n=SSLStateMachine_write_extract(pMachine,buf,sizeof buf);
 
393
            assert(n > 0);
 
394
 
 
395
            w=write(nFD,buf,n);
 
396
            /* FIXME: we should push back any unwritten data */
 
397
            assert(w == n);
 
398
            }
 
399
 
 
400
        /* Stdin is ready for input */
 
401
        if(FD_ISSET(0,&rfds))
 
402
            {
 
403
            n=read(0,buf,sizeof buf);
 
404
            if(n == 0)
 
405
                {
 
406
                fprintf(stderr,"Got EOF on stdin\n");
 
407
                exit(0);
 
408
                }
 
409
            assert(n > 0);
 
410
 
 
411
            SSLStateMachine_write_inject(pMachine,buf,n);
 
412
            }
 
413
        }
 
414
    /* not reached */
 
415
    return 0;
 
416
    }