提交 95d29597 编写于 作者: B Bodo Möller

BIO pairs.

上级 9bce3070
......@@ -4,6 +4,16 @@
Changes between 0.9.3a and 0.9.4
*) Add missing case to s3_clnt.c state machine -- one of the new SSL tests
through a BIO pair triggered the default case, i.e.
SSLerr(...,SSL_R_UNKNOWN_STATE).
[Bodo Moeller]
*) New "BIO pair" concept (crypto/bio/bss_bio.c) so that applications
can use the SSL library even if none of the specific BIOs is
appropriate.
[Bodo Moeller]
*) Fix a bug in i2d_DSAPublicKey() which meant it returned the wrong value
for the encoded length.
[Jeon KyoungHo <khjeon@sds.samsung.co.kr>]
......
......@@ -64,6 +64,7 @@ extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <openssl/crypto.h>
/* These are the 'types' of BIOs */
......@@ -317,6 +318,15 @@ typedef struct bio_f_buffer_ctx_struct
#define BIO_C_GET_SOCKS 134
#define BIO_C_SET_SOCKS 135
#define BIO_C_SET_WRITE_BUF_SIZE 136/* for BIO_s_bio */
#define BIO_C_GET_WRITE_BUF_SIZE 137
#define BIO_C_MAKE_BIO_PAIR 138
#define BIO_C_DESTROY_BIO_PAIR 139
#define BIO_C_GET_WRITE_GUARANTEE 140
#define BIO_C_GET_READ_REQUEST 141
#define BIO_C_SHUTDOWN_WR 142
#define BIO_set_app_data(s,arg) BIO_set_ex_data(s,0,(char *)arg)
#define BIO_get_app_data(s) BIO_get_ex_data(s,0)
......@@ -431,6 +441,9 @@ int BIO_read_filename(BIO *b,const char *name);
#define BIO_get_close(b) (int)BIO_ctrl(b,BIO_CTRL_GET_CLOSE,0,NULL)
#define BIO_pending(b) (int)BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL)
#define BIO_wpending(b) (int)BIO_ctrl(b,BIO_CTRL_WPENDING,0,NULL)
/* ...pending macros have inappropriate return type */
size_t BIO_ctrl_pending(BIO *b);
size_t BIO_ctrl_wpending(BIO *b);
#define BIO_flush(b) (int)BIO_ctrl(b,BIO_CTRL_FLUSH,0,NULL)
#define BIO_get_info_callback(b,cbp) (int)BIO_ctrl(b,BIO_CTRL_GET_CALLBACK,0,(char *)cbp)
#define BIO_set_info_callback(b,cb) (int)BIO_ctrl(b,BIO_CTRL_SET_CALLBACK,0,(char *)cb)
......@@ -438,6 +451,19 @@ int BIO_read_filename(BIO *b,const char *name);
/* For the BIO_f_buffer() type */
#define BIO_buffer_get_num_lines(b) BIO_ctrl(b,BIO_CTRL_GET,0,NULL)
/* For BIO_s_bio() */
#define BIO_set_write_buf_size(b,size) (int)BIO_ctrl(b,BIO_C_SET_WRITE_BUF_SIZE,size,NULL)
#define BIO_get_write_buf_size(b,size) (size_t)BIO_ctrl(b,BIO_C_GET_WRITE_BUF_SIZE,size,NULL)
#define BIO_make_bio_pair(b1,b2) (int)BIO_ctrl(b1,BIO_C_MAKE_BIO_PAIR,0,b2)
#define BIO_destroy_bio_pair(b) (int)BIO_ctrl(b,BIO_C_DESTROY_BIO_PAIR,0,NULL)
/* macros with inappropriate type -- but ...pending macros use int too: */
#define BIO_get_write_guarantee(b) (int)BIO_ctrl(b,BIO_C_GET_WRITE_GUARANTEE,0,NULL)
#define BIO_get_read_request(b) (int)BIO_ctrl(b,BIO_C_GET_READ_REQUEST,0,NULL)
size_t BIO_ctrl_get_write_guarantee(BIO *b);
size_t BIO_ctrl_get_read_request(BIO *b);
#ifdef NO_STDIO
#define NO_FP_API
#endif
......@@ -473,7 +499,7 @@ int BIO_read(BIO *b, void *data, int len);
int BIO_gets(BIO *bp,char *buf, int size);
int BIO_write(BIO *b, const char *data, int len);
int BIO_puts(BIO *bp,const char *buf);
long BIO_ctrl(BIO *bp,int cmd,long larg,char *parg);
long BIO_ctrl(BIO *bp,int cmd,long larg,void *parg);
char * BIO_ptr_ctrl(BIO *bp,int cmd,long larg);
long BIO_int_ctrl(BIO *bp,int cmd,long larg,int iarg);
BIO * BIO_push(BIO *b,BIO *append);
......@@ -538,6 +564,13 @@ BIO *BIO_new_fd(int fd, int close_flag);
BIO *BIO_new_connect(char *host_port);
BIO *BIO_new_accept(char *host_port);
int BIO_new_bio_pair(BIO **bio1, size_t writebuf1,
BIO **bio2, size_t writebuf2);
/* If successful, returns 1 and in *bio1, *bio2 two BIO pair endpoints.
* Otherwise returns 0 and sets *bio1 and *bio2 to NULL.
* Size 0 uses default value.
*/
void BIO_copy_next_retry(BIO *b);
long BIO_ghbn_ctrl(int cmd,int iarg,char *parg);
......@@ -579,6 +612,7 @@ int BIO_printf(BIO *bio, ...);
#define BIO_R_ACCEPT_ERROR 100
#define BIO_R_BAD_FOPEN_MODE 101
#define BIO_R_BAD_HOSTNAME_LOOKUP 102
#define BIO_R_BROKEN_PIPE 124
#define BIO_R_CONNECT_ERROR 103
#define BIO_R_ERROR_SETTING_NBIO 104
#define BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET 105
......
......@@ -95,6 +95,7 @@ static ERR_STRING_DATA BIO_str_reasons[]=
{BIO_R_ACCEPT_ERROR ,"accept error"},
{BIO_R_BAD_FOPEN_MODE ,"bad fopen mode"},
{BIO_R_BAD_HOSTNAME_LOOKUP ,"bad hostname lookup"},
{BIO_R_BROKEN_PIPE ,"broken pipe"},
{BIO_R_CONNECT_ERROR ,"connect error"},
{BIO_R_ERROR_SETTING_NBIO ,"error setting nbio"},
{BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET,"error setting nbio on accepted socket"},
......
......@@ -290,7 +290,7 @@ char *BIO_ptr_ctrl(BIO *b, int cmd, long larg)
return(p);
}
long BIO_ctrl(BIO *b, int cmd, long larg, char *parg)
long BIO_ctrl(BIO *b, int cmd, long larg, void *parg)
{
long ret;
long (*cb)();
......@@ -317,6 +317,20 @@ long BIO_ctrl(BIO *b, int cmd, long larg, char *parg)
return(ret);
}
/* It is unfortunate to duplicate in functions what the BIO_(w)pending macros
* do; but those macros have inappropriate return type, and for interfacing
* from other programming languages, C macros aren't much of a help anyway. */
size_t BIO_ctrl_pending(BIO *bio)
{
return BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL);
}
size_t BIO_ctrl_wpending(BIO *bio)
{
return BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL);
}
/* put the 'bio' on the end of b's list of operators */
BIO *BIO_push(BIO *b, BIO *bio)
{
......
/* crypto/bio/bss_bio.c -*- Mode: C; c-file-style: "eay" -*- */
/* *** Not yet finished (or even tested). *** */
/* Special method for a BIO where the other endpoint is also a BIO
* of this kind, handled by the same thread.
* of this kind, handled by the same thread (i.e. the "peer" is actually
* ourselves, wearing a different hat).
* Such "BIO pairs" are mainly for using the SSL library with I/O interfaces
* for which no specific BIO method is available. */
* for which no specific BIO method is available.
* See ssl/ssltest.c for some hints on how this can be used. */
#include <assert.h>
#include <stdlib.h>
......@@ -19,7 +19,7 @@ static int bio_new(BIO *bio);
static int bio_free(BIO *bio);
static int bio_read(BIO *bio, char *buf, int size);
static int bio_write(BIO *bio, char *buf, int num);
static long bio_ctrl(BIO *bio, int cmd, long num, char *ptr);
static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr);
static int bio_puts(BIO *bio, char *str);
static int bio_make_pair(BIO *bio1, BIO *bio2);
......@@ -74,6 +74,7 @@ static int bio_new(BIO *bio)
b->size = 17*1024; /* enough for one TLS record (just a default) */
b->buf = NULL;
bio->ptr = b;
return 1;
}
......@@ -103,19 +104,167 @@ static int bio_free(BIO *bio)
static int bio_read(BIO *bio, char *buf, int size)
static int bio_read(BIO *bio, char *buf, int size_)
{
size_t size = size_;
size_t rest;
struct bio_bio_st *b, *peer_b;
BIO_clear_retry_flags(bio);
if (!bio->init)
return 0;
b = bio->ptr;
assert(b != NULL);
assert(b->peer != NULL);
peer_b = b->peer->ptr;
assert(peer_b != NULL);
assert(peer_b->buf != NULL);
peer_b->request = 0; /* will be set in "retry_read" situation */
if (buf == NULL || size == 0)
return 0;
if (peer_b->len == 0)
{
if (peer_b->closed)
return 0; /* writer has closed, and no data is left */
else
{
BIO_set_retry_read(bio); /* buffer is empty */
if (size <= peer_b->size)
peer_b->request = size;
else
peer_b->request = peer_b->size; /* don't ask for more than
* the peer can deliver
* in one write */
return -1;
}
}
/* we can read */
if (peer_b->len < size)
size = peer_b->len;
/* now read "size" bytes */
rest = size;
assert(rest > 0);
do /* one or two iterations */
{
size_t chunk;
assert(rest <= peer_b->len);
if (peer_b->offset + rest <= peer_b->size)
chunk = rest;
else
/* wrap around ring buffer */
chunk = peer_b->size - peer_b->offset;
assert(peer_b->offset + chunk <= peer_b->size);
memcpy(buf, peer_b->buf + peer_b->offset, chunk);
peer_b->len -= chunk;
if (peer_b->len)
{
peer_b->offset += chunk;
assert(peer_b->offset <= peer_b->size);
if (peer_b->offset == peer_b->size)
peer_b->offset = 0;
buf += chunk;
}
else
{
/* buffer now empty, no need to advance "buf" */
assert(chunk == rest);
peer_b->offset = 0;
}
rest -= chunk;
}
while (rest);
peer_b->request -= size;
return size;
}
static int bio_write(BIO *bio, char *buf, int num_)
{
size_t num = num_;
size_t rest;
struct bio_bio_st *b;
BIO_clear_retry_flags(bio);
if (!bio->init || buf == NULL || num == 0)
return 0;
b = bio->ptr;
assert(b != NULL);
assert(b->peer != NULL);
assert(b->buf != NULL);
b->request = 0;
if (b->closed)
{
/* XXX */
/* we already closed */
BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE);
return -1;
}
static int bio_write(BIO *bio, char *buf, int num)
assert(b->len <= b->size);
if (b->len == b->size)
{
/* XXX */
BIO_set_retry_write(bio); /* buffer is full */
return -1;
}
static long bio_ctrl(BIO *bio, int cmd, long num, char *ptr)
/* we can write */
if (num > b->size - b->len)
num = b->size - b->len;
/* now write "num" bytes */
rest = num;
assert(rest > 0);
do /* one or two iterations */
{
size_t write_offset;
size_t chunk;
assert(b->len + rest <= b->size);
write_offset = b->offset + b->len;
if (write_offset >= b->size)
write_offset -= b->size;
/* b->buf[write_offset] is the first byte we can write to. */
if (write_offset + rest <= b->size)
chunk = rest;
else
/* wrap around ring buffer */
chunk = b->size - write_offset;
memcpy(b->buf + write_offset, buf, chunk);
b->len += chunk;
assert(b->len <= b->size);
rest -= chunk;
buf += chunk;
}
while (rest);
return num;
}
static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr)
{
long ret;
struct bio_bio_st *b = bio->ptr;
......@@ -124,13 +273,76 @@ static long bio_ctrl(BIO *bio, int cmd, long num, char *ptr)
switch (cmd)
{
/* XXX Additional commands: */
/* - Set buffer size */
/* - make pair */
/* - destroy pair */
/* - get number of bytes that the next write will accept */
/* - get number of bytes requested by peer */
/* - send "close" */
/* specific CTRL codes */
case BIO_C_SET_WRITE_BUF_SIZE:
if (b->peer)
{
BIOerr(BIO_F_BIO_CTRL, BIO_R_IN_USE);
ret = 0;
}
else
{
size_t new_size = num;
if (b->size != new_size)
{
if (b->buf)
{
Free(b->buf);
b->buf = NULL;
}
b->size = new_size;
}
ret = 1;
}
break;
case BIO_C_GET_WRITE_BUF_SIZE:
num = (long) b->size;
case BIO_C_MAKE_BIO_PAIR:
{
BIO *other_bio = ptr;
if (bio_make_pair(bio, other_bio))
ret = 1;
else
ret = 0;
}
break;
case BIO_C_DESTROY_BIO_PAIR:
/* Effects both BIOs in the pair -- call just once!
* Or let BIO_free(bio1); BIO_free(bio2); do the job. */
bio_destroy_pair(bio);
ret = 1;
break;
case BIO_C_GET_WRITE_GUARANTEE:
/* How many bytes can the caller feed to the next write
* withouth having to keep any? */
if (b->peer == NULL || b->closed)
ret = 0;
else
ret = (long) b->size - b->len;
break;
case BIO_C_GET_READ_REQUEST:
/* If the peer unsuccesfully tried to read, how many bytes
* were requested? (As with BIO_CTRL_PENDING, that number
* can usually be treated as boolean.) */
ret = (long) b->request;
break;
case BIO_C_SHUTDOWN_WR:
/* similar to shutdown(..., SHUT_WR) */
b->closed = 1;
ret = 1;
break;
/* standard CTRL codes follow */
case BIO_CTRL_RESET:
if (b->buf != NULL)
......@@ -169,7 +381,20 @@ static long bio_ctrl(BIO *bio, int cmd, long num, char *ptr)
break;
case BIO_CTRL_DUP:
/* XXX */
/* See BIO_dup_chain for circumstances we have to expect. */
{
BIO *other_bio = ptr;
struct bio_bio_st *other_b;
assert(other_bio != NULL);
other_b = other_bio->ptr;
assert(other_b != NULL);
assert(other_b->buf == NULL); /* other_bio is always fresh */
other_b->size = b->size;
}
ret = 1;
break;
......@@ -177,6 +402,22 @@ static long bio_ctrl(BIO *bio, int cmd, long num, char *ptr)
ret = 1;
break;
case BIO_CTRL_EOF:
{
BIO *other_bio = ptr;
if (other_bio)
{
struct bio_bio_st *other_b = other_bio->ptr;
assert(other_b != NULL);
ret = other_b->len == 0 && other_b->closed;
}
else
ret = 1;
}
break;
default:
ret = 0;
}
......@@ -188,8 +429,6 @@ static int bio_puts(BIO *bio, char *str)
return bio_write(bio, str, strlen(str));
}
/* Until bio_make_pair is used, make a dummy function use it for -pedantic */
void dummy() { bio_make_pair(NULL,NULL); }
static int bio_make_pair(BIO *bio1, BIO *bio2)
{
......@@ -273,3 +512,67 @@ static void bio_destroy_pair(BIO *bio)
}
}
}
/* Exported convenience functions */
int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1,
BIO **bio2_p, size_t writebuf2)
{
BIO *bio1 = NULL, *bio2 = NULL;
long r;
int ret = 0;
bio1 = BIO_new(BIO_s_bio());
if (bio1 == NULL)
goto err;
bio2 = BIO_new(BIO_s_bio());
if (bio2 == NULL)
goto err;
if (writebuf1)
{
r = BIO_set_write_buf_size(bio1, writebuf1);
if (!r)
goto err;
}
if (writebuf2)
{
r = BIO_set_write_buf_size(bio2, writebuf2);
if (!r)
goto err;
}
r = BIO_make_bio_pair(bio1, bio2);
if (!r)
goto err;
ret = 1;
err:
if (ret == 0)
{
if (bio1)
{
BIO_free(bio1);
bio1 = NULL;
}
if (bio2)
{
BIO_free(bio2);
bio2 = NULL;
}
}
*bio1_p = bio1;
*bio2_p = bio2;
return ret;
}
size_t BIO_ctrl_get_write_guarantee(BIO *bio)
{
return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL);
}
size_t BIO_ctrl_read_request(BIO *bio)
{
return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL);
}
......@@ -131,6 +131,53 @@ echo test sslv2/sslv3 with both client and server authentication
ssltest -server_auth -client_auth -CAfile cert.tmp
if errorlevel 1 goto done
echo test sslv2 via BIO pair
ssltest -bio_pair -ssl2
if errorlevel 1 goto done
echo test sslv2 with server authentication via BIO pair
ssltest -bio_pair -ssl2 -server_auth -CAfile cert.tmp
if errorlevel 1 goto done
echo test sslv2 with client authentication via BIO pair
ssltest -bio_pair -ssl2 -client_auth -CAfile cert.tmp
if errorlevel 1 goto done
echo test sslv2 with both client and server authentication via BIO pair
ssltest -bio_pair -ssl2 -server_auth -client_auth -CAfile cert.tmp
if errorlevel 1 goto done
echo test sslv3 via BIO pair
ssltest -bio_pair -ssl3
if errorlevel 1 goto done
echo test sslv3 with server authentication via BIO pair
ssltest -bio_pair -ssl3 -server_auth -CAfile cert.tmp
if errorlevel 1 goto done
echo test sslv3 with client authentication via BIO pair
ssltest -bio_pair -ssl3 -client_auth -CAfile cert.tmp
if errorlevel 1 goto done
echo test sslv3 with both client and server authentication via BIO pair
ssltest -bio_pair -ssl3 -server_auth -client_auth -CAfile cert.tmp
if errorlevel 1 goto done
echo test sslv2/sslv3 via BIO pair
ssltest
if errorlevel 1 goto done
echo test sslv2/sslv3 with server authentication
ssltest -bio_pair -server_auth -CAfile cert.tmp
if errorlevel 1 goto done
echo test sslv2/sslv3 with client authentication via BIO pair
ssltest -bio_pair -client_auth -CAfile cert.tmp
if errorlevel 1 goto done
echo test sslv2/sslv3 with both client and server authentication via BIO pair
ssltest -bio_pair -server_auth -client_auth -CAfile cert.tmp
if errorlevel 1 goto done
del cert.tmp
......
......@@ -254,6 +254,7 @@ int ssl3_connect(SSL *s)
case SSL3_ST_CW_CERT_A:
case SSL3_ST_CW_CERT_B:
case SSL3_ST_CW_CERT_C:
case SSL3_ST_CW_CERT_D:
ret=ssl3_send_client_certificate(s);
if (ret <= 0) goto end;
s->state=SSL3_ST_CW_KEY_EXCH_A;
......
......@@ -131,6 +131,8 @@ case SSL3_ST_CR_SRVR_DONE_A: str="SSLv3 read server done A"; break;
case SSL3_ST_CR_SRVR_DONE_B: str="SSLv3 read server done B"; break;
case SSL3_ST_CW_CERT_A: str="SSLv3 write client certificate A"; break;
case SSL3_ST_CW_CERT_B: str="SSLv3 write client certificate B"; break;
case SSL3_ST_CW_CERT_C: str="SSLv3 write client certificate C"; break;
case SSL3_ST_CW_CERT_D: str="SSLv3 write client certificate D"; break;
case SSL3_ST_CW_KEY_EXCH_A: str="SSLv3 write client key exchange A"; break;
case SSL3_ST_CW_KEY_EXCH_B: str="SSLv3 write client key exchange B"; break;
case SSL3_ST_CW_CERT_VRFY_A: str="SSLv3 write certificate verify A"; break;
......
......@@ -60,6 +60,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include "openssl/e_os.h"
......@@ -105,6 +106,7 @@ static int s_nbio=0;
#endif
int doit_biopair(SSL *s_ssl,SSL *c_ssl,long bytes);
int doit(SSL *s_ssl,SSL *c_ssl,long bytes);
static void sv_usage(void)
{
......@@ -132,12 +134,16 @@ static void sv_usage(void)
fprintf(stderr," -s_cert arg - Just the server certificate file\n");
fprintf(stderr," -c_cert arg - Just the client certificate file\n");
fprintf(stderr," -cipher arg - The cipher list\n");
fprintf(stderr," -bio_pair - Use BIO pairs\n");
fprintf(stderr," -f - Test even cases that can't work\n");
}
int main(int argc, char *argv[])
{
char *CApath=NULL,*CAfile=NULL;
int badop=0;
int bio_pair=0;
int force=0;
int tls1=0,ssl2=0,ssl3=0,ret=1;
int client_auth=0;
int server_auth=0,i;
......@@ -225,6 +231,14 @@ int main(int argc, char *argv[])
if (--argc < 1) goto bad;
CAfile= *(++argv);
}
else if (strcmp(*argv,"-bio_pair") == 0)
{
bio_pair = 1;
}
else if (strcmp(*argv,"-f") == 0)
{
force = 1;
}
else
{
fprintf(stderr,"unknown option %s\n",*argv);
......@@ -241,6 +255,17 @@ bad:
goto end;
}
if (!ssl2 && !ssl3 && !tls1 && number > 1 && !reuse && !force)
{
fprintf(stderr, "This case cannot work. Use -f switch to perform "
"the test anyway\n"
"(and -d to see what happens, "
"and -bio_pair to really make it happen :-)\n"
"or add one of -ssl2, -ssl3, -tls1, -reuse to "
"avoid protocol mismatch.\n");
exit(1);
}
/* if (cipher == NULL) cipher=getenv("SSL_CIPHER"); */
SSL_library_init();
......@@ -338,6 +363,9 @@ bad:
for (i=0; i<number; i++)
{
if (!reuse) SSL_set_session(c_ssl,NULL);
if (bio_pair)
ret=doit_biopair(s_ssl,c_ssl,bytes);
else
ret=doit(s_ssl,c_ssl,bytes);
}
......@@ -368,6 +396,353 @@ end:
EXIT(ret);
}
int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count)
{
long cw_num = count, cr_num = count, sw_num = count, sr_num = count;
BIO *s_ssl_bio = NULL, *c_ssl_bio = NULL;
BIO *server = NULL, *server_io = NULL, *client = NULL, *client_io = NULL;
SSL_CIPHER *ciph;
int ret = 1;
size_t bufsiz = 256; /* small buffer for testing */
if (!BIO_new_bio_pair(&server, bufsiz, &server_io, bufsiz))
goto err;
if (!BIO_new_bio_pair(&client, bufsiz, &client_io, bufsiz))
goto err;
s_ssl_bio = BIO_new(BIO_f_ssl());
if (!s_ssl_bio)
goto err;
c_ssl_bio = BIO_new(BIO_f_ssl());
if (!c_ssl_bio)
goto err;
SSL_set_connect_state(c_ssl);
SSL_set_bio(c_ssl, client, client);
(void)BIO_set_ssl(c_ssl_bio, c_ssl, BIO_NOCLOSE);
SSL_set_accept_state(s_ssl);
SSL_set_bio(s_ssl, server, server);
(void)BIO_set_ssl(s_ssl_bio, s_ssl, BIO_NOCLOSE);
do
{
/* c_ssl_bio: SSL filter BIO
*
* client: pseudo-I/O for SSL library
*
* client_io: client's SSL communication; usually to be
* relayed over some I/O facility, but in this
* test program, we're the server, too:
*
* server_io: server's SSL communication
*
* server: pseudo-I/O for SSL library
*
* s_ssl_bio: SSL filter BIO
*
* The client and the server each employ a "BIO pair":
* client + client_io, server + server_io.
* BIO pairs are symmetric. A BIO pair behaves similar
* to a non-blocking socketpair (but both endpoints must
* be handled by the same thread).
*
* Useful functions for querying the state of BIO pair endpoints:
*
* BIO_ctrl_pending(bio) number of bytes we can read now
* BIO_ctrl_get_read_request(bio) number of bytes needed to fulfil
* other side's read attempt
* BIO_ctrl_get_write_gurantee(bio) number of bytes we can write now
*
* ..._read_request is never more than ..._write_guarantee;
* it depends on the application which one you should use.
*/
/* We have non-blocking behaviour throughout this test program, but
* can be sure that there is *some* progress in each iteration; so
* we don't have to worry about ..._SHOULD_READ or ..._SHOULD_WRITE
* -- we just try everything in each iteration
*/
{
/* CLIENT */
MS_STATIC char cbuf[1024*8];
int i, r;
if (debug)
if (SSL_in_init(c_ssl))
printf("client waiting in SSL_connect - %s\n",
SSL_state_string_long(c_ssl));
if (cw_num > 0)
{
/* Write to server. */
if (cw_num > (long)sizeof cbuf)
i = sizeof cbuf;
else
i = (int)cw_num;
r = BIO_write(c_ssl_bio, cbuf, i);
if (r == -1)
{
if (!BIO_should_retry(c_ssl_bio))
{
fprintf(stderr,"ERROR in CLIENT\n");
goto err;
}
/* BIO_should_retry(...) can just be ignored here.
* The library expects us to call BIO_write with
* the same arguments again, and that's what we will
* do in the next iteration. */
}
else if (r == 0)
{
fprintf(stderr,"SSL CLIENT STARTUP FAILED\n");
goto err;
}
else
{
if (debug)
printf("client wrote %d\n", r);
cw_num -= r;
}
}
if (cr_num > 0)
{
/* Read from server. */
r = BIO_read(c_ssl_bio, cbuf, sizeof(cbuf));
if (r < 0)
{
if (!BIO_should_retry(c_ssl_bio))
{
fprintf(stderr,"ERROR in CLIENT\n");
goto err;
}
/* Again, "BIO_should_retry" can be ignored. */
}
else if (r == 0)
{
fprintf(stderr,"SSL CLIENT STARTUP FAILED\n");
goto err;
}
else
{
if (debug)
printf("client read %d\n", r);
cr_num -= r;
}
}
}
{
/* SERVER */
MS_STATIC char sbuf[1024*8];
int i, r;
if (debug)
if (SSL_in_init(s_ssl))
printf("server waiting in SSL_accept - %s\n",
SSL_state_string_long(s_ssl));
if (sw_num > 0)
{
/* Write to client. */
if (sw_num > (long)sizeof sbuf)
i = sizeof sbuf;
else
i = (int)sw_num;
r = BIO_write(s_ssl_bio, sbuf, i);
if (r == -1)
{
if (!BIO_should_retry(s_ssl_bio))
{
fprintf(stderr,"ERROR in SERVER\n");
goto err;
}
/* Ignore "BIO_should_retry". */
}
else if (r == 0)
{
fprintf(stderr,"SSL SERVER STARTUP FAILED\n");
goto err;
}
else
{
if (debug)
printf("server wrote %d\n", r);
sw_num -= r;
}
}
if (sr_num > 0)
{
/* Read from client. */
r = BIO_read(s_ssl_bio, sbuf, sizeof(sbuf));
if (r < 0)
{
if (!BIO_should_retry(s_ssl_bio))
{
fprintf(stderr,"ERROR in SERVER\n");
goto err;
}
/* blah, blah */
}
else if (r == 0)
{
fprintf(stderr,"SSL SERVER STARTUP FAILED\n");
goto err;
}
else
{
if (debug)
printf("server read %d\n", r);
sr_num -= r;
}
}
}
{
/* "I/O" BETWEEN CLIENT AND SERVER. */
#define RELAYBUFSIZ 200
static char buf[RELAYBUFSIZ];
/* RELAYBUF is arbitrary. When writing data over some real
* network, use a buffer of the same size as in the BIO_pipe
* and make that size large (for reading from the network
* small buffers usually won't hurt).
* Here sizes differ for testing. */
size_t r1, r2;
size_t num;
int r;
static int prev_progress = 1;
int progress = 0;
/* client to server */
do
{
r1 = BIO_ctrl_pending(client_io);
r2 = BIO_ctrl_get_write_guarantee(server_io);
num = r1;
if (r2 < num)
num = r2;
if (num)
{
if (sizeof buf < num)
num = sizeof buf;
if (INT_MAX < num) /* yeah, right */
num = INT_MAX;
r = BIO_read(client_io, buf, (int)num);
if (r != (int)num) /* can't happen */
{
fprintf(stderr, "ERROR: BIO_read could not read "
"BIO_ctrl_pending() bytes");
goto err;
}
r = BIO_write(server_io, buf, (int)num);
if (r != (int)num) /* can't happen */
{
fprintf(stderr, "ERROR: BIO_write could not write "
"BIO_ctrl_get_write_guarantee() bytes");
goto err;
}
progress = 1;
if (debug)
printf("C->S relaying: %d bytes\n", (int)num);
}
}
while (r1 && r2);
/* server to client */
do
{
r1 = BIO_ctrl_pending(server_io);
r2 = BIO_ctrl_get_write_guarantee(client_io);
num = r1;
if (r2 < num)
num = r2;
if (num)
{
if (sizeof buf < num)
num = sizeof buf;
if (INT_MAX < num)
num = INT_MAX;
r = BIO_read(server_io, buf, (int)num);
if (r != (int)num) /* can't happen */
{
fprintf(stderr, "ERROR: BIO_read could not read "
"BIO_ctrl_pending() bytes");
goto err;
}
r = BIO_write(client_io, buf, (int)num);
if (r != (int)num) /* can't happen */
{
fprintf(stderr, "ERROR: BIO_write could not write "
"BIO_ctrl_get_write_guarantee() bytes");
goto err;
}
progress = 1;
if (debug)
printf("S->C relaying: %d bytes\n", (int)num);
}
}
while (r1 && r2);
if (!progress && !prev_progress)
if (cw_num > 0 || cr_num > 0 || sw_num > 0 || sr_num > 0)
/* can't happen */
{
fprintf(stderr, "ERROR: got stuck\n");
goto err;
}
prev_progress = progress;
}
}
while (cw_num > 0 || cr_num > 0 || sw_num > 0 || sr_num > 0);
ciph = SSL_get_current_cipher(c_ssl);
if (verbose)
fprintf(stdout,"DONE via BIO pair, protocol %s, cipher %s, %s\n",
SSL_get_version(c_ssl),
SSL_CIPHER_get_version(ciph),
SSL_CIPHER_get_name(ciph));
ret = 0;
err:
ERR_print_errors(bio_err);
if (server)
BIO_free(server);
if (server_io)
BIO_free(server_io);
if (client)
BIO_free(client);
if (client_io)
BIO_free(client_io);
if (s_ssl_bio)
BIO_free(s_ssl_bio);
if (c_ssl_bio)
BIO_free(c_ssl_bio);
return ret;
}
#define W_READ 1
#define W_WRITE 2
#define C_DONE 1
......
......@@ -36,5 +36,40 @@ echo test sslv2/sslv3 with client authentication
echo test sslv2/sslv3 with both client and server authentication
./ssltest -server_auth -client_auth -CApath ../certs || exit 1
exit 0
echo test sslv2 via BIO pair
./ssltest -bio_pair -ssl2 || exit 1
echo test sslv2 with server authentication via BIO pair
./ssltest -bio_pair -ssl2 -server_auth -CApath ../certs || exit 1
echo test sslv2 with client authentication via BIO pair
./ssltest -bio_pair -ssl2 -client_auth -CApath ../certs || exit 1
echo test sslv2 with both client and server authentication via BIO pair
./ssltest -bio_pair -ssl2 -server_auth -client_auth -CApath ../certs || exit 1
echo test sslv3 via BIO pair
./ssltest -bio_pair -ssl3 || exit 1
echo test sslv3 with server authentication via BIO pair
./ssltest -bio_pair -ssl3 -server_auth -CApath ../certs || exit 1
echo test sslv3 with client authentication via BIO pair
./ssltest -bio_pair -ssl3 -client_auth -CApath ../certs || exit 1
echo test sslv3 with both client and server authentication via BIO pair
./ssltest -bio_pair -ssl3 -server_auth -client_auth -CApath ../certs || exit 1
echo test sslv2/sslv3 via BIO pair
./ssltest || exit 1
echo test sslv2/sslv3 with server authentication
./ssltest -bio_pair -server_auth -CApath ../certs || exit 1
echo test sslv2/sslv3 with client authentication via BIO pair
./ssltest -bio_pair -client_auth -CApath ../certs || exit 1
echo test sslv2/sslv3 with both client and server authentication via BIO pair
./ssltest -bio_pair -server_auth -client_auth -CApath ../certs || exit 1
exit 0
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册