summaryrefslogtreecommitdiff
path: root/src/tls
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/tls/tls.erl30
-rw-r--r--src/tls/tls_drv.c44
2 files changed, 50 insertions, 24 deletions
diff --git a/src/tls/tls.erl b/src/tls/tls.erl
index 361c92fc..e1925520 100644
--- a/src/tls/tls.erl
+++ b/src/tls/tls.erl
@@ -27,11 +27,12 @@
code_change/3,
terminate/2]).
--define(SET_CERTIFICATE_FILE, 1).
--define(SET_ENCRYPTED_INPUT, 2).
--define(SET_DECRYPTED_OUTPUT, 3).
--define(GET_ENCRYPTED_OUTPUT, 4).
--define(GET_DECRYPTED_INPUT, 5).
+-define(SET_CERTIFICATE_FILE_ACCEPT, 1).
+-define(SET_CERTIFICATE_FILE_CONNECT, 2).
+-define(SET_ENCRYPTED_INPUT, 3).
+-define(SET_DECRYPTED_OUTPUT, 4).
+-define(GET_ENCRYPTED_OUTPUT, 5).
+-define(GET_DECRYPTED_INPUT, 6).
-record(tlssock, {tcpsock, tlsport}).
@@ -44,7 +45,7 @@ start_link() ->
init([]) ->
ok = erl_ddll:load_driver(ejabberd:get_so_path(), tls_drv),
Port = open_port({spawn, tls_drv}, [binary]),
- Res = port_control(Port, ?SET_CERTIFICATE_FILE, "./ssl.pem" ++ [0]),
+ Res = port_control(Port, ?SET_CERTIFICATE_FILE_ACCEPT, "./ssl.pem" ++ [0]),
case Res of
<<0>> ->
%ets:new(iconv_table, [set, public, named_table]),
@@ -86,8 +87,13 @@ tcp_to_tls(TCPSocket, Options) ->
{value, {certfile, CertFile}} ->
ok = erl_ddll:load_driver(ejabberd:get_so_path(), tls_drv),
Port = open_port({spawn, tls_drv}, [binary]),
- case port_control(Port, ?SET_CERTIFICATE_FILE,
- CertFile ++ [0]) of
+ Command = case lists:member(connect, Options) of
+ true ->
+ ?SET_CERTIFICATE_FILE_CONNECT;
+ false ->
+ ?SET_CERTIFICATE_FILE_ACCEPT
+ end,
+ case port_control(Port, Command, CertFile ++ [0]) of
<<0>> ->
{ok, #tlssock{tcpsock = TCPSocket, tlsport = Port}};
<<1, Error/binary>> ->
@@ -145,7 +151,10 @@ send(#tlssock{tcpsock = TCPSocket, tlsport = Port}, Packet) ->
{error, binary_to_list(Error)}
end;
<<1, Error/binary>> ->
- {error, binary_to_list(Error)}
+ {error, binary_to_list(Error)};
+ <<2>> -> % Dirty hack
+ receive after 100 -> ok end,
+ send(#tlssock{tcpsock = TCPSocket, tlsport = Port}, Packet)
end.
@@ -158,7 +167,8 @@ test() ->
ok = erl_ddll:load_driver(ejabberd:get_so_path(), tls_drv),
Port = open_port({spawn, tls_drv}, [binary]),
io:format("open_port: ~p~n", [Port]),
- PCRes = port_control(Port, ?SET_CERTIFICATE_FILE, "./ssl.pem" ++ [0]),
+ PCRes = port_control(Port, ?SET_CERTIFICATE_FILE_ACCEPT,
+ "./ssl.pem" ++ [0]),
io:format("port_control: ~p~n", [PCRes]),
{ok, ListenSocket} = gen_tcp:listen(1234, [binary,
{packet, 0},
diff --git a/src/tls/tls_drv.c b/src/tls/tls_drv.c
index f320ee31..608830ff 100644
--- a/src/tls/tls_drv.c
+++ b/src/tls/tls_drv.c
@@ -4,6 +4,7 @@
#include <string.h>
#include <erl_driver.h>
#include <openssl/ssl.h>
+#include <openssl/err.h>
#define BUF_SIZE 1024
@@ -45,11 +46,12 @@ static void tls_drv_stop(ErlDrvData handle)
}
-#define SET_CERTIFICATE_FILE 1
-#define SET_ENCRYPTED_INPUT 2
-#define SET_DECRYPTED_OUTPUT 3
-#define GET_ENCRYPTED_OUTPUT 4
-#define GET_DECRYPTED_INPUT 5
+#define SET_CERTIFICATE_FILE_ACCEPT 1
+#define SET_CERTIFICATE_FILE_CONNECT 2
+#define SET_ENCRYPTED_INPUT 3
+#define SET_DECRYPTED_OUTPUT 4
+#define GET_ENCRYPTED_OUTPUT 5
+#define GET_DECRYPTED_INPUT 6
#define die_unless(cond, errstr) \
@@ -76,8 +78,9 @@ static int tls_drv_control(ErlDrvData handle,
switch (command)
{
- case SET_CERTIFICATE_FILE:
- d->ctx = SSL_CTX_new(SSLv23_server_method());
+ case SET_CERTIFICATE_FILE_ACCEPT:
+ case SET_CERTIFICATE_FILE_CONNECT:
+ d->ctx = SSL_CTX_new(SSLv23_method());
die_unless(d->ctx, "SSL_CTX_new failed");
res = SSL_CTX_use_certificate_file(d->ctx, buf, SSL_FILETYPE_PEM);
@@ -97,7 +100,10 @@ static int tls_drv_control(ErlDrvData handle,
SSL_set_bio(d->ssl, d->bio_read, d->bio_write);
- SSL_set_accept_state(d->ssl);
+ if (command == SET_CERTIFICATE_FILE_ACCEPT)
+ SSL_set_accept_state(d->ssl);
+ else
+ SSL_set_connect_state(d->ssl);
break;
case SET_ENCRYPTED_INPUT:
die_unless(d->ssl, "SSL not initialized");
@@ -106,6 +112,19 @@ static int tls_drv_control(ErlDrvData handle,
case SET_DECRYPTED_OUTPUT:
die_unless(d->ssl, "SSL not initialized");
res = SSL_write(d->ssl, buf, len);
+ if (res <= 0)
+ {
+ res = SSL_get_error(d->ssl, res);
+ if (res == SSL_ERROR_WANT_READ || res == SSL_ERROR_WANT_WRITE)
+ {
+ b = driver_alloc_binary(1);
+ b->orig_bytes[0] = 2;
+ *rbuf = (char *)b;
+ return 1;
+ } else {
+ die_unless(0, "SSL_write failed");
+ }
+ }
break;
case GET_ENCRYPTED_OUTPUT:
die_unless(d->ssl, "SSL not initialized");
@@ -128,13 +147,10 @@ static int tls_drv_control(ErlDrvData handle,
case GET_DECRYPTED_INPUT:
if (!SSL_is_init_finished(d->ssl))
{
- //printf("Doing SSL_accept\r\n");
- res = SSL_accept(d->ssl);
- //if (res == 0)
- // printf("SSL_accept returned zero\r\n");
- if (res < 0)
+ res = SSL_do_handshake(d->ssl);
+ if (res <= 0)
die_unless(SSL_get_error(d->ssl, res) == SSL_ERROR_WANT_READ,
- "SSL_accept failed");
+ "SSL_do_handshake failed");
} else {
size = BUF_SIZE + 1;
rlen = 1;