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 */ 121extern int SYS$QIOW(), SYS$ASSIGN(); 122int 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 134int MS_CALLBACK verify_callback(int ok, X509 *xs, X509 *xi, int depth, 135 int error); 136BIO *bio_err = NULL; 137BIO *bio_stdout = NULL; 138BIO_METHOD *BIO_s_rtcp(); 139 140static char *cipher = NULL; 141int verbose = 1; 142#ifdef FIONBIO 143static int s_nbio = 0; 144#endif 145#define TEST_SERVER_CERT "SSL_SERVER_CERTIFICATE" 146/*************************************************************************/ 147/* Should have member alignment inhibited */ 148struct rpc_msg { 149 /* 'A'-app data. 'R'-remote client 'G'-global */ 150 char channel; 151 /* 'G'-get, 'P'-put, 'C'-confirm, 'X'-close */ 152 char function; 153 /* Amount of data returned or max to return */ 154 unsigned short int length; 155 /* variable data */ 156 char data[4092]; 157}; 158#define RPC_HDR_SIZE (sizeof(struct rpc_msg) - 4092) 159 160static $DESCRIPTOR(sysnet, "SYS$NET"); 161typedef unsigned short io_channel; 162 163struct io_status { 164 unsigned short status; 165 unsigned short count; 166 unsigned long stsval; 167}; 168int doit(io_channel chan, SSL_CTX *s_ctx); 169/*****************************************************************************/ 170/* 171 * Decnet I/O routines. 172 */ 173static int get(io_channel chan, char *buffer, int maxlen, int *length) 174{ 175 int status; 176 struct io_status iosb; 177 status = SYS$QIOW(0, chan, IO$_READVBLK, &iosb, 0, 0, 178 buffer, maxlen, 0, 0, 0, 0); 179 if ((status & 1) == 1) 180 status = iosb.status; 181 if ((status & 1) == 1) 182 *length = iosb.count; 183 return status; 184} 185 186static int put(io_channel chan, char *buffer, int length) 187{ 188 int status; 189 struct io_status iosb; 190 status = SYS$QIOW(0, chan, IO$_WRITEVBLK, &iosb, 0, 0, 191 buffer, length, 0, 0, 0, 0); 192 if ((status & 1) == 1) 193 status = iosb.status; 194 return status; 195} 196 197/***************************************************************************/ 198/* 199 * Handle operations on the 'G' channel. 200 */ 201static int general_request(io_channel chan, struct rpc_msg *msg, int length) 202{ 203 return 48; 204} 205 206/***************************************************************************/ 207int main(int argc, char **argv) 208{ 209 int status, length; 210 io_channel chan; 211 struct rpc_msg msg; 212 213 char *CApath = NULL, *CAfile = NULL; 214 int badop = 0; 215 int ret = 1; 216 int client_auth = 0; 217 int server_auth = 0; 218 SSL_CTX *s_ctx = NULL; 219 /* 220 * Confirm logical link with initiating client. 221 */ 222 LIB$INIT_TIMER(); 223 status = SYS$ASSIGN(&sysnet, &chan, 0, 0, 0); 224 printf("status of assign to SYS$NET: %d\n", status); 225 /* 226 * Initialize standard out and error files. 227 */ 228 if (bio_err == NULL) 229 if ((bio_err = BIO_new(BIO_s_file())) != NULL) 230 BIO_set_fp(bio_err, stderr, BIO_NOCLOSE); 231 if (bio_stdout == NULL) 232 if ((bio_stdout = BIO_new(BIO_s_file())) != NULL) 233 BIO_set_fp(bio_stdout, stdout, BIO_NOCLOSE); 234 /* 235 * get the preferred cipher list and other initialization 236 */ 237 if (cipher == NULL) 238 cipher = getenv("SSL_CIPHER"); 239 printf("cipher list: %s\n", cipher ? cipher : "{undefined}"); 240 241 SSL_load_error_strings(); 242 OpenSSL_add_all_algorithms(); 243 244 /* 245 * DRM, this was the original, but there is no such thing as SSLv2() 246 * s_ctx=SSL_CTX_new(SSLv2()); 247 */ 248 s_ctx = SSL_CTX_new(SSLv2_server_method()); 249 250 if (s_ctx == NULL) 251 goto end; 252 253 SSL_CTX_use_certificate_file(s_ctx, TEST_SERVER_CERT, SSL_FILETYPE_PEM); 254 SSL_CTX_use_RSAPrivateKey_file(s_ctx, TEST_SERVER_CERT, SSL_FILETYPE_PEM); 255 printf("Loaded server certificate: '%s'\n", TEST_SERVER_CERT); 256 257 /* 258 * Take commands from client until bad status. 259 */ 260 LIB$SHOW_TIMER(); 261 status = doit(chan, s_ctx); 262 LIB$SHOW_TIMER(); 263 /* 264 * do final cleanup and exit. 265 */ 266 end: 267 if (s_ctx != NULL) 268 SSL_CTX_free(s_ctx); 269 LIB$SHOW_TIMER(); 270 return 1; 271} 272 273int doit(io_channel chan, SSL_CTX *s_ctx) 274{ 275 int status, length, link_state; 276 struct rpc_msg msg; 277 278 SSL *s_ssl = NULL; 279 BIO *c_to_s = NULL; 280 BIO *s_to_c = NULL; 281 BIO *c_bio = NULL; 282 BIO *s_bio = NULL; 283 int i; 284 int done = 0; 285 286 s_ssl = SSL_new(s_ctx); 287 if (s_ssl == NULL) 288 goto err; 289 290 c_to_s = BIO_new(BIO_s_rtcp()); 291 s_to_c = BIO_new(BIO_s_rtcp()); 292 if ((s_to_c == NULL) || (c_to_s == NULL)) 293 goto err; 294/*- original, DRM 24-SEP-1997 295 BIO_set_fd ( c_to_s, "", chan ); 296 BIO_set_fd ( s_to_c, "", chan ); 297*/ 298 BIO_set_fd(c_to_s, 0, chan); 299 BIO_set_fd(s_to_c, 0, chan); 300 301 c_bio = BIO_new(BIO_f_ssl()); 302 s_bio = BIO_new(BIO_f_ssl()); 303 if ((c_bio == NULL) || (s_bio == NULL)) 304 goto err; 305 306 SSL_set_accept_state(s_ssl); 307 SSL_set_bio(s_ssl, c_to_s, s_to_c); 308 BIO_set_ssl(s_bio, s_ssl, BIO_CLOSE); 309 310 /* We can always do writes */ 311 printf("Begin doit main loop\n"); 312 /* 313 * Link states: 0-idle, 1-read pending, 2-write pending, 3-closed. 314 */ 315 for (link_state = 0; link_state < 3;) { 316 /* 317 * Wait for remote end to request data action on A channel. 318 */ 319 while (link_state == 0) { 320 status = get(chan, (char *)&msg, sizeof(msg), &length); 321 if ((status & 1) == 0) { 322 printf("Error in main loop get: %d\n", status); 323 link_state = 3; 324 break; 325 } 326 if (length < RPC_HDR_SIZE) { 327 printf("Error in main loop get size: %d\n", length); 328 break; 329 link_state = 3; 330 } 331 if (msg.channel != 'A') { 332 printf("Error in main loop, unexpected channel: %c\n", 333 msg.channel); 334 break; 335 link_state = 3; 336 } 337 if (msg.function == 'G') { 338 link_state = 1; 339 } else if (msg.function == 'P') { 340 link_state = 2; /* write pending */ 341 } else if (msg.function == 'X') { 342 link_state = 3; 343 } else { 344 link_state = 3; 345 } 346 } 347 if (link_state == 1) { 348 i = BIO_read(s_bio, msg.data, msg.length); 349 if (i < 0) 350 link_state = 3; 351 else { 352 msg.channel = 'A'; 353 msg.function = 'C'; /* confirm */ 354 msg.length = i; 355 status = put(chan, (char *)&msg, i + RPC_HDR_SIZE); 356 if ((status & 1) == 0) 357 break; 358 link_state = 0; 359 } 360 } else if (link_state == 2) { 361 i = BIO_write(s_bio, msg.data, msg.length); 362 if (i < 0) 363 link_state = 3; 364 else { 365 msg.channel = 'A'; 366 msg.function = 'C'; /* confirm */ 367 msg.length = 0; 368 status = put(chan, (char *)&msg, RPC_HDR_SIZE); 369 if ((status & 1) == 0) 370 break; 371 link_state = 0; 372 } 373 } 374 } 375 fprintf(stdout, "DONE\n"); 376 err: 377 /* 378 * We have to set the BIO's to NULL otherwise they will be free()ed 379 * twice. Once when th s_ssl is SSL_free()ed and again when c_ssl is 380 * SSL_free()ed. This is a hack required because s_ssl and c_ssl are 381 * sharing the same BIO structure and SSL_set_bio() and SSL_free() 382 * automatically BIO_free non NULL entries. You should not normally do 383 * this or be required to do this 384 */ 385 s_ssl->rbio = NULL; 386 s_ssl->wbio = NULL; 387 388 if (c_to_s != NULL) 389 BIO_free(c_to_s); 390 if (s_to_c != NULL) 391 BIO_free(s_to_c); 392 if (c_bio != NULL) 393 BIO_free(c_bio); 394 if (s_bio != NULL) 395 BIO_free(s_bio); 396 return (0); 397} 398