├── LICENSE ├── README.md ├── S2NConfig.lua ├── S2NConnection.lua ├── api └── s2n_ffi.lua ├── crypto ├── s2n_hash.lua └── s2n_hmac.lua ├── error └── s2n_errno.lua ├── examples ├── echo.lua ├── s2nc.lua └── s2nd.lua ├── s2n.lua ├── stuffer └── s2n_stuffer.lua ├── testy ├── s2n_testlib.lua ├── test_s2n_blob.lua ├── test_s2n_ffi.lua ├── test_s2nconnection.lua └── test_stuffer.lua ├── tls ├── s2n_alerts.lua ├── s2n_connection.lua ├── s2n_record.lua └── s2n_tls.lua └── utils ├── s2n_blob.lua ├── s2n_mem.lua └── s2n_safety.lua /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 William Adams 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A LuaJIT binding to the s2n TLS library 2 | 3 | 4 | If you want to use the binding as if you were programming in 5 | C, then, the only file that is actually needed is: api/s2n_ffi.lua 6 | 7 | This will give you the raw API functions of the s2n library. 8 | 9 | If you want more of a Lua feel, then you'll want to use the 10 | s2n.lua file, wich will over time contain various 'class' constructs 11 | which are more convenient to use. 12 | 13 | This binding is a work in progress, and only the core API is effective 14 | at the moment. 15 | 16 | The S2NConnection object is fairly complex, but will be more complete 17 | once the Configuration object is finished as well. 18 | 19 | 20 | -------------------------------------------------------------------------------- /S2NConfig.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local s2n_api = require("api.s2n_ffi") 3 | 4 | local S2NConfig = {} 5 | setmetatable(S2Config, { 6 | __call = function(self, ...) 7 | return self:new(...); 8 | end, 9 | }) 10 | local S2Config_mt = { 11 | __index = S2Config 12 | } 13 | 14 | function S2NConfig.init(self, ...) 15 | local obj = { 16 | 17 | } 18 | setmetatable(obj, S2Config_mt); 19 | 20 | return obj; 21 | end 22 | 23 | function S2NConfig.new(self, ...) 24 | local handle = s2n_api.s2n_config_new(); 25 | if handle == nil then 26 | return nil 27 | end 28 | 29 | -- What to call if the handle goes out of scope 30 | ffi.gc(handle, s2n_api.s2n_config_free); 31 | 32 | return self:init(handle); 33 | end 34 | 35 | -- char * cert_chain_pem 36 | -- char * private_key_pem 37 | function S2Config.addCertChainAndKey(self, cert_chain_pem, private_key_pem) 38 | -- need to hold onto these so they're not 39 | -- garbage collected too early? 40 | self.cert_chain_pem = cert_chain_pem; 41 | self.private_key_pem = private_key_pem; 42 | 43 | local err = s2n_api.s2n_config_add_cert_chain_and_key(self.Handle, 44 | cert_chain_pem, private_key_pem); 45 | 46 | if err < 0 then 47 | return false, s2n_api.s2n_strerror(); 48 | end 49 | 50 | return true; 51 | end 52 | 53 | function S2Config.addDhParams(self, dhparams_pem) 54 | local err = s2n_api.s2n_config_add_dhparams(self.Handle, dhparams_pem) 55 | 56 | if err < 0 then 57 | return false, s2n_api.s2n_strerror(); 58 | end 59 | 60 | return true; 61 | end 62 | 63 | --[[ 64 | extern int s2n_config_free_dhparams(struct s2n_config *config); 65 | extern int s2n_config_free_cert_chain_and_key(struct s2n_config *config); 66 | extern int s2n_config_add_cert_chain_and_key_with_status(struct s2n_config *config, 67 | char *cert_chain_pem, char *private_key_pem, const uint8_t *status, uint32_t length); 68 | 69 | extern int s2n_config_set_key_exchange_preferences(struct s2n_config *config, const char *preferences); 70 | extern int s2n_config_set_cipher_preferences(struct s2n_config *config, const char *version); 71 | extern int s2n_config_set_protocol_preferences(struct s2n_config *config, const char * const *protocols, int protocol_count); 72 | 73 | extern int s2n_config_set_status_request_type(struct s2n_config *config, s2n_status_request_type type); 74 | --]] 75 | 76 | return S2NConfig; 77 | -------------------------------------------------------------------------------- /S2NConnection.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local s2n_api = require("api.s2n_ffi") 3 | 4 | --[[ 5 | connection object 6 | --]] 7 | local S2NConnection = {} 8 | setmetatable(S2NConnection, { 9 | __call = function(self, ...) 10 | return self:new(...); 11 | end, 12 | }) 13 | 14 | local S2NConnection_mt = { 15 | __index = S2NConnection; 16 | } 17 | 18 | function S2NConnection.init(self, handle) 19 | local obj = { 20 | Handle = handle; 21 | } 22 | setmetatable(obj, S2NConnection_mt); 23 | 24 | return obj; 25 | end 26 | 27 | function S2NConnection.new(self, mode) 28 | mode = mode or s2n_api.S2N_SERVER 29 | local handle = s2n_api.s2n_connection_new(mode) 30 | 31 | if handle == nil then 32 | return nil 33 | end 34 | 35 | -- what to call when handle goes out of scope 36 | ffi.gc(handle, s2n_api.s2n_connection_free); 37 | 38 | return self:init(handle); 39 | end 40 | 41 | function S2NConnection.applicationProtocol(self) 42 | local str = s2n_api.s2n_get_application_protocol(self.Handle); 43 | if str == nil then 44 | return false, s2n_api.s2n_strerror(); 45 | end 46 | 47 | return ffi.string(str); 48 | end 49 | 50 | function S2NConnection.blinding(self, value) 51 | blinding = blinding or s2n_api.S2N_BUILT_IN_BLINDING; 52 | local err = s2n_api.s2n_connection_set_blinding(self.Handle, blinding); 53 | 54 | if err < 0 then 55 | return false, s2n_api.s2n_strerror(); 56 | end 57 | 58 | return true; 59 | end 60 | 61 | -- set the configuration for the connection 62 | function S2NConnection.config(self, value) 63 | end 64 | 65 | function S2NConnection.delay(self) 66 | local delay = s2n_api.s2n_connection_get_delay(self.Handle); 67 | if delay < 0 then 68 | return false, s2n_api.s2n_strerror(); 69 | end 70 | 71 | return delay; 72 | end 73 | 74 | -- negotiate the handshake/connection 75 | function S2NConnection.negotiate(self) 76 | local more = ffi.new("int[1]"); 77 | 78 | repeat 79 | local err = s2n_api.s2n_negotiate(self.Handle, more); 80 | if err < 0 then 81 | return false, s2n_api.s2n_strerror(); 82 | end 83 | until more[0] == 0; 84 | 85 | return true; 86 | end 87 | 88 | -- get or set the server name 89 | function S2NConnection.serverName(self, value) 90 | if not value then 91 | -- get server name 92 | local server_name = s2n_api.s2n_get_server_name(self.Handle); 93 | if server_name == nil then 94 | return false, s2n_api.s2n_strerror(); 95 | end 96 | 97 | return ffi.string(server_name); 98 | end 99 | 100 | -- set server name 101 | local err = s2n_api.s2n_set_server_name(self.Handle, value); 102 | if err < 0 then 103 | return false, s2n_api.s2n_strerror(); 104 | end 105 | end 106 | 107 | function S2NConnection.receive(self, buff, size) 108 | local buffPtr = ffi.cast("uint8_t *", buff) 109 | 110 | local more = ffi.new("int[1]") 111 | local bytes_read = 0; 112 | 113 | repeat 114 | local received = s2n_api.s2n_recv(self.Handle, buffPtr+bytes_read, size-bytes_read, more); 115 | if received < 0 then 116 | return false, s2n_api.s2n_strerror(); 117 | end 118 | bytes_read = bytes_read + received; 119 | until more[0] == 0 or bytes_read >= size 120 | 121 | return true; 122 | end 123 | 124 | function S2NConnection.send(self, buff, size) 125 | local buffPtr = ffi.cast("uint8_t *", buff) 126 | local more = ffi.new("int[1]") 127 | local bytes_sent = 0; 128 | 129 | repeat 130 | local sent = s2n_api.s2n_send(self.Handle, buffPtr+bytes_sent, size-bytes_sent, more); 131 | if sent < 0 then 132 | return false, s2n_api.s2n_strerror(); 133 | end 134 | bytes_sent = bytes_sent + sent; 135 | until more[0] == 0 or bytes_sent >= size 136 | 137 | return true; 138 | end 139 | 140 | -- shutdown the connection object 141 | function S2NConnection.shutdown(self) 142 | local more = ffi.new("int[1]") 143 | 144 | repeat 145 | local err = s2n_api.s2n_shutdown(self.Handle, more); 146 | 147 | if err < 0 then 148 | return false, s2n_api.s2n_strerror(); 149 | end 150 | until more[0] == 0 151 | 152 | return true; 153 | end 154 | 155 | -- Wipe the connection object before reusing it 156 | -- on another connection 157 | function S2NConnection.wipe(self) 158 | local err = s2n_api.s2n_connection_wipe(self.Handle); 159 | if err < 0 then 160 | return false, s2n_api.s2n_strerror(); 161 | end 162 | 163 | return true; 164 | end 165 | 166 | -- Set the file descriptor for both reading and writing 167 | function S2NConnection.fileDescriptor(self, fd) 168 | local err = s2n_api.s2n_connection_set_fd(self.Handle, fd); 169 | 170 | if err < 0 then 171 | return false, s2n_api.s2n_strerror(); 172 | end 173 | 174 | return true; 175 | end 176 | 177 | -- Set the file descriptor that will be written to 178 | function S2NConnection.writingDescriptor(self, fd) 179 | local err = s2n_api.s2n_connection_set_write_fd(self.Handle, fd); 180 | 181 | if err < 0 then 182 | return false, s2n_api.s2n_strerror(); 183 | end 184 | 185 | return true; 186 | end 187 | 188 | -- Set the file descriptor that will be read from 189 | function S2NConnection.readingDescriptor(self, fd) 190 | local err = s2n_api.s2n_connection_set_read_fd(self.Handle, fd); 191 | 192 | if err < 0 then 193 | return false, s2n_api.s2n_strerror(); 194 | end 195 | 196 | return true; 197 | end 198 | 199 | -- total number of bytes on the wire coming in 200 | function S2NConnection.wireBytesIn(self) 201 | return tonumber(s2n_api.s2n_connection_get_wire_bytes_in(self.Handle)); 202 | end 203 | 204 | -- total number of bytes on the wire going out 205 | function S2NConnection.wireBytesOut(self) 206 | return tonumber(s2n_api.s2n_connection_get_wire_bytes_out(self.Handle)); 207 | end 208 | 209 | function S2NConnection.clientHelloVersion(self) 210 | local ver = s2n_api.s2n_connection_get_client_hello_version(self.Handle); 211 | if ver < 0 then 212 | return false, s2n_api.s2n_strerror(); 213 | end 214 | 215 | return ver; 216 | end 217 | 218 | function S2NConnection.clientProtocolVersion(self) 219 | local ver = s2n_api.s2n_connection_get_client_protocol_version(self.Handle); 220 | if ver < 0 then 221 | return false, s2n_api.s2n_strerror(); 222 | end 223 | 224 | return ver; 225 | end 226 | 227 | function S2NConnection.serverProtocolVersion(self) 228 | local ver = s2n_api.s2n_connection_get_server_protocol_version(self.Handle); 229 | if ver < 0 then 230 | return false, s2n_api.s2n_strerror(); 231 | end 232 | 233 | return ver; 234 | end 235 | 236 | function S2NConnection.actualProtocolVersion(self) 237 | local ver = s2n_api.s2n_connection_get_actual_protocol_version(self.Handle); 238 | if ver < 0 then 239 | return false, s2n_api.s2n_strerror(); 240 | end 241 | 242 | return ver; 243 | end 244 | 245 | --[[ 246 | extern const uint8_t *s2n_connection_get_ocsp_response(struct s2n_connection *conn, uint32_t *length); 247 | 248 | extern const char *s2n_connection_get_cipher(struct s2n_connection *conn); 249 | extern int s2n_connection_get_alert(struct s2n_connection *conn); 250 | --]] 251 | 252 | return S2NConnection 253 | -------------------------------------------------------------------------------- /api/s2n_ffi.lua: -------------------------------------------------------------------------------- 1 | 2 | local ffi = require("ffi") 3 | 4 | local Lib_ssl = ffi.load("ssl", true) 5 | local Lib_s2n = ffi.load("s2n", true) 6 | 7 | local S2N_SSLv2 = 20; 8 | local S2N_SSLv3 = 30; 9 | local S2N_TLS10 = 31; 10 | local S2N_TLS11 = 32; 11 | local S2N_TLS12 = 33; 12 | 13 | 14 | ffi.cdef[[ 15 | typedef intptr_t ssize_t; 16 | 17 | extern int s2n_errno; 18 | struct s2n_config; 19 | 20 | extern int s2n_init(); 21 | extern int s2n_cleanup(); 22 | extern struct s2n_config *s2n_config_new(); 23 | extern int s2n_config_free(struct s2n_config *config); 24 | extern int s2n_config_free_dhparams(struct s2n_config *config); 25 | extern int s2n_config_free_cert_chain_and_key(struct s2n_config *config); 26 | extern const char *s2n_strerror(int error, const char *lang); 27 | 28 | extern int s2n_config_add_cert_chain_and_key(struct s2n_config *config, char *cert_chain_pem, char *private_key_pem); 29 | extern int s2n_config_add_cert_chain_and_key_with_status(struct s2n_config *config, 30 | char *cert_chain_pem, char *private_key_pem, const uint8_t *status, uint32_t length); 31 | extern int s2n_config_add_dhparams(struct s2n_config *config, char *dhparams_pem); 32 | extern int s2n_config_set_key_exchange_preferences(struct s2n_config *config, const char *preferences); 33 | extern int s2n_config_set_cipher_preferences(struct s2n_config *config, const char *version); 34 | extern int s2n_config_set_protocol_preferences(struct s2n_config *config, const char * const *protocols, int protocol_count); 35 | 36 | typedef enum { 37 | S2N_STATUS_REQUEST_NONE = 0, 38 | S2N_STATUS_REQUEST_OCSP = 1 39 | } s2n_status_request_type; 40 | 41 | extern int s2n_config_set_status_request_type(struct s2n_config *config, s2n_status_request_type type); 42 | 43 | struct s2n_connection; 44 | 45 | typedef enum { 46 | S2N_SERVER, 47 | S2N_CLIENT 48 | } s2n_mode; 49 | 50 | extern struct s2n_connection *s2n_connection_new(s2n_mode mode); 51 | extern int s2n_connection_set_config(struct s2n_connection *conn, struct s2n_config *config); 52 | 53 | extern int s2n_connection_set_fd(struct s2n_connection *conn, int readfd); 54 | extern int s2n_connection_set_read_fd(struct s2n_connection *conn, int readfd); 55 | extern int s2n_connection_set_write_fd(struct s2n_connection *conn, int readfd); 56 | 57 | typedef enum { 58 | S2N_BUILT_IN_BLINDING, 59 | S2N_SELF_SERVICE_BLINDING 60 | } s2n_blinding; 61 | 62 | extern int s2n_connection_set_blinding(struct s2n_connection *conn, s2n_blinding blinding); 63 | extern int s2n_connection_get_delay(struct s2n_connection *conn); 64 | 65 | extern int s2n_set_server_name(struct s2n_connection *conn, const char *server_name); 66 | extern const char *s2n_get_server_name(struct s2n_connection *conn); 67 | extern const char *s2n_get_application_protocol(struct s2n_connection *conn); 68 | extern const uint8_t *s2n_connection_get_ocsp_response(struct s2n_connection *conn, uint32_t *length); 69 | 70 | extern int s2n_negotiate(struct s2n_connection *conn, int *more); 71 | extern ssize_t s2n_send(struct s2n_connection *conn, void *buf, ssize_t size, int *more); 72 | extern ssize_t s2n_recv(struct s2n_connection *conn, void *buf, ssize_t size, int *more); 73 | extern int s2n_shutdown(struct s2n_connection *conn, int *more); 74 | 75 | extern int s2n_connection_wipe(struct s2n_connection *conn); 76 | extern int s2n_connection_free(struct s2n_connection *conn); 77 | //extern int s2n_shutdown(struct s2n_connection *conn, int *more); 78 | 79 | extern uint64_t s2n_connection_get_wire_bytes_in(struct s2n_connection *conn); 80 | extern uint64_t s2n_connection_get_wire_bytes_out(struct s2n_connection *conn); 81 | extern int s2n_connection_get_client_protocol_version(struct s2n_connection *conn); 82 | extern int s2n_connection_get_server_protocol_version(struct s2n_connection *conn); 83 | extern int s2n_connection_get_actual_protocol_version(struct s2n_connection *conn); 84 | extern int s2n_connection_get_client_hello_version(struct s2n_connection *conn); 85 | extern const char *s2n_connection_get_cipher(struct s2n_connection *conn); 86 | extern int s2n_connection_get_alert(struct s2n_connection *conn); 87 | ]] 88 | 89 | local function strerror(errcode) 90 | errcode = errcode or Lib_s2n.s2n_errno; 91 | 92 | local errstr = Lib_s2n.s2n_strerror(errcode, "EN"); 93 | if errstr == nil then 94 | return "UNKNOWN ERROR"; 95 | end 96 | 97 | return ffi.string(errstr); 98 | end 99 | 100 | local exports = { 101 | Lib_s2n = Lib_s2n; 102 | 103 | -- some constants 104 | S2N_SSLv2 = S2N_SSLv2; 105 | S2N_SSLv3 = S2N_SSLv3; 106 | S2N_TLS10 = S2N_TLS10; 107 | S2N_TLS11 = S2N_TLS11; 108 | S2N_TLS12 = S2N_TLS12; 109 | 110 | -- enums 111 | -- s2n_mode 112 | S2N_SERVER = ffi.C.S2N_SERVER; 113 | S2N_CLIENT = ffi.C.S2N_CLIENT; 114 | -- s2n_blinding 115 | S2N_BUILT_IN_BLINDING = ffi.C.S2N_BUILT_IN_BLINDING; 116 | S2N_SELF_SERVICE_BLINDING = ffi.C.S2N_SELF_SERVICE_BLINDING; 117 | 118 | -- library functions 119 | s2n_init = Lib_s2n.s2n_init; 120 | s2n_cleanup = Lib_s2n.s2n_cleanup; 121 | s2n_strerror = strerror; 122 | 123 | s2n_set_server_name = Lib_s2n.s2n_set_server_name; 124 | s2n_get_server_name = Lib_s2n.s2n_get_server_name; 125 | s2n_get_application_protocol = Lib_s2n.s2n_get_application_protocol; 126 | s2n_connection_get_ocsp_response = Lib_s2n.s2n_connection_get_ocsp_response; 127 | 128 | s2n_negotiate = Lib_s2n.s2n_negotiate; 129 | s2n_send = Lib_s2n.s2n_send; 130 | s2n_recv = Lib_s2n.s2n_recv; 131 | s2n_shutdown = Lib_s2n.s2n_shutdown; 132 | 133 | 134 | s2n_config_new = Lib_s2n.s2n_config_new; 135 | s2n_config_free = Lib_s2n.s2n_config_free; 136 | s2n_config_free_dhparams = Lib_s2n.s2n_config_free_dhparams; 137 | s2n_config_free_cert_chain_and_key = Lib_s2n.s2n_config_free_cert_chain_and_key; 138 | s2n_config_add_cert_chain_and_key = Lib_s2n.s2n_config_add_cert_chain_and_key; 139 | s2n_config_add_cert_chain_and_key_with_status = Lib_s2n.s2n_config_add_cert_chain_and_key_with_status; 140 | s2n_config_add_dhparams = Lib_s2n.s2n_config_add_dhparams; 141 | --s2n_config_set_key_exchange_preferences = Lib_s2n.s2n_config_set_key_exchange_preferences; 142 | s2n_config_set_cipher_preferences = Lib_s2n.s2n_config_set_cipher_preferences; 143 | s2n_config_set_protocol_preferences = Lib_s2n.s2n_config_set_protocol_preferences; 144 | s2n_config_set_status_request_type = Lib_s2n.s2n_config_set_status_request_type; 145 | 146 | s2n_connection_new = Lib_s2n.s2n_connection_new; 147 | s2n_connection_set_config = Lib_s2n.s2n_connection_set_config; 148 | s2n_connection_set_fd = Lib_s2n.s2n_connection_set_fd; 149 | s2n_connection_set_read_fd = Lib_s2n.s2n_connection_set_read_fd; 150 | s2n_connection_set_write_fd = Lib_s2n.s2n_connection_set_write_fd; 151 | s2n_connection_set_blinding = Lib_s2n.s2n_connection_set_blinding; 152 | s2n_connection_get_delay = Lib_s2n.s2n_connection_get_delay; 153 | s2n_connection_wipe = Lib_s2n.s2n_connection_wipe; 154 | s2n_connection_free = Lib_s2n.s2n_connection_free; 155 | s2n_connection_get_wire_bytes_in = Lib_s2n.s2n_connection_get_wire_bytes_in; 156 | s2n_connection_get_wire_bytes_out = Lib_s2n.s2n_connection_get_wire_bytes_out; 157 | s2n_connection_get_client_protocol_version = Lib_s2n.s2n_connection_get_client_protocol_version; 158 | s2n_connection_get_server_protocol_version = Lib_s2n.s2n_connection_get_server_protocol_version; 159 | s2n_connection_get_actual_protocol_version = Lib_s2n.s2n_connection_get_actual_protocol_version; 160 | s2n_connection_get_client_hello_version = Lib_s2n.s2n_connection_get_client_hello_version; 161 | s2n_connection_get_cipher = Lib_s2n.s2n_connection_get_cipher; 162 | s2n_connection_get_alert = Lib_s2n.s2n_connection_get_alert; 163 | } 164 | 165 | 166 | Lib_s2n.s2n_init(); 167 | 168 | setmetatable(exports, { 169 | __call = function(self, ...) 170 | for k,v in pairs(exports) do 171 | _G[k] = v; 172 | end 173 | end, 174 | }) 175 | 176 | return exports; 177 | -------------------------------------------------------------------------------- /crypto/s2n_hash.lua: -------------------------------------------------------------------------------- 1 | 2 | local ffi = require("ffi") 3 | 4 | if __APPLE__ and __MACH__ then 5 | --[[ 6 | #define COMMON_DIGEST_FOR_OPENSSL 7 | #include 8 | #define SHA1 CC_SHA1 9 | #define SHA224 CC_SHA224 10 | #define SHA256 CC_SHA256 11 | #define SHA384 CC_SHA384 12 | #define SHA512 CC_SHA512 13 | 14 | #include 15 | #define HMAC CCHmac 16 | --]] 17 | else 18 | --require("openssl.md5") 19 | --require("openssl.sha") 20 | end 21 | 22 | ffi.cdef[[ 23 | typedef enum { 24 | S2N_HASH_NONE, 25 | S2N_HASH_MD5, 26 | S2N_HASH_SHA1, 27 | S2N_HASH_SHA224, 28 | S2N_HASH_SHA256, 29 | S2N_HASH_SHA384, 30 | S2N_HASH_SHA512, 31 | S2N_HASH_MD5_SHA1 32 | } s2n_hash_algorithm; 33 | 34 | struct s2n_hash_state { 35 | s2n_hash_algorithm alg; 36 | union { 37 | MD5_CTX md5; 38 | SHA_CTX sha1; 39 | SHA256_CTX sha224; 40 | SHA256_CTX sha256; 41 | SHA512_CTX sha384; 42 | SHA512_CTX sha512; 43 | struct { 44 | MD5_CTX md5; 45 | SHA_CTX sha1; 46 | } md5_sha1; 47 | } hash_ctx; 48 | }; 49 | 50 | extern int s2n_hash_digest_size(s2n_hash_algorithm alg); 51 | 52 | extern int s2n_hash_init(struct s2n_hash_state *state, s2n_hash_algorithm alg); 53 | extern int s2n_hash_update(struct s2n_hash_state *state, const void *in, uint32_t size); 54 | extern int s2n_hash_digest(struct s2n_hash_state *state, void *out, uint32_t size); 55 | extern int s2n_hash_reset(struct s2n_hash_state *state); 56 | extern int s2n_hash_copy(struct s2n_hash_state *to, struct s2n_hash_state *from); 57 | ]] 58 | 59 | local exports = {} 60 | 61 | return exports 62 | -------------------------------------------------------------------------------- /crypto/s2n_hmac.lua: -------------------------------------------------------------------------------- 1 | 2 | local ffi = require("ffi") 3 | 4 | require("crypto.s2n_hash") 5 | 6 | ffi.cdef[[ 7 | typedef enum { 8 | S2N_HMAC_NONE, 9 | S2N_HMAC_MD5, 10 | S2N_HMAC_SHA1, 11 | S2N_HMAC_SHA224, 12 | S2N_HMAC_SHA256, 13 | S2N_HMAC_SHA384, 14 | S2N_HMAC_SHA512, 15 | S2N_HMAC_SSLv3_MD5, 16 | S2N_HMAC_SSLv3_SHA1 17 | } s2n_hmac_algorithm; 18 | 19 | struct s2n_hmac_state { 20 | s2n_hmac_algorithm alg; 21 | 22 | uint16_t block_size; 23 | uint8_t digest_size; 24 | 25 | struct s2n_hash_state inner; 26 | struct s2n_hash_state inner_just_key; 27 | struct s2n_hash_state outer; 28 | 29 | /* key needs to be as large as the biggest block size */ 30 | uint8_t xor_pad[128]; 31 | 32 | /* For storing the inner digest */ 33 | uint8_t digest_pad[SHA512_DIGEST_LENGTH]; 34 | }; 35 | ]] 36 | 37 | ffi.cdef[[ 38 | extern int s2n_hmac_digest_size(s2n_hmac_algorithm alg); 39 | 40 | extern int s2n_hmac_init(struct s2n_hmac_state *state, s2n_hmac_algorithm alg, const void *key, uint32_t klen); 41 | extern int s2n_hmac_update(struct s2n_hmac_state *state, const void *in, uint32_t size); 42 | extern int s2n_hmac_digest(struct s2n_hmac_state *state, void *out, uint32_t size); 43 | extern int s2n_hmac_digest_verify(const void *a, uint32_t alen, const void *b, uint32_t blen); 44 | extern int s2n_hmac_reset(struct s2n_hmac_state *state); 45 | extern int s2n_hmac_copy(struct s2n_hmac_state *to, struct s2n_hmac_state *from); 46 | ]] 47 | 48 | local exports = {} 49 | 50 | return exports 51 | -------------------------------------------------------------------------------- /error/s2n_errno.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | ffi.cdef[[ 4 | typedef enum { 5 | S2N_ERR_OK] = 6 | S2N_ERR_KEY_INIT] = 7 | S2N_ERR_ENCRYPT] = 8 | S2N_ERR_DECRYPT] = 9 | S2N_ERR_MEMSET] = 10 | S2N_ERR_MEMCPY] = 11 | S2N_ERR_REALLOC] = 12 | S2N_ERR_MLOCK] = 13 | S2N_ERR_FSTAT] = 14 | S2N_ERR_OPEN] = 15 | S2N_ERR_MMAP] = 16 | S2N_ERR_NULL] = 17 | S2N_ERR_CLOSED] = 18 | S2N_ERR_SAFETY] = 19 | S2N_ERR_NOT_INITIALIZED] = 20 | S2N_ERR_RANDOM_UNITIALIZED] = 21 | S2N_ERR_OPEN_RANDOM] = 22 | S2N_ERR_RESIZE_STATIC_STUFFER] = 23 | S2N_ERR_RESIZE_TAINTED_STUFFER] = 24 | S2N_ERR_STUFFER_OUT_OF_DATA] = 25 | S2N_ERR_STUFFER_IS_FULL] = 26 | S2N_ERR_INVALID_BASE64] = 27 | S2N_ERR_INVALID_PEM] = 28 | S2N_ERR_DH_COPYING_PARAMETERS] = 29 | S2N_ERR_DH_COPYING_PUBLIC_KEY] = 30 | S2N_ERR_DH_GENERATING_PARAMETERS] = 31 | S2N_ERR_DH_PARAMS_CREATE] = 32 | S2N_ERR_DH_SERIAZING] = 33 | S2N_ERR_DH_SHARED_SECRET] = 34 | S2N_ERR_DH_WRITING_PUBLIC_KEY] = 35 | S2N_ERR_DH_FAILED_SIGNING] = 36 | S2N_ERR_DH_TOO_SMALL] = 37 | S2N_ERR_INVALID_PKCS3] = 38 | S2N_ERR_HASH_DIGEST_FAILED] = 39 | S2N_ERR_HASH_INIT_FAILED] = 40 | S2N_ERR_HASH_INVALID_ALGORITHM] = 41 | S2N_ERR_HASH_UPDATE_FAILED] = 42 | S2N_ERR_HMAC_INVALID_ALGORITHM] = 43 | S2N_ERR_SIZE_MISMATCH] = 44 | S2N_ERR_DECODE_CERTIFICATE] = 45 | S2N_ERR_DECODE_PRIVATE_KEY] = 46 | S2N_ERR_KEY_MISMATCH] = 47 | S2N_ERR_NOMEM] = 48 | S2N_ERR_SIGN] = 49 | S2N_ERR_VERIFY_SIGNATURE] = 50 | S2N_ERR_ALERT_PRESENT] = 51 | S2N_ERR_ALERT] = 52 | S2N_ERR_CBC_VERIFY] = 53 | S2N_ERR_CIPHER_NOT_SUPPORTED] = 54 | S2N_ERR_BAD_MESSAGE] = 55 | S2N_ERR_INVALID_SIGNATURE_ALGORITHM] = 56 | S2N_ERR_INVALID_KEY_EXCHANGE_ALGORITHM] = 57 | S2N_ERR_NO_CERTIFICATE_IN_PEM] = 58 | S2N_ERR_NO_ALERT] = 59 | S2N_ERR_CLIENT_MODE] = 60 | S2N_ERR_SERVER_NAME_TOO_LONG] = 61 | S2N_ERR_CLIENT_MODE_DISABLED] = 62 | S2N_ERR_HANDSHAKE_STATE] = 63 | S2N_ERR_FALLBACK_DETECTED] = 64 | S2N_ERR_INVALID_CIPHER_PREFERENCES] = 65 | S2N_ERR_APPLICATION_PROTOCOL_TOO_LONG] = 66 | S2N_ERR_NO_APPLICATION_PROTOCOL] = 67 | S2N_ERR_DRBG] = 68 | S2N_ERR_DRBG_REQUEST_SIZE] = 69 | S2N_ERR_ECDHE_GEN_KEY] = 70 | S2N_ERR_ECDHE_SHARED_SECRET] = 71 | S2N_ERR_ECDHE_UNSUPPORTED_CURVE] = 72 | S2N_ERR_ECDHE_SERIALIZING] = 73 | } s2n_error; 74 | ]] 75 | 76 | local errnos = { 77 | [ffi.C.S2N_ERR_OK] = "no error" ; 78 | [ffi.C.S2N_ERR_KEY_INIT] = "error initializing encryption key" ; 79 | [ffi.C.S2N_ERR_ENCRYPT] = "error encrypting data" ; 80 | [ffi.C.S2N_ERR_DECRYPT] = "error decrypting data" ; 81 | [ffi.C.S2N_ERR_MEMSET] = "error calling memset" ; 82 | [ffi.C.S2N_ERR_MEMCPY] = "error calling memcpy" ; 83 | [ffi.C.S2N_ERR_REALLOC] = "error calling realloc" ; 84 | [ffi.C.S2N_ERR_MLOCK] = "error calling mlock" ; 85 | [ffi.C.S2N_ERR_FSTAT] = "error calling fstat" ; 86 | [ffi.C.S2N_ERR_OPEN] = "error calling open" ; 87 | [ffi.C.S2N_ERR_MMAP] = "error calling mmap" ; 88 | [ffi.C.S2N_ERR_NULL] = "NULL pointer encountered" ; 89 | [ffi.C.S2N_ERR_CLOSED] = "connection is closed" ; 90 | [ffi.C.S2N_ERR_SAFETY] = "a safety check failed" ; 91 | [ffi.C.S2N_ERR_NOT_INITIALIZED] = "s2n not initialized" ; 92 | [ffi.C.S2N_ERR_RANDOM_UNITIALIZED] = "s2n enctropy not initialized" ; 93 | [ffi.C.S2N_ERR_OPEN_RANDOM] = "error opening urandom" ; 94 | [ffi.C.S2N_ERR_RESIZE_STATIC_STUFFER] = "cannot resize a static stuffer" ; 95 | [ffi.C.S2N_ERR_RESIZE_TAINTED_STUFFER] = "cannot resize a tainted stuffer" ; 96 | [ffi.C.S2N_ERR_STUFFER_OUT_OF_DATA] = "stuffer is out of data" ; 97 | [ffi.C.S2N_ERR_STUFFER_IS_FULL] = "stuffer is full" ; 98 | [ffi.C.S2N_ERR_INVALID_BASE64] = "invalid base64 encountered" ; 99 | [ffi.C.S2N_ERR_INVALID_PEM] = "invalid PEM encountered" ; 100 | [ffi.C.S2N_ERR_DH_COPYING_PARAMETERS] = "error copying Diffie-Hellman parameters" ; 101 | [ffi.C.S2N_ERR_DH_COPYING_PUBLIC_KEY] = "error copying Diffie-Hellman public key" ; 102 | [ffi.C.S2N_ERR_DH_GENERATING_PARAMETERS] = "error generating Diffie-Hellman parameters" ; 103 | [ffi.C.S2N_ERR_DH_PARAMS_CREATE] = "error creating Diffie-Hellman parameters" ; 104 | [ffi.C.S2N_ERR_DH_SERIAZING] = "error serializing Diffie-Hellman parameters" ; 105 | [ffi.C.S2N_ERR_DH_SHARED_SECRET] = "error computing Diffie-Hellman shared secret" ; 106 | [ffi.C.S2N_ERR_DH_WRITING_PUBLIC_KEY] = "error writing Diffie-Hellman public key" ; 107 | [ffi.C.S2N_ERR_DH_FAILED_SIGNING] = "error signing Diffie-Hellman values" ; 108 | [ffi.C.S2N_ERR_DH_TOO_SMALL] = "Diffie-Hellman parameters are too small" ; 109 | [ffi.C.S2N_ERR_INVALID_PKCS3] = "invalid PKCS3 encountered" ; 110 | [ffi.C.S2N_ERR_HASH_DIGEST_FAILED] = "failed to create hash digest" ; 111 | [ffi.C.S2N_ERR_HASH_INIT_FAILED] = "error initializing hash" ; 112 | [ffi.C.S2N_ERR_HASH_INVALID_ALGORITHM] = "invalid hash algorithm" ; 113 | [ffi.C.S2N_ERR_HASH_UPDATE_FAILED] = "error updating hash" ; 114 | [ffi.C.S2N_ERR_HMAC_INVALID_ALGORITHM] = "invalid HMAC algorithm" ; 115 | [ffi.C.S2N_ERR_SIZE_MISMATCH] = "size mismatch" ; 116 | [ffi.C.S2N_ERR_DECODE_CERTIFICATE] = "error decoding certificate" ; 117 | [ffi.C.S2N_ERR_DECODE_PRIVATE_KEY] = "error decoding private key" ; 118 | [ffi.C.S2N_ERR_KEY_MISMATCH] = "public and private key do not match" ; 119 | [ffi.C.S2N_ERR_NOMEM] = "no memory" ; 120 | [ffi.C.S2N_ERR_SIGN] = "error signing data" ; 121 | [ffi.C.S2N_ERR_VERIFY_SIGNATURE] = "error verifying signature" ; 122 | [ffi.C.S2N_ERR_ALERT_PRESENT] = "TLS alert is already pending" ; 123 | [ffi.C.S2N_ERR_ALERT] = "TLS alert received" ; 124 | [ffi.C.S2N_ERR_CBC_VERIFY] = "Failed CBC verification" ; 125 | [ffi.C.S2N_ERR_CIPHER_NOT_SUPPORTED] = "Cipher is not supported" ; 126 | [ffi.C.S2N_ERR_BAD_MESSAGE] = "Bad message encountered" ; 127 | [ffi.C.S2N_ERR_INVALID_SIGNATURE_ALGORITHM] = "Invalid signature algorithm" ; 128 | [ffi.C.S2N_ERR_INVALID_KEY_EXCHANGE_ALGORITHM] = "Invaid key exchange algorithm" ; 129 | [ffi.C.S2N_ERR_NO_CERTIFICATE_IN_PEM] = "No certificate in PEM" ; 130 | [ffi.C.S2N_ERR_NO_ALERT] = "No Alert present" ; 131 | [ffi.C.S2N_ERR_CLIENT_MODE] = "operation not allowed in client mode" ; 132 | [ffi.C.S2N_ERR_SERVER_NAME_TOO_LONG] = "server name is too long" ; 133 | [ffi.C.S2N_ERR_CLIENT_MODE_DISABLED] = "client connections not allowed" ; 134 | [ffi.C.S2N_ERR_HANDSHAKE_STATE] = "Invalid handshake state encountered" ; 135 | [ffi.C.S2N_ERR_FALLBACK_DETECTED] = "TLS fallback detected" ; 136 | [ffi.C.S2N_ERR_INVALID_CIPHER_PREFERENCES] = "Invalid Cipher Preferences version" ; 137 | [ffi.C.S2N_ERR_APPLICATION_PROTOCOL_TOO_LONG] = "Application protocol name is too long" ; 138 | [ffi.C.S2N_ERR_NO_APPLICATION_PROTOCOL] = "No supported application protocol to negotiate" ; 139 | [ffi.C.S2N_ERR_DRBG] = "Error using Determinstic Random Bit Generator" ; 140 | [ffi.C.S2N_ERR_DRBG_REQUEST_SIZE] = "Request for too much entropy" ; 141 | [ffi.C.S2N_ERR_ECDHE_GEN_KEY] = "Failed to generate an ECDHE key" ; 142 | [ffi.C.S2N_ERR_ECDHE_SHARED_SECRET] = "Error computing ECDHE shared secret" ; 143 | [ffi.C.S2N_ERR_ECDHE_UNSUPPORTED_CURVE] = "Unsupported EC curve was presented during an ECDHE handshake" ; 144 | [ffi.C.S2N_ERR_ECDHE_SERIALIZING] = "Error serializing ECDHE public" ; 145 | } 146 | 147 | local function errnoToString(errno) 148 | return errnos[errno] or "UNKNOWN ERROR: "..tostring(errno); 149 | end 150 | 151 | local exports = { 152 | errnos = errnos; 153 | 154 | -- local functions 155 | errnoToString = errnoToString; 156 | } 157 | 158 | return exports 159 | -------------------------------------------------------------------------------- /examples/echo.lua: -------------------------------------------------------------------------------- 1 | 2 | local ffi = require("ffi") 3 | local bit = require("bit") 4 | local band = bit.band 5 | 6 | local s2n = require("s2n") 7 | 8 | ffi.cdef[[ 9 | struct pollfd { 10 | int fd; /* file descriptor */ 11 | short events; /* requested events */ 12 | short revents; /* returned events */ 13 | }; 14 | ]] 15 | 16 | local POLLIN = 0x0001; 17 | local POLLPRI = 0x0002; 18 | local POLLOUT = 0x0004; 19 | 20 | 21 | local function echo(conn, sockfd) 22 | 23 | 24 | local success, err = conn:negotiate(); 25 | if not success then 26 | error(err, s2n_connection_get_alert(conn)); 27 | end 28 | 29 | -- print some meta information about the connection 30 | print("server name: ", conn:serverName()); 31 | print("app protocol: ", conn:applicationProtocol()) 32 | print("client hello Version: ", conn:clientHelloVersion()) 33 | print("client Version: ", conn:clientProtocolVersion()) 34 | print("server Version: ", conn:serverProtocolVersion()) 35 | print("actual Version: ", conn:actualProtocolVersion()) 36 | 37 | --[[ 38 | uint32_t length; 39 | const uint8_t *status = s2n_connection_get_ocsp_response(conn, &length); 40 | if (status && length > 0) { 41 | fprintf(stderr, "OCSP response received, length %d\n", length); 42 | } 43 | 44 | printf("Cipher negotiated: %s\n", s2n_connection_get_cipher(conn)); 45 | --]] 46 | 47 | -- Act as a simple proxy between stdin and the SSL connection 48 | local readers = ffi.new("struct pollfd[2]") 49 | 50 | readers[0].fd = sockfd; 51 | readers[0].events = POLLIN; 52 | readers[1].fd = STDIN_FILENO; 53 | readers[1].events = POLLIN; 54 | local buffer = ffi.new("char[10240]"); 55 | 56 | while (ffi.C.poll(readers, 2, -1) > 0) do 57 | local bytes_read, bytes_written = 0; 58 | 59 | if band(readers[0].revents, POLLIN) then 60 | repeat 61 | bytes_read = s2n_recv(conn, buffer, 10240, &more); 62 | if (bytes_read == 0) { 63 | /* Connection has been closed */ 64 | s2n_connection_wipe(conn); 65 | return 0; 66 | } 67 | if (bytes_read < 0) { 68 | fprintf(stderr, "Error reading from connection: '%s' %d\n", s2n_strerror(s2n_errno, "EN"), s2n_connection_get_alert(conn)); 69 | exit(1); 70 | } 71 | bytes_written = write(STDOUT_FILENO, buffer, bytes_read); 72 | if (bytes_written <= 0) { 73 | fprintf(stderr, "Error writing to stdout\n"); 74 | exit(1); 75 | } 76 | until (not more); 77 | end 78 | 79 | if band(readers[1].revents, POLLIN) then 80 | local bytes_available; 81 | if (ioctl(STDIN_FILENO, FIONREAD, &bytes_available) < 0) then 82 | bytes_available = 1; 83 | end 84 | 85 | if (bytes_available > sizeof(buffer)) then 86 | bytes_available = sizeof(buffer); 87 | end 88 | 89 | -- Read as many bytes as we think we can 90 | bytes_read = read(STDIN_FILENO, buffer, bytes_available); 91 | if (bytes_read < 0) then 92 | fprintf(stderr, "Error reading from stdin\n"); 93 | error(1); 94 | end 95 | 96 | if (bytes_read == 0) then 97 | -- Exit on EOF 98 | return 0; 99 | end 100 | 101 | local buf_ptr = buffer; 102 | repeat 103 | bytes_written, err = conn:send(buf_ptr, bytes_available, &more); 104 | if (bytes_written < 0) then 105 | fprintf(stderr, "Error writing to connection: '%s'\n", s2n_strerror(s2n_errno, "EN")); 106 | error(1); 107 | end 108 | 109 | bytes_available -= bytes_written; 110 | buf_ptr += bytes_written; 111 | until bytes_available=0 and more[0]==0 112 | end 113 | end 114 | 115 | return 0; 116 | end 117 | 118 | return echo 119 | -------------------------------------------------------------------------------- /examples/s2nc.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | 20 | local function usage() 21 | 22 | fprintf(stderr, "usage: s2nc [options] host [port]\n"); 23 | fprintf(stderr, " host: hostname or IP address to connect to\n"); 24 | fprintf(stderr, " port: port to connect to\n"); 25 | fprintf(stderr, "\n Options:\n\n"); 26 | fprintf(stderr, " -a [protocols]\n"); 27 | fprintf(stderr, " --alpn [protocols]\n"); 28 | fprintf(stderr, " Sets the application protocols supported by this client, as a comma seperated list.\n"); 29 | fprintf(stderr, " -h,--help\n"); 30 | fprintf(stderr, " Display this message and quit.\n"); 31 | fprintf(stderr, " -n [server name]\n"); 32 | fprintf(stderr, " --name [server name]\n"); 33 | fprintf(stderr, " Sets the SNI server name header for this client. If not specified, the host value is used.\n"); 34 | fprintf(stderr, " --s,--status\n"); 35 | fprintf(stderr, " Request the OCSP status of the remote server certificate\n"); 36 | fprintf(stderr, "\n"); 37 | exit(1); 38 | end 39 | 40 | extern int echo(struct s2n_connection *conn, int sockfd); 41 | 42 | int main(int argc, char * const *argv) 43 | { 44 | struct addrinfo hints, *ai_list, *ai; 45 | int r, sockfd = 0; 46 | /* Optional args */ 47 | const char *alpn_protocols = NULL; 48 | const char *server_name = NULL; 49 | s2n_status_request_type type = S2N_STATUS_REQUEST_NONE; 50 | /* required args */ 51 | const char *host = NULL; 52 | const char *port = "443"; 53 | 54 | static struct option long_options[] = { 55 | { "alpn", required_argument, 0, 'a' }, 56 | { "help", no_argument, 0, 'h' }, 57 | { "name", required_argument, 0, 'n' }, 58 | { "status", no_argument, 0, 's' }, 59 | }; 60 | while (1) { 61 | int option_index = 0; 62 | int c = getopt_long (argc, argv, "a:hn:s", long_options, &option_index); 63 | if (c == -1) { 64 | break; 65 | } 66 | switch (c) { 67 | case 'a': 68 | alpn_protocols = optarg; 69 | break; 70 | case 'h': 71 | usage(); 72 | break; 73 | case 'n': 74 | server_name = optarg; 75 | break; 76 | case 's': 77 | type = S2N_STATUS_REQUEST_OCSP; 78 | break; 79 | case '?': 80 | default: 81 | usage(); 82 | break; 83 | } 84 | } 85 | 86 | if (optind < argc) { 87 | host = argv[optind++]; 88 | } 89 | if (optind < argc) { 90 | port = argv[optind++]; 91 | } 92 | 93 | if (!host) { 94 | usage(); 95 | } 96 | 97 | if (!server_name) { 98 | server_name = host; 99 | } 100 | 101 | if (memset(&hints, 0, sizeof(hints)) != &hints) { 102 | fprintf(stderr, "memset error: %s\n", strerror(errno)); 103 | exit(1); 104 | } 105 | 106 | hints.ai_family = AF_UNSPEC; 107 | hints.ai_socktype = SOCK_STREAM; 108 | 109 | if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { 110 | fprintf(stderr, "Error disabling SIGPIPE\n"); 111 | exit(1); 112 | } 113 | 114 | if ((r = getaddrinfo(host, port, &hints, &ai_list)) != 0) { 115 | fprintf(stderr, "error: %s\n", gai_strerror(r)); 116 | exit(1); 117 | } 118 | 119 | int connected = 0; 120 | for (ai = ai_list; ai != NULL; ai = ai->ai_next) { 121 | if ((sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) { 122 | continue; 123 | } 124 | 125 | if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == -1) { 126 | close(sockfd); 127 | continue; 128 | } 129 | 130 | connected = 1; 131 | /* connect() succeeded */ 132 | break; 133 | } 134 | 135 | freeaddrinfo(ai_list); 136 | 137 | if (connected == 0) { 138 | fprintf(stderr, "Failed to connect to %s:%s\n", argv[1], port); 139 | close(sockfd); 140 | exit(1); 141 | } 142 | 143 | const char *error; 144 | 145 | if (s2n_init(&error) < 0) { 146 | fprintf(stderr, "Error running s2n_init(): '%s'\n", s2n_strerror(s2n_errno, "EN")); 147 | } 148 | 149 | struct s2n_config *config = s2n_config_new(); 150 | if (config == NULL) { 151 | fprintf(stderr, "Error getting new config: '%s'\n", s2n_strerror(s2n_errno, "EN")); 152 | exit(1); 153 | } 154 | 155 | if (s2n_config_set_status_request_type(config, type) < 0) { 156 | fprintf(stderr, "Error setting status request type: '%s'\n", s2n_strerror(s2n_errno, "EN")); 157 | exit(1); 158 | } 159 | 160 | if (alpn_protocols) { 161 | /* Count the number of commas, this tells us how many protocols there 162 | are in the list */ 163 | const char *ptr = alpn_protocols; 164 | int protocol_count = 1; 165 | while (*ptr) { 166 | if (*ptr == ',') { 167 | protocol_count++; 168 | } 169 | ptr++; 170 | } 171 | 172 | char **protocols = malloc(sizeof(char *) * protocol_count); 173 | if (!protocols) { 174 | fprintf(stderr, "Error allocating memory\n"); 175 | exit(1); 176 | } 177 | 178 | const char *next = alpn_protocols; 179 | int index = 0; 180 | int length = 0; 181 | ptr = alpn_protocols; 182 | while (*ptr) { 183 | if (*ptr == ',') { 184 | protocols[index] = malloc(length + 1); 185 | if (!protocols[index]) { 186 | fprintf(stderr, "Error allocating memory\n"); 187 | exit(1); 188 | } 189 | memcpy(protocols[index], next, length); 190 | protocols[index][length] = '\0'; 191 | length = 0; 192 | index++; 193 | ptr++; 194 | next = ptr; 195 | } else { 196 | length++; 197 | ptr++; 198 | } 199 | } 200 | if (ptr != next) { 201 | protocols[index] = malloc(length + 1); 202 | if (!protocols[index]) { 203 | fprintf(stderr, "Error allocating memory\n"); 204 | exit(1); 205 | } 206 | memcpy(protocols[index], next, length); 207 | protocols[index][length] = '\0'; 208 | } 209 | if (s2n_config_set_protocol_preferences(config, (const char * const *)protocols, protocol_count) < 0) { 210 | fprintf(stderr, "Failed to set protocol preferences: '%s'\n", s2n_strerror(s2n_errno, "EN")); 211 | exit(1); 212 | } 213 | while(protocol_count) { 214 | protocol_count--; 215 | free(protocols[protocol_count]); 216 | } 217 | free(protocols); 218 | } 219 | 220 | struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT); 221 | 222 | if (conn == NULL) { 223 | fprintf(stderr, "Error getting new connection: '%s'\n", s2n_strerror(s2n_errno, "EN")); 224 | exit(1); 225 | } 226 | 227 | printf("Connected to %s:%s\n", host, port); 228 | 229 | if (s2n_connection_set_config(conn, config) < 0) { 230 | fprintf(stderr, "Error setting configuration: '%s'\n", s2n_strerror(s2n_errno, "EN")); 231 | exit(1); 232 | } 233 | 234 | if (s2n_set_server_name(conn, server_name) < 0) { 235 | fprintf(stderr, "Error setting server name: '%s'\n", s2n_strerror(s2n_errno, "EN")); 236 | exit(1); 237 | } 238 | 239 | if (s2n_connection_set_fd(conn, sockfd) < 0) { 240 | fprintf(stderr, "Error setting file descriptor: '%s'\n", s2n_strerror(s2n_errno, "EN")); 241 | exit(1); 242 | } 243 | 244 | /* See echo.c */ 245 | echo(conn, sockfd); 246 | 247 | if (s2n_connection_free(conn) < 0) { 248 | fprintf(stderr, "Error freeing connection: '%s'\n", s2n_strerror(s2n_errno, "EN")); 249 | exit(1); 250 | } 251 | 252 | if (s2n_config_free(config) < 0) { 253 | fprintf(stderr, "Error freeing configuration: '%s'\n", s2n_strerror(s2n_errno, "EN")); 254 | exit(1); 255 | } 256 | 257 | if (s2n_cleanup(&error) < 0) { 258 | fprintf(stderr, "Error running s2n_cleanup(): '%s'\n", s2n_strerror(s2n_errno, "EN")); 259 | } 260 | 261 | return 0; 262 | } 263 | -------------------------------------------------------------------------------- /examples/s2nd.lua: -------------------------------------------------------------------------------- 1 | package.path = ";../?.lua;"..package.path 2 | 3 | local s2n = require("s2n") 4 | local S2Connection = s2n.S2Connection 5 | local S2Config = s2n.S2Config 6 | 7 | local echo = require("echo") 8 | 9 | local function printf(fmt, ...) 10 | io.write(string.format(fmt, ...)) 11 | end 12 | 13 | local function fprintf(fd, fmt, ...) 14 | fd:write(string.format(fmt, ...)) 15 | end 16 | 17 | local certificate =[[ 18 | -----BEGIN CERTIFICATE----- 19 | MIIDLjCCAhYCCQDL1lr6N8/gvzANBgkqhkiG9w0BAQUFADBZMQswCQYDVQQGEwJB 20 | VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0 21 | cyBQdHkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTQwNTEwMTcwODIzWhcN 22 | MjQwNTA3MTcwODIzWjBZMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0 23 | ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDEwls 24 | b2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIltaUmHg+ 25 | G7Ida2XCtEQx1YeWDX41U2zBKbY0lT+auXf81cT3dYTdfJblb+v4CTWaGNofogcz 26 | ebm8B2/OF9F+WWkKAJhKsTPAE7/SNAdi4Eqv4FfNbWKkGb4xacxxb4PH2XP9V3Ch 27 | J6lMSI3V68FmEf4kcEN14V8vufIC5HE/LT4gCPDJ4UfUUbAgEhSebT6r/KFYB5T3 28 | AeDc1VdnaaRblrP6KwM45vTs0Ii09/YrlzBxaTPMjLGCKa8JMv8PW2R0U9WCqHmz 29 | BH+W3Q9xPrfhCInm4JWob8WgM1NuiYuzFB0CNaQcdMS7h0aZEAVnayhQ96/Padpj 30 | KNE0Lur9nUxbAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAGRV71uRt/1dADsMD9fg 31 | JvzW89jFAN87hXCRhTWxfXhYMzknxJ5WMb2JAlaMc/gTpiDiQBkbvB+iJe5AepgQ 32 | WbyxPJNtSlA9GfKBz1INR5cFsOL27VrBoMYHMaolveeslc1AW2HfBtXWXeWSEF7F 33 | QNgye8ZDPNzeSWSI0VyK2762wsTgTuUhHAaJ45660eX57+e8IvaM7xOEfBPDKYtU 34 | 0a28ZuhvSr2akJtGCwcs2J6rs6I+rV84UktDxFC9LUezBo8D9FkMPLoPKKNH1dXR 35 | 6LO8GOkqWUrhPIEmfy9KYes3q2ZX6svk4rwBtommHRv30kPxnnU1YXt52Ri+XczO 36 | wEs= 37 | -----END CERTIFICATE-----; 38 | ]] 39 | 40 | local private_key = [[ 41 | -----BEGIN RSA PRIVATE KEY----- 42 | MIIEpAIBAAKCAQEAyJbWlJh4PhuyHWtlwrREMdWHlg1+NVNswSm2NJU/mrl3/NXE 43 | 93WE3XyW5W/r+Ak1mhjaH6IHM3m5vAdvzhfRfllpCgCYSrEzwBO/0jQHYuBKr+BX 44 | zW1ipBm+MWnMcW+Dx9lz/VdwoSepTEiN1evBZhH+JHBDdeFfL7nyAuRxPy0+IAjw 45 | yeFH1FGwIBIUnm0+q/yhWAeU9wHg3NVXZ2mkW5az+isDOOb07NCItPf2K5cwcWkz 46 | zIyxgimvCTL/D1tkdFPVgqh5swR/lt0PcT634QiJ5uCVqG/FoDNTbomLsxQdAjWk 47 | HHTEu4dGmRAFZ2soUPevz2naYyjRNC7q/Z1MWwIDAQABAoIBAHrkryLrJwAmR8Hu 48 | grH/b6h4glFUgvZ43jCaNZ+RsR5Cc1jcP4i832Izat+26oNUYRrADyNCSdcnxLuG 49 | cuF5hkg6zzfplWRtnJ8ZenR2m+/gKuIGOMULN1wCyZvMjg0RnVNbzsxwPfj+K6Mo 50 | 8H0Xq621aFc60JnwMjkzWyqaeyeQogn1pqybuL6Dm2huvN49LR64uHuDUStTRX33 51 | ou1fVWXOJ1kealYPbRPj8pDa31omB8q5Cf8Qe/b9anqyi9CsP17QbVg9k2IgoLlj 52 | agqOc0u/opOTZB4tqJbqsIdEhc5LD5RUkYJsw00Iq0RSiKTfiWSPyOFw99Y9Act0 53 | cbIIxEECgYEA8/SOsQjoUX1ipRvPbfO3suV1tU1hLCQbIpv7WpjNr1kHtngjzQMP 54 | dU/iriUPGF1H+AxJJcJQfCVThV1AwFYVKb/LCrjaxlneZSbwfehpjo+xQGaNYG7Q 55 | 1vQuBVejuYk/IvpZltQOdm838DjvYyWDMh4dcMFIycXxEg+oHxf/s+8CgYEA0n4p 56 | GBuLUNx9vv3e84BcarLaOF7wY7tb8z2oC/mXztMZpKjovTH0PvePgI5/b3KQ52R0 57 | 8zXHVX/4lSQVtCuhOVwKOCQq97/Zhlp5oTTShdQ0Qa1GQRl5wbTS6hrYEWSi9AQP 58 | BVUPZ+RIcxx00DfBNURkId8xEpvCOmvySN8sUlUCgYAtXmHbEqkB3qulwRJGhHi5 59 | UGsfmJBlwSE6wn9wTdKStZ/1k0o1KkiJrJ2ffUzdXxuvSbmgyA5nyBlMSBdurZOp 60 | +/0qtU4abUQq058OC1b2KEryix/nuzQjha25WJ8eNiQDwUNABZfa9rwUdMIwUh2g 61 | CHG5Mnjy7Vjz3u2JOtFXCQKBgQCVRo1EIHyLauLuaMINM9HWhWJGqeWXBM8v0GD1 62 | pRsovQKpiHQNgHizkwM861GqqrfisZZSyKfFlcynkACoVmyu7fv9VoD2VCMiqdUq 63 | IvjNmfE5RnXVQwja+668AS+MHi+GF77DTFBxoC5VHDAnXfLyIL9WWh9GEBoNLnKT 64 | hVm8RQKBgQCB9Skzdftc+14a4Vj3NCgdHZHz9mcdPhzJXUiQyZ3tYhaytX9E8mWq 65 | pm/OFqahbxw6EQd86mgANBMKayD6B1Id1INqtXN1XYI50bSs1D2nOGsBM7MK9aWD 66 | JXlJ2hwsIc4q9En/LR3GtBaL84xTHGfznNylNhXi7GbO1wNMJuAukA== 67 | -----END RSA PRIVATE KEY-----; 68 | ]] 69 | 70 | local dhparams = [[ 71 | -----BEGIN DH PARAMETERS----- 72 | MIIBCAKCAQEAy1+hVWCfNQoPB+NA733IVOONl8fCumiz9zdRRu1hzVa2yvGseUSq 73 | Bbn6k0FQ7yMED6w5XWQKDC0z2m0FI/BPE3AjUfuPzEYGqTDf9zQZ2Lz4oAN90Sud 74 | luOoEhYR99cEbCn0T4eBvEf9IUtczXUZ/wj7gzGbGG07dLfT+CmCRJxCjhrosenJ 75 | gzucyS7jt1bobgU66JKkgMNm7hJY4/nhR5LWTCzZyzYQh2HM2Vk4K5ZqILpj/n0S 76 | 5JYTQ2PVhxP+Uu8+hICs/8VvM72DznjPZzufADipjC7CsQ4S6x/ecZluFtbb+ZTv 77 | HI5CnYmkAwJ6+FSWGaZQDi8bgerFk9RWwwIBAg== 78 | -----END DH PARAMETERS-----; 79 | ]] 80 | 81 | 82 | local function usage() 83 | fprintf(io.stderr, "usage: s2nd host port\n"); 84 | fprintf(io.stderr, " host: hostname or IP address to listen on\n"); 85 | fprintf(io.stderr, " port: port to listen on\n"); 86 | 87 | error("usage"); 88 | end 89 | 90 | local main(argc, argv) 91 | 92 | struct addrinfo hints, *ai; 93 | int r, sockfd = 0; 94 | 95 | if (argc != 3) { 96 | usage(); 97 | } 98 | 99 | if (memset(&hints, 0, sizeof(hints)) != &hints) { 100 | fprintf(stderr, "memset error: %s\n", strerror(errno)); 101 | exit(1); 102 | } 103 | 104 | hints.ai_family = AF_UNSPEC; 105 | hints.ai_socktype = SOCK_STREAM; 106 | 107 | if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { 108 | fprintf(stderr, "Error disabling SIGPIPE\n"); 109 | exit(1); 110 | } 111 | 112 | if ((r = getaddrinfo(argv[1], argv[2], &hints, &ai)) < 0) { 113 | fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(r)); 114 | exit(1); 115 | } 116 | 117 | if ((sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) { 118 | fprintf(stderr, "socket error: %s\n", strerror(errno)); 119 | exit(1); 120 | } 121 | 122 | r = 1; 123 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &r, sizeof(int)) < 0) { 124 | fprintf(stderr, "setsockopt error: %s\n", strerror(errno)); 125 | exit(1); 126 | } 127 | 128 | if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) { 129 | fprintf(stderr, "bind error: %s\n", strerror(errno)); 130 | exit(1); 131 | } 132 | 133 | if (listen(sockfd, 1) == -1) { 134 | fprintf(stderr, "listen error: %s\n", strerror(errno)); 135 | exit(1); 136 | } 137 | 138 | printf("Listening on %s:%s\n", argv[1], argv[2]); 139 | 140 | local config = S2Config(); 141 | config:addCertChainAndKey(certificate, private_key); 142 | config:addDhParams(dhparams) 143 | 144 | local conn, err = S2Connection(S2N_SERVER); 145 | conn:setConfig(config); 146 | 147 | local fd=0; 148 | while ((fd = accept(sockfd, ai.ai_addr, &ai->ai_addrlen)) > 0) do 149 | local success, err = conn:fileDescriptor(fd); 150 | if not success then 151 | error(err); 152 | end 153 | 154 | echo(conn, fd); 155 | 156 | if (not conn:wipe()) then 157 | fprintf(stderr, "Error wiping connection: '%s'\n", s2n_strerror(s2n_errno, "EN")); 158 | exit(1); 159 | end 160 | end 161 | 162 | --[[ 163 | if (s2n_api.s2n_cleanup() < 0) { 164 | fprintf(stderr, "Error running s2n_cleanup(): '%s'\n", s2n_strerror(s2n_errno, "EN")); 165 | } 166 | --]] 167 | 168 | return 0; 169 | end 170 | 171 | main(#arg, arg) 172 | -------------------------------------------------------------------------------- /s2n.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local s2n_api = require("api.s2n_ffi") 3 | local S2NConnection = require("S2NConnection") 4 | local S2NConfig = require("S2NConfig") 5 | 6 | local exports = { 7 | s2n_api = s2n_api; 8 | 9 | -- classes 10 | S2NConnection = S2NConnection; 11 | S2NConfig = S2NConfig; 12 | } 13 | 14 | 15 | return exports 16 | -------------------------------------------------------------------------------- /stuffer/s2n_stuffer.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | local s2n_blob = require ("utils.s2n_blob") 4 | 5 | ffi.cdef[[ 6 | struct s2n_stuffer { 7 | /* The data for the s2n_stuffer */ 8 | struct s2n_blob blob; 9 | 10 | /* Cursors to the current read/write position in the s2n_stuffer */ 11 | uint32_t read_cursor; 12 | uint32_t write_cursor; 13 | 14 | /* The total size of the data segment */ 15 | /* Has the stuffer been wiped? */ 16 | unsigned int wiped:1; 17 | 18 | /* Was this stuffer alloc()'d ? */ 19 | unsigned int alloced:1; 20 | 21 | /* Is this stuffer growable? */ 22 | unsigned int growable:1; 23 | 24 | /* A growable stuffer can also be temporarily tainted */ 25 | unsigned int tainted:1; 26 | }; 27 | ]] 28 | 29 | local function s2n_stuffer_data_available( s ) 30 | return (s.write_cursor - s.read_cursor) 31 | end 32 | 33 | local function s2n_stuffer_space_remaining( s ) 34 | return (s.blob.size - s.write_cursor) 35 | end 36 | 37 | ffi.cdef[[ 38 | /* Initialize and destroying stuffers */ 39 | extern int s2n_stuffer_init(struct s2n_stuffer *stuffer, struct s2n_blob *in); 40 | extern int s2n_stuffer_alloc(struct s2n_stuffer *stuffer, uint32_t size); 41 | extern int s2n_stuffer_growable_alloc(struct s2n_stuffer *stuffer, uint32_t size); 42 | extern int s2n_stuffer_free(struct s2n_stuffer *stuffer); 43 | extern int s2n_stuffer_resize(struct s2n_stuffer *stuffer, uint32_t size); 44 | extern int s2n_stuffer_reread(struct s2n_stuffer *stuffer); 45 | extern int s2n_stuffer_rewrite(struct s2n_stuffer *stuffer); 46 | extern int s2n_stuffer_wipe(struct s2n_stuffer *stuffer); 47 | extern int s2n_stuffer_wipe_n(struct s2n_stuffer *stuffer, uint32_t n); 48 | 49 | /* Basic read and write */ 50 | extern int s2n_stuffer_read(struct s2n_stuffer *stuffer, struct s2n_blob *out); 51 | extern int s2n_stuffer_erase_and_read(struct s2n_stuffer *stuffer, struct s2n_blob *out); 52 | extern int s2n_stuffer_write(struct s2n_stuffer *stuffer, struct s2n_blob *in); 53 | extern int s2n_stuffer_read_bytes(struct s2n_stuffer *stuffer, uint8_t *out, uint32_t n); 54 | extern int s2n_stuffer_write_bytes(struct s2n_stuffer *stuffer, uint8_t *in, uint32_t n); 55 | extern int s2n_stuffer_skip_read(struct s2n_stuffer *stuffer, uint32_t n); 56 | extern int s2n_stuffer_skip_write(struct s2n_stuffer *stuffer, uint32_t n); 57 | 58 | /* Raw read/write move the cursor along and give you a pointer you can 59 | * read/write data_len bytes from/to in-place. 60 | */ 61 | extern void *s2n_stuffer_raw_write(struct s2n_stuffer *stuffer, uint32_t data_len); 62 | extern void *s2n_stuffer_raw_read(struct s2n_stuffer *stuffer, uint32_t data_len); 63 | 64 | /* Send/receive stuffer to/from a file descriptor */ 65 | extern int s2n_stuffer_recv_from_fd(struct s2n_stuffer *stuffer, int rfd, uint32_t len); 66 | extern int s2n_stuffer_send_to_fd(struct s2n_stuffer *stuffer, int wfd, uint32_t len); 67 | 68 | /* Read and write integers in network order */ 69 | extern int s2n_stuffer_read_uint8(struct s2n_stuffer *stuffer, uint8_t *u); 70 | extern int s2n_stuffer_read_uint16(struct s2n_stuffer *stuffer, uint16_t *u); 71 | extern int s2n_stuffer_read_uint24(struct s2n_stuffer *stuffer, uint32_t *u); 72 | extern int s2n_stuffer_read_uint32(struct s2n_stuffer *stuffer, uint32_t *u); 73 | extern int s2n_stuffer_read_uint64(struct s2n_stuffer *stuffer, uint64_t *u); 74 | 75 | extern int s2n_stuffer_write_uint8(struct s2n_stuffer *stuffer, uint8_t u); 76 | extern int s2n_stuffer_write_uint16(struct s2n_stuffer *stuffer, uint16_t u); 77 | extern int s2n_stuffer_write_uint24(struct s2n_stuffer *stuffer, uint32_t u); 78 | extern int s2n_stuffer_write_uint32(struct s2n_stuffer *stuffer, uint32_t u); 79 | extern int s2n_stuffer_write_uint64(struct s2n_stuffer *stuffer, uint64_t u); 80 | 81 | /* Copy one stuffer to another */ 82 | extern int s2n_stuffer_copy(struct s2n_stuffer *from, struct s2n_stuffer *to, uint32_t len); 83 | 84 | /* Read and write base64 */ 85 | extern int s2n_stuffer_read_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *out); 86 | extern int s2n_stuffer_write_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *in); 87 | ]] 88 | 89 | 90 | 91 | ffi.cdef[[ 92 | extern int s2n_stuffer_peek_char(struct s2n_stuffer *stuffer, char *c); 93 | extern int s2n_stuffer_read_token(struct s2n_stuffer *stuffer, struct s2n_stuffer *token, char delim); 94 | extern int s2n_stuffer_skip_whitespace(struct s2n_stuffer *stuffer); 95 | extern int s2n_stuffer_alloc_ro_from_string(struct s2n_stuffer *stuffer, char *str); 96 | 97 | /* Read an RSA private key from a PEM encoded stuffer to an ASN1/DER encoded one */ 98 | extern int s2n_stuffer_rsa_private_key_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1); 99 | 100 | /* Read a certificate from a PEM encoded stuffer to an ASN1/DER encoded one */ 101 | extern int s2n_stuffer_certificate_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1); 102 | 103 | /* Read DH parameters om a PEM encoded stuffer to a PKCS3 encoded one */ 104 | extern int s2n_stuffer_dhparams_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *pkcs3); 105 | ]] 106 | 107 | 108 | -- Useful for text manipulation ... 109 | local Lib_s2n = ffi.load("s2n") 110 | 111 | local function s2n_stuffer_init_text( stuffer, text, len) 112 | return Lib_s2n.s2n_stuffer_init(stuffer, ffi.cast("uint8_t *", text), len) 113 | end 114 | 115 | local function s2n_stuffer_write_char( stuffer, c) 116 | return Lib_s2n.s2n_stuffer_write_uint8(stuffer, ffi.cast("uint8_t", c)) 117 | end 118 | 119 | local function s2n_stuffer_read_char( stuffer, c) 120 | return Lib_s2n.s2n_stuffer_read_uint8(stuffer, ffi.cast("uint8_t *", c)) 121 | end 122 | 123 | local function s2n_stuffer_write_str( stuffer, c) 124 | local blob = s2n_blob.s2n_blob(ffi.cast("uint8_t *",c), #c) 125 | return Lib_s2n.s2n_stuffer_write(stuffer, blob) 126 | end 127 | 128 | local function s2n_stuffer_write_text( stuffer, c, n) 129 | return Lib_s2n.s2n_stuffer_write(stuffer, ffi.cast("const uint8_t *", c), n) 130 | end 131 | 132 | local function s2n_stuffer_read_text( stuffer, c, n) 133 | return Lib_s2n.s2n_stuffer_read(stuffer, ffi.cast("uint8_t *", c), n) 134 | end 135 | 136 | local exports = { 137 | s2n_stuffer = ffi.typeof("struct s2n_stuffer"); 138 | 139 | -- local functions 140 | s2n_stuffer_data_available = s2n_stuffer_data_available; 141 | s2n_stuffer_space_remaining = s2n_stuffer_space_remaining; 142 | 143 | s2n_stuffer_init_text = s2n_stuffer_init_text; 144 | s2n_stuffer_write_char = s2n_stuffer_write_char; 145 | s2n_stuffer_read_char = s2n_stuffer_read_char; 146 | s2n_stuffer_write_str = s2n_stuffer_write_str; 147 | s2n_stuffer_write_text = s2n_stuffer_write_text; 148 | s2n_stuffer_read_text = s2n_stuffer_read_text; 149 | 150 | -- library functions 151 | s2n_stuffer_init = Lib_s2n.s2n_stuffer_init; 152 | s2n_stuffer_alloc = Lib_s2n.s2n_stuffer_alloc; 153 | s2n_stuffer_growable_alloc = Lib_s2n.s2n_stuffer_growable_alloc; 154 | s2n_stuffer_free = Lib_s2n.s2n_stuffer_free; 155 | s2n_stuffer_resize = Lib_s2n.s2n_stuffer_resize; 156 | s2n_stuffer_reread = Lib_s2n.s2n_stuffer_reread; 157 | s2n_stuffer_rewrite = Lib_s2n.s2n_stuffer_rewrite; 158 | s2n_stuffer_wipe = Lib_s2n.s2n_stuffer_wipe; 159 | s2n_stuffer_wipe_n = Lib_s2n.s2n_stuffer_wipe_n; 160 | 161 | -- basic read/write 162 | s2n_stuffer_read = Lib_s2n.s2n_stuffer_read; 163 | s2n_stuffer_erase_and_read = Lib_s2n.s2n_stuffer_erase_and_read; 164 | s2n_stuffer_write = Lib_s2n.s2n_stuffer_write; 165 | s2n_stuffer_read_bytes = Lib_s2n.s2n_stuffer_read_bytes; 166 | s2n_stuffer_write_bytes = Lib_s2n.s2n_stuffer_write_bytes; 167 | s2n_stuffer_skip_read = Lib_s2n.s2n_stuffer_skip_read; 168 | s2n_stuffer_skip_write = Lib_s2n.s2n_stuffer_skip_write; 169 | 170 | s2n_stuffer_raw_write = Lib_s2n.s2n_stuffer_raw_write; 171 | s2n_stuffer_raw_read = Lib_s2n.s2n_stuffer_raw_read; 172 | 173 | s2n_stuffer_recv_from_fd = Lib_s2n.s2n_stuffer_recv_from_fd; 174 | s2n_stuffer_send_to_fd = Lib_s2n.s2n_stuffer_send_to_fd; 175 | 176 | -- read/write integers in network byte order 177 | s2n_stuffer_read_uint8 = Lib_s2n.s2n_stuffer_read_uint8; 178 | s2n_stuffer_read_uint16 = Lib_s2n.s2n_stuffer_read_uint16; 179 | s2n_stuffer_read_uint24 = Lib_s2n.s2n_stuffer_read_uint24; 180 | s2n_stuffer_read_uint32 = Lib_s2n.s2n_stuffer_read_uint32; 181 | --s2n_stuffer_read_uint64 = Lib_s2n.s2n_stuffer_read_uint64; 182 | 183 | s2n_stuffer_write_uint8 = Lib_s2n.s2n_stuffer_write_uint8; 184 | s2n_stuffer_write_uint16 = Lib_s2n.s2n_stuffer_write_uint16; 185 | s2n_stuffer_write_uint24 = Lib_s2n.s2n_stuffer_write_uint24; 186 | s2n_stuffer_write_uint32 = Lib_s2n.s2n_stuffer_write_uint32; 187 | --s2n_stuffer_write_uint64 = Lib_s2n.s2n_stuffer_write_uint64; 188 | 189 | -- copy one stuffer to another 190 | s2n_stuffer_copy = Lib_s2n.s2n_stuffer_copy; 191 | 192 | -- base64 read/write 193 | s2n_stuffer_read_base64 = Lib_s2n.s2n_stuffer_read_base64; 194 | s2n_stuffer_write_base64 = Lib_s2n.s2n_stuffer_write_base64; 195 | } 196 | 197 | return exports 198 | -------------------------------------------------------------------------------- /testy/s2n_testlib.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | require("stuffer.s2n_stuffer") 4 | require("tls.s2n_connection") 5 | require("error.s2n_errno") 6 | require("stuffer.s2n_stuffer") 7 | require("utils.s2n_safety") 8 | 9 | 10 | ffi.cdef[[ 11 | /* Read and write hex */ 12 | extern int s2n_stuffer_read_hex(struct s2n_stuffer *stuffer, struct s2n_stuffer *out, uint32_t n); 13 | extern int s2n_stuffer_read_uint8_hex(struct s2n_stuffer *stuffer, uint8_t *u); 14 | extern int s2n_stuffer_read_uint16_hex(struct s2n_stuffer *stuffer, uint16_t *u); 15 | extern int s2n_stuffer_read_uint32_hex(struct s2n_stuffer *stuffer, uint32_t *u); 16 | extern int s2n_stuffer_read_uint64_hex(struct s2n_stuffer *stuffer, uint64_t *u); 17 | 18 | extern int s2n_stuffer_write_hex(struct s2n_stuffer *stuffer, struct s2n_stuffer *in, uint32_t n); 19 | extern int s2n_stuffer_write_uint8_hex(struct s2n_stuffer *stuffer, uint8_t u); 20 | extern int s2n_stuffer_write_uint16_hex(struct s2n_stuffer *stuffer, uint16_t u); 21 | extern int s2n_stuffer_write_uint32_hex(struct s2n_stuffer *stuffer, uint32_t u); 22 | extern int s2n_stuffer_write_uint64_hex(struct s2n_stuffer *stuffer, uint64_t u); 23 | extern int s2n_stuffer_alloc_ro_from_hex_string(struct s2n_stuffer *stuffer, const char *str); 24 | 25 | void s2n_print_connection(struct s2n_connection *conn, const char *marker); 26 | ]] 27 | 28 | 29 | 30 | 31 | 32 | 33 | static uint8_t hex[16] = { 34 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' 35 | }; 36 | 37 | /** 38 | * Helper function: read n bits of hex data. 39 | */ 40 | static int s2n_stuffer_read_n_bits_hex(struct s2n_stuffer *stuffer, uint8_t n, uint64_t *u) 41 | { 42 | uint8_t hex_data[16]; 43 | struct s2n_blob b = { .data = hex_data, .size = n / 4 }; 44 | 45 | GUARD(s2n_stuffer_read(stuffer, &b)); 46 | 47 | /* Start with u = 0 */ 48 | *u = 0; 49 | 50 | for (int i = 0; i < b.size; i++) { 51 | *u <<= 4; 52 | if (b.data[i] >= '0' && b.data[i] <= '9') { 53 | *u |= b.data[i] - '0'; 54 | } else if (b.data[i] >= 'a' && b.data[i] <= 'f') { 55 | *u |= b.data[i] - 'a' + 10; 56 | } else if (b.data[i] >= 'A' && b.data[i] <= 'F') { 57 | *u |= b.data[i] - 'A' + 10; 58 | } else { 59 | S2N_ERROR(S2N_ERR_BAD_MESSAGE); 60 | } 61 | } 62 | 63 | return 0; 64 | } 65 | 66 | int s2n_stuffer_read_hex(struct s2n_stuffer *stuffer, struct s2n_stuffer *out, uint32_t n) 67 | { 68 | gte_check(s2n_stuffer_space_remaining(out), n); 69 | 70 | for (int i = 0; i < n; i++) { 71 | uint8_t c; 72 | GUARD(s2n_stuffer_read_uint8_hex(stuffer, &c)); 73 | GUARD(s2n_stuffer_write_uint8(out, c)); 74 | } 75 | 76 | return 0; 77 | } 78 | 79 | int s2n_stuffer_write_hex(struct s2n_stuffer *stuffer, struct s2n_stuffer *in, uint32_t n) 80 | { 81 | gte_check(s2n_stuffer_space_remaining(stuffer), n * 2); 82 | 83 | for (int i = 0; i < n; i++) { 84 | uint8_t c; 85 | GUARD(s2n_stuffer_read_uint8(in, &c)); 86 | GUARD(s2n_stuffer_write_uint8_hex(stuffer, c)); 87 | } 88 | 89 | return 0; 90 | } 91 | 92 | int s2n_stuffer_read_uint64_hex(struct s2n_stuffer *stuffer, uint64_t *u) 93 | { 94 | return s2n_stuffer_read_n_bits_hex(stuffer, 64, u); 95 | } 96 | 97 | int s2n_stuffer_read_uint32_hex(struct s2n_stuffer *stuffer, uint32_t *u) 98 | { 99 | uint64_t u64; 100 | 101 | GUARD(s2n_stuffer_read_n_bits_hex(stuffer, 32, &u64)); 102 | 103 | *u = u64 & 0xffffffff; 104 | 105 | return 0; 106 | } 107 | 108 | int s2n_stuffer_read_uint16_hex(struct s2n_stuffer *stuffer, uint16_t *u) 109 | { 110 | uint64_t u64; 111 | 112 | GUARD(s2n_stuffer_read_n_bits_hex(stuffer, 16, &u64)); 113 | 114 | *u = u64 & 0xffff; 115 | 116 | return 0; 117 | } 118 | 119 | int s2n_stuffer_read_uint8_hex(struct s2n_stuffer *stuffer, uint8_t *u) 120 | { 121 | uint64_t u64; 122 | 123 | GUARD(s2n_stuffer_read_n_bits_hex(stuffer, 8, &u64)); 124 | 125 | *u = u64 & 0xff; 126 | 127 | return 0; 128 | } 129 | 130 | /** 131 | * Private helper: write n (up to 64) bits of hex data 132 | */ 133 | static int s2n_stuffer_write_n_bits_hex(struct s2n_stuffer *stuffer, uint8_t n, uint64_t u) 134 | { 135 | uint8_t hex_data[16] = { 0 }; 136 | struct s2n_blob b = { .data = hex_data, .size = n / 4 }; 137 | 138 | lte_check(n, 64); 139 | 140 | for (int i = b.size; i > 0; i--) { 141 | b.data[i - 1] = hex[u & 0x0f]; 142 | u >>= 4; 143 | } 144 | 145 | GUARD(s2n_stuffer_write(stuffer, &b)); 146 | 147 | return 0; 148 | } 149 | 150 | int s2n_stuffer_write_uint64_hex(struct s2n_stuffer *stuffer, uint64_t u) 151 | { 152 | return s2n_stuffer_write_n_bits_hex(stuffer, 64, u); 153 | } 154 | 155 | int s2n_stuffer_write_uint32_hex(struct s2n_stuffer *stuffer, uint32_t u) 156 | { 157 | return s2n_stuffer_write_n_bits_hex(stuffer, 32, u); 158 | } 159 | 160 | int s2n_stuffer_write_uint16_hex(struct s2n_stuffer *stuffer, uint16_t u) 161 | { 162 | return s2n_stuffer_write_n_bits_hex(stuffer, 16, u); 163 | } 164 | 165 | int s2n_stuffer_write_uint8_hex(struct s2n_stuffer *stuffer, uint8_t u) 166 | { 167 | return s2n_stuffer_write_n_bits_hex(stuffer, 8, u); 168 | } 169 | 170 | int s2n_stuffer_alloc_ro_from_hex_string(struct s2n_stuffer *stuffer, const char *str) 171 | { 172 | if (strlen(str) % 2) { 173 | S2N_ERROR(S2N_ERR_SIZE_MISMATCH); 174 | } 175 | 176 | GUARD(s2n_stuffer_alloc(stuffer, strlen(str) / 2)); 177 | 178 | for (int i = 0; i < strlen(str); i += 2) { 179 | uint8_t u = 0; 180 | 181 | if (str[i] >= '0' && str[i] <= '9') { 182 | u = str[i] - '0'; 183 | } else if (str[i] >= 'a' && str[i] <= 'f') { 184 | u = str[i] - 'a' + 10; 185 | } else if (str[i] >= 'A' && str[i] <= 'F') { 186 | u = str[i] - 'A' + 10; 187 | } else { 188 | S2N_ERROR(S2N_ERR_BAD_MESSAGE); 189 | } 190 | u <<= 4; 191 | 192 | if (str[i + 1] >= '0' && str[i + 1] <= '9') { 193 | u |= str[i + 1] - '0'; 194 | } else if (str[i + 1] >= 'a' && str[i + 1] <= 'f') { 195 | u |= str[i + 1] - 'a' + 10; 196 | } else if (str[i + 1] >= 'A' && str[i + 1] <= 'F') { 197 | u |= str[i + 1] - 'A' + 10; 198 | } else { 199 | S2N_ERROR(S2N_ERR_BAD_MESSAGE); 200 | } 201 | 202 | GUARD(s2n_stuffer_write_uint8(stuffer, u)); 203 | } 204 | 205 | return 0; 206 | } 207 | 208 | local exports = { 209 | 210 | } 211 | 212 | return exports 213 | -------------------------------------------------------------------------------- /testy/test_s2n_blob.lua: -------------------------------------------------------------------------------- 1 | package.path = "../?.lua;"..package.path 2 | local ffi = require("ffi") 3 | 4 | local s2n_blob = require("utils.s2n_blob").s2n_blob 5 | 6 | local function test_constructor() 7 | print("==== test_constructor ====") 8 | local blob1 = s2n_blob(); 9 | print("Blob1: ", tostring(blob1)) 10 | 11 | local str = "Hello, World!" 12 | local blob2 = s2n_blob(ffi.cast("uint8_t *",str), #str) 13 | print("Blob2: ", tostring(blob2)) 14 | end 15 | 16 | local function test_clear() 17 | print("==== test_clear ====") 18 | local str = "Hello, World!" 19 | local blob1 = s2n_blob(ffi.cast("uint8_t *",str), #str) 20 | print("Blob1: ", tostring(blob1)) 21 | 22 | blob1:clear(); 23 | print("Blob Clear: ", blob1) 24 | end 25 | 26 | test_constructor(); 27 | test_clear(); -------------------------------------------------------------------------------- /testy/test_s2n_ffi.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | This 'test' won't actually work, as it's just a fragment 3 | from the web page. 4 | 5 | What it will show is that the ffi can be included without 6 | error. 7 | 8 | --]] 9 | 10 | package.path = "../?.lua;"..package.path 11 | 12 | local s2n_ffi = require("api.s2n_ffi") 13 | s2n_ffi(); 14 | 15 | local conn = s2n_connection_new(S2N_SERVER); 16 | if conn == nil then 17 | error(s2n_strerror(-1)); 18 | end 19 | 20 | -- Associate a connection with a file descriptor 21 | if (s2n_connection_set_fd(conn, fd) < 0) then 22 | error(); 23 | end 24 | 25 | -- Negotiate TLS handshake 26 | local more = ffi.new("int[1]"); 27 | if (s2n_negotiate(conn, more) < 0) then 28 | error(); 29 | end 30 | 31 | -- Write data to connection 32 | local bytes_written = s2n_send(conn, "Hello, World", 12, more); 33 | -------------------------------------------------------------------------------- /testy/test_s2nconnection.lua: -------------------------------------------------------------------------------- 1 | -- test_s2nconnection.lua 2 | package.path = "../?.lua;"..package.path 3 | 4 | local s2n = require("s2n") 5 | local S2NConnection = s2n.S2NConnection; 6 | 7 | local function test_negotiate() 8 | -- negotiate without actually connecting to something 9 | -- should cause an error. 10 | local conn = S2NConnection(); 11 | 12 | print("conn negotiate: ", conn:negotiate()); 13 | end 14 | 15 | local function test_getmetainfo() 16 | local conn = S2NConnection(); 17 | 18 | print("server name: ", conn:serverName()); 19 | print("app protocol: ", conn:applicationProtocol()) 20 | print("client Version: ", conn:clientProtocolVersion()) 21 | print("server Version: ", conn:serverProtocolVersion()) 22 | print("actual Version: ", conn:actualProtocolVersion()) 23 | end 24 | 25 | test_getmetainfo(); 26 | -------------------------------------------------------------------------------- /testy/test_stuffer.lua: -------------------------------------------------------------------------------- 1 | package.path = "../?.lua;"..package.path 2 | local ffi = require("ffi") 3 | 4 | local s2n_api = require("api.s2n_ffi") 5 | local stuffit = require("stuffer.s2n_stuffer") 6 | 7 | -- put them in global namespace 8 | for k,v in pairs(stuffit) do 9 | _G[k] = v; 10 | end 11 | 12 | local function EXPECTSUCCESS(f, ...) 13 | local err = f(...) 14 | if err < 0 then 15 | local errstr = s2n_api.s2n_strerror(); 16 | error(errstr) 17 | end 18 | end 19 | 20 | local function test_metadata() 21 | print("==== test_metadata ====") 22 | local stuffer = s2n_stuffer(); 23 | s2n_stuffer_growable_alloc(stuffer, 10); 24 | 25 | local avail = s2n_stuffer_data_available(stuffer) 26 | local remains = s2n_stuffer_space_remaining(stuffer) 27 | 28 | print("Available: ", avail) 29 | print("Remaining: ", remains) 30 | 31 | print("After Writing Some") 32 | s2n_stuffer_write_str(stuffer, "the quick brown fox jumped over the lazy dogs back") 33 | print("Available: ", s2n_stuffer_data_available(stuffer)) 34 | print("Remaining: ", s2n_stuffer_space_remaining(stuffer)) 35 | end 36 | 37 | local function test_growable() 38 | print("==== test_growable ====") 39 | local stuffer = s2n_stuffer(); 40 | s2n_stuffer_growable_alloc(stuffer, 10); 41 | 42 | -- write some stuff into it 43 | local written = s2n_stuffer_write_str(stuffer, "the quick brown fox jumped over the lazy dogs back") 44 | 45 | 46 | -- rewind to the beginning 47 | local buff = ffi.new("uint8_t[256]") 48 | s2n_stuffer_reread(stuffer); 49 | s2n_stuffer_read_bytes(stuffer, buff, 255); 50 | local str = ffi.string(buff, 255); 51 | 52 | print("READ: ", str) 53 | end 54 | 55 | local function test_readstring() 56 | local teststr = "the quick brown fox jumped over the lazy dogs back" 57 | local stuffer = s2n_stuffer(); 58 | s2n_stuffer_growable_alloc(stuffer, 10); 59 | 60 | local err = s2n_stuffer_write_str(stuffer, teststr) 61 | 62 | print("written: ", err) 63 | local buff = ffi.new("uint8_t[?]", #teststr+1) 64 | EXPECTSUCCESS(s2n_stuffer_reread, stuffer); 65 | EXPECTSUCCESS(s2n_stuffer_read_bytes, stuffer, buff, #teststr); 66 | 67 | if err < 0 then 68 | local errstr = s2n_api.s2n_strerror(); 69 | print(errstr) 70 | return false, errstr; 71 | end 72 | 73 | print(ffi.string(buff,#teststr)) 74 | end 75 | 76 | --test_growable() 77 | --test_metadata() 78 | test_readstring(); 79 | -------------------------------------------------------------------------------- /tls/s2n_alerts.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | 4 | local connection = require("tls.s2n_connection") 5 | 6 | ffi.cdef[[ 7 | extern int s2n_process_alert_fragment(struct s2n_connection *conn); 8 | extern int s2n_queue_writer_close_alert(struct s2n_connection *conn); 9 | extern int s2n_queue_reader_close_alert(struct s2n_connection *conn); 10 | extern int s2n_queue_reader_unsupported_protocol_version_alert(struct s2n_connection *conn); 11 | ]] 12 | 13 | local exports = { 14 | 15 | } 16 | 17 | return exports -------------------------------------------------------------------------------- /tls/s2n_connection.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | require("api.s2n") 4 | 5 | require("tls.s2n_tls_parameters") 6 | require("tls.s2n_handshake") 7 | require("tls.s2n_crypto") 8 | require("tls.s2n_config") 9 | require("tls.s2n_prf") 10 | 11 | require("stuffer.s2n_stuffer") 12 | 13 | require("crypto.s2n_hash") 14 | require("crypto.s2n_hmac") 15 | 16 | require("utils.s2n_mem") 17 | 18 | local S2N_TLS_PROTOCOL_VERSION_LEN = 2 19 | local S2N_TLS_SESSION_ID_LEN = 32 20 | 21 | ffi.cdef[[ 22 | struct s2n_connection { 23 | /* The configuration (cert, key .. etc ) */ 24 | struct s2n_config *config; 25 | 26 | /* The read and write fds don't have to be the same (e.g. two pipes) */ 27 | int readfd; 28 | int writefd; 29 | 30 | /* Is this connection a client or a server connection */ 31 | s2n_mode mode; 32 | 33 | /* Does s2n handle the blinding, or does the application */ 34 | s2n_blinding blinding; 35 | 36 | /* The version advertised by the client, by the 37 | * server, and the actual version we are currently 38 | * speaking. */ 39 | uint8_t client_hello_version; 40 | uint8_t client_protocol_version; 41 | uint8_t server_protocol_version; 42 | uint8_t actual_protocol_version; 43 | uint8_t actual_protocol_version_established; 44 | 45 | /* Our crypto paramaters */ 46 | struct s2n_crypto_parameters active; 47 | struct s2n_crypto_parameters pending; 48 | 49 | /* Which set is the client/server actually using? */ 50 | struct s2n_crypto_parameters *client; 51 | struct s2n_crypto_parameters *server; 52 | 53 | /* The PRF needs some storage elements to work with */ 54 | union s2n_prf_working_space prf_space; 55 | 56 | /* Our workhorse stuffers, used for buffering the plaintext 57 | * and encrypted data in both directions. 58 | */ 59 | uint8_t header_in_data[S2N_TLS_RECORD_HEADER_LENGTH]; 60 | struct s2n_stuffer header_in; 61 | struct s2n_stuffer in; 62 | struct s2n_stuffer out; 63 | enum { ENCRYPTED, PLAINTEXT } in_status; 64 | 65 | /* How big is the record we are actively reading? */ 66 | uint16_t current_in_record_size; 67 | 68 | /* An alert may be fragmented across multiple records, 69 | * this stuffer is used to re-assemble. 70 | */ 71 | uint8_t alert_in_data[S2N_ALERT_LENGTH]; 72 | struct s2n_stuffer alert_in; 73 | 74 | /* An alert may be partially written in the outbound 75 | * direction, so we keep this as a small 2 byte queue. 76 | * 77 | * We keep seperate queues for alerts generated by 78 | * readers (a response to an alert from a peer) and writers (an 79 | * intentional shutdown) so that the s2n reader and writer 80 | * can be seperate duplex I/O threads. 81 | */ 82 | uint8_t reader_alert_out_data[S2N_ALERT_LENGTH]; 83 | uint8_t writer_alert_out_data[S2N_ALERT_LENGTH]; 84 | struct s2n_stuffer reader_alert_out; 85 | struct s2n_stuffer writer_alert_out; 86 | 87 | /* Our handshake state machine */ 88 | struct s2n_handshake handshake; 89 | 90 | uint16_t max_fragment_length; 91 | 92 | /* Keep some accounting on each connection */ 93 | uint64_t wire_bytes_in; 94 | uint64_t wire_bytes_out; 95 | 96 | /* Is the connection open or closed ? We use C's only 97 | * atomic type as both the reader and the writer threads 98 | * may declare a connection closed. 99 | * 100 | * A connection can be gracefully closed or hard-closed. 101 | * When gracefully closed the reader or the writer mark 102 | * the connection as closing, and then the writer will 103 | * send an alert message before closing the connection 104 | * and marking it as closed. 105 | * 106 | * A hard-close goes straight to closed with no alert 107 | * message being sent. 108 | */ 109 | sig_atomic_t closing; 110 | sig_atomic_t closed; 111 | 112 | /* TLS extension data */ 113 | char server_name[256]; 114 | char application_protocol[256]; 115 | 116 | /* OCSP stapling response data */ 117 | s2n_status_request_type status_type; 118 | struct s2n_blob status_response; 119 | }; 120 | ]] 121 | 122 | local exports = { 123 | S2N_TLS_PROTOCOL_VERSION_LEN = S2N_TLS_PROTOCOL_VERSION_LEN; 124 | S2N_TLS_SESSION_ID_LEN = S2N_TLS_SESSION_ID_LEN; 125 | 126 | -- data types 127 | s2n_connection = ffi.typeof("struct s2n_connection"); 128 | } 129 | 130 | return exports 131 | -------------------------------------------------------------------------------- /tls/s2n_record.lua: -------------------------------------------------------------------------------- 1 | 2 | require ("tls.s2n_connection") 3 | 4 | ffi.cdef[[ 5 | extern int s2n_record_max_write_payload_size(struct s2n_connection *conn); 6 | extern int s2n_record_write(struct s2n_connection *conn, uint8_t content_type, struct s2n_blob *in); 7 | extern int s2n_record_parse(struct s2n_connection *conn); 8 | extern int s2n_record_header_parse(struct s2n_connection *conn, uint8_t *content_type, uint16_t *fragment_length); 9 | extern int s2n_sslv2_record_header_parse(struct s2n_connection *conn, uint8_t *record_type, uint8_t *client_protocol_version, uint16_t *fragment_length); 10 | extern int s2n_cbc_masks_init(); 11 | extern int s2n_verify_cbc(struct s2n_connection *conn, struct s2n_hmac_state *hmac, struct s2n_blob *decrypted); 12 | extern int s2n_aead_aad_init(const struct s2n_connection *conn, uint8_t *sequence_number, uint8_t content_type, uint16_t record_length, struct s2n_stuffer *ad); 13 | ]] 14 | 15 | local exports = {} 16 | 17 | return exports -------------------------------------------------------------------------------- /tls/s2n_tls.lua: -------------------------------------------------------------------------------- 1 | require("tls.s2n_connection") 2 | 3 | ffi.cdef[[ 4 | extern uint8_t s2n_highest_protocol_version; 5 | 6 | /* 7 | * A TLS session ID is between 0 and 32 bytes 8 | */ 9 | struct s2n_tls_session_id { 10 | uint8_t session_id[32]; 11 | uint8_t session_id_len; 12 | }; 13 | 14 | extern int s2n_flush(struct s2n_connection *conn, int *more); 15 | extern int s2n_client_hello_send(struct s2n_connection *conn); 16 | extern int s2n_client_hello_recv(struct s2n_connection *conn); 17 | extern int s2n_sslv2_client_hello_recv(struct s2n_connection *conn); 18 | extern int s2n_server_hello_send(struct s2n_connection *conn); 19 | extern int s2n_server_hello_recv(struct s2n_connection *conn); 20 | extern int s2n_server_cert_send(struct s2n_connection *conn); 21 | extern int s2n_server_cert_recv(struct s2n_connection *conn); 22 | extern int s2n_server_status_send(struct s2n_connection *conn); 23 | extern int s2n_server_status_recv(struct s2n_connection *conn); 24 | extern int s2n_server_key_send(struct s2n_connection *conn); 25 | extern int s2n_server_key_recv(struct s2n_connection *conn); 26 | extern int s2n_server_done_send(struct s2n_connection *conn); 27 | extern int s2n_server_done_recv(struct s2n_connection *conn); 28 | extern int s2n_client_key_send(struct s2n_connection *conn); 29 | extern int s2n_client_key_recv(struct s2n_connection *conn); 30 | extern int s2n_client_ccs_send(struct s2n_connection *conn); 31 | extern int s2n_client_ccs_recv(struct s2n_connection *conn); 32 | extern int s2n_server_ccs_send(struct s2n_connection *conn); 33 | extern int s2n_server_ccs_recv(struct s2n_connection *conn); 34 | extern int s2n_client_finished_send(struct s2n_connection *conn); 35 | extern int s2n_client_finished_recv(struct s2n_connection *conn); 36 | extern int s2n_server_finished_send(struct s2n_connection *conn); 37 | extern int s2n_server_finished_recv(struct s2n_connection *conn); 38 | extern int s2n_handshake_write_header(struct s2n_connection *conn, uint8_t message_type); 39 | extern int s2n_handshake_finish_header(struct s2n_connection *conn); 40 | extern int s2n_handshake_parse_header(struct s2n_connection *conn, uint8_t *message_type, uint32_t *length); 41 | extern int s2n_read_full_record(struct s2n_connection *conn, uint8_t *record_type, int *isSSLv2); 42 | extern int s2n_client_extensions_send(struct s2n_connection *conn, struct s2n_stuffer *out); 43 | extern int s2n_client_extensions_recv(struct s2n_connection *conn, struct s2n_blob *extensions); 44 | extern int s2n_server_extensions_send(struct s2n_connection *conn, struct s2n_stuffer *out); 45 | extern int s2n_server_extensions_recv(struct s2n_connection *conn, struct s2n_blob *extensions); 46 | ]] 47 | 48 | 49 | local function s2n_server_can_send_ocsp(conn) 50 | return ((conn)->status_type == S2N_STATUS_REQUEST_OCSP && \ 51 | (conn)->config->cert_and_key_pairs && \ 52 | (conn)->config->cert_and_key_pairs->ocsp_status.size > 0) 53 | end 54 | 55 | local exports = {} 56 | 57 | return exports 58 | -------------------------------------------------------------------------------- /utils/s2n_blob.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | local Lib_s2n = ffi.load("s2n", true) 4 | 5 | ffi.cdef[[ 6 | struct s2n_blob { 7 | uint8_t *data; 8 | uint32_t size; 9 | }; 10 | 11 | extern int s2n_blob_init(struct s2n_blob *b, uint8_t *data, uint32_t size); 12 | extern int s2n_blob_zero(struct s2n_blob *b); 13 | ]] 14 | 15 | local s2n_blob = ffi.typeof("struct s2n_blob") 16 | local s2n_blob_mt = { 17 | __new = function(ct, data, size) 18 | size = size or 0 19 | --[[ 20 | -- if we're passed a string, we should make a copy of it 21 | -- and free it when out of scope. But, that's fairly impossible 22 | -- as we don't know when the blob object will go out of scope. 23 | if type(data) == "string" then 24 | data = strdup(data); 25 | ffi.gc(data, ffi.C.free) 26 | end 27 | --]] 28 | return ffi.new(ct, data, size); 29 | end, 30 | 31 | __index = { 32 | clear = function(self) 33 | ffi.fill(self, ffi.sizeof(self), 0); 34 | end, 35 | }, 36 | 37 | __tostring = function(self) 38 | return string.format("0x%x [%d]", tonumber(ffi.cast("intptr_t",self.data)), tonumber(self.size)); 39 | end, 40 | } 41 | ffi.metatype(s2n_blob, s2n_blob_mt); 42 | 43 | 44 | local exports = { 45 | s2n_blob = s2n_blob; 46 | 47 | -- library functions 48 | s2n_blob_init = Lib_s2n.s2n_blob_init; 49 | s2n_blob_zero = Lib_s2n.s2n_blob_zero; 50 | } 51 | 52 | return exports 53 | -------------------------------------------------------------------------------- /utils/s2n_mem.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | require("utils.s2n_blob") 4 | 5 | local Lib_s2n = ffi.load("s2n", true) 6 | 7 | ffi.cdef[[ 8 | int s2n_alloc(struct s2n_blob *b, uint32_t size); 9 | int s2n_realloc(struct s2n_blob *b, uint32_t size); 10 | int s2n_free(struct s2n_blob *b); 11 | ]] 12 | 13 | 14 | local exports = { 15 | s2n_alloc = Lib_s2n.s2n_alloc; 16 | s2n_realloc = Lib_s2n.s2n_realloc; 17 | s2n_free = Lib_s2n.s2n_free; 18 | } 19 | 20 | return exports 21 | -------------------------------------------------------------------------------- /utils/s2n_safety.lua: -------------------------------------------------------------------------------- 1 | require("error.s2n_errno") 2 | 3 | -- NULL check a pointer */ 4 | local function notnull_check( ptr ) 5 | if ( ptr == nil ) then 6 | S2N_ERROR(S2N_ERR_NULL); 7 | end 8 | end 9 | 10 | -- Check memcpy's return, if it's not right (very unlikely!) bail, set an error 11 | -- err and return -1; 12 | -- 13 | local function memcpy_check( d, s, n ) 14 | notnull_check( (d) ); 15 | if ( memcpy( (d), (s), (n)) != (d) ) then 16 | S2N_ERROR(S2N_ERR_MEMCPY) 17 | end 18 | end 19 | 20 | local function memset_check( d, c, n ) 21 | notnull_check( (d) ); if ( memset( (d), (c), (n)) != (d) ) { S2N_ERROR(S2N_ERR_MEMSET); } } while(0) 22 | end 23 | 24 | -- Range check a number 25 | local function gte_check(n, min) 26 | if ( (n) < min ) then 27 | S2N_ERROR(S2N_ERR_SAFETY); 28 | end 29 | end 30 | 31 | local function lte_check(n, max) 32 | if ( (n) > max ) then 33 | S2N_ERROR(S2N_ERR_SAFETY); 34 | end 35 | end 36 | 37 | local function gt_check(n, min) if ( (n) <= min ) { S2N_ERROR(S2N_ERR_SAFETY); } } end 38 | local function lt_check(n, max) if ( (n) >= max ) { S2N_ERROR(S2N_ERR_SAFETY); } } end 39 | local function eq_check(a, b) if ( (a) != (b) ) { S2N_ERROR(S2N_ERR_SAFETY); } } end 40 | local function ne_check(a, b) if ( (a) == (b) ) { S2N_ERROR(S2N_ERR_SAFETY); } } end 41 | local function inclusive_range_check( low, n, high ) gte_check(n, low); lte_check(n, high) 42 | local function exclusive_range_check( low, n, high ) gt_check(n, low); lt_check(n, high) 43 | 44 | local function GUARD( x ) 45 | if (x < 0 ) return -1 46 | end 47 | 48 | 49 | local function GUARD_PTR( x ) 50 | if ( x < 0 ) return nil 51 | end 52 | 53 | local exports = { 54 | -- local functions 55 | GUARD = GUARD; 56 | GUARD_PTR = GUARD_PTR; 57 | } 58 | 59 | setmetatable(exports, { 60 | __call = function(self) 61 | for k,v in pairs(exports) do 62 | _G[k] = v; 63 | end 64 | end, 65 | }) 66 | 67 | return exports 68 | --------------------------------------------------------------------------------