BIO pairs.
This commit is contained in:
parent
9bce3070ac
commit
95d29597b7
10
CHANGES
10
CHANGES
@ -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)
|
||||
{
|
||||
|
@ -1,11 +1,11 @@
|
||||
/* 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_)
|
||||
{
|
||||
/* XXX */
|
||||
return -1;
|
||||
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)
|
||||
static int bio_write(BIO *bio, char *buf, int num_)
|
||||
{
|
||||
/* XXX */
|
||||
return -1;
|
||||
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)
|
||||
{
|
||||
/* we already closed */
|
||||
BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(b->len <= b->size);
|
||||
|
||||
if (b->len == b->size)
|
||||
{
|
||||
BIO_set_retry_write(bio); /* buffer is full */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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, char *ptr)
|
||||
|
||||
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);
|
||||
}
|
||||
|
47
ms/test.bat
47
ms/test.bat
@ -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;
|
||||
|
377
ssl/ssltest.c
377
ssl/ssltest.c
@ -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,7 +363,10 @@ bad:
|
||||
for (i=0; i<number; i++)
|
||||
{
|
||||
if (!reuse) SSL_set_session(c_ssl,NULL);
|
||||
ret=doit(s_ssl,c_ssl,bytes);
|
||||
if (bio_pair)
|
||||
ret=doit_biopair(s_ssl,c_ssl,bytes);
|
||||
else
|
||||
ret=doit(s_ssl,c_ssl,bytes);
|
||||
}
|
||||
|
||||
if (!verbose)
|
||||
@ -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
|
||||
|
37
test/testssl
37
test/testssl
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user