diff options
Diffstat (limited to 'libs/nixio/src')
-rw-r--r-- | libs/nixio/src/file.c | 12 | ||||
-rw-r--r-- | libs/nixio/src/io.c | 6 | ||||
-rw-r--r-- | libs/nixio/src/nixio.c | 2 | ||||
-rw-r--r-- | libs/nixio/src/nixio.h | 4 | ||||
-rw-r--r-- | libs/nixio/src/openssl-compat.c | 297 | ||||
-rw-r--r-- | libs/nixio/src/openssl-compat.h | 144 | ||||
-rw-r--r-- | libs/nixio/src/socket.c | 12 | ||||
-rw-r--r-- | libs/nixio/src/tls-context.c | 202 | ||||
-rw-r--r-- | libs/nixio/src/tls-socket.c | 196 |
9 files changed, 863 insertions, 12 deletions
diff --git a/libs/nixio/src/file.c b/libs/nixio/src/file.c index 7b65abdc1..3333e2369 100644 --- a/libs/nixio/src/file.c +++ b/libs/nixio/src/file.c @@ -33,7 +33,11 @@ static int nixio_file(lua_State *L) { return nixio__perror(L); } - FILE **udata = lua_newuserdata(L, sizeof(FILE**)); + FILE **udata = lua_newuserdata(L, sizeof(FILE*)); + if (!udata) { + return luaL_error(L, "out of memory"); + } + *udata = file; luaL_getmetatable(L, NIXIO_FILE_META); @@ -50,7 +54,11 @@ static int nixio_pipe(lua_State *L) { } luaL_getmetatable(L, NIXIO_FILE_META); - udata = lua_newuserdata(L, sizeof(FILE**)); + udata = lua_newuserdata(L, sizeof(FILE*)); + if (!udata) { + return luaL_error(L, "out of memory"); + } + if (!(*udata = fdopen(pipefd[0], "r"))) { return nixio__perror(L); } diff --git a/libs/nixio/src/io.c b/libs/nixio/src/io.c index 58054b2eb..b33746121 100644 --- a/libs/nixio/src/io.c +++ b/libs/nixio/src/io.c @@ -36,8 +36,8 @@ static int nixio_sock__sendto(lua_State *L, int to) { socklen_t alen = 0; if (to) { - const char *address = luaL_checklstring(L, 2, NULL); - uint16_t port = (uint16_t)luaL_checkinteger(L, 3); + const char *address = luaL_checklstring(L, 3, NULL); + uint16_t port = (uint16_t)luaL_checkinteger(L, 4); struct sockaddr_storage addrstor; addr = (struct sockaddr*)&addrstor; if (sock->domain == AF_INET) { @@ -65,7 +65,7 @@ static int nixio_sock__sendto(lua_State *L, int to) { do { sent = sendto(sock->fd, data, len, 0, addr, alen); } while(sent == -1 && errno == EINTR); - if (len >= 0) { + if (sent >= 0) { lua_pushinteger(L, sent); return 1; } else { diff --git a/libs/nixio/src/nixio.c b/libs/nixio/src/nixio.c index a4ef7462e..0c8ee6eeb 100644 --- a/libs/nixio/src/nixio.c +++ b/libs/nixio/src/nixio.c @@ -118,6 +118,8 @@ LUALIB_API int luaopen_nixio(lua_State *L) { nixio_open_poll(L); nixio_open_io(L); nixio_open_splice(L); + nixio_open_tls_context(L); + nixio_open_tls_socket(L); /* module version */ lua_pushnumber(L, VERSION); diff --git a/libs/nixio/src/nixio.h b/libs/nixio/src/nixio.h index cdb43599e..5a491c52b 100644 --- a/libs/nixio/src/nixio.h +++ b/libs/nixio/src/nixio.h @@ -3,6 +3,8 @@ #define NIXIO_META "nixio.socket" #define NIXIO_FILE_META "nixio.file" +#define NIXIO_TLS_CTX_META "nixio.tls.ctx" +#define NIXIO_TLS_SOCK_META "nixio.tls.sock" #define NIXIO_BUFFERSIZE 8096 #define _FILE_OFFSET_BITS 64 @@ -43,6 +45,8 @@ void nixio_open_address(lua_State *L); void nixio_open_poll(lua_State *L); void nixio_open_io(lua_State *L); void nixio_open_splice(lua_State *L); +void nixio_open_tls_context(lua_State *L); +void nixio_open_tls_socket(lua_State *L); /* Method functions */ diff --git a/libs/nixio/src/openssl-compat.c b/libs/nixio/src/openssl-compat.c new file mode 100644 index 000000000..ee7600c08 --- /dev/null +++ b/libs/nixio/src/openssl-compat.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Enable a subset of openssl compatible functions. We don't aim to be 100% + * compatible - just to be able to do basic ports etc. + * + * Only really tested on mini_httpd, so I'm not too sure how extensive this + * port is. + */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include "ssl.h" + +static char *key_password = NULL; + +void *SSLv23_server_method(void) { return NULL; } +void *SSLv3_server_method(void) { return NULL; } +void *TLSv1_server_method(void) { return NULL; } +void *SSLv23_client_method(void) { return NULL; } +void *SSLv3_client_method(void) { return NULL; } +void *TLSv1_client_method(void) { return NULL; } +void *SSLv23_method(void) { return NULL; } +void *TLSv1_method(void) { return NULL; } + +SSL_CTX * SSL_CTX_new(void *meth) +{ + SSL_CTX *ssl_ctx = ssl_ctx_new(SSL_SERVER_VERIFY_LATER, 5); + return ssl_ctx; +} + +void SSL_CTX_free(SSL_CTX * ssl_ctx) +{ + ssl_ctx_free(ssl_ctx); +} + +SSL * SSL_new(SSL_CTX *ssl_ctx) +{ + SSL *ssl; + + ssl = ssl_new(ssl_ctx, -1); /* fd is set later */ + + return ssl; +} + +int SSL_set_fd(SSL *s, int fd) +{ + s->client_fd = fd; + return 1; /* always succeeds */ +} + +int SSL_accept(SSL *ssl) +{ + ssl->next_state = HS_CLIENT_HELLO; + while (ssl_read(ssl, NULL) == SSL_OK) + { + if (ssl->next_state == HS_CLIENT_HELLO) + return 1; /* we're done */ + } + + return -1; +} + +int SSL_connect(SSL *ssl) +{ + SET_SSL_FLAG(SSL_IS_CLIENT); + int stat = do_client_connect(ssl); + ssl_display_error(stat); + return (stat == SSL_OK) ? 1 : -1; +} + +void SSL_free(SSL *ssl) +{ + ssl_free(ssl); +} + +int SSL_read(SSL *ssl, void *buf, int num) +{ + uint8_t *read_buf; + int ret; + + while ((ret = ssl_read(ssl, &read_buf)) == SSL_OK); + + if (ret > SSL_OK) + { + memcpy(buf, read_buf, ret > num ? num : ret); + } + + return ret; +} + +int SSL_write(SSL *ssl, const void *buf, int num) +{ + return ssl_write(ssl, buf, num); +} + +int SSL_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type) +{ + return (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, file, NULL) == SSL_OK); +} + +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type) +{ + return (ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, file, key_password) == SSL_OK); +} + +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d) +{ + return (ssl_obj_memory_load(ssl_ctx, + SSL_OBJ_X509_CERT, d, len, NULL) == SSL_OK); +} + +int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx, + unsigned int sid_ctx_len) +{ + return 1; +} + +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) +{ + return 1; +} + +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file) +{ + return (ssl_obj_load(ssl_ctx, + SSL_OBJ_X509_CERT, file, NULL) == SSL_OK); +} + +int SSL_shutdown(SSL *ssl) +{ + return 1; +} + +/*** get/set session ***/ +SSL_SESSION *SSL_get1_session(SSL *ssl) +{ + return (SSL_SESSION *)ssl_get_session_id(ssl); /* note: wrong cast */ +} + +int SSL_set_session(SSL *ssl, SSL_SESSION *session) +{ + memcpy(ssl->session_id, (uint8_t *)session, SSL_SESSION_ID_SIZE); + return 1; +} + +void SSL_SESSION_free(SSL_SESSION *session) { } +/*** end get/set session ***/ + +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) +{ + return 0; +} + +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*verify_callback)(int, void *)) { + if (mode & SSL_VERIFY_PEER) { + ctx->options &= ~SSL_SERVER_VERIFY_LATER; + ctx->options |= SSL_CLIENT_AUTHENTICATION; + } else { + ctx->options |= SSL_SERVER_VERIFY_LATER; + ctx->options &= ~SSL_CLIENT_AUTHENTICATION; + } +} + +void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth) { } + +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath) +{ + return 1; +} + +void *SSL_load_client_CA_file(const char *file) +{ + return (void *)file; +} + +void SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file) +{ + + ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, (const char *)file, NULL); +} + +void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb) { } + +void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u) +{ + key_password = (char *)u; +} + +int SSL_peek(SSL *ssl, void *buf, int num) +{ + memcpy(buf, ssl->bm_data, num); + return num; +} + +void SSL_set_bio(SSL *ssl, void *rbio, void *wbio) { } + +long SSL_get_verify_result(const SSL *ssl) +{ + return ssl_handshake_status(ssl); +} + +int SSL_state(SSL *ssl) +{ + return 0x03; // ok state +} + +/** end of could do better list */ + +void *SSL_get_peer_certificate(const SSL *ssl) +{ + return &ssl->ssl_ctx->certs[0]; +} + +int SSL_clear(SSL *ssl) +{ + return 1; +} + + +int SSL_CTX_check_private_key(const SSL_CTX *ctx) +{ + return 1; +} + +int SSL_CTX_set_cipher_list(SSL_CTX *s, const char *str) +{ + return 1; +} + +int SSL_get_error(const SSL *ssl, int ret) +{ + ssl_display_error(ret); + return 0; /* TODO: return proper return code */ +} + +void SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option) {} +int SSL_library_init(void ) { return 1; } +void SSL_load_error_strings(void ) {} +void ERR_print_errors_fp(FILE *fp) {} + +long SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx) { + return CONFIG_SSL_EXPIRY_TIME*3600; } +long SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t) { + return SSL_CTX_get_timeout(ssl_ctx); } +void BIO_printf(FILE *f, const char *format, ...) +{ + va_list(ap); + va_start(ap, format); + vfprintf(f, format, ap); + va_end(ap); +} + +void* BIO_s_null(void) { return NULL; } +FILE *BIO_new(bio_func_type_t func) +{ + if (func == BIO_s_null) + return fopen("/dev/null", "r"); + else + return NULL; +} + +FILE *BIO_new_fp(FILE *stream, int close_flag) { return stream; } +int BIO_free(FILE *a) { if (a != stdout && a != stderr) fclose(a); return 1; } diff --git a/libs/nixio/src/openssl-compat.h b/libs/nixio/src/openssl-compat.h new file mode 100644 index 000000000..afda58fba --- /dev/null +++ b/libs/nixio/src/openssl-compat.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Enable a subset of openssl compatible functions. We don't aim to be 100% + * compatible - just to be able to do basic ports etc. + * + * Only really tested on mini_httpd, so I'm not too sure how extensive this + * port is. + */ + +#include "config.h" + +#define WITH_AXTLS 1 +#define WITHOUT_OPENSSL 1 +#define SSL_OP_NO_SSLv3 0x02000000L +#define SSL_OP_NO_SSLv2 0x01000000L +#define SSL_FILETYPE_PEM 1 +#define SSL_VERIFY_NONE 0x00 +#define SSL_VERIFY_PEER 0x01 +#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 +#define SSL_VERIFY_CLIENT_ONCE 0x03 + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include "ssl.h" + +void *SSLv23_server_method(void); +void *SSLv3_server_method(void); +void *TLSv1_server_method(void); +void *SSLv23_client_method(void); +void *SSLv3_client_method(void); +void *TLSv1_client_method(void); +void *SSLv23_method(void); +void *TLSv1_method(void); + + +typedef void * (*ssl_func_type_t)(void); +typedef void * (*bio_func_type_t)(void); + +SSL_CTX * SSL_CTX_new(void *meth); +void SSL_CTX_free(SSL_CTX * ssl_ctx); +SSL * SSL_new(SSL_CTX *ssl_ctx); +int SSL_set_fd(SSL *s, int fd); +int SSL_accept(SSL *ssl); +int SSL_connect(SSL *ssl); +void SSL_free(SSL *ssl); +int SSL_read(SSL *ssl, void *buf, int num); +int SSL_write(SSL *ssl, const void *buf, int num); +int SSL_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type); +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type); +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d); +int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx, + unsigned int sid_ctx_len); +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file); +int SSL_shutdown(SSL *ssl); + +/*** get/set session ***/ +SSL_SESSION *SSL_get1_session(SSL *ssl); +int SSL_set_session(SSL *ssl, SSL_SESSION *session); +void SSL_SESSION_free(SSL_SESSION *session); +/*** end get/set session ***/ + +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg); +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*verify_callback)(int, void *)); + +void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth); + +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath); + +void *SSL_load_client_CA_file(const char *file); + +void SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file); + +void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb); + +void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u); + +int SSL_peek(SSL *ssl, void *buf, int num); + +void SSL_set_bio(SSL *ssl, void *rbio, void *wbio); + +long SSL_get_verify_result(const SSL *ssl); + +int SSL_state(SSL *ssl); + +/** end of could do better list */ + +void *SSL_get_peer_certificate(const SSL *ssl); + +int SSL_clear(SSL *ssl); + + +int SSL_CTX_check_private_key(const SSL_CTX *ctx); + +int SSL_CTX_set_cipher_list(SSL_CTX *s, const char *str); + +int SSL_get_error(const SSL *ssl, int ret); + +void SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option); +int SSL_library_init(void ); +void SSL_load_error_strings(void ); +void ERR_print_errors_fp(FILE *fp); + +long SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx); +long SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t); +void BIO_printf(FILE *f, const char *format, ...); + +void* BIO_s_null(void); +FILE *BIO_new(bio_func_type_t func); + +FILE *BIO_new_fp(FILE *stream, int close_flag); +int BIO_free(FILE *a); diff --git a/libs/nixio/src/socket.c b/libs/nixio/src/socket.c index f8fa3e649..258cdeece 100644 --- a/libs/nixio/src/socket.c +++ b/libs/nixio/src/socket.c @@ -34,6 +34,9 @@ static int nixio_socket(lua_State *L) { const char *proto = lua_tolstring(L, 3, NULL); nixio_sock *sock = lua_newuserdata(L, sizeof(nixio_sock)); + if (!sock) { + return luaL_error(L, "out of memory"); + } if (!strcmp(domain, "inet")) { sock->domain = AF_INET; @@ -142,17 +145,12 @@ static const luaL_reg R[] = { static const luaL_reg M[] = { {"close", nixio_sock_close}, {"shutdown", nixio_sock_shutdown}, + {"__gc", nixio_sock__gc}, + {"__tostring", nixio_sock__tostring}, {NULL, NULL} }; void nixio_open_socket(lua_State *L) { - luaL_getmetatable(L, NIXIO_META); - lua_pushcfunction(L, nixio_sock__gc); - lua_setfield(L, -2, "__gc"); - lua_pushcfunction(L, nixio_sock__tostring); - lua_setfield(L, -2, "__tostring"); - lua_pop(L, 1); - luaL_register(L, NULL, R); lua_pushvalue(L, -2); diff --git a/libs/nixio/src/tls-context.c b/libs/nixio/src/tls-context.c new file mode 100644 index 000000000..723f8a85f --- /dev/null +++ b/libs/nixio/src/tls-context.c @@ -0,0 +1,202 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include "string.h" + +#ifndef WITHOUT_OPENSSL +#include <openssl/ssl.h> +#endif + +static SSL_CTX* nixio__checktlsctx(lua_State *L) { + SSL_CTX **ctx = (SSL_CTX **)luaL_checkudata(L, 1, NIXIO_TLS_CTX_META); + luaL_argcheck(L, *ctx, 1, "invalid context"); + return *ctx; +} + +static int nixio__tls_perror(lua_State *L, int code) { + lua_pushnil(L); + lua_pushinteger(L, code); + return 2; +} + +static int nixio__tls_pstatus(lua_State *L, int code) { + if (code == 1) { + lua_pushboolean(L, 1); + return 1; + } else { + return nixio__tls_perror(L, code); + } +} + +static int nixio_tls_ctx(lua_State * L) { + const char *method = luaL_optlstring(L, 1, "tlsv1", NULL); + + SSL_CTX **ctx = lua_newuserdata(L, sizeof(SSL_CTX *)); + if (!ctx) { + return luaL_error(L, "out of memory"); + } + + /* create userdata */ + luaL_getmetatable(L, NIXIO_TLS_CTX_META); + lua_setmetatable(L, -2); + + if (!strcmp(method, "tlsv1")) { + *ctx = SSL_CTX_new(TLSv1_method()); + } else if (!strcmp(method, "sslv23")) { + *ctx = SSL_CTX_new(SSLv23_method()); + } else { + return luaL_argerror(L, 1, "supported values: tlsv1, sslv23"); + } + + + SSL_CTX_set_options(*ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + + if (!(*ctx)) { + return luaL_error(L, "unable to create TLS context"); + } + + return 1; +} + +static int nixio_tls_ctx_create(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + int fd = nixio__checkfd(L, 2); + + SSL **sock = lua_newuserdata(L, sizeof(SSL *)); + if (!sock) { + return luaL_error(L, "out of memory"); + } + + /* create userdata */ + luaL_getmetatable(L, NIXIO_TLS_SOCK_META); + lua_setmetatable(L, -2); + + *sock = SSL_new(ctx); + if (!(*sock)) { + return nixio__tls_perror(L, 0); + } + + if (SSL_set_fd(*sock, fd) != 1) { + return nixio__tls_perror(L, 0); + } + + return 1; +} + +static int nixio_tls_ctx_set_cert(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + const char *cert = luaL_checkstring(L, 2); + return nixio__tls_pstatus(L, SSL_CTX_use_certificate_chain_file(ctx, cert)); +} + +static int nixio_tls_ctx_set_key(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + const char *cert = luaL_checkstring(L, 2); + const int ktype = SSL_FILETYPE_PEM; + return nixio__tls_pstatus(L, SSL_CTX_use_PrivateKey_file(ctx, cert, ktype)); +} + +static int nixio_tls_ctx_set_ciphers(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + size_t len; + const char *ciphers = luaL_checklstring(L, 2, &len); + luaL_argcheck(L, len < 255, 2, "cipher string too long"); + return nixio__tls_pstatus(L, SSL_CTX_set_cipher_list(ctx, ciphers)); +} + +static int nixio_tls_ctx_set_verify_depth(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + const int depth = luaL_checkinteger(L, 2); + SSL_CTX_set_verify_depth(ctx, depth); + return 0; +} + +static int nixio_tls_ctx_set_verify(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + const int j = lua_gettop(L); + int flags = 0; + for (int i=2; i<=j; i++) { + const char *flag = luaL_checkstring(L, i); + if (!strcmp(flag, "none")) { + flags |= SSL_VERIFY_NONE; + } else if (!strcmp(flag, "peer")) { + flags |= SSL_VERIFY_PEER; + } else if (!strcmp(flag, "verify_fail_if_no_peer_cert")) { + flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } else if (!strcmp(flag, "client_once")) { + flags |= SSL_VERIFY_CLIENT_ONCE; + } else { + return luaL_argerror(L, i, "supported values: none, peer, " + "verify_fail_if_no_peer_cert, client_once"); + } + } + SSL_CTX_set_verify(ctx, flags, NULL); + return 0; +} + +static int nixio_tls_ctx__gc(lua_State *L) { + SSL_CTX **ctx = (SSL_CTX **)luaL_checkudata(L, 1, NIXIO_TLS_CTX_META); + if (*ctx) { + SSL_CTX_free(*ctx); + *ctx = NULL; + } + return 0; +} + +static int nixio_tls_ctx__tostring(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + lua_pushfstring(L, "nixio TLS context: %p", ctx); + return 1; +} + +/* module table */ +static const luaL_reg R[] = { + {"tls", nixio_tls_ctx}, + {NULL, NULL} +}; + +/* ctx function table */ +static const luaL_reg CTX_M[] = { + {"set_cert", nixio_tls_ctx_set_cert}, + {"set_key", nixio_tls_ctx_set_key}, + {"set_ciphers", nixio_tls_ctx_set_ciphers}, + {"set_verify_depth", nixio_tls_ctx_set_verify_depth}, + {"set_verify", nixio_tls_ctx_set_verify}, + {"create", nixio_tls_ctx_create}, + {"__gc", nixio_tls_ctx__gc}, + {"__tostring", nixio_tls_ctx__tostring}, + {NULL, NULL} +}; + + +void nixio_open_tls_context(lua_State *L) { + /* initialize tls library */ + SSL_load_error_strings(); + SSL_library_init(); + + /* register module functions */ + luaL_register(L, NULL, R); + + /* create context metatable */ + luaL_newmetatable(L, NIXIO_TLS_CTX_META); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_register(L, NULL, CTX_M); + lua_pop(L, 1); +} diff --git a/libs/nixio/src/tls-socket.c b/libs/nixio/src/tls-socket.c new file mode 100644 index 000000000..a305518cd --- /dev/null +++ b/libs/nixio/src/tls-socket.c @@ -0,0 +1,196 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include "string.h" + +#ifndef WITHOUT_OPENSSL +#include <openssl/ssl.h> +#endif + +static int nixio__tls_sock_perror(lua_State *L, SSL *sock, int code) { + lua_pushnil(L); + lua_pushinteger(L, code); + lua_pushinteger(L, SSL_get_error(sock, code)); + return 3; +} + +static int nixio__tls_sock_pstatus(lua_State *L, SSL *sock, int code) { + if (code == 1) { + lua_pushboolean(L, 1); + return 1; + } else { + return nixio__tls_sock_perror(L, sock, code); + } +} + +static SSL* nixio__checktlssock(lua_State *L) { + SSL **sock = (SSL **)luaL_checkudata(L, 1, NIXIO_TLS_SOCK_META); + luaL_argcheck(L, *sock, 1, "invalid context"); + return *sock; +} + +static int nixio_tls_sock_recv(lua_State *L) { + SSL *sock = nixio__checktlssock(L); + int req = luaL_checkinteger(L, 2); + + luaL_argcheck(L, req >= 0, 2, "out of range"); + + /* We limit the readsize to NIXIO_BUFFERSIZE */ + req = (req > NIXIO_BUFFERSIZE) ? NIXIO_BUFFERSIZE : req; +#ifndef WITH_AXTLS + char buffer[NIXIO_BUFFERSIZE]; + int readc = SSL_read(sock, buffer, req); + + if (readc < 0) { + return nixio__tls_sock_pstatus(L, sock, readc); + } else { + lua_pushlstring(L, buffer, readc); + return 1; + } +#else + if (!req) { + lua_pushliteral(L, ""); + return 1; + } + + /* AXTLS doesn't handle buffering for us, so we have to hack around*/ + int buflen = 0; + lua_getmetatable(L, 1); + lua_getfield(L, -1, "_axbuffer"); + + if (lua_isstring(L, -1)) { + buflen = lua_objlen(L, -1); + } + + if (req < buflen) { + const char *axbuf = lua_tostring(L, -1); + lua_pushlstring(L, axbuf, req); + lua_pushlstring(L, axbuf + req, buflen - req); + lua_setfield(L, -4, "_axbuffer"); + return 1; + } else { + if (!lua_isstring(L, -1)) { + lua_pop(L, 1); + lua_pushliteral(L, ""); + } + + char *axbuf; + int axread; + + /* while handshake pending */ + while ((axread = ssl_read(sock, (uint8_t**)&axbuf)) == SSL_OK); + + if (axread < 0) { + /* There is an error */ + + if (axread != SSL_ERROR_CONN_LOST) { + lua_pushliteral(L, ""); + lua_setfield(L, -3, "_axbuffer"); + return nixio__tls_sock_perror(L, sock, axread); + } else { + lua_pushliteral(L, ""); + } + } else { + int stillwant = req - buflen; + if (stillwant < axread) { + /* we got more data than we need */ + lua_pushlstring(L, axbuf, stillwant); + lua_concat(L, 2); + + /* remaining data goes into the buffer */ + lua_pushlstring(L, axbuf + stillwant, axread - stillwant); + } else { + lua_pushlstring(L, axbuf, axread); + lua_concat(L, 2); + lua_pushliteral(L, ""); + } + } + lua_setfield(L, -3, "_axbuffer"); + return 1; + } + +#endif +} + +static int nixio_tls_sock_send(lua_State *L) { + SSL *sock = nixio__checktlssock(L); + size_t len; + ssize_t sent; + const char *data = luaL_checklstring(L, 2, &len); + sent = SSL_write(sock, data, len); + if (sent > 0) { + lua_pushinteger(L, sent); + return 1; + } else { + return nixio__tls_sock_pstatus(L, sock, len); + } +} + +static int nixio_tls_sock_accept(lua_State *L) { + SSL *sock = nixio__checktlssock(L); + return nixio__tls_sock_pstatus(L, sock, SSL_accept(sock)); +} + +static int nixio_tls_sock_connect(lua_State *L) { + SSL *sock = nixio__checktlssock(L); + return nixio__tls_sock_pstatus(L, sock, SSL_connect(sock)); +} + +static int nixio_tls_sock_shutdown(lua_State *L) { + SSL *sock = nixio__checktlssock(L); + return nixio__tls_sock_pstatus(L, sock, SSL_shutdown(sock)); +} + +static int nixio_tls_sock__gc(lua_State *L) { + SSL **sock = (SSL **)luaL_checkudata(L, 1, NIXIO_TLS_SOCK_META); + if (*sock) { + SSL_free(*sock); + *sock = NULL; + } + return 0; +} + +static int nixio_tls_sock__tostring(lua_State *L) { + SSL *sock = nixio__checktlssock(L); + lua_pushfstring(L, "nixio TLS socket: %p", sock); + return 1; +} + + +/* ctx function table */ +static const luaL_reg M[] = { + {"recv", nixio_tls_sock_recv}, + {"send", nixio_tls_sock_send}, + {"accept", nixio_tls_sock_accept}, + {"connect", nixio_tls_sock_connect}, + {"shutdown", nixio_tls_sock_shutdown}, + {"__gc", nixio_tls_sock__gc}, + {"__tostring", nixio_tls_sock__tostring}, + {NULL, NULL} +}; + + +void nixio_open_tls_socket(lua_State *L) { + /* create socket metatable */ + luaL_newmetatable(L, NIXIO_TLS_SOCK_META); + luaL_register(L, NULL, M); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + lua_setfield(L, -2, "tls_socket_meta"); +} |