2 * popsbr.c -- POP client subroutines
4 * This code is Copyright (c) 2002, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
14 # include <sasl/sasl.h>
15 # include <sasl/saslutil.h>
16 # if SASL_VERSION_FULL < 0x020125
17 /* Cyrus SASL 2.1.25 introduced the sasl_callback_ft prototype,
18 which has an explicit void parameter list, according to best
19 practice. So we need to cast to avoid compile warnings.
20 Provide this prototype for earlier versions. */
21 typedef int (*sasl_callback_ft
)();
22 # endif /* SASL_VERSION_FULL < 0x020125 */
23 #endif /* CYRUS_SASL */
26 #include <openssl/ssl.h>
27 #include <openssl/err.h>
28 #endif /* TLS_SUPPORT */
31 #include <h/signals.h>
34 #define TRMLEN (sizeof TRM - 1)
36 static int poprint
= 0;
37 static int pophack
= 0;
39 char response
[BUFSIZ
];
45 static sasl_conn_t
*conn
; /* SASL connection state */
46 static int sasl_complete
= 0; /* Has sasl authentication succeeded? */
47 static int maxoutbuf
; /* Maximum output buffer size */
48 static sasl_ssf_t sasl_ssf
= 0; /* Security strength factor */
49 static int sasl_get_user(void *, int, const char **, unsigned *);
50 static int sasl_get_pass(sasl_conn_t
*, void *, int, sasl_secret_t
**);
57 static sasl_callback_t callbacks
[] = {
58 { SASL_CB_USER
, (sasl_callback_ft
) sasl_get_user
, NULL
},
59 #define POP_SASL_CB_N_USER 0
60 { SASL_CB_PASS
, (sasl_callback_ft
) sasl_get_pass
, NULL
},
61 #define POP_SASL_CB_N_PASS 1
62 { SASL_CB_LOG
, NULL
, NULL
},
63 { SASL_CB_LIST_END
, NULL
, NULL
},
65 #define SASL_BUFFER_SIZE 262144
67 #endif /* CYRUS_SASL */
73 static int command(const char *, ...);
74 static int multiline(void);
77 static int pop_auth_sasl(char *, char *, char *);
78 #endif /* CYRUS_SASL */
81 static SSL_CTX
*sslctx
= NULL
;
82 static SSL
*ssl
= NULL
;
83 static BIO
*sbior
= NULL
;
84 static BIO
*sbiow
= NULL
;
85 static BIO
*io
= NULL
;
87 static int tls_negotiate(void);
88 #endif /* TLS_SUPPORT */
90 static int tls_active
= 0;
92 static int traverse (int (*)(char *), const char *, ...);
93 static int vcommand(const char *, va_list);
94 static int sasl_getline (char *, int, FILE *);
95 static int sasl_fgetc(FILE *);
96 static int putline (char *, FILE *);
100 check_mech(char *server_mechs
, size_t server_mechs_size
, char *mech
)
102 int status
, sasl_capability
= 0;
105 * First off, we're going to send the CAPA command to see if we can
106 * even support the AUTH command, and if we do, then we'll get a
107 * list of mechanisms the server supports. If we don't support
108 * the CAPA command, then it's unlikely that we will support
112 if (command("CAPA") == NOTOK
) {
113 snprintf(response
, sizeof(response
),
114 "The POP CAPA command failed; POP server does not "
119 while ((status
= multiline()) != DONE
)
124 case DONE
: /* Shouldn't be possible, but just in case */
127 if (strncasecmp(response
, "SASL ", 5) == 0) {
129 * We've seen the SASL capability. Grab the mech list
132 strncpy(server_mechs
, response
+ 5, server_mechs_size
);
137 if (!sasl_capability
) {
138 snprintf(response
, sizeof(response
), "POP server does not support "
144 * If we received a preferred mechanism, see if the server supports it.
147 if (mech
&& stringdex(mech
, server_mechs
) == -1) {
148 snprintf(response
, sizeof(response
), "Requested SASL mech \"%s\" is "
149 "not in list of supported mechanisms:\n%s",
159 * This function implements the AUTH command for various SASL mechanisms
161 * We do the whole SASL dialog here. If this completes, then we've
162 * authenticated successfully and have (possibly) negotiated a security
166 #define CHECKB64SIZE(insize, outbuf, outsize) \
167 { size_t wantout = (((insize + 2) / 3) * 4) + 32; \
168 if (wantout > outsize) { \
169 outbuf = mh_xrealloc(outbuf, outsize = wantout); \
174 pop_auth_sasl(char *user
, char *host
, char *mech
)
177 unsigned int buflen
, outlen
;
178 char server_mechs
[256], *buf
, *outbuf
= NULL
;
179 size_t outbufsize
= 0;
180 const char *chosen_mech
;
181 sasl_security_properties_t secprops
;
182 struct pass_context p_context
;
186 if ((status
= check_mech(server_mechs
, sizeof(server_mechs
), mech
)) != OK
) {
191 * Start the SASL process. First off, initialize the SASL library.
194 callbacks
[POP_SASL_CB_N_USER
].context
= user
;
195 p_context
.user
= user
;
196 p_context
.host
= host
;
197 callbacks
[POP_SASL_CB_N_PASS
].context
= &p_context
;
199 result
= sasl_client_init(callbacks
);
201 if (result
!= SASL_OK
) {
202 snprintf(response
, sizeof(response
), "SASL library initialization "
203 "failed: %s", sasl_errstring(result
, NULL
, NULL
));
207 result
= sasl_client_new("pop", host
, NULL
, NULL
, NULL
, 0, &conn
);
209 if (result
!= SASL_OK
) {
210 snprintf(response
, sizeof(response
), "SASL client initialization "
211 "failed: %s", sasl_errstring(result
, NULL
, NULL
));
216 * Initialize the security properties
219 memset(&secprops
, 0, sizeof(secprops
));
220 secprops
.maxbufsize
= SASL_BUFFER_SIZE
;
221 secprops
.max_ssf
= tls_active
? 0 : UINT_MAX
;
223 result
= sasl_setprop(conn
, SASL_SEC_PROPS
, &secprops
);
225 if (result
!= SASL_OK
) {
226 snprintf(response
, sizeof(response
), "SASL security property "
227 "initialization failed: %s", sasl_errdetail(conn
));
232 * Start the actual protocol. Feed the mech list into the library
233 * and get out a possible initial challenge
236 result
= sasl_client_start(conn
,
237 (const char *) (mech
? mech
: server_mechs
),
238 NULL
, (const char **) &buf
,
239 &buflen
, &chosen_mech
);
241 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
242 snprintf(response
, sizeof(response
), "SASL client start failed: %s",
243 sasl_errdetail(conn
));
248 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
249 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
250 if (status
!= SASL_OK
) {
251 snprintf(response
, sizeof(response
), "SASL base64 encode "
252 "failed: %s", sasl_errstring(status
, NULL
, NULL
));
258 status
= command("AUTH %s %s", chosen_mech
, outbuf
);
260 status
= command("AUTH %s", chosen_mech
);
262 while (result
== SASL_CONTINUE
) {
265 if (status
== NOTOK
) {
272 * If we get a "+OK" prefix to our response, then we should
273 * exit out of this exchange now (because authenticated should
277 if (strncmp(response
, "+OK", 3) == 0)
281 * Otherwise, make sure the server challenge is correctly formatted
284 if (strncmp(response
, "+ ", 2) != 0) {
286 snprintf(response
, sizeof(response
),
287 "Malformed authentication message from server");
294 * For decode, it will always be shorter, so just make sure
295 * that outbuf is as at least as big as the encoded response.
298 inlen
= strlen(response
+ 2);
300 if (inlen
> outbufsize
) {
301 outbuf
= mh_xrealloc(outbuf
, outbufsize
= inlen
);
304 result
= sasl_decode64(response
+ 2, strlen(response
+ 2),
305 outbuf
, outbufsize
, &outlen
);
307 if (result
!= SASL_OK
) {
309 snprintf(response
, sizeof(response
), "SASL base64 decode "
310 "failed: %s", sasl_errstring(result
, NULL
, NULL
));
316 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
317 (const char **) &buf
, &buflen
);
319 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
321 snprintf(response
, sizeof(response
), "SASL client negotiaton "
322 "failed: %s", sasl_errdetail(conn
));
328 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
330 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
332 if (status
!= SASL_OK
) {
334 snprintf(response
, sizeof(response
), "SASL base64 encode "
335 "failed: %s", sasl_errstring(status
, NULL
, NULL
));
341 status
= command(outbuf
);
348 * If we didn't get a positive final response, then error out
349 * (that probably means we failed an authorization check).
356 * We _should_ be okay now. Get a few properties now that negotiation
360 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &moutbuf
);
362 if (result
!= SASL_OK
) {
363 snprintf(response
, sizeof(response
), "Cannot retrieve SASL negotiated "
364 "output buffer size: %s", sasl_errdetail(conn
));
368 maxoutbuf
= *moutbuf
;
370 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
374 if (result
!= SASL_OK
) {
375 snprintf(response
, sizeof(response
), "Cannot retrieve SASL negotiated "
376 "security strength factor: %s", sasl_errdetail(conn
));
381 * Limit this to what we can deal with. Shouldn't matter much because
382 * this is only outgoing data (which should be small)
385 if (maxoutbuf
== 0 || maxoutbuf
> BUFSIZ
)
394 * Callback to return the userid sent down via the user parameter
398 sasl_get_user(void *context
, int id
, const char **result
, unsigned *len
)
400 char *user
= (char *) context
;
402 if (! result
|| id
!= SASL_CB_USER
)
403 return SASL_BADPARAM
;
413 * Callback to return the password (we call ruserpass, which can get it
418 sasl_get_pass(sasl_conn_t
*conn
, void *context
, int id
, sasl_secret_t
**psecret
)
420 struct pass_context
*p_context
= (struct pass_context
*) context
;
421 struct nmh_creds creds
= { 0, 0, 0 };
426 if (! psecret
|| id
!= SASL_CB_PASS
)
427 return SASL_BADPARAM
;
429 if (creds
.password
== NULL
) {
431 * Pass the 0 third argument to nmh_get_credentials() so
432 * that the default password isn't used. With legacy/.netrc
433 * credentials support, we'll only get here if the -user
434 * switch to send(1)/post(8) wasn't used.
436 if (nmh_get_credentials (p_context
->host
, p_context
->user
, 0, &creds
)
438 return SASL_BADPARAM
;
442 len
= strlen (creds
.password
);
444 *psecret
= (sasl_secret_t
*) mh_xmalloc(sizeof(sasl_secret_t
) + len
);
446 (*psecret
)->len
= len
;
447 strcpy((char *) (*psecret
)->data
, creds
.password
);
451 #endif /* CYRUS_SASL */
454 pop_auth_xoauth(const char *client_res
)
456 char server_mechs
[256];
457 int status
= check_mech(server_mechs
, sizeof(server_mechs
), "XOAUTH");
459 if (status
!= OK
) return status
;
461 if ((status
= command("AUTH XOAUTH2 %s", client_res
)) != OK
) {
464 if (strncmp(response
, "+OK", 3) == 0) {
468 /* response contains base64-encoded JSON, which is always the same.
469 * See mts/smtp/smtp.c for more notes on that. */
470 /* Then we're supposed to send an empty response ("\r\n"). */
475 * Split string containing proxy command into an array of arguments
476 * suitable for passing to exec. Returned array must be freed. Shouldn't
477 * be possible to call this with host set to NULL.
480 parse_proxy(char *proxy
, char *host
)
484 int hlen
= strlen(host
);
486 unsigned char *cur
, *pro
;
489 /* skip any initial space */
490 for (pro
= (unsigned char *) proxy
; isspace(*pro
); pro
++)
493 /* calculate required size for argument array */
494 for (cur
= pro
; *cur
; cur
++) {
495 if (isspace(*cur
) && cur
[1] && !isspace(cur
[1]))
497 else if (*cur
== '%' && cur
[1] == 'h') {
500 } else if (!isspace(*cur
))
504 /* put together list of arguments */
505 p
= pargv
= mh_xmalloc(pargc
* sizeof(char *));
506 c
= *pargv
= mh_xmalloc(plen
* sizeof(char));
507 for (cur
= pro
; *cur
; cur
++) {
508 if (isspace(*cur
) && cur
[1] && !isspace(cur
[1])) {
511 } else if (*cur
== '%' && cur
[1] == 'h') {
515 } else if (!isspace(*cur
))
524 pop_init (char *host
, char *port
, char *user
, char *pass
, char *proxy
,
525 int snoop
, int sasl
, char *mech
, int tls
, const char *oauth_svc
)
529 const char *xoauth_client_res
= NULL
;
533 #endif /* ! CYRUS_SASL */
536 if (oauth_svc
!= NULL
) {
537 xoauth_client_res
= mh_oauth_do_xoauth(user
, oauth_svc
,
538 snoop
? stderr
: NULL
);
541 NMH_UNUSED (oauth_svc
);
542 NMH_UNUSED (xoauth_client_res
);
543 #endif /* OAUTH_SUPPORT */
545 if (proxy
&& *proxy
) {
547 int inpipe
[2]; /* for reading from the server */
548 int outpipe
[2]; /* for sending to the server */
550 if (pipe(inpipe
) < 0) {
551 adios ("inpipe", "pipe");
553 if (pipe(outpipe
) < 0) {
554 adios ("outpipe", "pipe");
564 dup2(outpipe
[0],0); /* connect read end of connection */
565 dup2(inpipe
[1], 1); /* connect write end of connection */
566 if(inpipe
[0]>1) close(inpipe
[0]);
567 if(inpipe
[1]>1) close(inpipe
[1]);
568 if(outpipe
[0]>1) close(outpipe
[0]);
569 if(outpipe
[1]>1) close(outpipe
[1]);
571 /* run the proxy command */
572 argv
=parse_proxy(proxy
, host
);
573 execvp(argv
[0],argv
);
583 /* okay in the parent we do some stuff */
584 close(inpipe
[1]); /* child uses this */
585 close(outpipe
[0]); /* child uses this */
589 /* and write on fd2 */
594 if ((fd1
= client (host
, port
? port
: "pop3", response
,
595 sizeof(response
), snoop
)) == NOTOK
) {
599 if ((fd2
= dup (fd1
)) == NOTOK
) {
602 if ((s
= strerror(errno
)))
603 snprintf (response
, sizeof(response
),
604 "unable to dup connection descriptor: %s", s
);
606 snprintf (response
, sizeof(response
),
607 "unable to dup connection descriptor: unknown error");
612 if (pop_set (fd1
, fd2
, snoop
) == NOTOK
)
615 SIGNAL (SIGPIPE
, SIG_IGN
);
617 if (tls
&& tls_negotiate())
620 switch (sasl_getline (response
, sizeof response
, input
)) {
623 fprintf (stderr
, "<--- %s\n", response
);
624 if (*response
== '+') {
627 if (pop_auth_sasl(user
, host
, mech
) != NOTOK
)
630 # endif /* CYRUS_SASL */
632 if (xoauth_client_res
!= NULL
) {
633 if (pop_auth_xoauth(xoauth_client_res
) != NOTOK
)
636 # endif /* OAUTH_SUPPORT */
637 if (command ("USER %s", user
) != NOTOK
638 && command ("%s %s", (pophack
++, "PASS"),
642 strncpy (buffer
, response
, sizeof(buffer
));
644 strncpy (response
, buffer
, sizeof(response
));
650 fprintf (stderr
, "%s\n", response
);
656 return NOTOK
; /* NOTREACHED */
660 pop_set (int in
, int out
, int snoop
)
663 if ((input
= fdopen (in
, "r")) == NULL
664 || (output
= fdopen (out
, "w")) == NULL
) {
665 strncpy (response
, "fdopen failed on connection descriptor", sizeof(response
));
681 pop_fd (char *in
, int inlen
, char *out
, int outlen
)
683 snprintf (in
, inlen
, "%d", fileno (input
));
684 snprintf (out
, outlen
, "%d", fileno (output
));
690 * Find out number of messages available
691 * and their total size.
695 pop_stat (int *nmsgs
, int *nbytes
)
698 if (command ("STAT") == NOTOK
)
701 *nmsgs
= *nbytes
= 0;
702 sscanf (response
, "+OK %d %d", nmsgs
, nbytes
);
709 pop_list (int msgno
, int *nmsgs
, int *msgs
, int *bytes
)
715 if (command ("LIST %d", msgno
) == NOTOK
)
720 sscanf (response
, "+OK %d %d %d", msgs
, bytes
, ids
);
723 sscanf (response
, "+OK %d %d", msgs
, bytes
);
727 if (command ("LIST") == NOTOK
)
730 for (i
= 0; i
< *nmsgs
; i
++)
731 switch (multiline ()) {
741 sscanf (response
, "%d %d %d",
742 msgs
++, bytes
++, ids
++);
745 sscanf (response
, "%d %d", msgs
++, bytes
++);
749 switch (multiline ()) {
761 pop_retr (int msgno
, int (*action
)(char *))
763 return traverse (action
, "RETR %d", msgno
);
768 traverse (int (*action
)(char *), const char *fmt
, ...)
772 char buffer
[sizeof(response
)];
775 result
= vcommand (fmt
, ap
);
780 strncpy (buffer
, response
, sizeof(buffer
));
783 switch (multiline ()) {
788 strncpy (response
, buffer
, sizeof(response
));
792 (*action
) (response
);
801 return command ("DELE %d", msgno
);
808 return command ("NOOP");
815 return command ("RSET");
820 pop_top (int msgno
, int lines
, int (*action
)(char *))
822 return traverse (action
, "TOP %d %d", msgno
, lines
);
831 i
= command ("QUIT");
844 #endif /* CYRUS_SASL */
853 command(const char *fmt
, ...)
859 result
= vcommand(fmt
, ap
);
867 vcommand (const char *fmt
, va_list ap
)
869 char *cp
, buffer
[65536];
871 vsnprintf (buffer
, sizeof(buffer
), fmt
, ap
);
876 fprintf(stderr
, "(sasl-encrypted) ");
877 #endif /* CYRUS_SASL */
880 fprintf(stderr
, "(tls-encrypted) ");
881 #endif /* TLS_SUPPORT */
883 if ((cp
= strchr (buffer
, ' ')))
885 fprintf (stderr
, "---> %s ********\n", buffer
);
891 fprintf (stderr
, "---> %s\n", buffer
);
894 if (putline (buffer
, output
) == NOTOK
)
898 if (poprint
&& sasl_ssf
)
899 fprintf(stderr
, "(decrypted) ");
900 #endif /* CYRUS_SASL */
902 switch (sasl_getline (response
, sizeof response
, input
)) {
905 fprintf (stderr
, "<--- %s\n", response
);
906 return (*response
== '+' ? OK
: NOTOK
);
911 fprintf (stderr
, "%s\n", response
);
915 return NOTOK
; /* NOTREACHED */
922 char buffer
[BUFSIZ
+ TRMLEN
];
924 if (sasl_getline (buffer
, sizeof buffer
, input
) != OK
)
930 fprintf(stderr
, "(decrypted) ");
931 #endif /* CYRUS_SASL */
932 fprintf (stderr
, "<--- %s\n", response
);
935 if (strncmp (buffer
, TRM
, TRMLEN
) == 0) {
936 if (buffer
[TRMLEN
] == 0)
939 strncpy (response
, buffer
+ TRMLEN
, sizeof(response
));
942 strncpy (response
, buffer
, sizeof(response
));
948 * Note that these functions have been modified to deal with layer encryption
953 sasl_getline (char *s
, int n
, FILE *iop
)
959 while (--n
> 0 && (c
= sasl_fgetc (iop
)) != EOF
&& c
!= -2)
960 if ((*p
++ = c
) == '\n')
964 if (ferror (iop
) && c
!= EOF
) {
965 strncpy (response
, "error on connection", sizeof(response
));
968 if (c
== EOF
&& p
== s
) {
969 strncpy (response
, "connection closed by foreign host", sizeof(response
));
975 if (p
> s
&& *--p
== '\r')
983 putline (char *s
, FILE *iop
)
986 char outbuf
[BUFSIZ
], *buf
;
990 if (sasl_complete
== 0 || sasl_ssf
== 0) {
991 #endif /* CYRUS_SASL */
996 BIO_printf(io
, "%s\r\n");
1000 strncpy(response
, "lost connection", sizeof(response
));
1006 #endif /* TLS_SUPPORT */
1007 fprintf (iop
, "%s\r\n", s
);
1011 * Build an output buffer, encrypt it using sasl_encode, and
1012 * squirt out the results.
1014 strncpy(outbuf
, s
, sizeof(outbuf
) - 3);
1015 outbuf
[sizeof(outbuf
) - 3] = '\0'; /* Just in case */
1016 strcat(outbuf
, "\r\n");
1018 result
= sasl_encode(conn
, outbuf
, strlen(outbuf
),
1019 (const char **) &buf
, &buflen
);
1021 if (result
!= SASL_OK
) {
1022 snprintf(response
, sizeof(response
), "SASL encoding error: %s",
1023 sasl_errdetail(conn
));
1027 if (fwrite(buf
, buflen
, 1, iop
) < 1) {
1028 advise ("putline", "fwrite");
1031 #endif /* CYRUS_SASL */
1035 strncpy (response
, "lost connection", sizeof(response
));
1044 * Okay, our little fgetc replacement. Hopefully this is a little more
1045 * efficient than the last one.
1050 static unsigned char *buffer
= NULL
, *ptr
;
1051 static unsigned int size
= 0;
1053 unsigned int retbufsize
= 0;
1055 char *retbuf
, tmpbuf
[SASL_BUFFER_SIZE
];
1058 * If we have some leftover data, return that
1063 return (int) *ptr
++;
1067 * Otherwise, fill our buffer until we have some data to return.
1070 while (retbufsize
== 0) {
1075 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1081 snprintf(response
, sizeof(response
), "Error during read from "
1082 "network: %s", strerror(errno
));
1087 * We're not allowed to call sasl_decode until sasl_complete is
1088 * true, so we do these gyrations ...
1091 if (!sasl_complete
) {
1098 result
= sasl_decode(conn
, tmpbuf
, cc
,
1099 (const char **) &retbuf
, &retbufsize
);
1101 if (result
!= SASL_OK
) {
1102 snprintf(response
, sizeof(response
), "Error during SASL "
1103 "decoding: %s", sasl_errdetail(conn
));
1109 if (retbufsize
> size
) {
1110 buffer
= mh_xrealloc(buffer
, retbufsize
);
1114 memcpy(buffer
, retbuf
, retbufsize
);
1116 cnt
= retbufsize
- 1;
1118 return (int) buffer
[0];
1120 #endif /* CYRUS_SASL */
1124 * Negotiate TLS at this point. Will call pop_done() on failure.
1134 SSL_load_error_strings();
1136 sslctx
= SSL_CTX_new(SSLv23_client_method());
1140 advise(NULL
, "Unable to initialize OpenSSL context: %s",
1141 ERR_error_string(ERR_get_error(), NULL
));
1145 SSL_CTX_set_options(sslctx
, SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv3
|
1149 ssl
= SSL_new(sslctx
);
1153 advise(NULL
, "Unable to create SSL connection: %s",
1154 ERR_error_string(ERR_get_error(), NULL
));
1158 sbior
= BIO_new_socket(fileno(input
), BIO_NOCLOSE
);
1159 sbiow
= BIO_new_socket(fileno(output
), BIO_NOCLOSE
);
1161 if (sbior
== NULL
|| sbiow
== NULL
) {
1163 advise(NULL
, "Unable to create BIO endpoints: %s",
1164 ERR_error_string(ERR_get_error(), NULL
));
1168 SSL_set_bio(ssl
, sbior
, sbiow
);
1169 SSL_set_connect_state(ssl
);
1172 * Set up a BIO to do buffering for us
1175 io
= BIO_new(BIO_f_buffer());
1179 advise(NULL
, "Unable to create a buffer BIO: %s",
1180 ERR_error_string(ERR_get_error(), NULL
));
1184 ssl_bio
= BIO_new(BIO_f_ssl());
1188 advise(NULL
, "Unable to create a SSL BIO: %s",
1189 ERR_error_string(ERR_get_error(), NULL
));
1193 BIO_set_ssl(ssl_bio
, ssl
, BIO_CLOSE
);
1194 BIO_push(io
, ssl_bio
);
1197 * Try doing the handshake now
1200 if (BIO_do_handshake(io
) < 1) {
1202 advise(NULL
, "Unable to negotiate SSL connection: %s",
1203 ERR_error_string(ERR_get_error(), NULL
));
1208 const SSL_CIPHER
*cipher
= SSL_get_current_cipher(ssl
);
1209 printf("SSL negotiation successful: %s(%d) %s\n",
1210 SSL_CIPHER_get_name(cipher
),
1211 SSL_CIPHER_get_bits(cipher
, NULL
),
1212 SSL_CIPHER_get_version(cipher
));
1219 #endif /* TLS_SUPPORT */