| 1 | /* |
|---|
| 2 | * nixio - Linux I/O library for lua |
|---|
| 3 | * |
|---|
| 4 | * Copyright (C) 2009 Steven Barth <steven@midlink.org> |
|---|
| 5 | * |
|---|
| 6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
|---|
| 7 | * you may not use this file except in compliance with the License. |
|---|
| 8 | * You may obtain a copy of the License at |
|---|
| 9 | * |
|---|
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
|---|
| 11 | * |
|---|
| 12 | * Unless required by applicable law or agreed to in writing, software |
|---|
| 13 | * distributed under the License is distributed on an "AS IS" BASIS, |
|---|
| 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|---|
| 15 | * See the License for the specific language governing permissions and |
|---|
| 16 | * limitations under the License. |
|---|
| 17 | */ |
|---|
| 18 | |
|---|
| 19 | #include "nixio-tls.h" |
|---|
| 20 | #include <string.h> |
|---|
| 21 | |
|---|
| 22 | static SSL_CTX* nixio__checktlsctx(lua_State *L) { |
|---|
| 23 | SSL_CTX **ctx = (SSL_CTX **)luaL_checkudata(L, 1, NIXIO_TLS_CTX_META); |
|---|
| 24 | luaL_argcheck(L, *ctx, 1, "invalid context"); |
|---|
| 25 | return *ctx; |
|---|
| 26 | } |
|---|
| 27 | |
|---|
| 28 | static int nixio__tls_perror(lua_State *L, int code) { |
|---|
| 29 | lua_pushnil(L); |
|---|
| 30 | lua_pushinteger(L, code); |
|---|
| 31 | return 2; |
|---|
| 32 | } |
|---|
| 33 | |
|---|
| 34 | static int nixio__tls_pstatus(lua_State *L, int code) { |
|---|
| 35 | if (code == 1) { |
|---|
| 36 | lua_pushboolean(L, 1); |
|---|
| 37 | return 1; |
|---|
| 38 | } else { |
|---|
| 39 | return nixio__tls_perror(L, code); |
|---|
| 40 | } |
|---|
| 41 | } |
|---|
| 42 | |
|---|
| 43 | static int nixio_tls_ctx(lua_State * L) { |
|---|
| 44 | const char *method = luaL_optlstring(L, 1, "tlsv1", NULL); |
|---|
| 45 | |
|---|
| 46 | SSL_CTX **ctx = lua_newuserdata(L, sizeof(SSL_CTX *)); |
|---|
| 47 | if (!ctx) { |
|---|
| 48 | return luaL_error(L, "out of memory"); |
|---|
| 49 | } |
|---|
| 50 | |
|---|
| 51 | /* create userdata */ |
|---|
| 52 | luaL_getmetatable(L, NIXIO_TLS_CTX_META); |
|---|
| 53 | lua_setmetatable(L, -2); |
|---|
| 54 | |
|---|
| 55 | if (!strcmp(method, "tlsv1")) { |
|---|
| 56 | *ctx = SSL_CTX_new(TLSv1_method()); |
|---|
| 57 | } else if (!strcmp(method, "sslv23")) { |
|---|
| 58 | *ctx = SSL_CTX_new(SSLv23_method()); |
|---|
| 59 | } else { |
|---|
| 60 | return luaL_argerror(L, 1, "supported values: tlsv1, sslv23"); |
|---|
| 61 | } |
|---|
| 62 | |
|---|
| 63 | |
|---|
| 64 | SSL_CTX_set_options(*ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); |
|---|
| 65 | |
|---|
| 66 | if (!(*ctx)) { |
|---|
| 67 | return luaL_error(L, "unable to create TLS context"); |
|---|
| 68 | } |
|---|
| 69 | |
|---|
| 70 | return 1; |
|---|
| 71 | } |
|---|
| 72 | |
|---|
| 73 | static int nixio_tls_ctx_create(lua_State *L) { |
|---|
| 74 | SSL_CTX *ctx = nixio__checktlsctx(L); |
|---|
| 75 | int fd = nixio__checkfd(L, 2); |
|---|
| 76 | |
|---|
| 77 | lua_createtable(L, 0, 3); |
|---|
| 78 | nixio_tls_sock *sock = lua_newuserdata(L, sizeof(nixio_tls_sock)); |
|---|
| 79 | if (!sock) { |
|---|
| 80 | return luaL_error(L, "out of memory"); |
|---|
| 81 | } |
|---|
| 82 | memset(sock, 0, sizeof(nixio_tls_sock)); |
|---|
| 83 | |
|---|
| 84 | /* create userdata */ |
|---|
| 85 | luaL_getmetatable(L, NIXIO_TLS_SOCK_META); |
|---|
| 86 | lua_pushvalue(L, -1); |
|---|
| 87 | lua_setmetatable(L, -3); |
|---|
| 88 | |
|---|
| 89 | sock->socket = SSL_new(ctx); |
|---|
| 90 | if (!sock->socket) { |
|---|
| 91 | return nixio__tls_perror(L, 0); |
|---|
| 92 | } |
|---|
| 93 | |
|---|
| 94 | if (SSL_set_fd(sock->socket, fd) != 1) { |
|---|
| 95 | return nixio__tls_perror(L, 0); |
|---|
| 96 | } |
|---|
| 97 | |
|---|
| 98 | /* save context and socket to prevent GC from collecting them */ |
|---|
| 99 | lua_setmetatable(L, -3); |
|---|
| 100 | lua_setfield(L, -2, "connection"); |
|---|
| 101 | |
|---|
| 102 | lua_pushvalue(L, 1); |
|---|
| 103 | lua_setfield(L, -2, "context"); |
|---|
| 104 | |
|---|
| 105 | lua_pushvalue(L, 2); |
|---|
| 106 | lua_setfield(L, -2, "socket"); |
|---|
| 107 | |
|---|
| 108 | return 1; |
|---|
| 109 | } |
|---|
| 110 | |
|---|
| 111 | static int nixio_tls_ctx_set_cert(lua_State *L) { |
|---|
| 112 | SSL_CTX *ctx = nixio__checktlsctx(L); |
|---|
| 113 | const char *cert = luaL_checkstring(L, 2); |
|---|
| 114 | return nixio__tls_pstatus(L, SSL_CTX_use_certificate_chain_file(ctx, cert)); |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | static int nixio_tls_ctx_set_key(lua_State *L) { |
|---|
| 118 | SSL_CTX *ctx = nixio__checktlsctx(L); |
|---|
| 119 | const char *cert = luaL_checkstring(L, 2); |
|---|
| 120 | const int ktype = SSL_FILETYPE_PEM; |
|---|
| 121 | return nixio__tls_pstatus(L, SSL_CTX_use_PrivateKey_file(ctx, cert, ktype)); |
|---|
| 122 | } |
|---|
| 123 | |
|---|
| 124 | static int nixio_tls_ctx_set_ciphers(lua_State *L) { |
|---|
| 125 | SSL_CTX *ctx = nixio__checktlsctx(L); |
|---|
| 126 | size_t len; |
|---|
| 127 | const char *ciphers = luaL_checklstring(L, 2, &len); |
|---|
| 128 | luaL_argcheck(L, len < 255, 2, "cipher string too long"); |
|---|
| 129 | return nixio__tls_pstatus(L, SSL_CTX_set_cipher_list(ctx, ciphers)); |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | static int nixio_tls_ctx_set_verify_depth(lua_State *L) { |
|---|
| 133 | SSL_CTX *ctx = nixio__checktlsctx(L); |
|---|
| 134 | const int depth = luaL_checkinteger(L, 2); |
|---|
| 135 | SSL_CTX_set_verify_depth(ctx, depth); |
|---|
| 136 | return 0; |
|---|
| 137 | } |
|---|
| 138 | |
|---|
| 139 | static int nixio_tls_ctx_set_verify(lua_State *L) { |
|---|
| 140 | SSL_CTX *ctx = nixio__checktlsctx(L); |
|---|
| 141 | const int j = lua_gettop(L); |
|---|
| 142 | int flags = 0; |
|---|
| 143 | for (int i=2; i<=j; i++) { |
|---|
| 144 | const char *flag = luaL_checkstring(L, i); |
|---|
| 145 | if (!strcmp(flag, "none")) { |
|---|
| 146 | flags |= SSL_VERIFY_NONE; |
|---|
| 147 | } else if (!strcmp(flag, "peer")) { |
|---|
| 148 | flags |= SSL_VERIFY_PEER; |
|---|
| 149 | } else if (!strcmp(flag, "verify_fail_if_no_peer_cert")) { |
|---|
| 150 | flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; |
|---|
| 151 | } else if (!strcmp(flag, "client_once")) { |
|---|
| 152 | flags |= SSL_VERIFY_CLIENT_ONCE; |
|---|
| 153 | } else { |
|---|
| 154 | return luaL_argerror(L, i, "supported values: none, peer, " |
|---|
| 155 | "verify_fail_if_no_peer_cert, client_once"); |
|---|
| 156 | } |
|---|
| 157 | } |
|---|
| 158 | SSL_CTX_set_verify(ctx, flags, NULL); |
|---|
| 159 | return 0; |
|---|
| 160 | } |
|---|
| 161 | |
|---|
| 162 | static int nixio_tls_ctx__gc(lua_State *L) { |
|---|
| 163 | SSL_CTX **ctx = (SSL_CTX **)luaL_checkudata(L, 1, NIXIO_TLS_CTX_META); |
|---|
| 164 | if (*ctx) { |
|---|
| 165 | SSL_CTX_free(*ctx); |
|---|
| 166 | *ctx = NULL; |
|---|
| 167 | } |
|---|
| 168 | return 0; |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | static int nixio_tls_ctx__tostring(lua_State *L) { |
|---|
| 172 | SSL_CTX *ctx = nixio__checktlsctx(L); |
|---|
| 173 | lua_pushfstring(L, "nixio TLS context: %p", ctx); |
|---|
| 174 | return 1; |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | /* module table */ |
|---|
| 178 | static const luaL_reg R[] = { |
|---|
| 179 | {"tls", nixio_tls_ctx}, |
|---|
| 180 | {NULL, NULL} |
|---|
| 181 | }; |
|---|
| 182 | |
|---|
| 183 | /* ctx function table */ |
|---|
| 184 | static const luaL_reg CTX_M[] = { |
|---|
| 185 | {"set_cert", nixio_tls_ctx_set_cert}, |
|---|
| 186 | {"set_key", nixio_tls_ctx_set_key}, |
|---|
| 187 | {"set_ciphers", nixio_tls_ctx_set_ciphers}, |
|---|
| 188 | {"set_verify_depth", nixio_tls_ctx_set_verify_depth}, |
|---|
| 189 | {"set_verify", nixio_tls_ctx_set_verify}, |
|---|
| 190 | {"create", nixio_tls_ctx_create}, |
|---|
| 191 | {"__gc", nixio_tls_ctx__gc}, |
|---|
| 192 | {"__tostring", nixio_tls_ctx__tostring}, |
|---|
| 193 | {NULL, NULL} |
|---|
| 194 | }; |
|---|
| 195 | |
|---|
| 196 | |
|---|
| 197 | void nixio_open_tls_context(lua_State *L) { |
|---|
| 198 | /* initialize tls library */ |
|---|
| 199 | SSL_load_error_strings(); |
|---|
| 200 | SSL_library_init(); |
|---|
| 201 | |
|---|
| 202 | /* register module functions */ |
|---|
| 203 | luaL_register(L, NULL, R); |
|---|
| 204 | |
|---|
| 205 | /* create context metatable */ |
|---|
| 206 | luaL_newmetatable(L, NIXIO_TLS_CTX_META); |
|---|
| 207 | lua_pushvalue(L, -1); |
|---|
| 208 | lua_setfield(L, -2, "__index"); |
|---|
| 209 | luaL_register(L, NULL, CTX_M); |
|---|
| 210 | lua_pop(L, 1); |
|---|
| 211 | } |
|---|