155714Skris/* ssl/ssl_task.c */ 255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 355714Skris * All rights reserved. 455714Skris * 555714Skris * This package is an SSL implementation written 655714Skris * by Eric Young (eay@cryptsoft.com). 755714Skris * The implementation was written so as to conform with Netscapes SSL. 8280297Sjkim * 955714Skris * This library is free for commercial and non-commercial use as long as 1055714Skris * the following conditions are aheared to. The following conditions 1155714Skris * apply to all code found in this distribution, be it the RC4, RSA, 1255714Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1355714Skris * included with this distribution is covered by the same copyright terms 1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15280297Sjkim * 1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1755714Skris * the code are not to be removed. 1855714Skris * If this package is used in a product, Eric Young should be given attribution 1955714Skris * as the author of the parts of the library used. 2055714Skris * This can be in the form of a textual message at program startup or 2155714Skris * in documentation (online or textual) provided with the package. 22280297Sjkim * 2355714Skris * Redistribution and use in source and binary forms, with or without 2455714Skris * modification, are permitted provided that the following conditions 2555714Skris * are met: 2655714Skris * 1. Redistributions of source code must retain the copyright 2755714Skris * notice, this list of conditions and the following disclaimer. 2855714Skris * 2. Redistributions in binary form must reproduce the above copyright 2955714Skris * notice, this list of conditions and the following disclaimer in the 3055714Skris * documentation and/or other materials provided with the distribution. 3155714Skris * 3. All advertising materials mentioning features or use of this software 3255714Skris * must display the following acknowledgement: 3355714Skris * "This product includes cryptographic software written by 3455714Skris * Eric Young (eay@cryptsoft.com)" 3555714Skris * The word 'cryptographic' can be left out if the rouines from the library 3655714Skris * being used are not cryptographic related :-). 37280297Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from 3855714Skris * the apps directory (application code) you must include an acknowledgement: 3955714Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40280297Sjkim * 4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4455714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5155714Skris * SUCH DAMAGE. 52280297Sjkim * 5355714Skris * The licence and distribution terms for any publically available version or 5455714Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5555714Skris * copied and put under another distribution licence 5655714Skris * [including the GNU Public Licence.] 5755714Skris */ 5855714Skris 5955714Skris/* VMS */ 60280297Sjkim/*- 6155714Skris * DECnet object for servicing SSL. We accept the inbound and speak a 6255714Skris * simple protocol for multiplexing the 2 data streams (application and 6355714Skris * ssl data) over this logical link. 6455714Skris * 6555714Skris * Logical names: 66280297Sjkim * SSL_CIPHER Defines a list of cipher specifications the server 67280297Sjkim * will support in order of preference. 6855714Skris * SSL_SERVER_CERTIFICATE 69280297Sjkim * Points to PEM (privacy enhanced mail) file that 70280297Sjkim * contains the server certificate and private password. 71280297Sjkim * SYS$NET Logical created by netserver.exe as hook for completing 72280297Sjkim * DECnet logical link. 7355714Skris * 7455714Skris * Each NSP message sent over the DECnet link has the following structure: 75280297Sjkim * struct rpc_msg { 7655714Skris * char channel; 7755714Skris * char function; 7855714Skris * short length; 7955714Skris * char data[MAX_DATA]; 8055714Skris * } msg; 8155714Skris * 8255714Skris * The channel field designates the virtual data stream this message applies 8355714Skris * to and is one of: 8455714Skris * A - Application data (payload). 8555714Skris * R - Remote client connection that initiated the SSL connection. Encrypted 8655714Skris * data is sent over this connection. 8755714Skris * G - General data, reserved for future use. 8855714Skris * 8955714Skris * The data streams are half-duplex read/write and have following functions: 9055714Skris * G - Get, requests that up to msg.length bytes of data be returned. The 9155714Skris * data is returned in the next 'C' function response that matches the 9255714Skris * requesting channel. 9355714Skris * P - Put, requests that the first msg.length bytes of msg.data be appended 9455714Skris * to the designated stream. 9555714Skris * C - Confirms a get or put. Every get and put will get a confirm response, 9655714Skris * you cannot initiate another function on a channel until the previous 9755714Skris * operation has been confirmed. 9855714Skris * 9955714Skris * The 2 channels may interleave their operations, for example: 10055714Skris * Server msg Client msg 10155714Skris * A, Get, 4092 ----> 10255714Skris * <---- R, get, 4092 10355714Skris * R, Confirm, {hello} ----> 10455714Skris * <---- R, put, {srv hello} 10555714Skris * R, Confirm, 0 ----> 106280297Sjkim * . (SSL handshake completed) 10755714Skris * . (read first app data). 10855714Skris * <---- A, confirm, {http data} 10955714Skris * A, Put, {http data} ----> 11055714Skris * <---- A, confirm, 0 11155714Skris * 11255714Skris * The length field is not permitted to be larger that 4092 bytes. 11355714Skris * 11455714Skris * Author: Dave Jones 11555714Skris * Date: 22-JUL-1996 11655714Skris */ 11755714Skris#include <stdlib.h> 11855714Skris#include <stdio.h> 119280297Sjkim#include <iodef.h> /* VMS IO$_ definitions */ 120280297Sjkim#include <descrip.h> /* VMS string descriptors */ 12155714Skrisextern int SYS$QIOW(), SYS$ASSIGN(); 12255714Skrisint LIB$INIT_TIMER(), LIB$SHOW_TIMER(); 12355714Skris 124280297Sjkim#include <string.h> /* from ssltest.c */ 12555714Skris#include <errno.h> 12655714Skris 127109998Smarkm#include "e_os.h" 12855714Skris 12955714Skris#include <openssl/buffer.h> 13055714Skris#include <openssl/x509.h> 13155714Skris#include <openssl/ssl.h> 13255714Skris#include <openssl/err.h> 13355714Skris 13455714Skrisint MS_CALLBACK verify_callback(int ok, X509 *xs, X509 *xi, int depth, 135280297Sjkim int error); 136280297SjkimBIO *bio_err = NULL; 137280297SjkimBIO *bio_stdout = NULL; 13855714SkrisBIO_METHOD *BIO_s_rtcp(); 13955714Skris 140280297Sjkimstatic char *cipher = NULL; 141280297Sjkimint verbose = 1; 14255714Skris#ifdef FIONBIO 143280297Sjkimstatic int s_nbio = 0; 14455714Skris#endif 14555714Skris#define TEST_SERVER_CERT "SSL_SERVER_CERTIFICATE" 14655714Skris/*************************************************************************/ 147280297Sjkim/* Should have member alignment inhibited */ 148280297Sjkimstruct rpc_msg { 149280297Sjkim /* 'A'-app data. 'R'-remote client 'G'-global */ 150280297Sjkim char channel; 151280297Sjkim /* 'G'-get, 'P'-put, 'C'-confirm, 'X'-close */ 152280297Sjkim char function; 153280297Sjkim /* Amount of data returned or max to return */ 154280297Sjkim unsigned short int length; 155280297Sjkim /* variable data */ 156280297Sjkim char data[4092]; 15755714Skris}; 15855714Skris#define RPC_HDR_SIZE (sizeof(struct rpc_msg) - 4092) 15955714Skris 16055714Skrisstatic $DESCRIPTOR(sysnet, "SYS$NET"); 16155714Skristypedef unsigned short io_channel; 16255714Skris 16355714Skrisstruct io_status { 16455714Skris unsigned short status; 16555714Skris unsigned short count; 16655714Skris unsigned long stsval; 16755714Skris}; 168280297Sjkimint doit(io_channel chan, SSL_CTX *s_ctx); 16955714Skris/*****************************************************************************/ 170280297Sjkim/* 171280297Sjkim * Decnet I/O routines. 17255714Skris */ 173280297Sjkimstatic int get(io_channel chan, char *buffer, int maxlen, int *length) 17455714Skris{ 17555714Skris int status; 17655714Skris struct io_status iosb; 177280297Sjkim status = SYS$QIOW(0, chan, IO$_READVBLK, &iosb, 0, 0, 178280297Sjkim buffer, maxlen, 0, 0, 0, 0); 179280297Sjkim if ((status & 1) == 1) 180280297Sjkim status = iosb.status; 181280297Sjkim if ((status & 1) == 1) 182280297Sjkim *length = iosb.count; 18355714Skris return status; 18455714Skris} 18555714Skris 186280297Sjkimstatic int put(io_channel chan, char *buffer, int length) 18755714Skris{ 18855714Skris int status; 18955714Skris struct io_status iosb; 190280297Sjkim status = SYS$QIOW(0, chan, IO$_WRITEVBLK, &iosb, 0, 0, 191280297Sjkim buffer, length, 0, 0, 0, 0); 192280297Sjkim if ((status & 1) == 1) 193280297Sjkim status = iosb.status; 19455714Skris return status; 19555714Skris} 196280297Sjkim 19755714Skris/***************************************************************************/ 198280297Sjkim/* 199280297Sjkim * Handle operations on the 'G' channel. 20055714Skris */ 201280297Sjkimstatic int general_request(io_channel chan, struct rpc_msg *msg, int length) 20255714Skris{ 20355714Skris return 48; 20455714Skris} 205280297Sjkim 20655714Skris/***************************************************************************/ 207280297Sjkimint main(int argc, char **argv) 20855714Skris{ 20955714Skris int status, length; 21055714Skris io_channel chan; 21155714Skris struct rpc_msg msg; 21255714Skris 213280297Sjkim char *CApath = NULL, *CAfile = NULL; 214280297Sjkim int badop = 0; 215280297Sjkim int ret = 1; 216280297Sjkim int client_auth = 0; 217280297Sjkim int server_auth = 0; 218280297Sjkim SSL_CTX *s_ctx = NULL; 21955714Skris /* 22055714Skris * Confirm logical link with initiating client. 22155714Skris */ 22255714Skris LIB$INIT_TIMER(); 223280297Sjkim status = SYS$ASSIGN(&sysnet, &chan, 0, 0, 0); 224280297Sjkim printf("status of assign to SYS$NET: %d\n", status); 22555714Skris /* 22655714Skris * Initialize standard out and error files. 22755714Skris */ 228280297Sjkim if (bio_err == NULL) 229280297Sjkim if ((bio_err = BIO_new(BIO_s_file())) != NULL) 230280297Sjkim BIO_set_fp(bio_err, stderr, BIO_NOCLOSE); 231280297Sjkim if (bio_stdout == NULL) 232280297Sjkim if ((bio_stdout = BIO_new(BIO_s_file())) != NULL) 233280297Sjkim BIO_set_fp(bio_stdout, stdout, BIO_NOCLOSE); 23455714Skris /* 23555714Skris * get the preferred cipher list and other initialization 23655714Skris */ 237280297Sjkim if (cipher == NULL) 238280297Sjkim cipher = getenv("SSL_CIPHER"); 239280297Sjkim printf("cipher list: %s\n", cipher ? cipher : "{undefined}"); 24055714Skris 241280297Sjkim SSL_load_error_strings(); 242280297Sjkim OpenSSL_add_all_algorithms(); 24355714Skris 244280297Sjkim /* 245280297Sjkim * DRM, this was the original, but there is no such thing as SSLv2() 246280297Sjkim * s_ctx=SSL_CTX_new(SSLv2()); 247280297Sjkim */ 248280297Sjkim s_ctx = SSL_CTX_new(SSLv2_server_method()); 24955714Skris 250280297Sjkim if (s_ctx == NULL) 251280297Sjkim goto end; 25255714Skris 253280297Sjkim SSL_CTX_use_certificate_file(s_ctx, TEST_SERVER_CERT, SSL_FILETYPE_PEM); 254280297Sjkim SSL_CTX_use_RSAPrivateKey_file(s_ctx, TEST_SERVER_CERT, SSL_FILETYPE_PEM); 255280297Sjkim printf("Loaded server certificate: '%s'\n", TEST_SERVER_CERT); 25655714Skris 25755714Skris /* 25855714Skris * Take commands from client until bad status. 25955714Skris */ 26055714Skris LIB$SHOW_TIMER(); 261280297Sjkim status = doit(chan, s_ctx); 26255714Skris LIB$SHOW_TIMER(); 26355714Skris /* 26455714Skris * do final cleanup and exit. 26555714Skris */ 266280297Sjkim end: 267280297Sjkim if (s_ctx != NULL) 268280297Sjkim SSL_CTX_free(s_ctx); 26955714Skris LIB$SHOW_TIMER(); 27055714Skris return 1; 27155714Skris} 27255714Skris 273280297Sjkimint doit(io_channel chan, SSL_CTX *s_ctx) 27455714Skris{ 27555714Skris int status, length, link_state; 276280297Sjkim struct rpc_msg msg; 277109998Smarkm 278280297Sjkim SSL *s_ssl = NULL; 279280297Sjkim BIO *c_to_s = NULL; 280280297Sjkim BIO *s_to_c = NULL; 281280297Sjkim BIO *c_bio = NULL; 282280297Sjkim BIO *s_bio = NULL; 283280297Sjkim int i; 284280297Sjkim int done = 0; 28555714Skris 286280297Sjkim s_ssl = SSL_new(s_ctx); 287280297Sjkim if (s_ssl == NULL) 288280297Sjkim goto err; 28955714Skris 290280297Sjkim c_to_s = BIO_new(BIO_s_rtcp()); 291280297Sjkim s_to_c = BIO_new(BIO_s_rtcp()); 292280297Sjkim if ((s_to_c == NULL) || (c_to_s == NULL)) 293280297Sjkim goto err; 294280297Sjkim/*- original, DRM 24-SEP-1997 295280297Sjkim BIO_set_fd ( c_to_s, "", chan ); 296280297Sjkim BIO_set_fd ( s_to_c, "", chan ); 29755714Skris*/ 298280297Sjkim BIO_set_fd(c_to_s, 0, chan); 299280297Sjkim BIO_set_fd(s_to_c, 0, chan); 30055714Skris 301280297Sjkim c_bio = BIO_new(BIO_f_ssl()); 302280297Sjkim s_bio = BIO_new(BIO_f_ssl()); 303280297Sjkim if ((c_bio == NULL) || (s_bio == NULL)) 304280297Sjkim goto err; 30555714Skris 306280297Sjkim SSL_set_accept_state(s_ssl); 307280297Sjkim SSL_set_bio(s_ssl, c_to_s, s_to_c); 308280297Sjkim BIO_set_ssl(s_bio, s_ssl, BIO_CLOSE); 30955714Skris 310280297Sjkim /* We can always do writes */ 311280297Sjkim printf("Begin doit main loop\n"); 312280297Sjkim /* 313280297Sjkim * Link states: 0-idle, 1-read pending, 2-write pending, 3-closed. 314280297Sjkim */ 315280297Sjkim for (link_state = 0; link_state < 3;) { 316280297Sjkim /* 317280297Sjkim * Wait for remote end to request data action on A channel. 318280297Sjkim */ 319280297Sjkim while (link_state == 0) { 320280297Sjkim status = get(chan, (char *)&msg, sizeof(msg), &length); 321280297Sjkim if ((status & 1) == 0) { 322280297Sjkim printf("Error in main loop get: %d\n", status); 323280297Sjkim link_state = 3; 324280297Sjkim break; 325280297Sjkim } 326280297Sjkim if (length < RPC_HDR_SIZE) { 327280297Sjkim printf("Error in main loop get size: %d\n", length); 328280297Sjkim break; 329280297Sjkim link_state = 3; 330280297Sjkim } 331280297Sjkim if (msg.channel != 'A') { 332280297Sjkim printf("Error in main loop, unexpected channel: %c\n", 333280297Sjkim msg.channel); 334280297Sjkim break; 335280297Sjkim link_state = 3; 336280297Sjkim } 337280297Sjkim if (msg.function == 'G') { 338280297Sjkim link_state = 1; 339280297Sjkim } else if (msg.function == 'P') { 340280297Sjkim link_state = 2; /* write pending */ 341280297Sjkim } else if (msg.function == 'X') { 342280297Sjkim link_state = 3; 343280297Sjkim } else { 344280297Sjkim link_state = 3; 345280297Sjkim } 346280297Sjkim } 347280297Sjkim if (link_state == 1) { 348280297Sjkim i = BIO_read(s_bio, msg.data, msg.length); 349280297Sjkim if (i < 0) 350280297Sjkim link_state = 3; 351280297Sjkim else { 352280297Sjkim msg.channel = 'A'; 353280297Sjkim msg.function = 'C'; /* confirm */ 354280297Sjkim msg.length = i; 355280297Sjkim status = put(chan, (char *)&msg, i + RPC_HDR_SIZE); 356280297Sjkim if ((status & 1) == 0) 357280297Sjkim break; 358280297Sjkim link_state = 0; 359280297Sjkim } 360280297Sjkim } else if (link_state == 2) { 361280297Sjkim i = BIO_write(s_bio, msg.data, msg.length); 362280297Sjkim if (i < 0) 363280297Sjkim link_state = 3; 364280297Sjkim else { 365280297Sjkim msg.channel = 'A'; 366280297Sjkim msg.function = 'C'; /* confirm */ 367280297Sjkim msg.length = 0; 368280297Sjkim status = put(chan, (char *)&msg, RPC_HDR_SIZE); 369280297Sjkim if ((status & 1) == 0) 370280297Sjkim break; 371280297Sjkim link_state = 0; 372280297Sjkim } 373280297Sjkim } 374280297Sjkim } 375280297Sjkim fprintf(stdout, "DONE\n"); 376280297Sjkim err: 377280297Sjkim /* 378280297Sjkim * We have to set the BIO's to NULL otherwise they will be free()ed 379280297Sjkim * twice. Once when th s_ssl is SSL_free()ed and again when c_ssl is 380280297Sjkim * SSL_free()ed. This is a hack required because s_ssl and c_ssl are 381280297Sjkim * sharing the same BIO structure and SSL_set_bio() and SSL_free() 382280297Sjkim * automatically BIO_free non NULL entries. You should not normally do 383280297Sjkim * this or be required to do this 384280297Sjkim */ 385280297Sjkim s_ssl->rbio = NULL; 386280297Sjkim s_ssl->wbio = NULL; 38755714Skris 388280297Sjkim if (c_to_s != NULL) 389280297Sjkim BIO_free(c_to_s); 390280297Sjkim if (s_to_c != NULL) 391280297Sjkim BIO_free(s_to_c); 392280297Sjkim if (c_bio != NULL) 393280297Sjkim BIO_free(c_bio); 394280297Sjkim if (s_bio != NULL) 395280297Sjkim BIO_free(s_bio); 396280297Sjkim return (0); 39755714Skris} 398