8 Commits
v1.0 ... ocsp

Author SHA1 Message Date
7ce63ad392 Return nil instead boolean 2021-06-25 19:59:22 -03:00
a3e74db781 Some work with OCSP 2021-06-25 19:50:47 -03:00
cdcf5fdb30 Off by one in cert:validat(notafter) #173 2021-06-23 13:35:49 -03:00
bdbc67b188 Move the fix of SSL_get_error() in OpenSSL 1.1.1
Moving to lsec_socket_error() coverts better 'errno == 0' with SSL_ERROR_SYSCALL.
2021-05-29 10:11:02 -03:00
359151144b Merge pull request #172 from edzius/master
Handle SSL_send SYSCALL error without errno
https://www.openssl.org/docs/man1.1.1/man3/SSL_get_error.html
2021-05-29 09:38:29 -03:00
d6b2fd7d35 Handle SSL_send SYSCALL error without errno
Either intentionaly or due to bug in openssl in some marginal
cases SSL_send reports SYSCALL error whilst errno is set to 0.
This either could mean that SSL_send did not made any system
call or errno were prematurely reset with consequent syscalls.
And in consequence sendraw() is not propagate correct errno
ends up in infinite loop trying to send same data.

Such behaviour was usually observed after third consequential
failed SSL send attempt which application was not aware of.
First send failed with syscall errno 32 (Broken pipe) second
one with SSL error 0x1409e10f (bad length) and lastly next
send attemt results with SYSCALL error and errno 0.

Tested using:
* OpenSSL v1.1.1
* musl v1.1.20 (c50985d5c8e316c5c464f352e79eeebfed1121a9)
* Linux 4.4.60+yocto armv7l
2021-05-21 21:20:19 +03:00
d5df315617 Update version and rockspec 2021-04-26 09:16:05 -03:00
34252fb10a Set parameter 2 and 3 to none before luaL_buffinit() 2021-04-26 08:37:09 -03:00
22 changed files with 473 additions and 27 deletions

View File

@ -1,3 +1,11 @@
--------------------------------------------------------------------------------
LuaSec 1.0.1
---------------
This version includes:
* Fix luaL_buffinit() can use the stack and broke buffer_meth_receive()
--------------------------------------------------------------------------------
LuaSec 1.0
---------------

View File

@ -1,4 +1,4 @@
LuaSec 1.0
LuaSec 1.0.1
------------
* OpenSSL options:

View File

@ -1,4 +1,4 @@
LuaSec 1.0 license
LuaSec 1.0.1 license
Copyright (C) 2006-2021 Bruno Silvestre, UFG
Permission is hereby granted, free of charge, to any person obtaining

View File

@ -1,4 +1,4 @@
LuaSec 1.0
LuaSec 1.0.1
===============
LuaSec depends on OpenSSL, and integrates with LuaSocket to make it
easy to add secure connections to any Lua applications or scripts.

View File

