155714Skris/* ssl/bio_ssl.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.
8296341Sdelphij *
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).
15296341Sdelphij *
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.
22296341Sdelphij *
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 :-).
37296341Sdelphij * 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)"
40296341Sdelphij *
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.
52296341Sdelphij *
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#include <stdio.h>
6055714Skris#include <stdlib.h>
6155714Skris#include <string.h>
6255714Skris#include <errno.h>
6355714Skris#include <openssl/crypto.h>
6455714Skris#include <openssl/bio.h>
6555714Skris#include <openssl/err.h>
6655714Skris#include <openssl/ssl.h>
6755714Skris
6868651Skrisstatic int ssl_write(BIO *h, const char *buf, int num);
6968651Skrisstatic int ssl_read(BIO *h, char *buf, int size);
7068651Skrisstatic int ssl_puts(BIO *h, const char *str);
7168651Skrisstatic long ssl_ctrl(BIO *h, int cmd, long arg1, void *arg2);
7255714Skrisstatic int ssl_new(BIO *h);
7355714Skrisstatic int ssl_free(BIO *data);
7468651Skrisstatic long ssl_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
75296341Sdelphijtypedef struct bio_ssl_st {
76296341Sdelphij    SSL *ssl;                   /* The ssl handle :-) */
77296341Sdelphij    /* re-negotiate every time the total number of bytes is this size */
78296341Sdelphij    int num_renegotiates;
79296341Sdelphij    unsigned long renegotiate_count;
80296341Sdelphij    unsigned long byte_count;
81296341Sdelphij    unsigned long renegotiate_timeout;
82296341Sdelphij    unsigned long last_time;
83296341Sdelphij} BIO_SSL;
8455714Skris
85296341Sdelphijstatic BIO_METHOD methods_sslp = {
86296341Sdelphij    BIO_TYPE_SSL, "ssl",
87296341Sdelphij    ssl_write,
88296341Sdelphij    ssl_read,
89296341Sdelphij    ssl_puts,
90296341Sdelphij    NULL,                       /* ssl_gets, */
91296341Sdelphij    ssl_ctrl,
92296341Sdelphij    ssl_new,
93296341Sdelphij    ssl_free,
94296341Sdelphij    ssl_callback_ctrl,
95296341Sdelphij};
9655714Skris
9755714SkrisBIO_METHOD *BIO_f_ssl(void)
98296341Sdelphij{
99296341Sdelphij    return (&methods_sslp);
100296341Sdelphij}
10155714Skris
10255714Skrisstatic int ssl_new(BIO *bi)
103296341Sdelphij{
104296341Sdelphij    BIO_SSL *bs;
10555714Skris
106296341Sdelphij    bs = (BIO_SSL *)OPENSSL_malloc(sizeof(BIO_SSL));
107296341Sdelphij    if (bs == NULL) {
108296341Sdelphij        BIOerr(BIO_F_SSL_NEW, ERR_R_MALLOC_FAILURE);
109296341Sdelphij        return (0);
110296341Sdelphij    }
111296341Sdelphij    memset(bs, 0, sizeof(BIO_SSL));
112296341Sdelphij    bi->init = 0;
113296341Sdelphij    bi->ptr = (char *)bs;
114296341Sdelphij    bi->flags = 0;
115296341Sdelphij    return (1);
116296341Sdelphij}
11755714Skris
11855714Skrisstatic int ssl_free(BIO *a)
119296341Sdelphij{
120296341Sdelphij    BIO_SSL *bs;
12155714Skris
122296341Sdelphij    if (a == NULL)
123296341Sdelphij        return (0);
124296341Sdelphij    bs = (BIO_SSL *)a->ptr;
125296341Sdelphij    if (bs->ssl != NULL)
126296341Sdelphij        SSL_shutdown(bs->ssl);
127296341Sdelphij    if (a->shutdown) {
128296341Sdelphij        if (a->init && (bs->ssl != NULL))
129296341Sdelphij            SSL_free(bs->ssl);
130296341Sdelphij        a->init = 0;
131296341Sdelphij        a->flags = 0;
132296341Sdelphij    }
133296341Sdelphij    if (a->ptr != NULL)
134296341Sdelphij        OPENSSL_free(a->ptr);
135296341Sdelphij    return (1);
136296341Sdelphij}
137296341Sdelphij
13855714Skrisstatic int ssl_read(BIO *b, char *out, int outl)
139296341Sdelphij{
140296341Sdelphij    int ret = 1;
141296341Sdelphij    BIO_SSL *sb;
142296341Sdelphij    SSL *ssl;
143296341Sdelphij    int retry_reason = 0;
144296341Sdelphij    int r = 0;
14555714Skris
146296341Sdelphij    if (out == NULL)
147296341Sdelphij        return (0);
148296341Sdelphij    sb = (BIO_SSL *)b->ptr;
149296341Sdelphij    ssl = sb->ssl;
15055714Skris
151296341Sdelphij    BIO_clear_retry_flags(b);
15255714Skris
15355714Skris#if 0
154296341Sdelphij    if (!SSL_is_init_finished(ssl)) {
155296341Sdelphij/*              ret=SSL_do_handshake(ssl); */
156296341Sdelphij        if (ret > 0) {
15755714Skris
158296341Sdelphij            outflags = (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
159296341Sdelphij            ret = -1;
160296341Sdelphij            goto end;
161296341Sdelphij        }
162296341Sdelphij    }
16355714Skris#endif
164296341Sdelphij/*      if (ret > 0) */
165296341Sdelphij    ret = SSL_read(ssl, out, outl);
16655714Skris
167296341Sdelphij    switch (SSL_get_error(ssl, ret)) {
168296341Sdelphij    case SSL_ERROR_NONE:
169296341Sdelphij        if (ret <= 0)
170296341Sdelphij            break;
171296341Sdelphij        if (sb->renegotiate_count > 0) {
172296341Sdelphij            sb->byte_count += ret;
173296341Sdelphij            if (sb->byte_count > sb->renegotiate_count) {
174296341Sdelphij                sb->byte_count = 0;
175296341Sdelphij                sb->num_renegotiates++;
176296341Sdelphij                SSL_renegotiate(ssl);
177296341Sdelphij                r = 1;
178296341Sdelphij            }
179296341Sdelphij        }
180296341Sdelphij        if ((sb->renegotiate_timeout > 0) && (!r)) {
181296341Sdelphij            unsigned long tm;
18255714Skris
183296341Sdelphij            tm = (unsigned long)time(NULL);
184296341Sdelphij            if (tm > sb->last_time + sb->renegotiate_timeout) {
185296341Sdelphij                sb->last_time = tm;
186296341Sdelphij                sb->num_renegotiates++;
187296341Sdelphij                SSL_renegotiate(ssl);
188296341Sdelphij            }
189296341Sdelphij        }
19055714Skris
191296341Sdelphij        break;
192296341Sdelphij    case SSL_ERROR_WANT_READ:
193296341Sdelphij        BIO_set_retry_read(b);
194296341Sdelphij        break;
195296341Sdelphij    case SSL_ERROR_WANT_WRITE:
196296341Sdelphij        BIO_set_retry_write(b);
197296341Sdelphij        break;
198296341Sdelphij    case SSL_ERROR_WANT_X509_LOOKUP:
199296341Sdelphij        BIO_set_retry_special(b);
200296341Sdelphij        retry_reason = BIO_RR_SSL_X509_LOOKUP;
201296341Sdelphij        break;
202296341Sdelphij    case SSL_ERROR_WANT_ACCEPT:
203296341Sdelphij        BIO_set_retry_special(b);
204296341Sdelphij        retry_reason = BIO_RR_ACCEPT;
205296341Sdelphij        break;
206296341Sdelphij    case SSL_ERROR_WANT_CONNECT:
207296341Sdelphij        BIO_set_retry_special(b);
208296341Sdelphij        retry_reason = BIO_RR_CONNECT;
209296341Sdelphij        break;
210296341Sdelphij    case SSL_ERROR_SYSCALL:
211296341Sdelphij    case SSL_ERROR_SSL:
212296341Sdelphij    case SSL_ERROR_ZERO_RETURN:
213296341Sdelphij    default:
214296341Sdelphij        break;
215296341Sdelphij    }
21655714Skris
217296341Sdelphij    b->retry_reason = retry_reason;
218296341Sdelphij    return (ret);
219296341Sdelphij}
22055714Skris
22168651Skrisstatic int ssl_write(BIO *b, const char *out, int outl)
222296341Sdelphij{
223296341Sdelphij    int ret, r = 0;
224296341Sdelphij    int retry_reason = 0;
225296341Sdelphij    SSL *ssl;
226296341Sdelphij    BIO_SSL *bs;
22755714Skris
228296341Sdelphij    if (out == NULL)
229296341Sdelphij        return (0);
230296341Sdelphij    bs = (BIO_SSL *)b->ptr;
231296341Sdelphij    ssl = bs->ssl;
23255714Skris
233296341Sdelphij    BIO_clear_retry_flags(b);
23455714Skris
235296341Sdelphij    /*
236296341Sdelphij     * ret=SSL_do_handshake(ssl); if (ret > 0)
237296341Sdelphij     */
238296341Sdelphij    ret = SSL_write(ssl, out, outl);
23955714Skris
240296341Sdelphij    switch (SSL_get_error(ssl, ret)) {
241296341Sdelphij    case SSL_ERROR_NONE:
242296341Sdelphij        if (ret <= 0)
243296341Sdelphij            break;
244296341Sdelphij        if (bs->renegotiate_count > 0) {
245296341Sdelphij            bs->byte_count += ret;
246296341Sdelphij            if (bs->byte_count > bs->renegotiate_count) {
247296341Sdelphij                bs->byte_count = 0;
248296341Sdelphij                bs->num_renegotiates++;
249296341Sdelphij                SSL_renegotiate(ssl);
250296341Sdelphij                r = 1;
251296341Sdelphij            }
252296341Sdelphij        }
253296341Sdelphij        if ((bs->renegotiate_timeout > 0) && (!r)) {
254296341Sdelphij            unsigned long tm;
25555714Skris
256296341Sdelphij            tm = (unsigned long)time(NULL);
257296341Sdelphij            if (tm > bs->last_time + bs->renegotiate_timeout) {
258296341Sdelphij                bs->last_time = tm;
259296341Sdelphij                bs->num_renegotiates++;
260296341Sdelphij                SSL_renegotiate(ssl);
261296341Sdelphij            }
262296341Sdelphij        }
263296341Sdelphij        break;
264296341Sdelphij    case SSL_ERROR_WANT_WRITE:
265296341Sdelphij        BIO_set_retry_write(b);
266296341Sdelphij        break;
267296341Sdelphij    case SSL_ERROR_WANT_READ:
268296341Sdelphij        BIO_set_retry_read(b);
269296341Sdelphij        break;
270296341Sdelphij    case SSL_ERROR_WANT_X509_LOOKUP:
271296341Sdelphij        BIO_set_retry_special(b);
272296341Sdelphij        retry_reason = BIO_RR_SSL_X509_LOOKUP;
273296341Sdelphij        break;
274296341Sdelphij    case SSL_ERROR_WANT_CONNECT:
275296341Sdelphij        BIO_set_retry_special(b);
276296341Sdelphij        retry_reason = BIO_RR_CONNECT;
277296341Sdelphij    case SSL_ERROR_SYSCALL:
278296341Sdelphij    case SSL_ERROR_SSL:
279296341Sdelphij    default:
280296341Sdelphij        break;
281296341Sdelphij    }
28255714Skris
283296341Sdelphij    b->retry_reason = retry_reason;
284296341Sdelphij    return (ret);
285296341Sdelphij}
28655714Skris
28768651Skrisstatic long ssl_ctrl(BIO *b, int cmd, long num, void *ptr)
288296341Sdelphij{
289296341Sdelphij    SSL **sslp, *ssl;
290296341Sdelphij    BIO_SSL *bs;
291296341Sdelphij    BIO *dbio, *bio;
292296341Sdelphij    long ret = 1;
29355714Skris
294296341Sdelphij    bs = (BIO_SSL *)b->ptr;
295296341Sdelphij    ssl = bs->ssl;
296296341Sdelphij    if ((ssl == NULL) && (cmd != BIO_C_SET_SSL))
297296341Sdelphij        return (0);
298296341Sdelphij    switch (cmd) {
299296341Sdelphij    case BIO_CTRL_RESET:
300296341Sdelphij        SSL_shutdown(ssl);
30155714Skris
302296341Sdelphij        if (ssl->handshake_func == ssl->method->ssl_connect)
303296341Sdelphij            SSL_set_connect_state(ssl);
304296341Sdelphij        else if (ssl->handshake_func == ssl->method->ssl_accept)
305296341Sdelphij            SSL_set_accept_state(ssl);
30655714Skris
307296341Sdelphij        SSL_clear(ssl);
30855714Skris
309296341Sdelphij        if (b->next_bio != NULL)
310296341Sdelphij            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
311296341Sdelphij        else if (ssl->rbio != NULL)
312296341Sdelphij            ret = BIO_ctrl(ssl->rbio, cmd, num, ptr);
313296341Sdelphij        else
314296341Sdelphij            ret = 1;
315296341Sdelphij        break;
316296341Sdelphij    case BIO_CTRL_INFO:
317296341Sdelphij        ret = 0;
318296341Sdelphij        break;
319296341Sdelphij    case BIO_C_SSL_MODE:
320296341Sdelphij        if (num)                /* client mode */
321296341Sdelphij            SSL_set_connect_state(ssl);
322296341Sdelphij        else
323296341Sdelphij            SSL_set_accept_state(ssl);
324296341Sdelphij        break;
325296341Sdelphij    case BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT:
326296341Sdelphij        ret = bs->renegotiate_timeout;
327296341Sdelphij        if (num < 60)
328296341Sdelphij            num = 5;
329296341Sdelphij        bs->renegotiate_timeout = (unsigned long)num;
330296341Sdelphij        bs->last_time = (unsigned long)time(NULL);
331296341Sdelphij        break;
332296341Sdelphij    case BIO_C_SET_SSL_RENEGOTIATE_BYTES:
333296341Sdelphij        ret = bs->renegotiate_count;
334296341Sdelphij        if ((long)num >= 512)
335296341Sdelphij            bs->renegotiate_count = (unsigned long)num;
336296341Sdelphij        break;
337296341Sdelphij    case BIO_C_GET_SSL_NUM_RENEGOTIATES:
338296341Sdelphij        ret = bs->num_renegotiates;
339296341Sdelphij        break;
340296341Sdelphij    case BIO_C_SET_SSL:
341296341Sdelphij        if (ssl != NULL) {
342296341Sdelphij            ssl_free(b);
343296341Sdelphij            if (!ssl_new(b))
344296341Sdelphij                return 0;
345296341Sdelphij        }
346296341Sdelphij        b->shutdown = (int)num;
347296341Sdelphij        ssl = (SSL *)ptr;
348296341Sdelphij        ((BIO_SSL *)b->ptr)->ssl = ssl;
349296341Sdelphij        bio = SSL_get_rbio(ssl);
350296341Sdelphij        if (bio != NULL) {
351296341Sdelphij            if (b->next_bio != NULL)
352296341Sdelphij                BIO_push(bio, b->next_bio);
353296341Sdelphij            b->next_bio = bio;
354296341Sdelphij            CRYPTO_add(&bio->references, 1, CRYPTO_LOCK_BIO);
355296341Sdelphij        }
356296341Sdelphij        b->init = 1;
357296341Sdelphij        break;
358296341Sdelphij    case BIO_C_GET_SSL:
359296341Sdelphij        if (ptr != NULL) {
360296341Sdelphij            sslp = (SSL **)ptr;
361296341Sdelphij            *sslp = ssl;
362296341Sdelphij        } else
363296341Sdelphij            ret = 0;
364296341Sdelphij        break;
365296341Sdelphij    case BIO_CTRL_GET_CLOSE:
366296341Sdelphij        ret = b->shutdown;
367296341Sdelphij        break;
368296341Sdelphij    case BIO_CTRL_SET_CLOSE:
369296341Sdelphij        b->shutdown = (int)num;
370296341Sdelphij        break;
371296341Sdelphij    case BIO_CTRL_WPENDING:
372296341Sdelphij        ret = BIO_ctrl(ssl->wbio, cmd, num, ptr);
373296341Sdelphij        break;
374296341Sdelphij    case BIO_CTRL_PENDING:
375296341Sdelphij        ret = SSL_pending(ssl);
376296341Sdelphij        if (ret == 0)
377296341Sdelphij            ret = BIO_pending(ssl->rbio);
378296341Sdelphij        break;
379296341Sdelphij    case BIO_CTRL_FLUSH:
380296341Sdelphij        BIO_clear_retry_flags(b);
381296341Sdelphij        ret = BIO_ctrl(ssl->wbio, cmd, num, ptr);
382296341Sdelphij        BIO_copy_next_retry(b);
383296341Sdelphij        break;
384296341Sdelphij    case BIO_CTRL_PUSH:
385296341Sdelphij        if ((b->next_bio != NULL) && (b->next_bio != ssl->rbio)) {
386296341Sdelphij            SSL_set_bio(ssl, b->next_bio, b->next_bio);
387296341Sdelphij            CRYPTO_add(&b->next_bio->references, 1, CRYPTO_LOCK_BIO);
388296341Sdelphij        }
389296341Sdelphij        break;
390296341Sdelphij    case BIO_CTRL_POP:
391296341Sdelphij        /* Only detach if we are the BIO explicitly being popped */
392296341Sdelphij        if (b == ptr) {
393296341Sdelphij            /*
394296341Sdelphij             * Shouldn't happen in practice because the rbio and wbio are the
395296341Sdelphij             * same when pushed.
396296341Sdelphij             */
397296341Sdelphij            if (ssl->rbio != ssl->wbio)
398296341Sdelphij                BIO_free_all(ssl->wbio);
399296341Sdelphij            if (b->next_bio != NULL)
400296341Sdelphij                CRYPTO_add(&b->next_bio->references, -1, CRYPTO_LOCK_BIO);
401296341Sdelphij            ssl->wbio = NULL;
402296341Sdelphij            ssl->rbio = NULL;
403296341Sdelphij        }
404296341Sdelphij        break;
405296341Sdelphij    case BIO_C_DO_STATE_MACHINE:
406296341Sdelphij        BIO_clear_retry_flags(b);
40755714Skris
408296341Sdelphij        b->retry_reason = 0;
409296341Sdelphij        ret = (int)SSL_do_handshake(ssl);
41055714Skris
411296341Sdelphij        switch (SSL_get_error(ssl, (int)ret)) {
412296341Sdelphij        case SSL_ERROR_WANT_READ:
413296341Sdelphij            BIO_set_flags(b, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
414296341Sdelphij            break;
415296341Sdelphij        case SSL_ERROR_WANT_WRITE:
416296341Sdelphij            BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
417296341Sdelphij            break;
418296341Sdelphij        case SSL_ERROR_WANT_CONNECT:
419296341Sdelphij            BIO_set_flags(b, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY);
420296341Sdelphij            b->retry_reason = b->next_bio->retry_reason;
421296341Sdelphij            break;
422296341Sdelphij        default:
423296341Sdelphij            break;
424296341Sdelphij        }
425296341Sdelphij        break;
426296341Sdelphij    case BIO_CTRL_DUP:
427296341Sdelphij        dbio = (BIO *)ptr;
428296341Sdelphij        if (((BIO_SSL *)dbio->ptr)->ssl != NULL)
429296341Sdelphij            SSL_free(((BIO_SSL *)dbio->ptr)->ssl);
430296341Sdelphij        ((BIO_SSL *)dbio->ptr)->ssl = SSL_dup(ssl);
431296341Sdelphij        ((BIO_SSL *)dbio->ptr)->renegotiate_count =
432296341Sdelphij            ((BIO_SSL *)b->ptr)->renegotiate_count;
433296341Sdelphij        ((BIO_SSL *)dbio->ptr)->byte_count = ((BIO_SSL *)b->ptr)->byte_count;
434296341Sdelphij        ((BIO_SSL *)dbio->ptr)->renegotiate_timeout =
435296341Sdelphij            ((BIO_SSL *)b->ptr)->renegotiate_timeout;
436296341Sdelphij        ((BIO_SSL *)dbio->ptr)->last_time = ((BIO_SSL *)b->ptr)->last_time;
437296341Sdelphij        ret = (((BIO_SSL *)dbio->ptr)->ssl != NULL);
438296341Sdelphij        break;
439296341Sdelphij    case BIO_C_GET_FD:
440296341Sdelphij        ret = BIO_ctrl(ssl->rbio, cmd, num, ptr);
441296341Sdelphij        break;
442296341Sdelphij    case BIO_CTRL_SET_CALLBACK:
443296341Sdelphij        {
444296341Sdelphij#if 0                           /* FIXME: Should this be used? -- Richard
445296341Sdelphij                                 * Levitte */
446296341Sdelphij            SSLerr(SSL_F_SSL_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
447296341Sdelphij            ret = -1;
44859191Skris#else
449296341Sdelphij            ret = 0;
45059191Skris#endif
451296341Sdelphij        }
452296341Sdelphij        break;
453296341Sdelphij    case BIO_CTRL_GET_CALLBACK:
454296341Sdelphij        {
455296341Sdelphij            void (**fptr) (const SSL *xssl, int type, int val);
45655714Skris
457296341Sdelphij            fptr = (void (**)(const SSL *xssl, int type, int val))ptr;
458296341Sdelphij            *fptr = SSL_get_info_callback(ssl);
459296341Sdelphij        }
460296341Sdelphij        break;
461296341Sdelphij    default:
462296341Sdelphij        ret = BIO_ctrl(ssl->rbio, cmd, num, ptr);
463296341Sdelphij        break;
464296341Sdelphij    }
465296341Sdelphij    return (ret);
466296341Sdelphij}
46755714Skris
46868651Skrisstatic long ssl_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
469296341Sdelphij{
470296341Sdelphij    SSL *ssl;
471296341Sdelphij    BIO_SSL *bs;
472296341Sdelphij    long ret = 1;
47359191Skris
474296341Sdelphij    bs = (BIO_SSL *)b->ptr;
475296341Sdelphij    ssl = bs->ssl;
476296341Sdelphij    switch (cmd) {
477296341Sdelphij    case BIO_CTRL_SET_CALLBACK:
478296341Sdelphij        {
479296341Sdelphij            /*
480296341Sdelphij             * FIXME: setting this via a completely different prototype seems
481296341Sdelphij             * like a crap idea
482296341Sdelphij             */
483296341Sdelphij            SSL_set_info_callback(ssl, (void (*)(const SSL *, int, int))fp);
484296341Sdelphij        }
485296341Sdelphij        break;
486296341Sdelphij    default:
487296341Sdelphij        ret = BIO_callback_ctrl(ssl->rbio, cmd, fp);
488296341Sdelphij        break;
489296341Sdelphij    }
490296341Sdelphij    return (ret);
491296341Sdelphij}
49259191Skris
49368651Skrisstatic int ssl_puts(BIO *bp, const char *str)
494296341Sdelphij{
495296341Sdelphij    int n, ret;
49655714Skris
497296341Sdelphij    n = strlen(str);
498296341Sdelphij    ret = BIO_write(bp, str, n);
499296341Sdelphij    return (ret);
500296341Sdelphij}
50155714Skris
50255714SkrisBIO *BIO_new_buffer_ssl_connect(SSL_CTX *ctx)
503296341Sdelphij{
504111147Snectar#ifndef OPENSSL_NO_SOCK
505296341Sdelphij    BIO *ret = NULL, *buf = NULL, *ssl = NULL;
50655714Skris
507296341Sdelphij    if ((buf = BIO_new(BIO_f_buffer())) == NULL)
508296341Sdelphij        return (NULL);
509296341Sdelphij    if ((ssl = BIO_new_ssl_connect(ctx)) == NULL)
510296341Sdelphij        goto err;
511296341Sdelphij    if ((ret = BIO_push(buf, ssl)) == NULL)
512296341Sdelphij        goto err;
513296341Sdelphij    return (ret);
514296341Sdelphij err:
515296341Sdelphij    if (buf != NULL)
516296341Sdelphij        BIO_free(buf);
517296341Sdelphij    if (ssl != NULL)
518296341Sdelphij        BIO_free(ssl);
519111147Snectar#endif
520296341Sdelphij    return (NULL);
521296341Sdelphij}
52255714Skris
52355714SkrisBIO *BIO_new_ssl_connect(SSL_CTX *ctx)
524296341Sdelphij{
525238405Sjkim#ifndef OPENSSL_NO_SOCK
526296341Sdelphij    BIO *ret = NULL, *con = NULL, *ssl = NULL;
52755714Skris
528296341Sdelphij    if ((con = BIO_new(BIO_s_connect())) == NULL)
529296341Sdelphij        return (NULL);
530296341Sdelphij    if ((ssl = BIO_new_ssl(ctx, 1)) == NULL)
531296341Sdelphij        goto err;
532296341Sdelphij    if ((ret = BIO_push(ssl, con)) == NULL)
533296341Sdelphij        goto err;
534296341Sdelphij    return (ret);
535296341Sdelphij err:
536296341Sdelphij    if (con != NULL)
537296341Sdelphij        BIO_free(con);
538238405Sjkim#endif
539296341Sdelphij    return (NULL);
540296341Sdelphij}
54155714Skris
54255714SkrisBIO *BIO_new_ssl(SSL_CTX *ctx, int client)
543296341Sdelphij{
544296341Sdelphij    BIO *ret;
545296341Sdelphij    SSL *ssl;
54655714Skris
547296341Sdelphij    if ((ret = BIO_new(BIO_f_ssl())) == NULL)
548296341Sdelphij        return (NULL);
549296341Sdelphij    if ((ssl = SSL_new(ctx)) == NULL) {
550296341Sdelphij        BIO_free(ret);
551296341Sdelphij        return (NULL);
552296341Sdelphij    }
553296341Sdelphij    if (client)
554296341Sdelphij        SSL_set_connect_state(ssl);
555296341Sdelphij    else
556296341Sdelphij        SSL_set_accept_state(ssl);
55755714Skris
558296341Sdelphij    BIO_set_ssl(ret, ssl, BIO_CLOSE);
559296341Sdelphij    return (ret);
560296341Sdelphij}
561296341Sdelphij
56255714Skrisint BIO_ssl_copy_session_id(BIO *t, BIO *f)
563296341Sdelphij{
564296341Sdelphij    t = BIO_find_type(t, BIO_TYPE_SSL);
565296341Sdelphij    f = BIO_find_type(f, BIO_TYPE_SSL);
566296341Sdelphij    if ((t == NULL) || (f == NULL))
567296341Sdelphij        return (0);
568296341Sdelphij    if ((((BIO_SSL *)t->ptr)->ssl == NULL) ||
569296341Sdelphij        (((BIO_SSL *)f->ptr)->ssl == NULL))
570296341Sdelphij        return (0);
571296341Sdelphij    SSL_copy_session_id(((BIO_SSL *)t->ptr)->ssl, ((BIO_SSL *)f->ptr)->ssl);
572296341Sdelphij    return (1);
573296341Sdelphij}
57455714Skris
57555714Skrisvoid BIO_ssl_shutdown(BIO *b)
576296341Sdelphij{
577296341Sdelphij    SSL *s;
57855714Skris
579296341Sdelphij    while (b != NULL) {
580296341Sdelphij        if (b->method->type == BIO_TYPE_SSL) {
581296341Sdelphij            s = ((BIO_SSL *)b->ptr)->ssl;
582296341Sdelphij            SSL_shutdown(s);
583296341Sdelphij            break;
584296341Sdelphij        }
585296341Sdelphij        b = b->next_bio;
586296341Sdelphij    }
587296341Sdelphij}
588