1 /* ssl/ssl_task.c */ 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59 /* VMS */ 60 /* 61 * DECnet object for servicing SSL. We accept the inbound and speak a 62 * simple protocol for multiplexing the 2 data streams (application and 63 * ssl data) over this logical link. 64 * 65 * Logical names: 66 * SSL_CIPHER Defines a list of cipher specifications the server 67 * will support in order of preference. 68 * SSL_SERVER_CERTIFICATE 69 * Points to PEM (privacy enhanced mail) file that 70 * contains the server certificate and private password. 71 * SYS$NET Logical created by netserver.exe as hook for completing 72 * DECnet logical link. 73 * 74 * Each NSP message sent over the DECnet link has the following structure: 75 * struct rpc_msg { 76 * char channel; 77 * char function; 78 * short length; 79 * char data[MAX_DATA]; 80 * } msg; 81 * 82 * The channel field designates the virtual data stream this message applies 83 * to and is one of: 84 * A - Application data (payload). 85 * R - Remote client connection that initiated the SSL connection. Encrypted 86 * data is sent over this connection. 87 * G - General data, reserved for future use. 88 * 89 * The data streams are half-duplex read/write and have following functions: 90 * G - Get, requests that up to msg.length bytes of data be returned. The 91 * data is returned in the next 'C' function response that matches the 92 * requesting channel. 93 * P - Put, requests that the first msg.length bytes of msg.data be appended 94 * to the designated stream. 95 * C - Confirms a get or put. Every get and put will get a confirm response, 96 * you cannot initiate another function on a channel until the previous 97 * operation has been confirmed. 98 * 99 * The 2 channels may interleave their operations, for example: 100 * Server msg Client msg 101 * A, Get, 4092 ----> 102 * <---- R, get, 4092 103 * R, Confirm, {hello} ----> 104 * <---- R, put, {srv hello} 105 * R, Confirm, 0 ----> 106 * . (SSL handshake completed) 107 * . (read first app data). 108 * <---- A, confirm, {http data} 109 * A, Put, {http data} ----> 110 * <---- A, confirm, 0 111 * 112 * The length field is not permitted to be larger that 4092 bytes. 113 * 114 * Author: Dave Jones 115 * Date: 22-JUL-1996 116 */ 117 #include <stdlib.h> 118 #include <stdio.h> 119 #include <iodef.h> /* VMS IO$_ definitions */ 120 #include <descrip.h> /* VMS string descriptors */ 121 extern int SYS$QIOW(), SYS$ASSIGN(); 122 int LIB$INIT_TIMER(), LIB$SHOW_TIMER(); 123 124 #include <string.h> /* from ssltest.c */ 125 #include <errno.h> 126 127 #include "e_os.h" 128 129 #include <openssl/buffer.h> 130 #include <openssl/x509.h> 131 #include <openssl/ssl.h> 132 #include <openssl/err.h> 133 134 int MS_CALLBACK verify_callback(int ok, X509 *xs, X509 *xi, int depth, 135 int error); 136 BIO *bio_err=NULL; 137 BIO *bio_stdout=NULL; 138 BIO_METHOD *BIO_s_rtcp(); 139 140 static char *cipher=NULL; 141 int verbose=1; 142 #ifdef FIONBIO 143 static int s_nbio=0; 144 #endif 145 #define TEST_SERVER_CERT "SSL_SERVER_CERTIFICATE" 146 /*************************************************************************/ 147 struct rpc_msg { /* Should have member alignment inhibited */ 148 char channel; /* 'A'-app data. 'R'-remote client 'G'-global */ 149 char function; /* 'G'-get, 'P'-put, 'C'-confirm, 'X'-close */ 150 unsigned short int length; /* Amount of data returned or max to return */ 151 char data[4092]; /* variable data */ 152 }; 153 #define RPC_HDR_SIZE (sizeof(struct rpc_msg) - 4092) 154 155 static $DESCRIPTOR(sysnet, "SYS$NET"); 156 typedef unsigned short io_channel; 157 158 struct io_status { 159 unsigned short status; 160 unsigned short count; 161 unsigned long stsval; 162 }; 163 int doit(io_channel chan, SSL_CTX *s_ctx ); 164 /*****************************************************************************/ 165 /* Decnet I/O routines. 166 */ 167 static int get ( io_channel chan, char *buffer, int maxlen, int *length ) 168 { 169 int status; 170 struct io_status iosb; 171 status = SYS$QIOW ( 0, chan, IO$_READVBLK, &iosb, 0, 0, 172 buffer, maxlen, 0, 0, 0, 0 ); 173 if ( (status&1) == 1 ) status = iosb.status; 174 if ( (status&1) == 1 ) *length = iosb.count; 175 return status; 176 } 177 178 static int put ( io_channel chan, char *buffer, int length ) 179 { 180 int status; 181 struct io_status iosb; 182 status = SYS$QIOW ( 0, chan, IO$_WRITEVBLK, &iosb, 0, 0, 183 buffer, length, 0, 0, 0, 0 ); 184 if ( (status&1) == 1 ) status = iosb.status; 185 return status; 186 } 187 /***************************************************************************/ 188 /* Handle operations on the 'G' channel. 189 */ 190 static int general_request ( io_channel chan, struct rpc_msg *msg, int length ) 191 { 192 return 48; 193 } 194 /***************************************************************************/ 195 int main ( int argc, char **argv ) 196 { 197 int status, length; 198 io_channel chan; 199 struct rpc_msg msg; 200 201 char *CApath=NULL,*CAfile=NULL; 202 int badop=0; 203 int ret=1; 204 int client_auth=0; 205 int server_auth=0; 206 SSL_CTX *s_ctx=NULL; 207 /* 208 * Confirm logical link with initiating client. 209 */ 210 LIB$INIT_TIMER(); 211 status = SYS$ASSIGN ( &sysnet, &chan, 0, 0, 0 ); 212 printf("status of assign to SYS$NET: %d\n", status ); 213 /* 214 * Initialize standard out and error files. 215 */ 216 if (bio_err == NULL) 217 if ((bio_err=BIO_new(BIO_s_file())) != NULL) 218 BIO_set_fp(bio_err,stderr,BIO_NOCLOSE); 219 if (bio_stdout == NULL) 220 if ((bio_stdout=BIO_new(BIO_s_file())) != NULL) 221 BIO_set_fp(bio_stdout,stdout,BIO_NOCLOSE); 222 /* 223 * get the preferred cipher list and other initialization 224 */ 225 if (cipher == NULL) cipher=getenv("SSL_CIPHER"); 226 printf("cipher list: %s\n", cipher ? cipher : "{undefined}" ); 227 228 SSL_load_error_strings(); 229 OpenSSL_add_all_algorithms(); 230 231 /* DRM, this was the original, but there is no such thing as SSLv2() 232 s_ctx=SSL_CTX_new(SSLv2()); 233 */ 234 s_ctx=SSL_CTX_new(SSLv2_server_method()); 235 236 if (s_ctx == NULL) goto end; 237 238 SSL_CTX_use_certificate_file(s_ctx,TEST_SERVER_CERT,SSL_FILETYPE_PEM); 239 SSL_CTX_use_RSAPrivateKey_file(s_ctx,TEST_SERVER_CERT,SSL_FILETYPE_PEM); 240 printf("Loaded server certificate: '%s'\n", TEST_SERVER_CERT ); 241 242 /* 243 * Take commands from client until bad status. 244 */ 245 LIB$SHOW_TIMER(); 246 status = doit ( chan, s_ctx ); 247 LIB$SHOW_TIMER(); 248 /* 249 * do final cleanup and exit. 250 */ 251 end: 252 if (s_ctx != NULL) SSL_CTX_free(s_ctx); 253 LIB$SHOW_TIMER(); 254 return 1; 255 } 256 257 int doit(io_channel chan, SSL_CTX *s_ctx ) 258 { 259 int status, length, link_state; 260 struct rpc_msg msg; 261 262 SSL *s_ssl=NULL; 263 BIO *c_to_s=NULL; 264 BIO *s_to_c=NULL; 265 BIO *c_bio=NULL; 266 BIO *s_bio=NULL; 267 int i; 268 int done=0; 269 270 s_ssl=SSL_new(s_ctx); 271 if (s_ssl == NULL) goto err; 272 273 c_to_s=BIO_new(BIO_s_rtcp()); 274 s_to_c=BIO_new(BIO_s_rtcp()); 275 if ((s_to_c == NULL) || (c_to_s == NULL)) goto err; 276 /* original, DRM 24-SEP-1997 277 BIO_set_fd ( c_to_s, "", chan ); 278 BIO_set_fd ( s_to_c, "", chan ); 279 */ 280 BIO_set_fd ( c_to_s, 0, chan ); 281 BIO_set_fd ( s_to_c, 0, chan ); 282 283 c_bio=BIO_new(BIO_f_ssl()); 284 s_bio=BIO_new(BIO_f_ssl()); 285 if ((c_bio == NULL) || (s_bio == NULL)) goto err; 286 287 SSL_set_accept_state(s_ssl); 288 SSL_set_bio(s_ssl,c_to_s,s_to_c); 289 BIO_set_ssl(s_bio,s_ssl,BIO_CLOSE); 290 291 /* We can always do writes */ 292 printf("Begin doit main loop\n"); 293 /* 294 * Link states: 0-idle, 1-read pending, 2-write pending, 3-closed. 295 */ 296 for (link_state = 0; link_state < 3; ) { 297 /* 298 * Wait for remote end to request data action on A channel. 299 */ 300 while ( link_state == 0 ) { 301 status = get ( chan, (char *) &msg, sizeof(msg), &length ); 302 if ( (status&1) == 0 ) { 303 printf("Error in main loop get: %d\n", status ); 304 link_state = 3; 305 break; 306 } 307 if ( length < RPC_HDR_SIZE ) { 308 printf("Error in main loop get size: %d\n", length ); 309 break; 310 link_state = 3; 311 } 312 if ( msg.channel != 'A' ) { 313 printf("Error in main loop, unexpected channel: %c\n", 314 msg.channel ); 315 break; 316 link_state = 3; 317 } 318 if ( msg.function == 'G' ) { 319 link_state = 1; 320 } else if ( msg.function == 'P' ) { 321 link_state = 2; /* write pending */ 322 } else if ( msg.function == 'X' ) { 323 link_state = 3; 324 } else { 325 link_state = 3; 326 } 327 } 328 if ( link_state == 1 ) { 329 i = BIO_read ( s_bio, msg.data, msg.length ); 330 if ( i < 0 ) link_state = 3; 331 else { 332 msg.channel = 'A'; 333 msg.function = 'C'; /* confirm */ 334 msg.length = i; 335 status = put ( chan, (char *) &msg, i+RPC_HDR_SIZE ); 336 if ( (status&1) == 0 ) break; 337 link_state = 0; 338 } 339 } else if ( link_state == 2 ) { 340 i = BIO_write ( s_bio, msg.data, msg.length ); 341 if ( i < 0 ) link_state = 3; 342 else { 343 msg.channel = 'A'; 344 msg.function = 'C'; /* confirm */ 345 msg.length = 0; 346 status = put ( chan, (char *) &msg, RPC_HDR_SIZE ); 347 if ( (status&1) == 0 ) break; 348 link_state = 0; 349 } 350 } 351 } 352 fprintf(stdout,"DONE\n"); 353 err: 354 /* We have to set the BIO's to NULL otherwise they will be 355 * free()ed twice. Once when th s_ssl is SSL_free()ed and 356 * again when c_ssl is SSL_free()ed. 357 * This is a hack required because s_ssl and c_ssl are sharing the same 358 * BIO structure and SSL_set_bio() and SSL_free() automatically 359 * BIO_free non NULL entries. 360 * You should not normally do this or be required to do this */ 361 s_ssl->rbio=NULL; 362 s_ssl->wbio=NULL; 363 364 if (c_to_s != NULL) BIO_free(c_to_s); 365 if (s_to_c != NULL) BIO_free(s_to_c); 366 if (c_bio != NULL) BIO_free(c_bio); 367 if (s_bio != NULL) BIO_free(s_bio); 368 return(0); 369 } 370