@ -1,8 +1,8 @@
package = "LuaSec"
version = "1.0-1"
version = "1.0.1-1"
source = {
url = "git://github.com/brunoos/luasec",
tag = "v1.0",
tag = "v1.0.1",
}
description = {
summary = "A binding for OpenSSL library to provide TLS/SSL communication over LuaSocket.",

54
samples/ocsp/client.lua Normal file
View File

@ -0,0 +1,54 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local ocsp = ssl.ocsp
-- Parameters
-- * status:
-- * nil (no status was sent by server)
-- * ocsp.status.successful
-- * ocsp.status.malformedrequest
-- * ocsp.status.internalerror
-- * ocsp.status.trylater
-- * ocsp.status.sigrequired
-- * ocsp.status.unauthorized
--
-- Returns
-- * nil: on error
-- * true: status was accepted (continue the handshake)
-- * false: status not accepted (handshake stops with error)
--
local callback = function(status)
print("Status: ", status)
print("---")
if status == nil then
print("[WARN] No OCSP response")
return true
end
return (status == ocsp.status.successful)
end
local params = {
mode = "client",
protocol = "tlsv1_2",
verify = "none",
options = "all",
ocsp = callback,
}
while true do
local peer = socket.tcp()
peer:connect("127.0.0.1", 8443)
peer = assert(ssl.wrap(peer, params))
assert(peer:dohandshake())
print(peer:receive())
print("------------")
peer:close()
end

89
samples/ocsp/server.lua Normal file
View File

@ -0,0 +1,89 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local mime = require("mime")
local ltn12 = require("ltn12")
local http = require("socket.http")
local ocsp = ssl.ocsp
--------------------------------------------------------------------------------
local response
function loadresponse(certfile, cafile)
local f = io.open(cafile)
local ca = f:read("*a")
ca = ssl.loadcertificate(ca)
f:close()
f = io.open(certfile)
local cert = f:read("*a")
cert = ssl.loadcertificate(cert)
f:close()
local res = {}
local req = ocsp.buildrequest(cert, ca)
req = mime.b64(req)
local a, b = http.request {
url = "http://zerossl.ocsp.sectigo.com/" .. req,
method = "GET",
sink = ltn12.sink.table(res),
header = {
["Content-Type"] = "application/ocsp-request",
["Host"] = "zerossl.ocsp.sectigo.com",
},
}
response = table.concat(res)
local thisupd, nextupd = ocsp.responsetime(response)
print("This update: ", thisupd)
print("Next update: ", nextupd)
end
--------------------------------------------------------------------------------
local cafile = "ca.pem"
local certfile = "server.pem"
-- Remember to update 'response' before 'next update'
local callback = function()
if not response then
loadresponse(certfile, cafile)
end
return response
end
local params = {
mode = "server",
protocol = "any",
key = "server.key",
certificate = certfile,
verify = "none",
options = "all",
ocsp = callback,
}
--------------------------------------------------------------------------------
local ctx = assert(ssl.newcontext(params))
local server = socket.tcp()
server:setoption('reuseaddr', true)
assert(server:bind("127.0.0.1", 8443))
server:listen()
while true do
local peer = server:accept()
peer = assert(ssl.wrap(peer, ctx))
local succ = peer:dohandshake()
if succ then
peer:send("OCSP test\n")
peer:close()
end
end

View File

@ -1,5 +1,5 @@
/*--------------------------------------------------------------------------
* LuaSec 1.0
* LuaSec 1.0.1
*
* Copyright (C) 2006-2021 Bruno Silvestre
*
@ -48,4 +48,10 @@
//------------------------------------------------------------------------------
#if !defined(LIBRESSL_VERSION_NUMBER) && ((OPENSSL_VERSION_NUMBER & 0xFFFFF000L) == 0x10101000L)
#define LSEC_OPENSSL_1_1_1
#endif
//------------------------------------------------------------------------------
#endif

View File

@ -1,5 +1,5 @@
/*--------------------------------------------------------------------------
* LuaSec 1.0
* LuaSec 1.0.1
*
* Copyright (C) 2006-2021 Bruno Silvestre.
*
@ -81,6 +81,13 @@ LSEC_API int luaopen_ssl_config(lua_State *L)
lua_rawset(L, -3);
#endif
#ifndef OPENSSL_NO_OCSP
// OCSP
lua_pushstring(L, "ocsp");
lua_pushboolean(L, 1);
lua_rawset(L, -3);
#endif
#ifndef OPENSSL_NO_EC
lua_pushstring(L, "curves_list");
lua_pushboolean(L, 1);

View File

@ -1,5 +1,5 @@
/*--------------------------------------------------------------------------
* LuaSec 1.0
* LuaSec 1.0.1
*
* Copyright (C) 2014-2021 Kim Alvefur, Paul Aurich, Tobias Markmann,
* Matthew Wild.
@ -19,12 +19,17 @@
#include <openssl/x509v3.h>
#include <openssl/dh.h>
#ifndef OPENSSL_NO_OCSP
#include <openssl/ocsp.h>
#endif
#include <lua.h>
#include <lauxlib.h>
#include "compat.h"
#include "context.h"
#include "options.h"
#include "x509.h"
#ifndef OPENSSL_NO_EC
#include <openssl/ec.h>
@ -707,6 +712,198 @@ static int set_alpn_cb(lua_State *L)
return 1;
}
#ifndef OPENSSL_NO_OCSP
static int ocsp_server_cb(SSL *ssl, void *arg)
{
int len;
BIO *bio;
const char *data;
unsigned char *r = NULL;
OCSP_RESPONSE *resp = NULL;
p_context ctx = (p_context)arg;
lua_State *L = ctx->L;
// Retrieve the callback
luaL_getmetatable(L, "SSL:OCSP:Registry");
lua_pushlightuserdata(L, ctx->context);
lua_rawget(L, -2);
lua_call(L, 0, 1);
if (lua_type(L, -1) != LUA_TSTRING) {
return SSL_TLSEXT_ERR_NOACK;
}
data = lua_tostring(L, -1);
len = (int)lua_rawlen(L, -1);
bio = BIO_new_mem_buf(data, len);
if (bio == NULL)
return SSL_TLSEXT_ERR_NOACK;
resp = d2i_OCSP_RESPONSE_bio(bio, NULL);
BIO_free(bio);
if (resp == NULL)
return SSL_TLSEXT_ERR_NOACK;
len = i2d_OCSP_RESPONSE(resp, &r);
if (len <= 0) {
OCSP_RESPONSE_free(resp);
return SSL_TLSEXT_ERR_NOACK;
}
SSL_set_tlsext_status_ocsp_resp(ssl, r, len);
OCSP_RESPONSE_free(resp);
return SSL_TLSEXT_ERR_OK;
}
static int ocsp_client_cb(SSL *ssl, void *arg)
{
long len;
const unsigned char *b;
OCSP_RESPONSE *ocsp = NULL;
p_context ctx = (p_context)arg;
lua_State *L = ctx->L;
// Retrieve the callback
luaL_getmetatable(L, "SSL:OCSP:Registry");
lua_pushlightuserdata(L, ctx->context);
lua_rawget(L, -2);
len = SSL_get_tlsext_status_ocsp_resp(ssl, &b);
if (len == -1)
lua_pushnil(L);
else {
ocsp = d2i_OCSP_RESPONSE(NULL, &b, len);
lua_pushinteger(L, OCSP_response_status(ocsp));
OCSP_RESPONSE_free(ocsp);
}
lua_call(L, 1, 1);
return (lua_type(L, -1) != LUA_TBOOLEAN) ? -1 : (int)lua_toboolean(L, -1);
}
static int set_ocsp_cb(lua_State *L)
{
int ret;
p_context ctx = checkctx(L, 1);
luaL_getmetatable(L, "SSL:OCSP:Registry");
lua_pushlightuserdata(L, (void*)ctx->context);
lua_pushvalue(L, 2);
lua_settable(L, -3);
ret = (int)SSL_CTX_set_tlsext_status_type(ctx->context, TLSEXT_STATUSTYPE_ocsp);
if (ret == 0) {
lua_pushboolean(L, 0);
return 1;
}
if (ctx->mode == LSEC_MODE_CLIENT)
ret = (int)SSL_CTX_set_tlsext_status_cb(ctx->context, ocsp_client_cb);
else
ret = (int)SSL_CTX_set_tlsext_status_cb(ctx->context, ocsp_server_cb);
if (ret == 0) {
lua_pushboolean(L, 0);
return 1;
}
ret = (int)SSL_CTX_set_tlsext_status_arg(ctx->context, ctx);
lua_pushboolean(L, ret == 1);
return 1;
}
static int ocsp_build_request(lua_State *L)
{
long len;
BIO *bio;
X509 *cert;
X509 *issuer;
OCSP_CERTID *cid;
OCSP_REQUEST *req;
char *buf;
cert = lsec_checkx509(L, 1);
issuer = lsec_checkx509(L, 2);
req = OCSP_REQUEST_new();
if (req == NULL) {
lua_pushnil(L);
return 1;
}
cid = OCSP_cert_to_id(NULL, cert, issuer);
if (cid == NULL) {
lua_pushnil(L);
return 1;
}
if (OCSP_request_add0_id(req, cid) == NULL) {
lua_pushnil(L);
return 1;
}
bio = BIO_new(BIO_s_mem());
i2d_OCSP_REQUEST_bio(bio, req);
len = BIO_get_mem_data(bio, &buf);
lua_pushlstring(L, buf, len);
BIO_free(bio);
OCSP_REQUEST_free(req);
return 1;
}
static int ocsp_response_time(lua_State *L)
{
long len;
BIO *bio;
char *buf;
int reason;
OCSP_BASICRESP *bs;
OCSP_SINGLERESP *sr;
OCSP_RESPONSE *res;
ASN1_GENERALIZEDTIME *revtime, *thisupd, *nextupd;
buf = (char*)lua_tostring(L, 1);
len = (long)lua_rawlen(L, 1);
res = d2i_OCSP_RESPONSE(NULL, (const unsigned char**)&buf, (int)len);
if (res == NULL) {
lua_pushnil(L);
lua_pushnil(L);
return 2;
}
bs = OCSP_response_get1_basic(res);
if (bs == NULL) {
lua_pushnil(L);
lua_pushnil(L);
return 2;
}
sr = OCSP_resp_get0(bs, 0);
OCSP_single_get0_status(sr, &reason, &revtime, &thisupd, &nextupd);
bio = BIO_new(BIO_s_mem());
ASN1_GENERALIZEDTIME_print(bio, thisupd);
len = BIO_get_mem_data(bio, &buf);
lua_pushlstring(L, buf, len);
BIO_free(bio);
bio = BIO_new(BIO_s_mem());
ASN1_GENERALIZEDTIME_print(bio, nextupd);
len = BIO_get_mem_data(bio, &buf);
lua_pushlstring(L, buf, len);
BIO_free(bio);
OCSP_BASICRESP_free(bs);
OCSP_RESPONSE_free(res);
return 2;
}
#endif
#if defined(LSEC_ENABLE_DANE)
/*
* DANE
@ -745,6 +942,9 @@ static luaL_Reg funcs[] = {
#endif
#if defined(LSEC_ENABLE_DANE)
{"setdane", set_dane},
#endif
#if !defined(OPENSSL_NO_OCSP)
{"setocspcb", set_ocsp_cb},
#endif
{NULL, NULL}
};
@ -771,6 +971,10 @@ static int meth_destroy(lua_State *L)
lua_pushlightuserdata(L, (void*)ctx->context);
lua_pushnil(L);
lua_settable(L, -3);
luaL_getmetatable(L, "SSL:OCSP:Registry");
lua_pushlightuserdata(L, (void*)ctx->context);
lua_pushnil(L);
lua_settable(L, -3);
SSL_CTX_free(ctx->context);
ctx->context = NULL;
@ -908,6 +1112,55 @@ void *lsec_testudata (lua_State *L, int ud, const char *tname) {
/*------------------------------ Initialization ------------------------------*/
#ifndef OPENSSL_NO_OCSP
struct ocsp_status_response_s {
const char *name;
int value;
};
typedef struct ocsp_status_response_s ocsp_status_response_t;
static ocsp_status_response_t status_response[] = {
{"successful", OCSP_RESPONSE_STATUS_SUCCESSFUL},
{"malformedrequest", OCSP_RESPONSE_STATUS_MALFORMEDREQUEST},
{"internalerror", OCSP_RESPONSE_STATUS_INTERNALERROR},
{"trylater", OCSP_RESPONSE_STATUS_TRYLATER},
{"sigrequired", OCSP_RESPONSE_STATUS_SIGREQUIRED},
{"unauthorized", OCSP_RESPONSE_STATUS_UNAUTHORIZED},
{NULL, 0}
};
static luaL_Reg ocsp_funcs[] = {
{"buildrequest", ocsp_build_request},
{"responsetime", ocsp_response_time},
{NULL, NULL}
};
/**
* OCSP module
*/
LSEC_API int luaopen_ssl_context_ocsp(lua_State *L)
{
ocsp_status_response_t *ptr;
luaL_newlib(L, ocsp_funcs);
lua_pushstring(L, "status");
lua_newtable(L);
for (ptr = status_response; ptr->name; ptr++) {
lua_pushstring(L, ptr->name);
lua_pushinteger(L, ptr->value);
lua_rawset(L, -3);
}
lua_rawset(L, -3);
return 1;
}
#endif
//------------------------------------------------------------------------------
/**
* Registre the module.
*/
@ -916,6 +1169,7 @@ LSEC_API int luaopen_ssl_context(lua_State *L)
luaL_newmetatable(L, "SSL:DH:Registry"); /* Keep all DH callbacks */
luaL_newmetatable(L, "SSL:ALPN:Registry"); /* Keep all ALPN callbacks */
luaL_newmetatable(L, "SSL:Verify:Registry"); /* Keep all verify flags */
luaL_newmetatable(L, "SSL:OCSP:Registry"); /* Keep all OCSP callbacks */
luaL_newmetatable(L, "SSL:Context");
setfuncs(L, meta);

View File

@ -2,7 +2,7 @@
#define LSEC_CONTEXT_H
/*--------------------------------------------------------------------------
* LuaSec 1.0
* LuaSec 1.0.1
*
* Copyright (C) 2006-2021 Bruno Silvestre
*

View File

@ -1,5 +1,5 @@
/*--------------------------------------------------------------------------
* LuaSec 1.0
* LuaSec 1.0.1
*
* Copyright (C) 2006-2021 Bruno Silvestre
*

View File

@ -1,5 +1,5 @@
----------------------------------------------------------------------------
-- LuaSec 1.0
-- LuaSec 1.0.1
-- Copyright (C) 2009-2021 PUC-Rio
--
-- Author: Pablo Musa
@ -18,8 +18,8 @@ local try = socket.try
-- Module
--
local _M = {
_VERSION = "1.0",
_COPYRIGHT = "LuaSec 1.0 - Copyright (C) 2009-2021 PUC-Rio",
_VERSION = "1.0.1",
_COPYRIGHT = "LuaSec 1.0.1 - Copyright (C) 2009-2021 PUC-Rio",
PORT = 443,
TIMEOUT = 60
}

View File

@ -107,10 +107,16 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
* object:receive() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_receive(lua_State *L, p_buffer buf) {
int err = IO_DONE, top = lua_gettop(L);
luaL_Buffer b;
size_t size;
const char *part = luaL_optlstring(L, 3, "", &size);
const char *part;
int err = IO_DONE;
int top = lua_gettop(L);
if (top < 3) {
lua_settop(L, 3);
top = 3;
}
part = luaL_optlstring(L, 3, "", &size);
#ifdef LUASOCKET_DEBUG
p_timeout tm = timeout_markstart(buf->tm);
#endif

View File

@ -1,5 +1,5 @@
/*--------------------------------------------------------------------------
* LuaSec 1.0
* LuaSec 1.0.1
*
* Copyright (C) 2006-2021 Bruno Silvestre
*

View File

@ -2,7 +2,7 @@
#define LSEC_OPTIONS_H
/*--------------------------------------------------------------------------
* LuaSec 1.0
* LuaSec 1.0.1
*
* Copyright (C) 2006-2021 Bruno Silvestre
*

View File

@ -18,7 +18,7 @@ end
local function generate(options, version)
print([[
/*--------------------------------------------------------------------------
* LuaSec 1.0
* LuaSec 1.0.1
*
* Copyright (C) 2006-2021 Bruno Silvestre
*

View File

@ -1,5 +1,5 @@
/*--------------------------------------------------------------------------
* LuaSec 1.0
* LuaSec 1.0.1
*
* Copyright (C) 2014-2021 Kim Alvefur, Paul Aurich, Tobias Markmann,
* Matthew Wild.
@ -48,6 +48,11 @@ static int lsec_socket_error()
#if defined(WIN32)
return WSAGetLastError();
#else
#if defined(LSEC_OPENSSL_1_1_1)
// Bug in OpenSSL 1.1.1
if (errno == 0)
return LSEC_IO_SSL;
#endif
return errno;
#endif
}
@ -819,7 +824,7 @@ static int meth_getalpn(lua_State *L)
static int meth_copyright(lua_State *L)
{
lua_pushstring(L, "LuaSec 1.0 - Copyright (C) 2006-2021 Bruno Silvestre, UFG"
lua_pushstring(L, "LuaSec 1.0.1 - Copyright (C) 2006-2021 Bruno Silvestre, UFG"
#if defined(WITH_LUASOCKET)
"\nLuaSocket 3.0-RC1 - Copyright (C) 2004-2013 Diego Nehab"
#endif

View File

@ -2,7 +2,7 @@
#define LSEC_SSL_H
/*--------------------------------------------------------------------------
* LuaSec 1.0
* LuaSec 1.0.1
*
* Copyright (C) 2006-2021 Bruno Silvestre
*

View File

@ -1,5 +1,5 @@
------------------------------------------------------------------------------
-- LuaSec 1.0
-- LuaSec 1.0.1
--
-- Copyright (C) 2006-2021 Bruno Silvestre
--
@ -10,6 +10,11 @@ local context = require("ssl.context")
local x509 = require("ssl.x509")
local config = require("ssl.config")
local ocsp
if config.capabilities.ocsp then
ocsp = require("ssl.context.ocsp")
end
local unpack = table.unpack or unpack
-- We must prevent the contexts to be collected before the connections,
@ -205,6 +210,14 @@ local function newcontext(cfg)
context.setdane(ctx)
end
if config.capabilities.ocsp and cfg.ocsp then
msg = "error setting OCSP"
succ = type(cfg.ocsp) == "function"
if not succ then return nil, msg end
succ = context.setocspcb(ctx, cfg.ocsp)
if not succ then return nil, msg end
end
return ctx
end
@ -271,9 +284,10 @@ core.setmethod("info", info)
--
local _M = {
_VERSION = "1.0",
_VERSION = "1.0.1",
_COPYRIGHT = core.copyright(),
config = config,
ocsp = ocsp,
loadcertificate = x509.load,
newcontext = newcontext,
wrap = wrap,

View File

@ -1,5 +1,5 @@
/*--------------------------------------------------------------------------
* LuaSec 1.0
* LuaSec 1.0.1
*
* Copyright (C) 2014-2021 Kim Alvefur, Paul Aurich, Tobias Markmann
* Matthew Wild, Bruno Silvestre.
@ -485,10 +485,13 @@ static int meth_digest(lua_State* L)
*/
static int meth_valid_at(lua_State* L)
{
int nb, na;
X509* cert = lsec_checkx509(L, 1);
time_t time = luaL_checkinteger(L, 2);
lua_pushboolean(L, (X509_cmp_time(X509_get0_notAfter(cert), &time) >= 0
&& X509_cmp_time(X509_get0_notBefore(cert), &time) <= 0));
nb = X509_cmp_time(X509_get0_notBefore(cert), &time);
time -= 1;
na = X509_cmp_time(X509_get0_notAfter(cert), &time);
lua_pushboolean(L, nb == -1 && na == 1);
return 1;
}

View File

@ -1,5 +1,5 @@
/*--------------------------------------------------------------------------
* LuaSec 1.0
* LuaSec 1.0.1
*
* Copyright (C) 2014-2021 Kim Alvefur, Paul Aurich, Tobias Markmann
* Matthew Wild, Bruno Silvestre.