Newer
Older
SSL_CTX_set_tlsext_status_arg(ctx, bio_c_out);
#if 0
{
STACK_OF(OCSP_RESPID) *ids = sk_OCSP_RESPID_new_null();
OCSP_RESPID *id = OCSP_RESPID_new();
id->value.byKey = ASN1_OCTET_STRING_new();
id->type = V_OCSP_RESPID_KEY;
ASN1_STRING_set(id->value.byKey, "Hello World", -1);
sk_OCSP_RESPID_push(ids, id);
SSL_set_tlsext_status_ids(con, ids);
}
#endif
}
Dr. Stephen Henson
committed
#endif
SSL_set_bio(con,sbio,sbio);
SSL_set_connect_state(con);
/* ok, lets connect */
width=SSL_get_fd(con)+1;
read_tty=1;
write_tty=0;
tty_on=0;
read_ssl=1;
write_ssl=1;
cbuf_len=0;
cbuf_off=0;
sbuf_len=0;
sbuf_off=0;
/* This is an ugly hack that does a lot of assumptions */
/* We do have to handle multi-line responses which may come
in a single packet or not. We therefore have to use
BIO_gets() which does need a buffering BIO. So during
the initial chitchat we do push a buffering BIO into the
chain that is removed again later on to not disturb the
rest of the s_client operation. */
if (starttls_proto == PROTO_SMTP)
{
int foundit=0;
BIO *fbio = BIO_new(BIO_f_buffer());
BIO_push(fbio, sbio);
/* wait for multi-line response to end from SMTP */
do
{
mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
}
while (mbuf_len>3 && mbuf[3]=='-');
/* STARTTLS command requires EHLO... */
BIO_printf(fbio,"EHLO openssl.client.net\r\n");
/* wait for multi-line response to end EHLO SMTP response */
do
{
mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
if (strstr(mbuf,"STARTTLS"))
foundit=1;
}
while (mbuf_len>3 && mbuf[3]=='-');
BIO_pop(fbio);
BIO_free(fbio);
if (!foundit)
BIO_printf(bio_err,
"didn't found starttls in server response,"
" try anyway...\n");
BIO_printf(sbio,"STARTTLS\r\n");
BIO_read(sbio,sbuf,BUFSIZZ);
}
else if (starttls_proto == PROTO_POP3)
Lutz Jänicke
committed
{
BIO_read(sbio,mbuf,BUFSIZZ);
BIO_printf(sbio,"STLS\r\n");
BIO_read(sbio,sbuf,BUFSIZZ);
}
else if (starttls_proto == PROTO_IMAP)
{
int foundit=0;
BIO *fbio = BIO_new(BIO_f_buffer());
BIO_push(fbio, sbio);
BIO_gets(fbio,mbuf,BUFSIZZ);
/* STARTTLS command requires CAPABILITY... */
BIO_printf(fbio,". CAPABILITY\r\n");
/* wait for multi-line CAPABILITY response */
do
{
mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
if (strstr(mbuf,"STARTTLS"))
foundit=1;
}
while (mbuf_len>3 && mbuf[0]!='.');
BIO_pop(fbio);
BIO_free(fbio);
if (!foundit)
BIO_printf(bio_err,
"didn't found STARTTLS in server response,"
" try anyway...\n");
BIO_printf(sbio,". STARTTLS\r\n");
BIO_read(sbio,sbuf,BUFSIZZ);
}
else if (starttls_proto == PROTO_FTP)
{
BIO *fbio = BIO_new(BIO_f_buffer());
BIO_push(fbio, sbio);
/* wait for multi-line response to end from FTP */
do
{
mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
}
while (mbuf_len>3 && mbuf[3]=='-');
BIO_pop(fbio);
BIO_free(fbio);
BIO_printf(sbio,"AUTH TLS\r\n");
BIO_read(sbio,sbuf,BUFSIZZ);
}
for (;;)
{
FD_ZERO(&readfds);
FD_ZERO(&writefds);
if (SSL_in_init(con) && !SSL_total_renegotiations(con))
{
in_init=1;
tty_on=0;
}
else
{
tty_on=1;
if (in_init)
{
in_init=0;
#if 0 /* This test doesn't really work as intended (needs to be fixed) */
#ifndef OPENSSL_NO_TLSEXT
if (servername != NULL && !SSL_session_reused(con))
{
BIO_printf(bio_c_out,"Server did %sacknowledge servername extension.\n",tlsextcbp.ack?"":"not ");
}
Dr. Stephen Henson
committed
if (sess_out)
{
BIO *stmp = BIO_new_file(sess_out, "w");
if (stmp)
{
PEM_write_bio_SSL_SESSION(stmp, SSL_get_session(con));
BIO_free(stmp);
}
else
BIO_printf(bio_err, "Error writing session file %s\n", sess_out);
}
print_stuff(bio_c_out,con,full_log);
if (full_log > 0) full_log--;
Lutz Jänicke
committed
if (starttls_proto)
{
BIO_printf(bio_err,"%s",mbuf);
/* We don't need to know any more */
}
if (reconnect)
{
reconnect--;
BIO_printf(bio_c_out,"drop connection and then reconnect\n");
SSL_shutdown(con);
SSL_set_connect_state(con);
SHUTDOWN(SSL_get_fd(con));
goto re_start;
}
}
}
ssl_pending = read_ssl && SSL_pending(con);
if (!ssl_pending)
#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE) && !defined (OPENSSL_SYS_BEOS_R5)
if (tty_on)
{
if (read_tty) openssl_fdset(fileno(stdin),&readfds);
if (write_tty) openssl_fdset(fileno(stdout),&writefds);
}
if (read_ssl)
openssl_fdset(SSL_get_fd(con),&readfds);
if (write_ssl)
openssl_fdset(SSL_get_fd(con),&writefds);
Dr. Stephen Henson
committed
#else
if(!tty_on || !write_tty) {
if (read_ssl)
openssl_fdset(SSL_get_fd(con),&readfds);
Dr. Stephen Henson
committed
if (write_ssl)
openssl_fdset(SSL_get_fd(con),&writefds);
Dr. Stephen Henson
committed
}
#endif
/* printf("mode tty(%d %d%d) ssl(%d%d)\n",
tty_on,read_tty,write_tty,read_ssl,write_ssl);*/
/* Note: under VMS with SOCKETSHR the second parameter
* is currently of type (int *) whereas under other
* systems it is (void *) if you don't have a cast it
* will choke the compiler: if you do have a cast then
* you can either go for (int *) or (void *).
*/
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS)
/* Under Windows/DOS we make the assumption that we can
Dr. Stephen Henson
committed
* always write to the tty: therefore if we need to
* write to the tty we just fall through. Otherwise
* we timeout the select every second and see if there
* are any keypresses. Note: this is a hack, in a proper
* Windows application we wouldn't do this.
*/
Dr. Stephen Henson
committed
if(!write_tty) {
if(read_tty) {
tv.tv_sec = 1;
tv.tv_usec = 0;
i=select(width,(void *)&readfds,(void *)&writefds,
NULL,&tv);
#if defined(OPENSSL_SYS_WINCE) || defined(OPENSSL_SYS_MSDOS)
if(!i && (!_kbhit() || !read_tty) ) continue;
#else
if(!i && (!((_kbhit()) || (WAIT_OBJECT_0 == WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0))) || !read_tty) ) continue;
Dr. Stephen Henson
committed
} else i=select(width,(void *)&readfds,(void *)&writefds,
NULL,NULL);
}
#elif defined(OPENSSL_SYS_NETWARE)
if(!write_tty) {
if(read_tty) {
tv.tv_sec = 1;
tv.tv_usec = 0;
i=select(width,(void *)&readfds,(void *)&writefds,
NULL,&tv);
} else i=select(width,(void *)&readfds,(void *)&writefds,
NULL,NULL);
}
#elif defined(OPENSSL_SYS_BEOS_R5)
/* Under BeOS-R5 the situation is similar to DOS */
i=0;
stdin_set = 0;
(void)fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
if(!write_tty) {
if(read_tty) {
tv.tv_sec = 1;
tv.tv_usec = 0;
i=select(width,(void *)&readfds,(void *)&writefds,
NULL,&tv);
if (read(fileno(stdin), sbuf, 0) >= 0)
stdin_set = 1;
if (!i && (stdin_set != 1 || !read_tty))
continue;
} else i=select(width,(void *)&readfds,(void *)&writefds,
NULL,NULL);
}
(void)fcntl(fileno(stdin), F_SETFL, 0);
Dr. Stephen Henson
committed
#else
i=select(width,(void *)&readfds,(void *)&writefds,
NULL,NULL);
Dr. Stephen Henson
committed
#endif
if ( i < 0)
{
BIO_printf(bio_err,"bad select %d\n",
get_last_socket_error());
goto shut;
/* goto end; */
}
if (!ssl_pending && FD_ISSET(SSL_get_fd(con),&writefds))
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
{
k=SSL_write(con,&(cbuf[cbuf_off]),
(unsigned int)cbuf_len);
switch (SSL_get_error(con,k))
{
case SSL_ERROR_NONE:
cbuf_off+=k;
cbuf_len-=k;
if (k <= 0) goto end;
/* we have done a write(con,NULL,0); */
if (cbuf_len <= 0)
{
read_tty=1;
write_ssl=0;
}
else /* if (cbuf_len > 0) */
{
read_tty=0;
write_ssl=1;
}
break;
case SSL_ERROR_WANT_WRITE:
BIO_printf(bio_c_out,"write W BLOCK\n");
write_ssl=1;
read_tty=0;
break;
case SSL_ERROR_WANT_READ:
BIO_printf(bio_c_out,"write R BLOCK\n");
write_tty=0;
read_ssl=1;
write_ssl=0;
break;
case SSL_ERROR_WANT_X509_LOOKUP:
BIO_printf(bio_c_out,"write X BLOCK\n");
break;
case SSL_ERROR_ZERO_RETURN:
if (cbuf_len != 0)
{
BIO_printf(bio_c_out,"shutdown\n");
ret = 0;
goto shut;
}
else
{
read_tty=1;
write_ssl=0;
break;
}
case SSL_ERROR_SYSCALL:
if ((k != 0) || (cbuf_len != 0))
{
BIO_printf(bio_err,"write:errno=%d\n",
get_last_socket_error());
goto shut;
}
else
{
read_tty=1;
write_ssl=0;
}
break;
case SSL_ERROR_SSL:
ERR_print_errors(bio_err);
goto shut;
}
}
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_BEOS_R5)
/* Assume Windows/DOS/BeOS can always write */
Dr. Stephen Henson
committed
else if (!ssl_pending && write_tty)
#else
else if (!ssl_pending && FD_ISSET(fileno(stdout),&writefds))
Dr. Stephen Henson
committed
#endif
#ifdef CHARSET_EBCDIC
ascii2ebcdic(&(sbuf[sbuf_off]),&(sbuf[sbuf_off]),sbuf_len);
#endif
i=raw_write_stdout(&(sbuf[sbuf_off]),sbuf_len);
if (i <= 0)
{
BIO_printf(bio_c_out,"DONE\n");
ret = 0;
goto shut;
/* goto end; */
}
sbuf_len-=i;;
sbuf_off+=i;
if (sbuf_len <= 0)
{
read_ssl=1;
write_tty=0;
}
}
else if (ssl_pending || FD_ISSET(SSL_get_fd(con),&readfds))
#ifdef RENEG
{ static int iiii; if (++iiii == 52) { SSL_renegotiate(con); iiii=0; } }
#endif
k=SSL_read(con,sbuf,1024 /* BUFSIZZ */ );
#else
/* Demo for pending and peek :-) */
k=SSL_read(con,sbuf,16);
{ char zbuf[10240];
printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240));
}
#endif
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
switch (SSL_get_error(con,k))
{
case SSL_ERROR_NONE:
if (k <= 0)
goto end;
sbuf_off=0;
sbuf_len=k;
read_ssl=0;
write_tty=1;
break;
case SSL_ERROR_WANT_WRITE:
BIO_printf(bio_c_out,"read W BLOCK\n");
write_ssl=1;
read_tty=0;
break;
case SSL_ERROR_WANT_READ:
BIO_printf(bio_c_out,"read R BLOCK\n");
write_tty=0;
read_ssl=1;
if ((read_tty == 0) && (write_ssl == 0))
write_ssl=1;
break;
case SSL_ERROR_WANT_X509_LOOKUP:
BIO_printf(bio_c_out,"read X BLOCK\n");
break;
case SSL_ERROR_SYSCALL:
ret=get_last_socket_error();
BIO_printf(bio_err,"read:errno=%d\n",ret);
goto shut;
case SSL_ERROR_ZERO_RETURN:
BIO_printf(bio_c_out,"closed\n");
ret=0;
goto shut;
case SSL_ERROR_SSL:
ERR_print_errors(bio_err);
goto shut;
/* break; */
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS)
#if defined(OPENSSL_SYS_WINCE) || defined(OPENSSL_SYS_MSDOS)
else if ((_kbhit()) || (WAIT_OBJECT_0 == WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0)))
else if (_kbhit())
#elif defined(OPENSSL_SYS_BEOS_R5)
else if (stdin_set)
Dr. Stephen Henson
committed
#else
else if (FD_ISSET(fileno(stdin),&readfds))
Dr. Stephen Henson
committed
#endif
if (crlf)
{
int j, lf_num;
i=raw_read_stdin(cbuf,BUFSIZZ/2);
lf_num = 0;
/* both loops are skipped when i <= 0 */
for (j = 0; j < i; j++)
if (cbuf[j] == '\n')
lf_num++;
for (j = i-1; j >= 0; j--)
{
cbuf[j+lf_num] = cbuf[j];
if (cbuf[j] == '\n')
{
lf_num--;
i++;
cbuf[j+lf_num] = '\r';
}
}
assert(lf_num == 0);
}
else
i=raw_read_stdin(cbuf,BUFSIZZ);
if ((!c_ign_eof) && ((i <= 0) || (cbuf[0] == 'Q')))
{
BIO_printf(bio_err,"DONE\n");
ret=0;
goto shut;
}
if ((!c_ign_eof) && (cbuf[0] == 'R'))
SSL_renegotiate(con);
}
else
{
cbuf_len=i;
cbuf_off=0;
#ifdef CHARSET_EBCDIC
ebcdic2ascii(cbuf, cbuf, i);
#endif
}
write_ssl=1;
ret=0;
if (in_init)
print_stuff(bio_c_out,con,full_log);
SSL_shutdown(con);
SHUTDOWN(SSL_get_fd(con));
end:
if (con != NULL)
{
if (prexit != 0)
print_stuff(bio_c_out,con,1);
SSL_free(con);
}
if (ctx != NULL) SSL_CTX_free(ctx);
if (cert)
X509_free(cert);
if (key)
EVP_PKEY_free(key);
if (pass)
OPENSSL_free(pass);
if (cbuf != NULL) { OPENSSL_cleanse(cbuf,BUFSIZZ); OPENSSL_free(cbuf); }
if (sbuf != NULL) { OPENSSL_cleanse(sbuf,BUFSIZZ); OPENSSL_free(sbuf); }
if (mbuf != NULL) { OPENSSL_cleanse(mbuf,BUFSIZZ); OPENSSL_free(mbuf); }
if (bio_c_out != NULL)
{
BIO_free(bio_c_out);
bio_c_out=NULL;
}
apps_shutdown();
OPENSSL_EXIT(ret);
static void print_stuff(BIO *bio, SSL *s, int full)
STACK_OF(X509) *sk;
STACK_OF(X509_NAME) *sk2;
SSL_CIPHER *c;
X509_NAME *xn;
int j,i;
const COMP_METHOD *comp, *expansion;
if (full)
{
int got_a_chain = 0;
sk=SSL_get_peer_cert_chain(s);
if (sk != NULL)
{
got_a_chain = 1; /* we don't have it for SSL2 (yet) */
BIO_printf(bio,"---\nCertificate chain\n");
sk_X509_value(sk,i)),buf,sizeof buf);
BIO_printf(bio,"%2d s:%s\n",i,buf);
sk_X509_value(sk,i)),buf,sizeof buf);
BIO_printf(bio," i:%s\n",buf);
PEM_write_bio_X509(bio,sk_X509_value(sk,i));
}
}
BIO_printf(bio,"---\n");
peer=SSL_get_peer_certificate(s);
if (peer != NULL)
{
BIO_printf(bio,"Server certificate\n");
if (!(c_showcerts && got_a_chain)) /* Redundant if we showed the whole chain */
X509_NAME_oneline(X509_get_subject_name(peer),
BIO_printf(bio,"subject=%s\n",buf);
X509_NAME_oneline(X509_get_issuer_name(peer),
BIO_printf(bio,"issuer=%s\n",buf);
}
else
BIO_printf(bio,"no peer certificate available\n");
if ((sk2 != NULL) && (sk_X509_NAME_num(sk2) > 0))
{
BIO_printf(bio,"---\nAcceptable client certificate CA names\n");
X509_NAME_oneline(xn,buf,sizeof(buf));
BIO_write(bio,buf,strlen(buf));
BIO_write(bio,"\n",1);
}
}
else
{
BIO_printf(bio,"---\nNo client certificate CA names sent\n");
}
p=SSL_get_shared_ciphers(s,buf,sizeof buf);
if (p != NULL)
{
/* This works only for SSL 2. In later protocol
* versions, the client does not know what other
* ciphers (in addition to the one to be used
* in the current connection) the server supports. */
BIO_printf(bio,"---\nCiphers common between both SSL endpoints:\n");
j=i=0;
while (*p)
{
if (*p == ':')
{
BIO_write(bio,space,15-j%25);
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
i++;
j=0;
BIO_write(bio,((i%3)?" ":"\n"),1);
}
else
{
BIO_write(bio,p,1);
j++;
}
p++;
}
BIO_write(bio,"\n",1);
}
BIO_printf(bio,"---\nSSL handshake has read %ld bytes and written %ld bytes\n",
BIO_number_read(SSL_get_rbio(s)),
BIO_number_written(SSL_get_wbio(s)));
}
BIO_printf(bio,((s->hit)?"---\nReused, ":"---\nNew, "));
c=SSL_get_current_cipher(s);
BIO_printf(bio,"%s, Cipher is %s\n",
SSL_CIPHER_get_version(c),
SSL_CIPHER_get_name(c));
if (peer != NULL) {
EVP_PKEY *pktmp;
pktmp = X509_get_pubkey(peer);
BIO_printf(bio,"Server public key is %d bit\n",
EVP_PKEY_bits(pktmp));
EVP_PKEY_free(pktmp);
}
Richard Levitte
committed
comp=SSL_get_current_compression(s);
expansion=SSL_get_current_expansion(s);
Richard Levitte
committed
BIO_printf(bio,"Compression: %s\n",
comp ? SSL_COMP_get_name(comp) : "NONE");
BIO_printf(bio,"Expansion: %s\n",
expansion ? SSL_COMP_get_name(expansion) : "NONE");
SSL_SESSION_print(bio,SSL_get_session(s));
BIO_printf(bio,"---\n");
if (peer != NULL)
X509_free(peer);
/* flush, or debugging output gets mixed with http response */
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
static int ocsp_resp_cb(SSL *s, void *arg)
{
const unsigned char *p;
int len;
OCSP_RESPONSE *rsp;
len = SSL_get_tlsext_status_ocsp_resp(s, &p);
BIO_puts(arg, "OCSP response: ");
if (!p)
{
BIO_puts(arg, "no response sent\n");
return 1;
}
rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
if (!rsp)
{
BIO_puts(arg, "response parse error\n");
BIO_dump_indent(arg, (char *)p, len, 4);
return 0;
}
BIO_puts(arg, "\n======================================\n");
OCSP_RESPONSE_print(arg, rsp, 0);
BIO_puts(arg, "======================================\n");
OCSP_RESPONSE_free(rsp);
return 1;
}