33 Commits

Author SHA1 Message Date
47cc914e69 Update version number. 2015-11-20 19:39:32 -02:00
90d4f2d95c typo: intall -> install.
update MacOSX version -> 10.11.
2015-11-20 19:20:07 -02:00
172d324243 Fix push_asn1_string(). 2015-11-20 19:16:16 -02:00
6cc8e951d4 Update samples. 2015-11-20 19:12:19 -02:00
d36e156fac Guard SSLv3_method() with #ifndef OPENSSL_NO_SSL3.
Use TLS_method() instead of SSLv32_method(), when it is the case.
2015-11-20 18:54:57 -02:00
21aefcf67d Version number -> 0.5. 2014-01-29 18:43:33 -02:00
89375f495a Examples update. 2014-01-29 17:47:27 -02:00
46d6078e82 Merge branch 'master' of https://github.com/brunoos/luasec 2013-10-23 13:53:43 -02:00
ce504d3554 Add x509:setencode() function to change the encode of ASN.1 string. 2013-10-23 13:42:34 -02:00
4a95102cc8 Merge pull request #8 from xnyhps/protocol_version
Report the actual TLS version used, not the version the cipher belongs to.
2013-09-16 09:25:39 -07:00
fe782fde14 Merge pull request #10 from darkrain42/master
Various minor fixes (build on Fedora/RH, memory leaks)
2013-09-16 09:17:58 -07:00
1d920fc13c context: Don't leak DH* in dhparam_cb
==1429== 336 (144 direct, 192 indirect) bytes in 1 blocks are definitely lost in loss record 567 of 611
...
==1429==    by 0x5ECCBC7: PEM_ASN1_read_bio (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==1429==    by 0x4E39D8F: dhparam_cb (context.c:184)
==1429==    by 0x5B679D3: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==1429==    by 0x5B6A6EE: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==1429==    by 0x4E3C00D: meth_handshake (ssl.c:103)
...
2013-09-11 21:55:25 -07:00
0dab860770 context: Link SSL_CTX to p_context (not lua_State)
This is needed because the p_context is going to cache DH (and eventually
EC_KEY) objects, to plug a leak in the dhparam callback.
2013-09-11 21:55:25 -07:00
8cf7eb2d78 context: for dhparam_cb, pass is_export as boolean
The integer value that's actually returned for this flag is 2, which is fine
for C (it is defined as true), but it's sufficiently surprising (because it's
not 1), that this is worth fixing -- even if export ciphers aren't common.

It should be a boolean anyway.
2013-09-11 21:55:25 -07:00
9c7c96f2a0 Add useful context to various error messages 2013-09-11 21:55:25 -07:00
9262f9e7de ssl.lua: Comment subtle DH/ECDH ordering caveat 2013-09-11 21:55:25 -07:00
3fb33cdc4e context: Don't leak EC_KEY in set_curve()
SSL_CTX_set_tmp_ecdh() takes a reference to the provided key.

==8323== 1,044 (56 direct, 988 indirect) bytes in 1 blocks are definitely lost in loss record 611 of 631
==8323==    at 0x4C2935B: malloc (vg_replace_malloc.c:270)
==8323==    by 0x5E05D9F: CRYPTO_malloc (mem.c:308)
==8323==    by 0x5E59859: EC_KEY_new (ec_key.c:75)
==8323==    by 0x5E59974: EC_KEY_new_by_curve_name (ec_key.c:96)
==8323==    by 0x4E395A7: set_curve (context.c:261)
...
2013-09-11 21:55:25 -07:00
a344f58b20 context: Wrap find_ec_key in #ifndef OPENSSL_NO_ECDH
"#ifndef OPENSSL_NO_ECDH" is a ridiculous conditional, by the way.
2013-09-11 21:55:25 -07:00
1a75704ff0 Report the actual TLS version used, not the version the cipher belongs
to.
2013-09-08 15:00:07 +02:00
063e8a8a5c - using buffer from luasocket 3.0.
- adding getstats() and setstats().
2013-06-20 13:03:58 -03:00
9f16c6fb11 Merge pull request #4 from darkrain42/master
no_compression fix for OpenSSL 0.9.8
2013-06-13 15:04:54 -07:00
7532f3b729 context: Support explicit selection of TLS v1.1 and v1.2 2013-06-12 19:06:16 -07:00
2dae14877e options: Remove dead code
The workaround for 'no_compression' on older OpenSSL is handled in context.c;
set_option_flag (which uses ssl_options) is never called, so this shouldn't
exist.
2013-06-12 18:38:44 -07:00
4c5ce1b177 context: Incidental cleanup 2013-06-12 18:36:35 -07:00
9bda3322fb context: no_compression is options, not verify
The OpenSSL 0.9.8 compat needs to be handled as part of the options, not the
verification flags.
2013-06-12 18:33:19 -07:00
f77fb40033 Merge pull request #3 from msva/master
DESTDIR compatibility + *FLAGs/utils configurability + ld -fpic error fix + #1 fix
2013-05-15 04:02:47 -07:00
fceef56dce DESTDIR compatibility + *FLAGs/utils configurability + ld -fpic error fix. Also fixes #1
Signed-off-by: Vadim A. Misbakh-Soloviov <mva@mva.name>
2013-05-14 08:13:57 +07:00
4aecd53dc1 Update README with version explanation 2013-03-30 13:12:57 +00:00
1b899afd38 Remove duplicate files (now in luasocket/) 2013-03-30 12:49:55 +00:00
77ac210283 LuaSec 20120616 (unofficial) + patches 2013-03-30 12:21:40 +00:00
908fc346d2 LuaSec 0.4.1 2012-09-02 11:40:59 -03:00
67e5176b6b LuaSec 0.4 2012-09-02 11:32:26 -03:00
29c6bd65d2 LuaSec 0.3.3 2012-09-02 11:31:22 -03:00
75 changed files with 4351 additions and 778 deletions

View File

@ -1,3 +1,67 @@
--------------------------------------------------------------------------------
LuaSec 0.5.1
------------
- Check if SSLv3 protocol is available.
- Fix push_asn1_string().
- Update samples to use 'sslv23' and 'tlsv1_2'.
- Update MACOSX_VERSION to 10.11 on Makefile.
--------------------------------------------------------------------------------
LuaSec 0.5
------------
LuaSec depends on OpenSSL, and integrates with LuaSocket to make it
easy to add secure connections to any Lua applications or scripts.
This version includes:
* A new certificate (X509) API, which supports:
- Reading the subject (identity) and issuer of the certificate.
- Reading various X509 extensions, including email and dnsName.
- Converting certificates to and from the standard ASCII PEM
format.
- Generating the fingerprint/digest of a certificate (using SHA1,
SHA256 or SHA512).
- Reading the certificate's expiration, serial number, and other
info.
* The ability to get more detailed information from OpenSSL about
why a certificate failed verification, for each certificate in the
chain.
* Flags to force acceptance of invalid certificates, e.g. to allow
the use of self-signed certificates in a Trust On First Use model.
* Flags to control checking CRLs for certificate revocation status.
* Support for ECDH cipher suites.
* An API to get the TLS 'finished' messages used for SASL channel
binding (e.g. the SCRAM PLUS mechanisms).
The work in this release was undertaken by Kim Alvefur, Paul Aurich,
Tobias Markmann, Bruno Silvestre and Matthew Wild.
--------------------------------------------------------------------------------
LuaSec 0.4.1
------------
- SSL options updated --- based on OpenSSL 1.0.0d.
- Activate SSL_MODE_RELEASE_BUFFERS by default if it is available.
(thanks Prosody project)
---------------------------------------------------------------------------------
LuaSec 0.4
------------
- Add option 'no_ticket' (included in OpenSSL 0.9.8f).
- Add HTTPS module. (thanks Tomas Guisasola and Pablo Musa)
--------------------------------------------------------------------------------
LuaSec 0.3.3
------------
- BUG: Clear the error queue before call I/O functions (see SSL_get_error
manual).
(thanks Matthew Wild)
--------------------------------------------------------------------------------
LuaSec 0.3.2
------------

20
INSTALL
View File

@ -1,10 +1,22 @@
LuaSec 0.3.2
LuaSec 0.5.1
------------
* OpenSSL options:
By default, LuaSec 0.5.1 includes options for OpenSSL 1.0.1e.
If you need to generate the options for a different version of OpenSSL:
$ cd src
$ lua options.lua -g /usr/include/openssl/ssl.h > options.h
--------------------------------------------------------------------------------
* On Linux, BSD, and Mac OS X:
- Edit 'Makefile'
* Inform the path to install the modules.
* Inform the path to where install the Lua modules (LUAPATH) and binaries
modules (LUACPATH)
* If Lua or OpenSSL are not in the default path, set the
variables INCDIR and LIBDIR.
* For Mac OS X, set the variable MACOSX_VERSION.
@ -14,6 +26,8 @@ LuaSec 0.3.2
- Use 'make install' to install the modules.
--------------------------------------------------------------------------------
* On Windows:
- Use the Visual C++ project to compile the library.
@ -21,3 +35,5 @@ LuaSec 0.3.2
- Copy the 'ssl.lua' file to some place in your LUA_PATH.
- Copy the 'ssl.dll' file to some place in your LUA_CPATH.
- Create a directory 'ssl' in your LUA_PATH and copy 'https.lua' to it.

28
LICENSE
View File

@ -1,5 +1,5 @@
LuaSec 0.3.2 license
Copyright (C) 2006-2009 Bruno Silvestre
LuaSec 0.5.1 license
Copyright (C) 2006-2015 Bruno Silvestre, UFG
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -19,27 +19,3 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------
LuaSocket 2.0.2 license
Copyright <20> 2004-2007 Diego Nehab
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,16 +1,22 @@
# Inform the location to intall the modules
LUAPATH=/usr/local/share/lua/5.1
CPATH=/usr/local/lib/lua/5.1
# Inform the location to install the modules
LUAPATH ?= /usr/share/lua/5.1
LUACPATH ?= /usr/lib/lua/5.1
# Edit the lines below to inform new path, if necessary
#
#INCDIR=-I/usr/local/lua-5.1/include -I/usr/local/openssl-0.9.8/include
#LIBDIR=-L/usr/local/openssl-0.9.8/lib -R/usr/local/openssl-0.9.8/lib
# Compile with build-in LuaSocket's help files.
# Comment this lines if you will link with non-internal LuaSocket's help files
# and edit INCDIR and LIBDIR properly.
EXTRA = luasocket
DEFS = -DWITH_LUASOCKET
# Edit the lines below to inform new path, if necessary.
# Path below points to internal LuaSocket's help files.
INC_PATH ?= -I/usr/include
LIB_PATH ?= -L/usr/lib
INCDIR = -I. $(INC_PATH)
LIBDIR = -L./luasocket $(LIB_PATH)
# For Mac OS X: set the system version
MACOSX_VERSION=10.4
DEFS=-DBUFFER_DEBUG
MACOSX_VERSION?=10.11
#----------------------
# Do not edit this part
@ -26,25 +32,25 @@ none:
@echo " * macosx"
install:
@cd src ; $(MAKE) CPATH="$(CPATH)" LUAPATH="$(LUAPATH)" install
@cd src && $(MAKE) LUACPATH="$(LUACPATH)" LUAPATH="$(LUAPATH)" install
linux:
@echo "---------------------"
@echo "** Build for Linux **"
@echo "---------------------"
@cd src ; $(MAKE) INCDIR="$(INCDIR)" LIBDIR="$(LIBDIR)" DEFS="$(DEFS)" $@
@cd src && $(MAKE) INCDIR="$(INCDIR)" LIBDIR="$(LIBDIR)" DEFS="$(DEFS)" EXTRA="$(EXTRA)" $@
bsd:
@echo "-------------------"
@echo "** Build for BSD **"
@echo "-------------------"
@cd src ; $(MAKE) INCDIR="$(INCDIR)" LIBDIR="$(LIBDIR)" DEFS="$(DEFS)" $@
@cd src && $(MAKE) INCDIR="$(INCDIR)" LIBDIR="$(LIBDIR)" DEFS="$(DEFS)" EXTRA="$(EXTRA)" $@
macosx:
@echo "------------------------------"
@echo "** Build for Mac OS X $(MACOSX_VERSION) **"
@echo "------------------------------"
@cd src ; $(MAKE) INCDIR="$(INCDIR)" LIBDIR="$(LIBDIR)" DEFS="$(DEFS)" MACVER="$(MACOSX_VERSION)" $@
@cd src && $(MAKE) INCDIR="$(INCDIR)" LIBDIR="$(LIBDIR)" MACVER="$(MACOSX_VERSION)" DEFS="$(DEFS)" EXTRA="$(EXTRA)" $@
clean:
@cd src ; $(MAKE) clean
@cd src && $(MAKE) clean

View File

@ -1,4 +1,41 @@
luasec
======
LuaSec 0.5.1
============
- Check if SSLv3 protocol is available.
- Fix push_asn1_string().
- Update samples to use 'sslv23' and 'tlsv1_2'.
- Update MACOSX_VERSION to 10.11 on Makefile.
LuaSec
LuaSec 0.5
==========
LuaSec depends on OpenSSL, and integrates with LuaSocket to make it
easy to add secure connections to any Lua applications or scripts.
This version includes:
* A new certificate (X509) API, which supports:
- Reading the subject (identity) and issuer of the certificate.
- Reading various X509 extensions, including email and dnsName.
- Converting certificates to and from the standard ASCII PEM
format.
- Generating the fingerprint/digest of a certificate (using SHA1,
SHA256 or SHA512).
- Reading the certificate's expiration, serial number, and other
info.
* The ability to get more detailed information from OpenSSL about
why a certificate failed verification, for each certificate in the
chain.
* Flags to force acceptance of invalid certificates, e.g. to allow
the use of self-signed certificates in a Trust On First Use model.
* Flags to control checking CRLs for certificate revocation status.
* Support for ECDH cipher suites.
* An API to get the TLS 'finished' messages used for SASL channel
binding (e.g. the SCRAM PLUS mechanisms).
The work in this release was undertaken by Kim Alvefur, Paul Aurich,
Tobias Markmann, Bruno Silvestre and Matthew Wild.

View File

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luasec", "luasec.vcproj", "{A629932F-8819-4C0B-8835-CBF1FEED6376}"
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C++ Express 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luasec", "luasec.vcxproj", "{A629932F-8819-4C0B-8835-CBF1FEED6376}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

Binary file not shown.

View File

@ -121,7 +121,7 @@
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="C:\devel\openssl\include;C:\devel\lua-dll9\include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASEC_EXPORTS;BUFFER_DEBUG;LUASEC_API=__declspec(dllexport)"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;BUFFER_DEBUG"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
@ -141,7 +141,7 @@
AdditionalDependencies="ws2_32.lib libeay32MD.lib ssleay32MD.lib lua5.1.lib"
OutputFile="$(OutDir)/ssl.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="C:\devel\openssl\lib\VC;C:\devel\lua-dll9"
AdditionalLibraryDirectories="C:\devel\openssl\lib\VC;C:\devel\lua-dll9\lib"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"

125
luasec.vcxproj Normal file
View File

@ -0,0 +1,125 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{A629932F-8819-4C0B-8835-CBF1FEED6376}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
<TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ssl</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>C:\devel\openssl\include;C:\devel\lua-dll9\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASEC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;libeay32MDd.lib;ssleay32MDd.lib;lua5.1.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)ssl.dll</OutputFile>
<AdditionalLibraryDirectories>C:\devel\openssl\lib\VC;C:\devel\lua-dll9;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)luasec.pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)ssl.lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>C:\devel\openssl\include;C:\devel\lua5.2\include;.\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_DEBUG;WITH_LUASOCKET;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;libeay32MD.lib;ssleay32MD.lib;lua52.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalLibraryDirectories>C:\devel\openssl\lib\VC;C:\devel\lua5.2\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)ssl.lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src\context.c" />
<ClCompile Include="src\luasocket\buffer.c" />
<ClCompile Include="src\luasocket\io.c" />
<ClCompile Include="src\luasocket\timeout.c" />
<ClCompile Include="src\luasocket\wsocket.c" />
<ClCompile Include="src\ssl.c" />
<ClCompile Include="src\x509.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\config.h" />
<ClInclude Include="src\context.h" />
<ClInclude Include="src\ec.h" />
<ClInclude Include="src\luasocket\buffer.h" />
<ClInclude Include="src\luasocket\io.h" />
<ClInclude Include="src\luasocket\socket.h" />
<ClInclude Include="src\luasocket\timeout.h" />
<ClInclude Include="src\luasocket\wsocket.h" />
<ClInclude Include="src\options.h" />
<ClInclude Include="src\ssl.h" />
<ClInclude Include="src\x509.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

75
luasec.vcxproj.filters Normal file
View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\x509.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\context.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ssl.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\luasocket\wsocket.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\luasocket\buffer.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\luasocket\io.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\luasocket\timeout.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\x509.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\config.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\context.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ec.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\options.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ssl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\luasocket\wsocket.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\luasocket\buffer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\luasocket\io.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\luasocket\socket.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\luasocket\timeout.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -1,17 +1,26 @@
In all examples, the SSL/TLS layer can be disable just commenting the
wrap section. In this case, the examples work with normal TCP
communication.
Directories:
------------
* certs
It contains a set of certificates used in the examples. You can use
the scrits to recreate them if necessary (due to certificates
expiration date, for example). First, generate the Root CA 'A' and
'B', then the servers and clients.
Contains scripts to generate the certificates used by the examples.
Generate Root CA 'A' and 'B' first, then the servers and clients.
* oneshot
A simple connection example.
* chain
Example of certificate chain in handshake.
* dhparam
DH parameters for handshake.
* digest
Certificate digest.
* ecdh
Elliptic curve cipher.
* info
Informations about the connection.
* key
Test encrypted private key.
* loop
Test successive connections between the server and the client
@ -19,7 +28,16 @@ Directories:
* loop-gc
Same of above, but the connection is not explicit closed, the gabage
collector is encharge of it.
collector is encharge of that.
* oneshot
A simple connection example.
* verification
Retrieve the certificate verification errors from the handshake.
* verify
Ignore handshake errors and proceed.
* wantread
Test timeout in handshake() and receive().
@ -28,7 +46,4 @@ Directories:
Test timeout in send().
* want
Test want().
* key
Test encrypted private key.
Test want() method.

View File

@ -172,7 +172,7 @@ basicConstraints=CA:FALSE
# the certificate can be used for anything *except* object signing.
# This is OK for an SSL server.
# nsCertType = server
nsCertType = server
# For an object signing certificate this would be used.
# nsCertType = objsign

View File

@ -172,7 +172,7 @@ basicConstraints=CA:FALSE
# the certificate can be used for anything *except* object signing.
# This is OK for an SSL server.
# nsCertType = server
nsCertType = server
# For an object signing certificate this would be used.
# nsCertType = objsign

36
samples/chain/client.lua Normal file
View File

@ -0,0 +1,36 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local util = require("util")
local params = {
mode = "client",
protocol = "tlsv1_2",
key = "../certs/clientAkey.pem",
certificate = "../certs/clientA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all",
}
local conn = socket.tcp()
conn:connect("127.0.0.1", 8888)
conn = assert( ssl.wrap(conn, params) )
assert(conn:dohandshake())
util.show( conn:getpeercertificate() )
print("----------------------------------------------------------------------")
for k, cert in ipairs( conn:getpeerchain() ) do
util.show(cert)
end
local cert = conn:getpeercertificate()
print( cert )
print( cert:pem() )
conn:close()

53
samples/chain/server.lua Normal file
View File

@ -0,0 +1,53 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local util = require("util")
local params = {
mode = "server",
protocol = "sslv23",
key = "../certs/serverAkey.pem",
certificate = "../certs/serverA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all",
}
local ctx = assert(ssl.newcontext(params))
local server = socket.tcp()
server:setoption('reuseaddr', true)
assert( server:bind("127.0.0.1", 8888) )
server:listen()
local conn = server:accept()
conn = assert( ssl.wrap(conn, ctx) )
assert( conn:dohandshake() )
util.show( conn:getpeercertificate() )
print("----------------------------------------------------------------------")
for k, cert in ipairs( conn:getpeerchain() ) do
util.show(cert)
end
local f = io.open(params.certificate)
local str = f:read("*a")
f:close()
util.show( ssl.loadcertificate(str) )
print("----------------------------------------------------------------------")
local cert = conn:getpeercertificate()
print( cert )
print( cert:digest() )
print( cert:digest("sha1") )
print( cert:digest("sha256") )
print( cert:digest("sha512") )
conn:close()
server:close()

22
samples/chain/util.lua Normal file
View File

@ -0,0 +1,22 @@
local print = print
local ipairs = ipairs
local _ENV = {}
function _ENV.show(cert)
print("Serial:", cert:serial())
print("NotBefore:", cert:notbefore())
print("NotAfter:", cert:notafter())
print("--- Issuer ---")
for k, v in ipairs(cert:issuer()) do
print(v.name .. " = " .. v.value)
end
print("--- Subject ---")
for k, v in ipairs(cert:subject()) do
print(v.name .. " = " .. v.value)
end
print("----------------------------------------------------------------------")
end
return _ENV

View File

@ -0,0 +1,26 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "tlsv1_2",
key = "../certs/clientAkey.pem",
certificate = "../certs/clientA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all",
}
local peer = socket.tcp()
peer:connect("127.0.0.1", 8888)
-- [[ SSL wrapper
peer = assert( ssl.wrap(peer, params) )
assert(peer:dohandshake())
--]]
print(peer:receive("*l"))
peer:close()

4
samples/dhparam/params.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
openssl dhparam -2 -out dh-512.pem -outform PEM 512
openssl dhparam -2 -out dh-1024.pem -outform PEM 1024

View File

@ -0,0 +1,61 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local function readfile(filename)
local fd = assert(io.open(filename))
local dh = fd:read("*a")
fd:close()
return dh
end
local function dhparam_cb(export, keylength)
print("---")
print("DH Callback")
print("Export", export)
print("Key length", keylength)
print("---")
local filename
if keylength == 512 then
filename = "dh-512.pem"
elseif keylength == 1024 then
filename = "dh-1024.pem"
else
-- No key
return nil
end
return readfile(filename)
end
local params = {
mode = "server",
protocol = "sslv23",
key = "../certs/serverAkey.pem",
certificate = "../certs/serverA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all",
dhparam = dhparam_cb,
}
-- [[ SSL context
local ctx = assert(ssl.newcontext(params))
--]]
local server = socket.tcp()
server:setoption('reuseaddr', true)
assert( server:bind("127.0.0.1", 8888) )
server:listen()
local peer = server:accept()
-- [[ SSL wrapper
peer = assert( ssl.wrap(peer, ctx) )
assert( peer:dohandshake() )
--]]
peer:send("oneshot test\n")
peer:close()

26
samples/digest/client.lua Normal file
View File

@ -0,0 +1,26 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "tlsv1_2",
key = "../certs/clientAkey.pem",
certificate = "../certs/clientA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all",
}
local peer = socket.tcp()
peer:connect("127.0.0.1", 8888)
-- [[ SSL wrapper
peer = assert( ssl.wrap(peer, params) )
assert(peer:dohandshake())
--]]
print(peer:receive("*l"))
peer:close()

44
samples/digest/server.lua Normal file
View File

@ -0,0 +1,44 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "server",
protocol = "sslv23",
key = "../certs/serverAkey.pem",
certificate = "../certs/serverA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all",
}
-- [[ SSL context
local ctx = assert(ssl.newcontext(params))
--]]
local server = socket.tcp()
server:setoption('reuseaddr', true)
assert( server:bind("127.0.0.1", 8888) )
server:listen()
local peer = server:accept()
-- [[ SSL wrapper
peer = assert( ssl.wrap(peer, ctx) )
assert( peer:dohandshake() )
--]]
local cert = peer:getpeercertificate()
local sha1 = cert:digest("sha1")
local sha256 = cert:digest("sha256")
local sha512 = cert:digest("sha512")
print("SHA1", sha1)
print("SHA256", sha256)
print("SHA512", sha512)
peer:send("oneshot test\n")
peer:close()

33
samples/ecdh/client.lua Normal file
View File

@ -0,0 +1,33 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "tlsv1_2",
key = "../certs/clientAkey.pem",
certificate = "../certs/clientA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all",
--
curve = "secp384r1",
}
--------------------------------------------------------------------------------
local peer = socket.tcp()
peer:connect("127.0.0.1", 8888)
peer = assert( ssl.wrap(peer, params) )
assert(peer:dohandshake())
print("--- INFO ---")
local info = peer:info()
for k, v in pairs(info) do
print(k, v)
end
print("---")
peer:close()

40
samples/ecdh/server.lua Normal file
View File

@ -0,0 +1,40 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "server",
protocol = "sslv23",
key = "../certs/serverAkey.pem",
certificate = "../certs/serverA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all",
--
curve = "secp384r1",
}
------------------------------------------------------------------------------
local ctx = assert(ssl.newcontext(params))
local server = socket.tcp()
server:setoption('reuseaddr', true)
assert( server:bind("127.0.0.1", 8888) )
server:listen()
local peer = server:accept()
peer = assert( ssl.wrap(peer, ctx) )
assert( peer:dohandshake() )
print("--- INFO ---")
local info = peer:info()
for k, v in pairs(info) do
print(k, v)
end
print("---")
peer:close()
server:close()

26
samples/info/client.lua Normal file
View File

@ -0,0 +1,26 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "tlsv1_2",
key = "../certs/clientAkey.pem",
certificate = "../certs/clientA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all",
}
local peer = socket.tcp()
peer:connect("127.0.0.1", 8888)
-- [[ SSL wrapper
peer = assert( ssl.wrap(peer, params) )
assert(peer:dohandshake())
--]]
print(peer:receive("*l"))
peer:close()

48
samples/info/server.lua Normal file
View File

@ -0,0 +1,48 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "server",
protocol = "sslv23",
key = "../certs/serverAkey.pem",
certificate = "../certs/serverA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all",
}
-- [[ SSL context
local ctx = assert(ssl.newcontext(params))
--]]
local server = socket.tcp()
server:setoption('reuseaddr', true)
assert( server:bind("127.0.0.1", 8888) )
server:listen()
local peer = server:accept()
-- [[ SSL wrapper
peer = assert( ssl.wrap(peer, ctx) )
-- Before handshake: nil
print( peer:info() )
assert( peer:dohandshake() )
--]]
print("---")
local info = peer:info()
for k, v in pairs(info) do
print(k, v)
end
print("---")
print("-> Compression", peer:info("compression"))
peer:send("oneshot test\n")
peer:close()

View File

@ -1,11 +1,11 @@
--
-- Public domain
--
require("ssl")
local ssl = require("ssl")
local pass = "foobar"
local cfg = {
protocol = "tlsv1",
protocol = "tlsv1_2",
mode = "client",
key = "key.pem",
}

View File

@ -1,17 +1,17 @@
--
-- Public domain
--
require("socket")
require("ssl")
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "sslv3",
protocol = "tlsv1_2",
key = "../certs/clientAkey.pem",
certificate = "../certs/clientA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = {"all", "no_sslv2"},
options = "all",
}
while true do

View File

@ -1,17 +1,17 @@
--
-- Public domain
--
require("socket")
require("ssl")
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "server",
protocol = "sslv3",
protocol = "sslv23",
key = "../certs/serverAkey.pem",
certificate = "../certs/serverA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = {"all", "no_sslv2"},
options = "all",
}
-- [[ SSL context

View File

@ -1,17 +1,17 @@
--
-- Public domain
--
require("socket")
require("ssl")
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "sslv3",
protocol = "tlsv1_2",
key = "../certs/clientAkey.pem",
certificate = "../certs/clientA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = {"all", "no_sslv2"},
options = "all",
}
while true do

View File

@ -1,17 +1,17 @@
--
-- Public domain
--
require("socket")
require("ssl")
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "server",
protocol = "sslv3",
protocol = "sslv23",
key = "../certs/serverAkey.pem",
certificate = "../certs/serverA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = {"all", "no_sslv2"},
options = "all",
}
-- [[ SSL context

View File

@ -1,17 +1,17 @@
--
-- Public domain
--
require("socket")
require("ssl")
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "sslv3",
protocol = "tlsv1_2",
key = "../certs/clientAkey.pem",
certificate = "../certs/clientA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = {"all", "no_sslv2"},
options = "all",
}
local peer = socket.tcp()

View File

@ -1,17 +1,17 @@
--
-- Public domain
--
require("socket")
require("ssl")
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "server",
protocol = "sslv3",
protocol = "sslv23",
key = "../certs/serverAkey.pem",
certificate = "../certs/serverA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = {"all", "no_sslv2"},
options = "all",
}

View File

@ -0,0 +1,29 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "tlsv1_2",
key = "../../certs/clientBkey.pem",
certificate = "../../certs/clientB.pem",
cafile = "../../certs/rootB.pem",
verify = "none",
options = "all",
}
local peer = socket.tcp()
peer:connect("127.0.0.1", 8888)
-- [[ SSL wrapper
peer = assert( ssl.wrap(peer, params) )
assert(peer:dohandshake())
--]]
local err, msg = peer:getpeerverification()
print(err, msg)
print(peer:receive("*l"))
peer:close()

View File

@ -0,0 +1,37 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "server",
protocol = "sslv23",
key = "../../certs/serverAkey.pem",
certificate = "../../certs/serverA.pem",
cafile = "../../certs/rootA.pem",
verify = "none",
options = "all",
}
-- [[ SSL context
local ctx = assert(ssl.newcontext(params))
--]]
local server = socket.tcp()
server:setoption('reuseaddr', true)
assert( server:bind("127.0.0.1", 8888) )
server:listen()
local peer = server:accept()
-- [[ SSL wrapper
peer = assert( ssl.wrap(peer, ctx) )
assert( peer:dohandshake() )
--]]
local err, msg = peer:getpeerverification()
print(err, msg)
peer:send("oneshot test\n")
peer:close()

View File

@ -0,0 +1,39 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "tlsv1_2",
key = "../../certs/clientBkey.pem",
certificate = "../../certs/clientB.pem",
cafile = "../../certs/rootB.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all", ,
verifyext = "lsec_continue",
}
-- [[ SSL context
local ctx = assert(ssl.newcontext(params))
--]]
local peer = socket.tcp()
peer:connect("127.0.0.1", 8888)
-- [[ SSL wrapper
peer = assert( ssl.wrap(peer, ctx) )
assert(peer:dohandshake())
--]]
local succ, errs = peer:getpeerverification()
print(succ, errs)
for i, err in pairs(errs) do
for j, msg in ipairs(err) do
print("depth = " .. i, "error = " .. msg)
end
end
print(peer:receive("*l"))
peer:close()

View File

@ -0,0 +1,43 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "server",
protocol = "sslv23",
key = "../../certs/serverAkey.pem",
certificate = "../../certs/serverA.pem",
cafile = "../../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all",
verifyext = {"lsec_continue", "crl_check", "crl_check_chain"},
}
-- [[ SSL context
local ctx = assert(ssl.newcontext(params))
--]]
local server = socket.tcp()
server:setoption('reuseaddr', true)
assert( server:bind("127.0.0.1", 8888) )
server:listen()
local peer = server:accept()
-- [[ SSL wrapper
peer = assert( ssl.wrap(peer, ctx) )
assert( peer:dohandshake() )
--]]
local succ, errs = peer:getpeerverification()
print(succ, errs)
for i, err in pairs(errs) do
for j, msg in ipairs(err) do
print("depth = " .. i, "error = " .. msg)
end
end
peer:send("oneshot test\n")
peer:close()

View File

@ -0,0 +1,29 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "tlsv1_2",
key = "../../certs/clientAkey.pem",
certificate = "../../certs/clientA.pem",
cafile = "../../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all",
}
local peer = socket.tcp()
peer:connect("127.0.0.1", 8888)
-- [[ SSL wrapper
peer = assert( ssl.wrap(peer, params) )
assert(peer:dohandshake())
--]]
local err, msg = peer:getpeerverification()
print(err, msg)
print(peer:receive("*l"))
peer:close()

View File

@ -0,0 +1,38 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "server",
protocol = "sslv23",
key = "../../certs/serverAkey.pem",
certificate = "../../certs/serverA.pem",
cafile = "../../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = "all",
}
-- [[ SSL context
local ctx = assert(ssl.newcontext(params))
--]]
local server = socket.tcp()
server:setoption('reuseaddr', true)
assert( server:bind("127.0.0.1", 8888) )
server:listen()
local peer = server:accept()
-- [[ SSL wrapper
peer = assert( ssl.wrap(peer, ctx) )
assert( peer:dohandshake() )
--]]
local err, msg = peer:getpeerverification()
print(err, msg)
peer:send("oneshot test\n")
peer:close()

35
samples/verify/client.lua Normal file
View File

@ -0,0 +1,35 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "tlsv1_2",
key = "../certs/serverBkey.pem",
certificate = "../certs/serverB.pem",
cafile = "../certs/rootB.pem",
verify = {"peer", "fail_if_no_peer_cert"},
verifyext = {"lsec_continue", "lsec_ignore_purpose"},
options = "all",
}
local ctx = assert(ssl.newcontext(params))
local peer = socket.tcp()
peer:connect("127.0.0.1", 8888)
peer = assert( ssl.wrap(peer, ctx) )
assert(peer:dohandshake())
local succ, errs = peer:getpeerverification()
print(succ, errs)
for i, err in pairs(errs) do
for j, msg in ipairs(err) do
print("depth = " .. i, "error = " .. msg)
end
end
print(peer:receive("*l"))
peer:close()

40
samples/verify/server.lua Normal file
View File

@ -0,0 +1,40 @@
--
-- Public domain
--
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "server",
protocol = "sslv23",
key = "../certs/serverAkey.pem",
certificate = "../certs/serverA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
verifyext = {"lsec_continue", "lsec_ignore_purpose"},
options = "all",
}
local ctx = assert(ssl.newcontext(params))
local server = socket.tcp()
server:setoption('reuseaddr', true)
assert( server:bind("127.0.0.1", 8888) )
server:listen()
local peer = server:accept()
peer = assert( ssl.wrap(peer, ctx) )
assert( peer:dohandshake() )
local succ, errs = peer:getpeerverification()
print(succ, errs)
for i, err in pairs(errs) do
for j, msg in ipairs(err) do
print("depth = " .. i, "error = " .. msg)
end
end
peer:send("oneshot test\n")
peer:close()

View File

@ -3,17 +3,17 @@
--
-- Public domain
--
require("socket")
require("ssl")
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "sslv3",
protocol = "tlsv1_2",
key = "../certs/clientAkey.pem",
certificate = "../certs/clientA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = {"all", "no_sslv2"},
options = "all",
}
-- Wait until socket is ready (for reading or writing)

View File

@ -1,17 +1,17 @@
--
-- Public domain
--
require("socket")
require("ssl")
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "server",
protocol = "sslv3",
protocol = "sslv23",
key = "../certs/serverAkey.pem",
certificate = "../certs/serverA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = {"all", "no_sslv2"},
options = "all",
}
-- [[ SSL context

View File

@ -1,17 +1,17 @@
--
-- Public domain
--
require("socket")
require("ssl")
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "sslv3",
protocol = "tlsv1_2",
key = "../certs/clientAkey.pem",
certificate = "../certs/clientA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = {"all", "no_sslv2"},
options = "all",
}

View File

@ -3,17 +3,17 @@
--
-- Public domain
--
require("socket")
require("ssl")
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "server",
protocol = "sslv3",
protocol = "sslv23",
key = "../certs/serverAkey.pem",
certificate = "../certs/serverA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = {"all", "no_sslv2"},
options = "all",
}
-- [[ SSL context

View File

@ -1,17 +1,17 @@
--
-- Public domain
--
require("socket")
require("ssl")
local socket = require("socket")
local ssl = require("ssl")
local params = {
mode = "client",
protocol = "sslv3",
protocol = "tlsv1_2",
key = "../certs/clientAkey.pem",
certificate = "../certs/clientA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = {"all", "no_sslv2"},
options = "all",
}
local function wait(peer, err)

View File

@ -1,19 +1,19 @@
--
-- Public domain
--
require("socket")
require("ssl")
local socket = require("socket")
local ssl = require("ssl")
print("Use Ctrl+S and Ctrl+Q to suspend and resume the server.")
local params = {
mode = "server",
protocol = "sslv3",
protocol = "sslv23",
key = "../certs/serverAkey.pem",
certificate = "../certs/serverA.pem",
cafile = "../certs/rootA.pem",
verify = {"peer", "fail_if_no_peer_cert"},
options = {"all", "no_sslv2"},
options = "all",
}

View File

@ -2,60 +2,60 @@ CMOD=ssl.so
LMOD=ssl.lua
OBJS= \
timeout.o \
buffer.o \
io.o \
usocket.o \
x509.o \
context.o \
ssl.o
LIBS=-lssl -lcrypto
LIBS=-lssl -lcrypto -lluasocket
WARN=-Wall -pedantic
BSD_CFLAGS=-O2 -fpic $(WARN) $(INCDIR) $(DEFS)
BSD_LDFLAGS=-O -shared -fpic $(LIBDIR)
BSD_CFLAGS=-O2 -fPIC $(WARN) $(INCDIR) $(DEFS)
BSD_LDFLAGS=-O -fPIC -shared $(LIBDIR)
LNX_CFLAGS=-O2 -fpic $(WARN) $(INCDIR) $(DEFS)
LNX_LDFLAGS=-O -shared -fpic $(LIBDIR)
LNX_CFLAGS=-O2 -fPIC $(WARN) $(INCDIR) $(DEFS)
LNX_LDFLAGS=-O -fPIC -shared $(LIBDIR)
MAC_ENV=env MACOSX_DEPLOYMENT_TARGET='$(MACVER)'
MAC_CFLAGS=-O2 -fno-common $(WARN) $(INCDIR) $(DEFS)
MAC_LDFLAGS=-bundle -undefined dynamic_lookup $(LIBDIR)
CP=cp
CC=gcc
LD=$(MYENV) gcc
CFLAGS=$(MYCFLAGS)
LDFLAGS=$(MYLDFLAGS)
INSTALL ?= install
CC ?= cc
LD ?= $(MYENV) cc
CFLAGS += $(MYCFLAGS)
LDFLAGS += $(MYLDFLAGS)
DESTDIR ?= /
.PHONY: all clean install none linux bsd macosx
.PHONY: all clean install none linux bsd macosx luasocket
all:
install: $(CMOD) $(LMOD)
$(CP) $(CMOD) $(CPATH)
$(CP) $(LMOD) $(LUAPATH)
$(INSTALL) -d $(DESTDIR)$(LUAPATH)/ssl $(DESTDIR)$(LUACPATH)
$(INSTALL) -D $(CMOD) $(DESTDIR)$(LUACPATH)
$(INSTALL) -m644 -D $(LMOD) $(DESTDIR)$(LUAPATH)
$(INSTALL) -m644 -D https.lua $(DESTDIR)$(LUAPATH)/ssl
linux:
@$(MAKE) $(CMOD) MYCFLAGS="$(LNX_CFLAGS)" MYLDFLAGS="$(LNX_LDFLAGS)"
@$(MAKE) $(CMOD) MYCFLAGS="$(LNX_CFLAGS)" MYLDFLAGS="$(LNX_LDFLAGS)" EXTRA="$(EXTRA)"
bsd:
@$(MAKE) $(CMOD) MYCFLAGS="$(BSD_CFLAGS)" MYLDFLAGS="$(BSD_LDFLAGS)"
@$(MAKE) $(CMOD) MYCFLAGS="$(BSD_CFLAGS)" MYLDFLAGS="$(BSD_LDFLAGS)" EXTRA="$(EXTRA)"
macosx:
@$(MAKE) $(CMOD) MYCFLAGS="$(MAC_CFLAGS)" MYLDFLAGS="$(MAC_LDFLAGS)" MYENV="$(MAC_ENV)"
@$(MAKE) $(CMOD) MYCFLAGS="$(MAC_CFLAGS)" MYLDFLAGS="$(MAC_LDFLAGS)" MYENV="$(MAC_ENV)" EXTRA="$(EXTRA)"
luasocket:
@cd luasocket && $(MAKE)
$(CMOD): $(OBJS)
$(CMOD): $(EXTRA) $(OBJS)
$(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
clean:
cd luasocket && $(MAKE) clean
rm -f $(OBJS) $(CMOD)
buffer.o: buffer.c buffer.h io.h timeout.h
io.o: io.c io.h timeout.h
timeout.o: timeout.c timeout.h
usocket.o: usocket.c socket.h io.h timeout.h usocket.h
context.o: context.c context.h
ssl.o: ssl.c socket.h io.h timeout.h usocket.h buffer.h context.h context.c
x509.o: x509.c x509.h config.h
context.o: context.c context.h ec.h config.h
ssl.o: ssl.c ssl.h context.h x509.h config.h

20
src/config.h Normal file
View File

@ -0,0 +1,20 @@
/*--------------------------------------------------------------------------
* LuaSec 0.5.1
* Copyright (C) 2006-2015 Bruno Silvestre
*
*--------------------------------------------------------------------------*/
#ifndef LSEC_CONFIG_H
#define LSEC_CONFIG_H
#if defined(_WIN32)
#define LSEC_API __declspec(dllexport)
#else
#define LSEC_API extern
#endif
#if (LUA_VERSION_NUM == 501)
#define lua_rawlen(L, i) lua_objlen(L, i)
#endif
#endif

View File

@ -1,59 +1,43 @@
/*--------------------------------------------------------------------------
* LuaSec 0.3.2
* Copyright (C) 2006-2009 Bruno Silvestre
* LuaSec 0.5.1
*
* Copyright (C) 2014-2015 Kim Alvefur, Paul Aurich, Tobias Markmann,
* Matthew Wild.
* Copyright (C) 2006-2015 Bruno Silvestre.
*
*--------------------------------------------------------------------------*/
#include <string.h>
#if defined(WIN32)
#include <windows.h>
#endif
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <lua.h>
#include <lauxlib.h>
#include "context.h"
#include "options.h"
struct ssl_option_s {
const char *name;
unsigned long code;
};
typedef struct ssl_option_s ssl_option_t;
static ssl_option_t ssl_options[] = {
/* OpenSSL 0.9.7 and 0.9.8 */
{"all", SSL_OP_ALL},
{"cipher_server_preference", SSL_OP_CIPHER_SERVER_PREFERENCE},
{"dont_insert_empty_fragments", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS},
{"ephemeral_rsa", SSL_OP_EPHEMERAL_RSA},
{"netscape_ca_dn_bug", SSL_OP_NETSCAPE_CA_DN_BUG},
{"netscape_challenge_bug", SSL_OP_NETSCAPE_CHALLENGE_BUG},
{"microsoft_big_sslv3_buffer", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER},
{"microsoft_sess_id_bug", SSL_OP_MICROSOFT_SESS_ID_BUG},
{"msie_sslv2_rsa_padding", SSL_OP_MSIE_SSLV2_RSA_PADDING},
{"netscape_demo_cipher_change_bug", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG},
{"netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG},
{"no_session_resumption_on_renegotiation",
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION},
{"no_sslv2", SSL_OP_NO_SSLv2},
{"no_sslv3", SSL_OP_NO_SSLv3},
{"no_tlsv1", SSL_OP_NO_TLSv1},
{"pkcs1_check_1", SSL_OP_PKCS1_CHECK_1},
{"pkcs1_check_2", SSL_OP_PKCS1_CHECK_2},
{"single_dh_use", SSL_OP_SINGLE_DH_USE},
{"ssleay_080_client_dh_bug", SSL_OP_SSLEAY_080_CLIENT_DH_BUG},
{"sslref2_reuse_cert_type_bug", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG},
{"tls_block_padding_bug", SSL_OP_TLS_BLOCK_PADDING_BUG},
{"tls_d5_bug", SSL_OP_TLS_D5_BUG},
{"tls_rollback_bug", SSL_OP_TLS_ROLLBACK_BUG},
/* OpenSSL 0.9.8 only */
#if OPENSSL_VERSION_NUMBER > 0x00908000L
{"cookie_exchange", SSL_OP_COOKIE_EXCHANGE},
{"no_query_mtu", SSL_OP_NO_QUERY_MTU},
{"single_ecdh_use", SSL_OP_SINGLE_ECDH_USE},
#ifndef OPENSSL_NO_ECDH
#include <openssl/ec.h>
#include "ec.h"
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x1000000fL)
typedef const SSL_METHOD LSEC_SSL_METHOD;
#else
typedef SSL_METHOD LSEC_SSL_METHOD;
#endif
#if OPENSSL_VERSION_NUMBER>=0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
#define SSLv23_method() TLS_method()
#endif
{NULL, 0L}
};
/*--------------------------- Auxiliary Functions ----------------------------*/
@ -83,11 +67,17 @@ static int set_option_flag(const char *opt, unsigned long *flag)
/**
* Find the protocol.
*/
static SSL_METHOD* str2method(const char *method)
static LSEC_SSL_METHOD* str2method(const char *method)
{
if (!strcmp(method, "sslv3")) return SSLv3_method();
if (!strcmp(method, "tlsv1")) return TLSv1_method();
if (!strcmp(method, "sslv23")) return SSLv23_method();
if (!strcmp(method, "sslv23")) return SSLv23_method();
#ifndef OPENSSL_NO_SSL3
if (!strcmp(method, "sslv3")) return SSLv3_method();
#endif
if (!strcmp(method, "tlsv1")) return TLSv1_method();
#if (OPENSSL_VERSION_NUMBER >= 0x1000100fL)
if (!strcmp(method, "tlsv1_1")) return TLSv1_1_method();
if (!strcmp(method, "tlsv1_2")) return TLSv1_2_method();
#endif
return NULL;
}
@ -125,17 +115,179 @@ static int passwd_cb(char *buf, int size, int flag, void *udata)
case LUA_TFUNCTION:
lua_pushvalue(L, 3);
lua_call(L, 0, 1);
if (lua_type(L, -1) != LUA_TSTRING)
if (lua_type(L, -1) != LUA_TSTRING) {
lua_pop(L, 1); /* Remove the result from the stack */
return 0;
}
/* fallback */
case LUA_TSTRING:
strncpy(buf, lua_tostring(L, -1), size);
lua_pop(L, 1); /* Remove the result from the stack */
buf[size-1] = '\0';
return (int)strlen(buf);
}
return 0;
}
/**
* Add an error related to a depth certificate of the chain.
*/
static void add_cert_error(lua_State *L, SSL *ssl, int err, int depth)
{
luaL_getmetatable(L, "SSL:Verify:Registry");
lua_pushlightuserdata(L, (void*)ssl);
lua_gettable(L, -2);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
/* Create an error table for this connection */
lua_newtable(L);
lua_pushlightuserdata(L, (void*)ssl);
lua_pushvalue(L, -2); /* keep the table on stack */
lua_settable(L, -4);
}
lua_rawgeti(L, -1, depth+1);
/* If the table doesn't exist, create it */
if (lua_isnil(L, -1)) {
lua_pop(L, 1); /* remove 'nil' from stack */
lua_newtable(L);
lua_pushvalue(L, -1); /* keep the table on stack */
lua_rawseti(L, -3, depth+1);
}
lua_pushstring(L, X509_verify_cert_error_string(err));
lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
/* Clear the stack */
lua_pop(L, 3);
}
/**
* Call Lua user function to get the DH key.
*/
static DH *dhparam_cb(SSL *ssl, int is_export, int keylength)
{
BIO *bio;
lua_State *L;
DH *dh_tmp = NULL;
SSL_CTX *ctx = SSL_get_SSL_CTX(ssl);
p_context pctx = (p_context)SSL_CTX_get_app_data(ctx);
L = pctx->L;
/* Get the callback */
luaL_getmetatable(L, "SSL:DH:Registry");
lua_pushlightuserdata(L, (void*)ctx);
lua_gettable(L, -2);
/* Invoke the callback */
lua_pushboolean(L, is_export);
lua_pushnumber(L, keylength);
lua_call(L, 2, 1);
/* Load parameters from returned value */
if (lua_type(L, -1) != LUA_TSTRING) {
lua_pop(L, 2); /* Remove values from stack */
return NULL;
}
bio = BIO_new_mem_buf((void*)lua_tostring(L, -1),
lua_rawlen(L, -1));
if (bio) {
dh_tmp = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
}
/*
* OpenSSL exepcts the callback to maintain a reference to the DH*. So,
* cache it here, and clean up the previous set of parameters. Any remaining
* set is cleaned up when destroying the LuaSec context.
*/
if (pctx->dh_param)
DH_free(pctx->dh_param);
pctx->dh_param = dh_tmp;
lua_pop(L, 2); /* Remove values from stack */
return dh_tmp;
}
/**
* Set the "ignore purpose" before to start verifing the certificate chain.
*/
static int cert_verify_cb(X509_STORE_CTX *x509_ctx, void *ptr)
{
int verify;
lua_State *L;
SSL_CTX *ctx = (SSL_CTX*)ptr;
p_context pctx = (p_context)SSL_CTX_get_app_data(ctx);
L = pctx->L;
/* Get verify flags */
luaL_getmetatable(L, "SSL:Verify:Registry");
lua_pushlightuserdata(L, (void*)ctx);
lua_gettable(L, -2);
verify = (int)lua_tonumber(L, -1);
lua_pop(L, 2); /* Remove values from stack */
if (verify & LSEC_VERIFY_IGNORE_PURPOSE) {
/* Set parameters to ignore the server purpose */
X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(x509_ctx);
if (param) {
X509_VERIFY_PARAM_set_purpose(param, X509_PURPOSE_SSL_SERVER);
X509_VERIFY_PARAM_set_trust(param, X509_TRUST_SSL_SERVER);
}
}
/* Call OpenSSL standard verification function */
return X509_verify_cert(x509_ctx);
}
/**
* This callback implements the "continue on error" flag and log the errors.
*/
static int verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
int err;
int verify;
SSL *ssl;
SSL_CTX *ctx;
p_context pctx;
lua_State *L;
/* Short-circuit optimization */
if (preverify_ok)
return 1;
ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
ctx = SSL_get_SSL_CTX(ssl);
pctx = (p_context)SSL_CTX_get_app_data(ctx);
L = pctx->L;
/* Get verify flags */
luaL_getmetatable(L, "SSL:Verify:Registry");
lua_pushlightuserdata(L, (void*)ctx);
lua_gettable(L, -2);
verify = (int)lua_tonumber(L, -1);
lua_pop(L, 2); /* Remove values from stack */
err = X509_STORE_CTX_get_error(x509_ctx);
if (err != X509_V_OK)
add_cert_error(L, ssl, err, X509_STORE_CTX_get_error_depth(x509_ctx));
return (verify & LSEC_VERIFY_CONTINUE ? 1 : preverify_ok);
}
#ifndef OPENSSL_NO_ECDH
static EC_KEY *find_ec_key(const char *str)
{
p_ec ptr;
for (ptr = curves; ptr->name; ptr++) {
if (!strcmp(str, ptr->name))
return EC_KEY_new_by_curve_name(ptr->nid);
}
return NULL;
}
#endif
/*------------------------------ Lua Functions -------------------------------*/
/**
@ -144,12 +296,14 @@ static int passwd_cb(char *buf, int size, int flag, void *udata)
static int create(lua_State *L)
{
p_context ctx;
SSL_METHOD *method;
const char *str_method;
LSEC_SSL_METHOD *method;
method = str2method(luaL_checkstring(L, 1));
str_method = luaL_checkstring(L, 1);
method = str2method(str_method);
if (!method) {
lua_pushnil(L);
lua_pushstring(L, "invalid protocol");
lua_pushfstring(L, "invalid protocol (%s)", str_method);
return 2;
}
ctx = (p_context) lua_newuserdata(L, sizeof(t_context));
@ -157,18 +311,25 @@ static int create(lua_State *L)
lua_pushnil(L);
lua_pushstring(L, "error creating context");
return 2;
}
}
memset(ctx, 0, sizeof(t_context));
ctx->context = SSL_CTX_new(method);
if (!ctx->context) {
lua_pushnil(L);
lua_pushstring(L, "error creating context");
lua_pushfstring(L, "error creating context (%s)",
ERR_reason_error_string(ERR_get_error()));
return 2;
}
ctx->mode = MD_CTX_INVALID;
/* No session support */
SSL_CTX_set_session_cache_mode(ctx->context, SSL_SESS_CACHE_OFF);
ctx->mode = LSEC_MODE_INVALID;
ctx->L = L;
luaL_getmetatable(L, "SSL:Context");
lua_setmetatable(L, -2);
/* No session support */
SSL_CTX_set_session_cache_mode(ctx->context, SSL_SESS_CACHE_OFF);
/* Link LuaSec context with the OpenSSL context */
SSL_CTX_set_app_data(ctx->context, ctx);
return 1;
}
@ -177,7 +338,7 @@ static int create(lua_State *L)
*/
static int load_locations(lua_State *L)
{
SSL_CTX *ctx = ctx_getcontext(L, 1);
SSL_CTX *ctx = lsec_checkcontext(L, 1);
const char *cafile = luaL_optstring(L, 2, NULL);
const char *capath = luaL_optstring(L, 3, NULL);
if (SSL_CTX_load_verify_locations(ctx, cafile, capath) != 1) {
@ -195,7 +356,7 @@ static int load_locations(lua_State *L)
*/
static int load_cert(lua_State *L)
{
SSL_CTX *ctx = ctx_getcontext(L, 1);
SSL_CTX *ctx = lsec_checkcontext(L, 1);
const char *filename = luaL_checkstring(L, 2);
if (SSL_CTX_use_certificate_chain_file(ctx, filename) != 1) {
lua_pushboolean(L, 0);
@ -213,7 +374,7 @@ static int load_cert(lua_State *L)
static int load_key(lua_State *L)
{
int ret = 1;
SSL_CTX *ctx = ctx_getcontext(L, 1);
SSL_CTX *ctx = lsec_checkcontext(L, 1);
const char *filename = luaL_checkstring(L, 2);
switch (lua_type(L, 3)) {
case LUA_TSTRING:
@ -245,7 +406,7 @@ static int load_key(lua_State *L)
*/
static int set_cipher(lua_State *L)
{
SSL_CTX *ctx = ctx_getcontext(L, 1);
SSL_CTX *ctx = lsec_checkcontext(L, 1);
const char *list = luaL_checkstring(L, 2);
if (SSL_CTX_set_cipher_list(ctx, list) != 1) {
lua_pushboolean(L, 0);
@ -262,7 +423,7 @@ static int set_cipher(lua_State *L)
*/
static int set_depth(lua_State *L)
{
SSL_CTX *ctx = ctx_getcontext(L, 1);
SSL_CTX *ctx = lsec_checkcontext(L, 1);
SSL_CTX_set_verify_depth(ctx, luaL_checkint(L, 2));
lua_pushboolean(L, 1);
return 1;
@ -274,20 +435,19 @@ static int set_depth(lua_State *L)
static int set_verify(lua_State *L)
{
int i;
const char *str;
int flag = 0;
SSL_CTX *ctx = ctx_getcontext(L, 1);
SSL_CTX *ctx = lsec_checkcontext(L, 1);
int max = lua_gettop(L);
/* any flag? */
if (max > 1) {
for (i = 2; i <= max; i++) {
if (!set_verify_flag(luaL_checkstring(L, i), &flag)) {
lua_pushboolean(L, 0);
lua_pushstring(L, "invalid verify option");
return 2;
}
for (i = 2; i <= max; i++) {
str = luaL_checkstring(L, i);
if (!set_verify_flag(str, &flag)) {
lua_pushboolean(L, 0);
lua_pushfstring(L, "invalid verify option (%s)", str);
return 2;
}
SSL_CTX_set_verify(ctx, flag, NULL);
}
if (flag) SSL_CTX_set_verify(ctx, flag, NULL);
lua_pushboolean(L, 1);
return 1;
}
@ -298,15 +458,23 @@ static int set_verify(lua_State *L)
static int set_options(lua_State *L)
{
int i;
const char *str;
unsigned long flag = 0L;
SSL_CTX *ctx = ctx_getcontext(L, 1);
SSL_CTX *ctx = lsec_checkcontext(L, 1);
int max = lua_gettop(L);
/* any option? */
if (max > 1) {
for (i = 2; i <= max; i++) {
if (!set_option_flag(luaL_checkstring(L, i), &flag)) {
str = luaL_checkstring(L, i);
#if !defined(SSL_OP_NO_COMPRESSION) && (OPENSSL_VERSION_NUMBER >= 0x0090800f) && (OPENSSL_VERSION_NUMBER < 0x1000000fL)
/* Version 0.9.8 has a different way to disable compression */
if (!strcmp(str, "no_compression"))
ctx->comp_methods = NULL;
else
#endif
if (!set_option_flag(str, &flag)) {
lua_pushboolean(L, 0);
lua_pushstring(L, "invalid option");
lua_pushfstring(L, "invalid option (%s)", str);
return 2;
}
}
@ -324,44 +492,91 @@ static int set_mode(lua_State *L)
p_context ctx = checkctx(L, 1);
const char *str = luaL_checkstring(L, 2);
if (!strcmp("server", str)) {
ctx->mode = MD_CTX_SERVER;
ctx->mode = LSEC_MODE_SERVER;
lua_pushboolean(L, 1);
return 1;
}
if(!strcmp("client", str)) {
ctx->mode = MD_CTX_CLIENT;
if (!strcmp("client", str)) {
ctx->mode = LSEC_MODE_CLIENT;
lua_pushboolean(L, 1);
return 1;
}
lua_pushboolean(L, 0);
lua_pushstring(L, "invalid mode");
lua_pushfstring(L, "invalid mode (%s)", str);
return 1;
}
/**
* Return a pointer to SSL_CTX structure.
* Configure DH parameters.
*/
static int raw_ctx(lua_State *L)
static int set_dhparam(lua_State *L)
{
p_context ctx = checkctx(L, 1);
lua_pushlightuserdata(L, (void*)ctx->context);
SSL_CTX *ctx = lsec_checkcontext(L, 1);
SSL_CTX_set_tmp_dh_callback(ctx, dhparam_cb);
/* Save callback */
luaL_getmetatable(L, "SSL:DH:Registry");
lua_pushlightuserdata(L, (void*)ctx);
lua_pushvalue(L, 2);
lua_settable(L, -3);
return 0;
}
/**
* Set elliptic curve.
*/
#ifdef OPENSSL_NO_ECDH
static int set_curve(lua_State *L)
{
lua_pushboolean(L, 0);
lua_pushstring(L, "OpenSSL does not support ECDH");
return 2;
}
#else
static int set_curve(lua_State *L)
{
long ret;
SSL_CTX *ctx = lsec_checkcontext(L, 1);
const char *str = luaL_checkstring(L, 2);
EC_KEY *key = find_ec_key(str);
if (!key) {
lua_pushboolean(L, 0);
lua_pushfstring(L, "elliptic curve %s not supported", str);
return 2;
}
ret = SSL_CTX_set_tmp_ecdh(ctx, key);
/* SSL_CTX_set_tmp_ecdh takes its own reference */
EC_KEY_free(key);
if (!ret) {
lua_pushboolean(L, 0);
lua_pushfstring(L, "error setting elliptic curve (%s)",
ERR_reason_error_string(ERR_get_error()));
return 2;
}
lua_pushboolean(L, 1);
return 1;
}
#endif
/**
* Package functions
*/
static luaL_Reg funcs[] = {
{"create", create},
{"locations", load_locations},
{"loadcert", load_cert},
{"loadkey", load_key},
{"setcipher", set_cipher},
{"setdepth", set_depth},
{"setverify", set_verify},
{"setoptions", set_options},
{"setmode", set_mode},
{"rawcontext", raw_ctx},
{"create", create},
{"locations", load_locations},
{"loadcert", load_cert},
{"loadkey", load_key},
{"setcipher", set_cipher},
{"setdepth", set_depth},
{"setdhparam", set_dhparam},
{"setcurve", set_curve},
{"setverify", set_verify},
{"setoptions", set_options},
{"setmode", set_mode},
{NULL, NULL}
};
@ -374,9 +589,24 @@ static int meth_destroy(lua_State *L)
{
p_context ctx = checkctx(L, 1);
if (ctx->context) {
/* Clear registries */
luaL_getmetatable(L, "SSL:DH:Registry");
lua_pushlightuserdata(L, (void*)ctx->context);
lua_pushnil(L);
lua_settable(L, -3);
luaL_getmetatable(L, "SSL:Verify:Registry");
lua_pushlightuserdata(L, (void*)ctx->context);
lua_pushnil(L);
lua_settable(L, -3);
SSL_CTX_free(ctx->context);
ctx->context = NULL;
}
if (ctx->dh_param) {
DH_free(ctx->dh_param);
ctx->dh_param = NULL;
}
return 0;
}
@ -390,6 +620,60 @@ static int meth_tostring(lua_State *L)
return 1;
}
/**
* Set extra flags for handshake verification.
*/
static int meth_set_verify_ext(lua_State *L)
{
int i;
const char *str;
int crl_flag = 0;
int lsec_flag = 0;
SSL_CTX *ctx = lsec_checkcontext(L, 1);
int max = lua_gettop(L);
for (i = 2; i <= max; i++) {
str = luaL_checkstring(L, i);
if (!strcmp(str, "lsec_continue")) {
lsec_flag |= LSEC_VERIFY_CONTINUE;
} else if (!strcmp(str, "lsec_ignore_purpose")) {
lsec_flag |= LSEC_VERIFY_IGNORE_PURPOSE;
} else if (!strcmp(str, "crl_check")) {
crl_flag |= X509_V_FLAG_CRL_CHECK;
} else if (!strcmp(str, "crl_check_chain")) {
crl_flag |= X509_V_FLAG_CRL_CHECK_ALL;
} else {
lua_pushboolean(L, 0);
lua_pushfstring(L, "invalid verify option (%s)", str);
return 2;
}
}
/* Set callback? */
if (lsec_flag) {
SSL_CTX_set_verify(ctx, SSL_CTX_get_verify_mode(ctx), verify_cb);
SSL_CTX_set_cert_verify_callback(ctx, cert_verify_cb, (void*)ctx);
/* Save flag */
luaL_getmetatable(L, "SSL:Verify:Registry");
lua_pushlightuserdata(L, (void*)ctx);
lua_pushnumber(L, lsec_flag);
lua_settable(L, -3);
} else {
SSL_CTX_set_verify(ctx, SSL_CTX_get_verify_mode(ctx), NULL);
SSL_CTX_set_cert_verify_callback(ctx, NULL, NULL);
/* Remove flag */
luaL_getmetatable(L, "SSL:Verify:Registry");
lua_pushlightuserdata(L, (void*)ctx);
lua_pushnil(L);
lua_settable(L, -3);
}
/* X509 flag */
X509_STORE_set_flags(SSL_CTX_get_cert_store(ctx), crl_flag);
/* Ok */
lua_pushboolean(L, 1);
return 1;
}
/**
* Context metamethods.
*/
@ -399,13 +683,21 @@ static luaL_Reg meta[] = {
{NULL, NULL}
};
/**
* Index metamethods.
*/
static luaL_Reg meta_index[] = {
{"setverifyext", meth_set_verify_ext},
{NULL, NULL}
};
/*----------------------------- Public Functions ---------------------------*/
/**
* Retrieve the SSL context from the Lua stack.
*/
SSL_CTX* ctx_getcontext(lua_State *L, int idx)
SSL_CTX* lsec_checkcontext(lua_State *L, int idx)
{
p_context ctx = checkctx(L, idx);
return ctx->context;
@ -414,7 +706,7 @@ SSL_CTX* ctx_getcontext(lua_State *L, int idx)
/**
* Retrieve the mode from the context in the Lua stack.
*/
char ctx_getmode(lua_State *L, int idx)
int lsec_getmode(lua_State *L, int idx)
{
p_context ctx = checkctx(L, idx);
return ctx->mode;
@ -425,10 +717,39 @@ char ctx_getmode(lua_State *L, int idx)
/**
* Registre the module.
*/
int luaopen_ssl_context(lua_State *L)
#if (LUA_VERSION_NUM == 501)
LSEC_API int luaopen_ssl_context(lua_State *L)
{
luaL_newmetatable(L, "SSL:DH:Registry"); /* Keep all DH callbacks */
luaL_newmetatable(L, "SSL:Verify:Registry"); /* Keep all verify flags */
luaL_newmetatable(L, "SSL:Context");
luaL_register(L, NULL, meta);
/* Create __index metamethods for context */
lua_newtable(L);
luaL_register(L, NULL, meta_index);
lua_setfield(L, -2, "__index");
/* Register the module */
luaL_register(L, "ssl.context", funcs);
return 1;
}
#else
LSEC_API int luaopen_ssl_context(lua_State *L)
{
luaL_newmetatable(L, "SSL:DH:Registry"); /* Keep all DH callbacks */
luaL_newmetatable(L, "SSL:Verify:Registry"); /* Keep all verify flags */
luaL_newmetatable(L, "SSL:Context");
luaL_setfuncs(L, meta, 0);
/* Create __index metamethods for context */
lua_newtable(L);
luaL_setfuncs(L, meta_index, 0);
lua_setfield(L, -2, "__index");
/* Return the module */
lua_newtable(L);
luaL_setfuncs(L, funcs, 0);
return 1;
}
#endif

View File

@ -1,35 +1,39 @@
#ifndef __CONTEXT_H__
#define __CONTEXT_H__
#ifndef LSEC_CONTEXT_H
#define LSEC_CONTEXT_H
/*--------------------------------------------------------------------------
* LuaSec 0.3.2
* Copyright (C) 2006-2009 Bruno Silvestre
* LuaSec 0.5.1
* Copyright (C) 2006-2015 Bruno Silvestre
*
*--------------------------------------------------------------------------*/
#include <lua.h>
#include <openssl/ssl.h>
#ifndef LUASEC_API
#define LUASEC_API extern
#endif
#include "config.h"
#define MD_CTX_INVALID 0
#define MD_CTX_SERVER 1
#define MD_CTX_CLIENT 2
#define LSEC_MODE_INVALID 0
#define LSEC_MODE_SERVER 1
#define LSEC_MODE_CLIENT 2
#define LSEC_VERIFY_CONTINUE 1
#define LSEC_VERIFY_IGNORE_PURPOSE 2
typedef struct t_context_ {
SSL_CTX *context;
char mode;
lua_State *L;
DH *dh_param;
int mode;
} t_context;
typedef t_context* p_context;
/* Retrieve the SSL context from the Lua stack */
SSL_CTX *ctx_getcontext(lua_State *L, int idx);
SSL_CTX *lsec_checkcontext(lua_State *L, int idx);
/* Retrieve the mode from the context in the Lua stack */
char ctx_getmode(lua_State *L, int idx);
int lsec_getmode(lua_State *L, int idx);
/* Registre the module. */
LUASEC_API int luaopen_ssl_context(lua_State *L);
LSEC_API int luaopen_ssl_context(lua_State *L);
#endif

64
src/ec.h Normal file
View File

@ -0,0 +1,64 @@
/*--------------------------------------------------------------------------
* LuaSec 0.5.1
* Copyright (C) 2006-2015 Bruno Silvestre
*
*--------------------------------------------------------------------------*/
#ifndef LSEC_EC_H
#define LSEC_EC_H
#include <openssl/objects.h>
typedef struct t_ec_ {
char *name;
int nid;
} t_ec;
typedef t_ec* p_ec;
/* Elliptic curves supported */
static t_ec curves[] = {
/* SECG */
{"secp112r1", NID_secp112r1},
{"secp112r2", NID_secp112r2},
{"secp128r1", NID_secp128r1},
{"secp128r2", NID_secp128r2},
{"secp160k1", NID_secp160k1},
{"secp160r1", NID_secp160r1},
{"secp160r2", NID_secp160r2},
{"secp192k1", NID_secp192k1},
{"secp224k1", NID_secp224k1},
{"secp224r1", NID_secp224r1},
{"secp256k1", NID_secp256k1},
{"secp384r1", NID_secp384r1},
{"secp521r1", NID_secp521r1},
{"sect113r1", NID_sect113r1},
{"sect113r2", NID_sect113r2},
{"sect131r1", NID_sect131r1},
{"sect131r2", NID_sect131r2},
{"sect163k1", NID_sect163k1},
{"sect163r1", NID_sect163r1},
{"sect163r2", NID_sect163r2},
{"sect193r1", NID_sect193r1},
{"sect193r2", NID_sect193r2},
{"sect233k1", NID_sect233k1},
{"sect233r1", NID_sect233r1},
{"sect239k1", NID_sect239k1},
{"sect283k1", NID_sect283k1},
{"sect283r1", NID_sect283r1},
{"sect409k1", NID_sect409k1},
{"sect409r1", NID_sect409r1},
{"sect571k1", NID_sect571k1},
{"sect571r1", NID_sect571r1},
/* ANSI X9.62 */
{"prime192v1", NID_X9_62_prime192v1},
{"prime192v2", NID_X9_62_prime192v2},
{"prime192v3", NID_X9_62_prime192v3},
{"prime239v1", NID_X9_62_prime239v1},
{"prime239v2", NID_X9_62_prime239v2},
{"prime239v3", NID_X9_62_prime239v3},
{"prime256v1", NID_X9_62_prime256v1},
/* End */
{NULL, 0U}
};
#endif

138
src/https.lua Normal file
View File

@ -0,0 +1,138 @@
----------------------------------------------------------------------------
-- LuaSec 0.5.1
-- Copyright (C) 2009-2015 PUC-Rio
--
-- Author: Pablo Musa
-- Author: Tomas Guisasola
---------------------------------------------------------------------------
local socket = require("socket")
local ssl = require("ssl")
local ltn12 = require("ltn12")
local http = require("socket.http")
local url = require("socket.url")
local table = require("table")
local string = require("string")
local try = socket.try
local type = type
local pairs = pairs
local getmetatable = getmetatable
module("ssl.https")
_VERSION = "0.5.1"
_COPYRIGHT = "LuaSec 0.5.1 - Copyright (C) 2009-2015 PUC-Rio"
-- Default settings
PORT = 443
local cfg = {
protocol = "tlsv1",
options = "all",
verify = "none",
}
--------------------------------------------------------------------
-- Auxiliar Functions
--------------------------------------------------------------------
-- Insert default HTTPS port.
local function default_https_port(u)
return url.build(url.parse(u, {port = PORT}))
end
-- Convert an URL to a table according to Luasocket needs.
local function urlstring_totable(url, body, result_table)
url = {
url = default_https_port(url),
method = body and "POST" or "GET",
sink = ltn12.sink.table(result_table)
}
if body then
url.source = ltn12.source.string(body)
url.headers = {
["content-length"] = #body,
["content-type"] = "application/x-www-form-urlencoded",
}
end
return url
end
-- Forward calls to the real connection object.
local function reg(conn)
local mt = getmetatable(conn.sock).__index
for name, method in pairs(mt) do
if type(method) == "function" then
conn[name] = function (self, ...)
return method(self.sock, ...)
end
end
end
end
-- Return a function which performs the SSL/TLS connection.
local function tcp(params)
params = params or {}
-- Default settings
for k, v in pairs(cfg) do
params[k] = params[k] or v
end
-- Force client mode
params.mode = "client"
-- 'create' function for LuaSocket
return function ()
local conn = {}
conn.sock = try(socket.tcp())
local st = getmetatable(conn.sock).__index.settimeout
function conn:settimeout(...)
return st(self.sock, ...)
end
-- Replace TCP's connection function
function conn:connect(host, port)
try(self.sock:connect(host, port))
self.sock = try(ssl.wrap(self.sock, params))
try(self.sock:dohandshake())
reg(self, getmetatable(self.sock))
return 1
end
return conn
end
end
--------------------------------------------------------------------
-- Main Function
--------------------------------------------------------------------
-- Make a HTTP request over secure connection. This function receives
-- the same parameters of LuaSocket's HTTP module (except 'proxy' and
-- 'redirect') plus LuaSec parameters.
--
-- @param url mandatory (string or table)
-- @param body optional (string)
-- @return (string if url == string or 1), code, headers, status
--
function request(url, body)
local result_table = {}
local stringrequest = type(url) == "string"
if stringrequest then
url = urlstring_totable(url, body, result_table)
else
url.url = default_https_port(url.url)
end
if http.PROXY or url.proxy then
return nil, "proxy not supported"
elseif url.redirect then
return nil, "redirect not supported"
elseif url.create then
return nil, "create function not permitted"
end
-- New 'create' function to establish a secure connection
url.create = tcp(url)
local res, code, headers, status = http.request(url)
if res and stringrequest then
return table.concat(result_table), code, headers, status
end
return res, code, headers, status
end

21
src/luasocket/LICENSE Normal file
View File

@ -0,0 +1,21 @@
LuaSocket 3.0-RC1 license
Copyright (C) 2004-2013 Diego Nehab
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

26
src/luasocket/Makefile Normal file
View File

@ -0,0 +1,26 @@
OBJS= \
io.o \
buffer.o \
timeout.o \
usocket.o
CC ?= cc
CFLAGS += $(MYCFLAGS) -DLUASOCKET_DEBUG
AR := ar rcu
RANLIB ?= ranlib
.PHONY: all clean
all: libluasocket.a
libluasocket.a: $(OBJS)
$(AR) $@ $(OBJS)
$(RANLIB) $@
clean:
rm -f $(OBJS) libluasocket.a
buffer.o: buffer.c buffer.h io.h timeout.h
io.o: io.c io.h timeout.h
timeout.o: timeout.c timeout.h
usocket.o: usocket.c socket.h io.h timeout.h usocket.h

View File

@ -1,10 +1,6 @@
/*=========================================================================*\
* LuaSocket 2.0.2
* Copyright (C) 2004-2007 Diego Nehab
*
* Input/Output interface for Lua programs
*
* RCS ID: $Id: buffer.c,v 1.28 2007/06/11 23:44:54 diego Exp $
* LuaSocket toolkit
\*=========================================================================*/
#include "lua.h"
#include "lauxlib.h"
@ -32,6 +28,14 @@ static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent);
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int buffer_open(lua_State *L) {
(void) L;
return 0;
}
/*-------------------------------------------------------------------------*\
* Initializes C structure
\*-------------------------------------------------------------------------*/
@ -39,6 +43,29 @@ void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
buf->first = buf->last = 0;
buf->io = io;
buf->tm = tm;
buf->received = buf->sent = 0;
buf->birthday = timeout_gettime();
}
/*-------------------------------------------------------------------------*\
* object:getstats() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_getstats(lua_State *L, p_buffer buf) {
lua_pushnumber(L, (lua_Number) buf->received);
lua_pushnumber(L, (lua_Number) buf->sent);
lua_pushnumber(L, timeout_gettime() - buf->birthday);
return 3;
}
/*-------------------------------------------------------------------------*\
* object:setstats() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_setstats(lua_State *L, p_buffer buf) {
buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received);
buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent);
if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
@ -51,7 +78,9 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
const char *data = luaL_checklstring(L, 2, &size);
long start = (long) luaL_optnumber(L, 3, 1);
long end = (long) luaL_optnumber(L, 4, -1);
#ifdef LUASOCKET_DEBUG
p_timeout tm = timeout_markstart(buf->tm);
#endif
if (start < 0) start = (long) (size+start+1);
if (end < 0) end = (long) (size+end+1);
if (start < 1) start = (long) 1;
@ -61,13 +90,13 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushnumber(L, sent+start-1);
lua_pushnumber(L, (lua_Number) (sent+start-1));
} else {
lua_pushnumber(L, sent+start-1);
lua_pushnumber(L, (lua_Number) (sent+start-1));
lua_pushnil(L);
lua_pushnil(L);
}
#ifdef BUFFER_DEBUG
#ifdef LUASOCKET_DEBUG
/* push time elapsed during operation as the last return value */
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
#endif
@ -82,7 +111,9 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
luaL_Buffer b;
size_t size;
const char *part = luaL_optlstring(L, 3, "", &size);
#ifdef LUASOCKET_DEBUG
p_timeout tm = timeout_markstart(buf->tm);
#endif
/* initialize buffer with optional extra prefix
* (useful for concatenating previous partial results) */
luaL_buffinit(L, &b);
@ -93,9 +124,15 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
else luaL_argcheck(L, 0, 2, "invalid receive pattern");
/* get a fixed number of bytes (minus what was already partially
* received) */
} else err = recvraw(buf, (size_t) lua_tonumber(L, 2)-size, &b);
/* get a fixed number of bytes (minus what was already partially
* received) */
} else {
double n = lua_tonumber(L, 2);
size_t wanted = (size_t) n;
luaL_argcheck(L, n >= 0, 2, "invalid receive pattern");
if (size == 0 || wanted > size)
err = recvraw(buf, wanted-size, &b);
}
/* check if there was an error */
if (err != IO_DONE) {
/* we can't push anyting in the stack before pushing the
@ -110,7 +147,7 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
lua_pushnil(L);
lua_pushnil(L);
}
#ifdef BUFFER_DEBUG
#ifdef LUASOCKET_DEBUG
/* push time elapsed during operation as the last return value */
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
#endif
@ -137,12 +174,13 @@ static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) {
size_t total = 0;
int err = IO_DONE;
while (total < count && err == IO_DONE) {
size_t done;
size_t done = 0;
size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE;
err = io->send(io->ctx, data+total, step, &done, tm);
total += done;
}
*sent = total;
buf->sent += total;
return err;
}
@ -195,7 +233,7 @@ static int recvline(p_buffer buf, luaL_Buffer *b) {
pos = 0;
while (pos < count && data[pos] != '\n') {
/* we ignore all \r's */
if (data[pos] != '\r') luaL_putchar(b, data[pos]);
if (data[pos] != '\r') luaL_addchar(b, data[pos]);
pos++;
}
if (pos < count) { /* found '\n' */
@ -212,6 +250,7 @@ static int recvline(p_buffer buf, luaL_Buffer *b) {
* transport layer
\*-------------------------------------------------------------------------*/
static void buffer_skip(p_buffer buf, size_t count) {
buf->received += count;
buf->first += count;
if (buffer_isempty(buf))
buf->first = buf->last = 0;

View File

@ -1,10 +1,8 @@
#ifndef BUF_H
#define BUF_H
/*=========================================================================*\
* LuaSocket 2.0.2
* Copyright (C) 2004-2007 Diego Nehab
*
* Input/Output interface for Lua programs
* LuaSocket toolkit
*
* Line patterns require buffering. Reading one character at a time involves
* too many system calls and is very slow. This module implements the
@ -16,11 +14,8 @@
*
* The module is built on top of the I/O abstraction defined in io.h and the
* timeout management is done with the timeout.h interface.
*
*
* RCS ID: $Id: buffer.h,v 1.12 2005/10/07 04:40:59 diego Exp $
\*=========================================================================*/
#include <lua.h>
#include "lua.h"
#include "io.h"
#include "timeout.h"
@ -30,6 +25,8 @@
/* buffer control structure */
typedef struct t_buffer_ {
double birthday; /* throttle support info: creation time, */
size_t sent, received; /* bytes sent, and bytes received */
p_io io; /* IO driver used for this buffer */
p_timeout tm; /* timeout management for this buffer */
size_t first, last; /* index of first and last bytes of stored data */
@ -37,9 +34,12 @@ typedef struct t_buffer_ {
} t_buffer;
typedef t_buffer *p_buffer;
int buffer_open(lua_State *L);
void buffer_init(p_buffer buf, p_io io, p_timeout tm);
int buffer_meth_send(lua_State *L, p_buffer buf);
int buffer_meth_receive(lua_State *L, p_buffer buf);
int buffer_meth_getstats(lua_State *L, p_buffer buf);
int buffer_meth_setstats(lua_State *L, p_buffer buf);
int buffer_isempty(p_buffer buf);
#endif /* BUF_H */

View File

@ -1,10 +1,6 @@
/*=========================================================================*\
* LuaSocket 2.0.2
* Copyright (C) 2004-2007 Diego Nehab
*
* Input/Output abstraction
*
* RCS ID: $Id: io.c 2 2006-04-30 19:30:47Z brunoos $
* LuaSocket toolkit
\*=========================================================================*/
#include "io.h"

View File

@ -1,10 +1,8 @@
#ifndef IO_H
#define IO_H
/*=========================================================================*\
* LuaSocket 2.0.2
* Copyright (C) 2004-2007 Diego Nehab
*
* Input/Output abstraction
* LuaSocket toolkit
*
* This module defines the interface that LuaSocket expects from the
* transport layer for streamed input/output. The idea is that if any
@ -13,21 +11,18 @@
*
* The module socket.h implements this interface, and thus the module tcp.h
* is very simple.
*
* RCS ID: $Id: io.h 6 2006-04-30 20:33:05Z brunoos $
\*=========================================================================*/
#include <stdio.h>
#include <lua.h>
#include "lua.h"
#include "timeout.h"
/* IO error codes */
enum {
IO_DONE = 0, /* operation completed successfully */
IO_TIMEOUT = -1, /* operation timed out */
IO_CLOSED = -2, /* the connection has been closed */
IO_UNKNOWN = -3, /* Unknown error */
IO_SSL = -4 /* SSL error */
IO_DONE = 0, /* operation completed successfully */
IO_TIMEOUT = -1, /* operation timed out */
IO_CLOSED = -2, /* the connection has been closed */
IO_UNKNOWN = -3
};
/* interface to error message function */

View File

@ -1,17 +1,13 @@
#ifndef SOCKET_H
#define SOCKET_H
/*=========================================================================*\
* LuaSocket 2.0.2
* Copyright (C) 2004-2007 Diego Nehab
*
* Socket compatibilization module
* LuaSocket toolkit
*
* BSD Sockets and WinSock are similar, but there are a few irritating
* differences. Also, not all *nix platforms behave the same. This module
* (and the associated usocket.h and wsocket.h) factor these differences and
* creates a interface compatible with the io.h module.
*
* RCS ID: $Id: socket.h 2 2006-04-30 19:30:47Z brunoos $
\*=========================================================================*/
#include "io.h"
@ -32,6 +28,9 @@
\*=========================================================================*/
#include "timeout.h"
/* we are lazy... */
typedef struct sockaddr SA;
/*=========================================================================*\
* Functions bellow implement a comfortable platform independent
* interface to sockets
@ -39,10 +38,41 @@
int socket_open(void);
int socket_close(void);
void socket_destroy(p_socket ps);
void socket_shutdown(p_socket ps, int how);
int socket_sendto(p_socket ps, const char *data, size_t count,
size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm);
int socket_recvfrom(p_socket ps, char *data, size_t count,
size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm);
void socket_setnonblocking(p_socket ps);
void socket_setblocking(p_socket ps);
int socket_waitfd(p_socket ps, int sw, p_timeout tm);
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
p_timeout tm);
int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm);
int socket_create(p_socket ps, int domain, int type, int protocol);
int socket_bind(p_socket ps, SA *addr, socklen_t addr_len);
int socket_listen(p_socket ps, int backlog);
int socket_accept(p_socket ps, p_socket pa, SA *addr,
socklen_t *addr_len, p_timeout tm);
const char *socket_hoststrerror(int err);
const char *socket_gaistrerror(int err);
const char *socket_strerror(int err);
int socket_error();
/* these are perfect to use with the io abstraction module
and the buffered input module */
int socket_send(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm);
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
int socket_write(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm);
int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
const char *socket_ioerror(p_socket ps, int err);
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);
int socket_gethostbyname(const char *addr, struct hostent **hp);
#endif /* SOCKET_H */

View File

@ -1,12 +1,15 @@
/*=========================================================================*\
* LuaSocket 2.0.2
* Copyright (C) 2004-2007 Diego Nehab
*
* Timeout management functions
*
* RCS ID: $Id: timeout.c,v 1.30 2005/10/07 04:40:59 diego Exp $
* LuaSocket toolkit
\*=========================================================================*/
#include <stdio.h>
#include <limits.h>
#include <float.h>
#include "lua.h"
#include "lauxlib.h"
#include "timeout.h"
#ifdef _WIN32
#include <windows.h>
@ -15,11 +18,6 @@
#include <sys/time.h>
#endif
#include <lua.h>
#include <lauxlib.h>
#include "timeout.h"
/* min and max macros */
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? x : y)
@ -28,6 +26,18 @@
#define MAX(x, y) ((x) > (y) ? x : y)
#endif
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int timeout_lua_gettime(lua_State *L);
static int timeout_lua_sleep(lua_State *L);
static luaL_Reg func[] = {
{ "gettime", timeout_lua_gettime },
{ "sleep", timeout_lua_sleep },
{ NULL, NULL }
};
/*=========================================================================*\
* Exported functions.
\*=========================================================================*/
@ -129,6 +139,18 @@ double timeout_gettime(void) {
}
#endif
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int timeout_open(lua_State *L) {
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, NULL, func, 0);
#endif
return 0;
}
/*-------------------------------------------------------------------------*\
* Sets timeout values for IO operations
* Lua Input: base, time [, mode]
@ -153,3 +175,46 @@ int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
return 1;
}
/*=========================================================================*\
* Test support functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Returns the time the system has been up, in secconds.
\*-------------------------------------------------------------------------*/
static int timeout_lua_gettime(lua_State *L)
{
lua_pushnumber(L, timeout_gettime());
return 1;
}
/*-------------------------------------------------------------------------*\
* Sleep for n seconds.
\*-------------------------------------------------------------------------*/
#ifdef _WIN32
int timeout_lua_sleep(lua_State *L)
{
double n = luaL_checknumber(L, 1);
if (n < 0.0) n = 0.0;
if (n < DBL_MAX/1000.0) n *= 1000.0;
if (n > INT_MAX) n = INT_MAX;
Sleep((int)n);
return 0;
}
#else
int timeout_lua_sleep(lua_State *L)
{
double n = luaL_checknumber(L, 1);
struct timespec t, r;
if (n < 0.0) n = 0.0;
if (n > INT_MAX) n = INT_MAX;
t.tv_sec = (int) n;
n -= t.tv_sec;
t.tv_nsec = (int) (n * 1000000000);
if (t.tv_nsec >= 1000000000) t.tv_nsec = 999999999;
while (nanosleep(&t, &r) != 0) {
t.tv_sec = r.tv_sec;
t.tv_nsec = r.tv_nsec;
}
return 0;
}
#endif

View File

@ -1,14 +1,10 @@
#ifndef TIMEOUT_H
#define TIMEOUT_H
/*=========================================================================*\
* LuaSocket 2.0.2
* Copyright (C) 2004-2007 Diego Nehab
*
* Timeout management functions
*
* RCS ID: $Id: timeout.h 2 2006-04-30 19:30:47Z brunoos $
* LuaSocket toolkit
\*=========================================================================*/
#include <lua.h>
#include "lua.h"
/* timeout control structure */
typedef struct t_timeout_ {

439
src/luasocket/usocket.c Normal file
View File

@ -0,0 +1,439 @@
/*=========================================================================*\
* Socket compatibilization module for Unix
* LuaSocket toolkit
*
* The code is now interrupt-safe.
* The penalty of calling select to avoid busy-wait is only paid when
* the I/O call fail in the first place.
\*=========================================================================*/
#include <string.h>
#include <signal.h>
#include "socket.h"
/*-------------------------------------------------------------------------*\
* Wait for readable/writable/connected socket with timeout
\*-------------------------------------------------------------------------*/
#ifndef SOCKET_SELECT
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
int ret;
struct pollfd pfd;
pfd.fd = *ps;
pfd.events = sw;
pfd.revents = 0;
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
do {
int t = (int)(timeout_getretry(tm)*1e3);
ret = poll(&pfd, 1, t >= 0? t: -1);
} while (ret == -1 && errno == EINTR);
if (ret == -1) return errno;
if (ret == 0) return IO_TIMEOUT;
if (sw == WAITFD_C && (pfd.revents & (POLLIN|POLLERR))) return IO_CLOSED;
return IO_DONE;
}
#else
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
int ret;
fd_set rfds, wfds, *rp, *wp;
struct timeval tv, *tp;
double t;
if (*ps >= FD_SETSIZE) return EINVAL;
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
do {
/* must set bits within loop, because select may have modifed them */
rp = wp = NULL;
if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(*ps, &rfds); rp = &rfds; }
if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
t = timeout_getretry(tm);
tp = NULL;
if (t >= 0.0) {
tv.tv_sec = (int)t;
tv.tv_usec = (int)((t-tv.tv_sec)*1.0e6);
tp = &tv;
}
ret = select(*ps+1, rp, wp, NULL, tp);
} while (ret == -1 && errno == EINTR);
if (ret == -1) return errno;
if (ret == 0) return IO_TIMEOUT;
if (sw == WAITFD_C && FD_ISSET(*ps, &rfds)) return IO_CLOSED;
return IO_DONE;
}
#endif
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int socket_open(void) {
/* instals a handler to ignore sigpipe or it will crash us */
signal(SIGPIPE, SIG_IGN);
return 1;
}
/*-------------------------------------------------------------------------*\
* Close module
\*-------------------------------------------------------------------------*/
int socket_close(void) {
return 1;
}
/*-------------------------------------------------------------------------*\
* Close and inutilize socket
\*-------------------------------------------------------------------------*/
void socket_destroy(p_socket ps) {
if (*ps != SOCKET_INVALID) {
socket_setblocking(ps);
close(*ps);
*ps = SOCKET_INVALID;
}
}
/*-------------------------------------------------------------------------*\
* Select with timeout control
\*-------------------------------------------------------------------------*/
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
p_timeout tm) {
int ret;
do {
struct timeval tv;
double t = timeout_getretry(tm);
tv.tv_sec = (int) t;
tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
/* timeout = 0 means no wait */
ret = select(n, rfds, wfds, efds, t >= 0.0 ? &tv: NULL);
} while (ret < 0 && errno == EINTR);
return ret;
}
/*-------------------------------------------------------------------------*\
* Creates and sets up a socket
\*-------------------------------------------------------------------------*/
int socket_create(p_socket ps, int domain, int type, int protocol) {
*ps = socket(domain, type, protocol);
if (*ps != SOCKET_INVALID) return IO_DONE;
else return errno;
}
/*-------------------------------------------------------------------------*\
* Binds or returns error message
\*-------------------------------------------------------------------------*/
int socket_bind(p_socket ps, SA *addr, socklen_t len) {
int err = IO_DONE;
socket_setblocking(ps);
if (bind(*ps, addr, len) < 0) err = errno;
socket_setnonblocking(ps);
return err;
}
/*-------------------------------------------------------------------------*\
*
\*-------------------------------------------------------------------------*/
int socket_listen(p_socket ps, int backlog) {
int err = IO_DONE;
socket_setblocking(ps);
if (listen(*ps, backlog)) err = errno;
socket_setnonblocking(ps);
return err;
}
/*-------------------------------------------------------------------------*\
*
\*-------------------------------------------------------------------------*/
void socket_shutdown(p_socket ps, int how) {
socket_setblocking(ps);
shutdown(*ps, how);
socket_setnonblocking(ps);
}
/*-------------------------------------------------------------------------*\
* Connects or returns error message
\*-------------------------------------------------------------------------*/
int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
int err;
/* avoid calling on closed sockets */
if (*ps == SOCKET_INVALID) return IO_CLOSED;
/* call connect until done or failed without being interrupted */
do if (connect(*ps, addr, len) == 0) return IO_DONE;
while ((err = errno) == EINTR);
/* if connection failed immediately, return error code */
if (err != EINPROGRESS && err != EAGAIN) return err;
/* zero timeout case optimization */
if (timeout_iszero(tm)) return IO_TIMEOUT;
/* wait until we have the result of the connection attempt or timeout */
err = socket_waitfd(ps, WAITFD_C, tm);
if (err == IO_CLOSED) {
if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE;
else return errno;
} else return err;
}
/*-------------------------------------------------------------------------*\
* Accept with timeout
\*-------------------------------------------------------------------------*/
int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout tm) {
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
int err;
if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE;
err = errno;
if (err == EINTR) continue;
if (err != EAGAIN && err != ECONNABORTED) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
/* can't reach here */
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Send with timeout
\*-------------------------------------------------------------------------*/
int socket_send(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm)
{
int err;
*sent = 0;
/* avoid making system calls on closed sockets */
if (*ps == SOCKET_INVALID) return IO_CLOSED;
/* loop until we send something or we give up on error */
for ( ;; ) {
long put = (long) send(*ps, data, count, 0);
/* if we sent anything, we are done */
if (put >= 0) {
*sent = put;
return IO_DONE;
}
err = errno;
/* EPIPE means the connection was closed */
if (err == EPIPE) return IO_CLOSED;
/* we call was interrupted, just try again */
if (err == EINTR) continue;
/* if failed fatal reason, report error */
if (err != EAGAIN) return err;
/* wait until we can send something or we timeout */
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
}
/* can't reach here */
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Sendto with timeout
\*-------------------------------------------------------------------------*/
int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
SA *addr, socklen_t len, p_timeout tm)
{
int err;
*sent = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
long put = (long) sendto(*ps, data, count, 0, addr, len);
if (put >= 0) {
*sent = put;
return IO_DONE;
}
err = errno;
if (err == EPIPE) return IO_CLOSED;
if (err == EINTR) continue;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
}
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Receive with timeout
\*-------------------------------------------------------------------------*/
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
int err;
*got = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
long taken = (long) recv(*ps, data, count, 0);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
err = errno;
if (taken == 0) return IO_CLOSED;
if (err == EINTR) continue;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Recvfrom with timeout
\*-------------------------------------------------------------------------*/
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *len, p_timeout tm) {
int err;
*got = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
long taken = (long) recvfrom(*ps, data, count, 0, addr, len);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
err = errno;
if (taken == 0) return IO_CLOSED;
if (err == EINTR) continue;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Write with timeout
*
* socket_read and socket_write are cut-n-paste of socket_send and socket_recv,
* with send/recv replaced with write/read. We can't just use write/read
* in the socket version, because behaviour when size is zero is different.
\*-------------------------------------------------------------------------*/
int socket_write(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm)
{
int err;
*sent = 0;
/* avoid making system calls on closed sockets */
if (*ps == SOCKET_INVALID) return IO_CLOSED;
/* loop until we send something or we give up on error */
for ( ;; ) {
long put = (long) write(*ps, data, count);
/* if we sent anything, we are done */
if (put >= 0) {
*sent = put;
return IO_DONE;
}
err = errno;
/* EPIPE means the connection was closed */
if (err == EPIPE) return IO_CLOSED;
/* we call was interrupted, just try again */
if (err == EINTR) continue;
/* if failed fatal reason, report error */
if (err != EAGAIN) return err;
/* wait until we can send something or we timeout */
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
}
/* can't reach here */
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Read with timeout
* See note for socket_write
\*-------------------------------------------------------------------------*/
int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
int err;
*got = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
long taken = (long) read(*ps, data, count);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
err = errno;
if (taken == 0) return IO_CLOSED;
if (err == EINTR) continue;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Put socket into blocking mode
\*-------------------------------------------------------------------------*/
void socket_setblocking(p_socket ps) {
int flags = fcntl(*ps, F_GETFL, 0);
flags &= (~(O_NONBLOCK));
fcntl(*ps, F_SETFL, flags);
}
/*-------------------------------------------------------------------------*\
* Put socket into non-blocking mode
\*-------------------------------------------------------------------------*/
void socket_setnonblocking(p_socket ps) {
int flags = fcntl(*ps, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(*ps, F_SETFL, flags);
}
/*-------------------------------------------------------------------------*\
* DNS helpers
\*-------------------------------------------------------------------------*/
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
*hp = gethostbyaddr(addr, len, AF_INET);
if (*hp) return IO_DONE;
else if (h_errno) return h_errno;
else if (errno) return errno;
else return IO_UNKNOWN;
}
int socket_gethostbyname(const char *addr, struct hostent **hp) {
*hp = gethostbyname(addr);
if (*hp) return IO_DONE;
else if (h_errno) return h_errno;
else if (errno) return errno;
else return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Error translation functions
* Make sure important error messages are standard
\*-------------------------------------------------------------------------*/
const char *socket_hoststrerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case HOST_NOT_FOUND: return "host not found";
default: return hstrerror(err);
}
}
const char *socket_strerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case EADDRINUSE: return "address already in use";
case EISCONN: return "already connected";
case EACCES: return "permission denied";
case ECONNREFUSED: return "connection refused";
case ECONNABORTED: return "closed";
case ECONNRESET: return "closed";
case ETIMEDOUT: return "timeout";
default: return strerror(err);
}
}
const char *socket_ioerror(p_socket ps, int err) {
(void) ps;
return socket_strerror(err);
}
const char *socket_gaistrerror(int err) {
if (err == 0) return NULL;
switch (err) {
case EAI_AGAIN: return "temporary failure in name resolution";
case EAI_BADFLAGS: return "invalid value for ai_flags";
#ifdef EAI_BADHINTS
case EAI_BADHINTS: return "invalid value for hints";
#endif
case EAI_FAIL: return "non-recoverable failure in name resolution";
case EAI_FAMILY: return "ai_family not supported";
case EAI_MEMORY: return "memory allocation failure";
case EAI_NONAME:
return "host or service not provided, or not known";
case EAI_OVERFLOW: return "argument buffer overflow";
#ifdef EAI_PROTOCOL
case EAI_PROTOCOL: return "resolved protocol is unknown";
#endif
case EAI_SERVICE: return "service not supported for socket type";
case EAI_SOCKTYPE: return "ai_socktype not supported";
case EAI_SYSTEM: return strerror(errno);
default: return gai_strerror(err);
}
}

70
src/luasocket/usocket.h Normal file
View File

@ -0,0 +1,70 @@
#ifndef USOCKET_H
#define USOCKET_H
/*=========================================================================*\
* Socket compatibilization module for Unix
* LuaSocket toolkit
\*=========================================================================*/
/*=========================================================================*\
* BSD include files
\*=========================================================================*/
/* error codes */
#include <errno.h>
/* close function */
#include <unistd.h>
/* fnctnl function and associated constants */
#include <fcntl.h>
/* struct sockaddr */
#include <sys/types.h>
/* socket function */
#include <sys/socket.h>
/* struct timeval */
#include <sys/time.h>
/* gethostbyname and gethostbyaddr functions */
#include <netdb.h>
/* sigpipe handling */
#include <signal.h>
/* IP stuff*/
#include <netinet/in.h>
#include <arpa/inet.h>
/* TCP options (nagle algorithm disable) */
#include <netinet/tcp.h>
#include <net/if.h>
#ifndef SOCKET_SELECT
#include <sys/poll.h>
#define WAITFD_R POLLIN
#define WAITFD_W POLLOUT
#define WAITFD_C (POLLIN|POLLOUT)
#else
#define WAITFD_R 1
#define WAITFD_W 2
#define WAITFD_C (WAITFD_R|WAITFD_W)
#endif
#ifndef SO_REUSEPORT
#define SO_REUSEPORT SO_REUSEADDR
#endif
/* Some platforms use IPV6_JOIN_GROUP instead if
* IPV6_ADD_MEMBERSHIP. The semantics are same, though. */
#ifndef IPV6_ADD_MEMBERSHIP
#ifdef IPV6_JOIN_GROUP
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
#endif /* IPV6_JOIN_GROUP */
#endif /* !IPV6_ADD_MEMBERSHIP */
/* Same with IPV6_DROP_MEMBERSHIP / IPV6_LEAVE_GROUP. */
#ifndef IPV6_DROP_MEMBERSHIP
#ifdef IPV6_LEAVE_GROUP
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
#endif /* IPV6_LEAVE_GROUP */
#endif /* !IPV6_DROP_MEMBERSHIP */
typedef int t_socket;
typedef t_socket *p_socket;
typedef struct sockaddr_storage t_sockaddr_storage;
#define SOCKET_INVALID (-1)
#endif /* USOCKET_H */

429
src/luasocket/wsocket.c Normal file
View File

@ -0,0 +1,429 @@
/*=========================================================================*\
* Socket compatibilization module for Win32
* LuaSocket toolkit
*
* The penalty of calling select to avoid busy-wait is only paid when
* the I/O call fail in the first place.
\*=========================================================================*/
#include <string.h>
#include "socket.h"
/* WinSock doesn't have a strerror... */
static const char *wstrerror(int err);
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int socket_open(void) {
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 0);
int err = WSAStartup(wVersionRequested, &wsaData );
if (err != 0) return 0;
if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) &&
(LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) {
WSACleanup();
return 0;
}
return 1;
}
/*-------------------------------------------------------------------------*\
* Close module
\*-------------------------------------------------------------------------*/
int socket_close(void) {
WSACleanup();
return 1;
}
/*-------------------------------------------------------------------------*\
* Wait for readable/writable/connected socket with timeout
\*-------------------------------------------------------------------------*/
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
int ret;
fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL;
struct timeval tv, *tp = NULL;
double t;
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
if (sw & WAITFD_R) {
FD_ZERO(&rfds);
FD_SET(*ps, &rfds);
rp = &rfds;
}
if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; }
if ((t = timeout_get(tm)) >= 0.0) {
tv.tv_sec = (int) t;
tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6);
tp = &tv;
}
ret = select(0, rp, wp, ep, tp);
if (ret == -1) return WSAGetLastError();
if (ret == 0) return IO_TIMEOUT;
if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED;
return IO_DONE;
}
/*-------------------------------------------------------------------------*\
* Select with int timeout in ms
\*-------------------------------------------------------------------------*/
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
p_timeout tm) {
struct timeval tv;
double t = timeout_get(tm);
tv.tv_sec = (int) t;
tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
if (n <= 0) {
Sleep((DWORD) (1000*t));
return 0;
} else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
}
/*-------------------------------------------------------------------------*\
* Close and inutilize socket
\*-------------------------------------------------------------------------*/
void socket_destroy(p_socket ps) {
if (*ps != SOCKET_INVALID) {
socket_setblocking(ps); /* close can take a long time on WIN32 */
closesocket(*ps);
*ps = SOCKET_INVALID;
}
}
/*-------------------------------------------------------------------------*\
*
\*-------------------------------------------------------------------------*/
void socket_shutdown(p_socket ps, int how) {
socket_setblocking(ps);
shutdown(*ps, how);
socket_setnonblocking(ps);
}
/*-------------------------------------------------------------------------*\
* Creates and sets up a socket
\*-------------------------------------------------------------------------*/
int socket_create(p_socket ps, int domain, int type, int protocol) {
*ps = socket(domain, type, protocol);
if (*ps != SOCKET_INVALID) return IO_DONE;
else return WSAGetLastError();
}
/*-------------------------------------------------------------------------*\
* Connects or returns error message
\*-------------------------------------------------------------------------*/
int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
int err;
/* don't call on closed socket */
if (*ps == SOCKET_INVALID) return IO_CLOSED;
/* ask system to connect */
if (connect(*ps, addr, len) == 0) return IO_DONE;
/* make sure the system is trying to connect */
err = WSAGetLastError();
if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err;
/* zero timeout case optimization */
if (timeout_iszero(tm)) return IO_TIMEOUT;
/* we wait until something happens */
err = socket_waitfd(ps, WAITFD_C, tm);
if (err == IO_CLOSED) {
int len = sizeof(err);
/* give windows time to set the error (yes, disgusting) */
Sleep(10);
/* find out why we failed */
getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
/* we KNOW there was an error. if 'why' is 0, we will return
* "unknown error", but it's not really our fault */
return err > 0? err: IO_UNKNOWN;
} else return err;
}
/*-------------------------------------------------------------------------*\
* Binds or returns error message
\*-------------------------------------------------------------------------*/
int socket_bind(p_socket ps, SA *addr, socklen_t len) {
int err = IO_DONE;
socket_setblocking(ps);
if (bind(*ps, addr, len) < 0) err = WSAGetLastError();
socket_setnonblocking(ps);
return err;
}
/*-------------------------------------------------------------------------*\
*
\*-------------------------------------------------------------------------*/
int socket_listen(p_socket ps, int backlog) {
int err = IO_DONE;
socket_setblocking(ps);
if (listen(*ps, backlog) < 0) err = WSAGetLastError();
socket_setnonblocking(ps);
return err;
}
/*-------------------------------------------------------------------------*\
* Accept with timeout
\*-------------------------------------------------------------------------*/
int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len,
p_timeout tm) {
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
int err;
/* try to get client socket */
if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE;
/* find out why we failed */
err = WSAGetLastError();
/* if we failed because there was no connectoin, keep trying */
if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err;
/* call select to avoid busy wait */
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
}
/*-------------------------------------------------------------------------*\
* Send with timeout
* On windows, if you try to send 10MB, the OS will buffer EVERYTHING
* this can take an awful lot of time and we will end up blocked.
* Therefore, whoever calls this function should not pass a huge buffer.
\*-------------------------------------------------------------------------*/
int socket_send(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm)
{
int err;
*sent = 0;
/* avoid making system calls on closed sockets */
if (*ps == SOCKET_INVALID) return IO_CLOSED;
/* loop until we send something or we give up on error */
for ( ;; ) {
/* try to send something */
int put = send(*ps, data, (int) count, 0);
/* if we sent something, we are done */
if (put > 0) {
*sent = put;
return IO_DONE;
}
/* deal with failure */
err = WSAGetLastError();
/* we can only proceed if there was no serious error */
if (err != WSAEWOULDBLOCK) return err;
/* avoid busy wait */
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
}
}
/*-------------------------------------------------------------------------*\
* Sendto with timeout
\*-------------------------------------------------------------------------*/
int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
SA *addr, socklen_t len, p_timeout tm)
{
int err;
*sent = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
int put = sendto(*ps, data, (int) count, 0, addr, len);
if (put > 0) {
*sent = put;
return IO_DONE;
}
err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) return err;
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
}
}
/*-------------------------------------------------------------------------*\
* Receive with timeout
\*-------------------------------------------------------------------------*/
int socket_recv(p_socket ps, char *data, size_t count, size_t *got,
p_timeout tm)
{
int err, prev = IO_DONE;
*got = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
int taken = recv(*ps, data, (int) count, 0);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
if (taken == 0) return IO_CLOSED;
err = WSAGetLastError();
/* On UDP, a connreset simply means the previous send failed.
* So we try again.
* On TCP, it means our socket is now useless, so the error passes.
* (We will loop again, exiting because the same error will happen) */
if (err != WSAEWOULDBLOCK) {
if (err != WSAECONNRESET || prev == WSAECONNRESET) return err;
prev = err;
}
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
}
/*-------------------------------------------------------------------------*\
* Recvfrom with timeout
\*-------------------------------------------------------------------------*/
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *len, p_timeout tm)
{
int err, prev = IO_DONE;
*got = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
int taken = recvfrom(*ps, data, (int) count, 0, addr, len);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
if (taken == 0) return IO_CLOSED;
err = WSAGetLastError();
/* On UDP, a connreset simply means the previous send failed.
* So we try again.
* On TCP, it means our socket is now useless, so the error passes.
* (We will loop again, exiting because the same error will happen) */
if (err != WSAEWOULDBLOCK) {
if (err != WSAECONNRESET || prev == WSAECONNRESET) return err;
prev = err;
}
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
}
/*-------------------------------------------------------------------------*\
* Put socket into blocking mode
\*-------------------------------------------------------------------------*/
void socket_setblocking(p_socket ps) {
u_long argp = 0;
ioctlsocket(*ps, FIONBIO, &argp);
}
/*-------------------------------------------------------------------------*\
* Put socket into non-blocking mode
\*-------------------------------------------------------------------------*/
void socket_setnonblocking(p_socket ps) {
u_long argp = 1;
ioctlsocket(*ps, FIONBIO, &argp);
}
/*-------------------------------------------------------------------------*\
* DNS helpers
\*-------------------------------------------------------------------------*/
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
*hp = gethostbyaddr(addr, len, AF_INET);
if (*hp) return IO_DONE;
else return WSAGetLastError();
}
int socket_gethostbyname(const char *addr, struct hostent **hp) {
*hp = gethostbyname(addr);
if (*hp) return IO_DONE;
else return WSAGetLastError();
}
/*-------------------------------------------------------------------------*\
* Error translation functions
\*-------------------------------------------------------------------------*/
const char *socket_hoststrerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case WSAHOST_NOT_FOUND: return "host not found";
default: return wstrerror(err);
}
}
const char *socket_strerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case WSAEADDRINUSE: return "address already in use";
case WSAECONNREFUSED: return "connection refused";
case WSAEISCONN: return "already connected";
case WSAEACCES: return "permission denied";
case WSAECONNABORTED: return "closed";
case WSAECONNRESET: return "closed";
case WSAETIMEDOUT: return "timeout";
default: return wstrerror(err);
}
}
const char *socket_ioerror(p_socket ps, int err) {
(void) ps;
return socket_strerror(err);
}
static const char *wstrerror(int err) {
switch (err) {
case WSAEINTR: return "Interrupted function call";
case WSAEACCES: return "Permission denied";
case WSAEFAULT: return "Bad address";
case WSAEINVAL: return "Invalid argument";
case WSAEMFILE: return "Too many open files";
case WSAEWOULDBLOCK: return "Resource temporarily unavailable";
case WSAEINPROGRESS: return "Operation now in progress";
case WSAEALREADY: return "Operation already in progress";
case WSAENOTSOCK: return "Socket operation on nonsocket";
case WSAEDESTADDRREQ: return "Destination address required";
case WSAEMSGSIZE: return "Message too long";
case WSAEPROTOTYPE: return "Protocol wrong type for socket";
case WSAENOPROTOOPT: return "Bad protocol option";
case WSAEPROTONOSUPPORT: return "Protocol not supported";
case WSAESOCKTNOSUPPORT: return "Socket type not supported";
case WSAEOPNOTSUPP: return "Operation not supported";
case WSAEPFNOSUPPORT: return "Protocol family not supported";
case WSAEAFNOSUPPORT:
return "Address family not supported by protocol family";
case WSAEADDRINUSE: return "Address already in use";
case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
case WSAENETDOWN: return "Network is down";
case WSAENETUNREACH: return "Network is unreachable";
case WSAENETRESET: return "Network dropped connection on reset";
case WSAECONNABORTED: return "Software caused connection abort";
case WSAECONNRESET: return "Connection reset by peer";
case WSAENOBUFS: return "No buffer space available";
case WSAEISCONN: return "Socket is already connected";
case WSAENOTCONN: return "Socket is not connected";
case WSAESHUTDOWN: return "Cannot send after socket shutdown";
case WSAETIMEDOUT: return "Connection timed out";
case WSAECONNREFUSED: return "Connection refused";
case WSAEHOSTDOWN: return "Host is down";
case WSAEHOSTUNREACH: return "No route to host";
case WSAEPROCLIM: return "Too many processes";
case WSASYSNOTREADY: return "Network subsystem is unavailable";
case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range";
case WSANOTINITIALISED:
return "Successful WSAStartup not yet performed";
case WSAEDISCON: return "Graceful shutdown in progress";
case WSAHOST_NOT_FOUND: return "Host not found";
case WSATRY_AGAIN: return "Nonauthoritative host not found";
case WSANO_RECOVERY: return "Nonrecoverable name lookup error";
case WSANO_DATA: return "Valid name, no data record of requested type";
default: return "Unknown error";
}
}
const char *socket_gaistrerror(int err) {
if (err == 0) return NULL;
switch (err) {
case EAI_AGAIN: return "temporary failure in name resolution";
case EAI_BADFLAGS: return "invalid value for ai_flags";
#ifdef EAI_BADHINTS
case EAI_BADHINTS: return "invalid value for hints";
#endif
case EAI_FAIL: return "non-recoverable failure in name resolution";
case EAI_FAMILY: return "ai_family not supported";
case EAI_MEMORY: return "memory allocation failure";
case EAI_NONAME:
return "host or service not provided, or not known";
#ifdef EAI_OVERFLOW
case EAI_OVERFLOW: return "argument buffer overflow";
#endif
#ifdef EAI_PROTOCOL
case EAI_PROTOCOL: return "resolved protocol is unknown";
#endif
case EAI_SERVICE: return "service not supported for socket type";
case EAI_SOCKTYPE: return "ai_socktype not supported";
#ifdef EAI_SYSTEM
case EAI_SYSTEM: return strerror(errno);
#endif
default: return gai_strerror(err);
}
}

View File

@ -1,28 +1,38 @@
#ifndef WSOCKET_H
#define WSOCKET_H
/*=========================================================================*\
* LuaSocket 2.0.2
* Copyright (C) 2004-2007 Diego Nehab
*
* Socket compatibilization module for Win32
*
* RCS ID: $Id: wsocket.h 2 2006-04-30 19:30:47Z brunoos $
* LuaSocket toolkit
\*=========================================================================*/
/*=========================================================================*\
* WinSock include files
\*=========================================================================*/
#include <winsock.h>
#include <winsock2.h>
#include <ws2tcpip.h>
typedef int socklen_t;
typedef SOCKADDR_STORAGE t_sockaddr_storage;
typedef SOCKET t_socket;
typedef t_socket *p_socket;
#define WAITFD_R 1
#define WAITFD_W 2
#define WAITFD_E 4
#define WAITFD_C (WAITFD_E|WAITFD_W)
#ifndef IPV6_V6ONLY
#define IPV6_V6ONLY 27
#endif
#define SOCKET_INVALID (INVALID_SOCKET)
typedef int socklen_t;
typedef SOCKET t_socket;
typedef t_socket *p_socket;
#ifndef SO_REUSEPORT
#define SO_REUSEPORT SO_REUSEADDR
#endif
#ifndef AI_NUMERICSERV
#define AI_NUMERICSERV (0)
#endif
#endif /* WSOCKET_H */

131
src/options.h Normal file
View File

@ -0,0 +1,131 @@
#ifndef LSEC_OPTIONS_H
#define LSEC_OPTIONS_H
/*--------------------------------------------------------------------------
* LuaSec 0.5.1
* Copyright (C) 2006-2015 Bruno Silvestre
*
*--------------------------------------------------------------------------*/
#include <openssl/ssl.h>
/* If you need to generate these options again, see options.lua */
/*
OpenSSL version: OpenSSL 1.0.1e 2013-06-12
*/
struct ssl_option_s {
const char *name;
unsigned long code;
};
typedef struct ssl_option_s ssl_option_t;
static ssl_option_t ssl_options[] = {
#if defined(SSL_OP_ALL)
{"all", SSL_OP_ALL},
#endif
#if defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)
{"allow_unsafe_legacy_renegotiation", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION},
#endif
#if defined(SSL_OP_CIPHER_SERVER_PREFERENCE)
{"cipher_server_preference", SSL_OP_CIPHER_SERVER_PREFERENCE},
#endif
#if defined(SSL_OP_CISCO_ANYCONNECT)
{"cisco_anyconnect", SSL_OP_CISCO_ANYCONNECT},
#endif
#if defined(SSL_OP_COOKIE_EXCHANGE)
{"cookie_exchange", SSL_OP_COOKIE_EXCHANGE},
#endif
#if defined(SSL_OP_CRYPTOPRO_TLSEXT_BUG)
{"cryptopro_tlsext_bug", SSL_OP_CRYPTOPRO_TLSEXT_BUG},
#endif
#if defined(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)
{"dont_insert_empty_fragments", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS},
#endif
#if defined(SSL_OP_EPHEMERAL_RSA)
{"ephemeral_rsa", SSL_OP_EPHEMERAL_RSA},
#endif
#if defined(SSL_OP_LEGACY_SERVER_CONNECT)
{"legacy_server_connect", SSL_OP_LEGACY_SERVER_CONNECT},
#endif
#if defined(SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
{"microsoft_big_sslv3_buffer", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER},
#endif
#if defined(SSL_OP_MICROSOFT_SESS_ID_BUG)
{"microsoft_sess_id_bug", SSL_OP_MICROSOFT_SESS_ID_BUG},
#endif
#if defined(SSL_OP_MSIE_SSLV2_RSA_PADDING)
{"msie_sslv2_rsa_padding", SSL_OP_MSIE_SSLV2_RSA_PADDING},
#endif
#if defined(SSL_OP_NETSCAPE_CA_DN_BUG)
{"netscape_ca_dn_bug", SSL_OP_NETSCAPE_CA_DN_BUG},
#endif
#if defined(SSL_OP_NETSCAPE_CHALLENGE_BUG)
{"netscape_challenge_bug", SSL_OP_NETSCAPE_CHALLENGE_BUG},
#endif
#if defined(SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG)
{"netscape_demo_cipher_change_bug", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG},
#endif
#if defined(SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG)
{"netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG},
#endif
#if defined(SSL_OP_NO_COMPRESSION)
{"no_compression", SSL_OP_NO_COMPRESSION},
#endif
#if defined(SSL_OP_NO_QUERY_MTU)
{"no_query_mtu", SSL_OP_NO_QUERY_MTU},
#endif
#if defined(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)
{"no_session_resumption_on_renegotiation", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION},
#endif
#if defined(SSL_OP_NO_SSLv2)
{"no_sslv2", SSL_OP_NO_SSLv2},
#endif
#if defined(SSL_OP_NO_SSLv3)
{"no_sslv3", SSL_OP_NO_SSLv3},
#endif
#if defined(SSL_OP_NO_TICKET)
{"no_ticket", SSL_OP_NO_TICKET},
#endif
#if defined(SSL_OP_NO_TLSv1)
{"no_tlsv1", SSL_OP_NO_TLSv1},
#endif
#if defined(SSL_OP_NO_TLSv1_1)
{"no_tlsv1_1", SSL_OP_NO_TLSv1_1},
#endif
#if defined(SSL_OP_NO_TLSv1_2)
{"no_tlsv1_2", SSL_OP_NO_TLSv1_2},
#endif
#if defined(SSL_OP_PKCS1_CHECK_1)
{"pkcs1_check_1", SSL_OP_PKCS1_CHECK_1},
#endif
#if defined(SSL_OP_PKCS1_CHECK_2)
{"pkcs1_check_2", SSL_OP_PKCS1_CHECK_2},
#endif
#if defined(SSL_OP_SINGLE_DH_USE)
{"single_dh_use", SSL_OP_SINGLE_DH_USE},
#endif
#if defined(SSL_OP_SINGLE_ECDH_USE)
{"single_ecdh_use", SSL_OP_SINGLE_ECDH_USE},
#endif
#if defined(SSL_OP_SSLEAY_080_CLIENT_DH_BUG)
{"ssleay_080_client_dh_bug", SSL_OP_SSLEAY_080_CLIENT_DH_BUG},
#endif
#if defined(SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG)
{"sslref2_reuse_cert_type_bug", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG},
#endif
#if defined(SSL_OP_TLS_BLOCK_PADDING_BUG)
{"tls_block_padding_bug", SSL_OP_TLS_BLOCK_PADDING_BUG},
#endif
#if defined(SSL_OP_TLS_D5_BUG)
{"tls_d5_bug", SSL_OP_TLS_D5_BUG},
#endif
#if defined(SSL_OP_TLS_ROLLBACK_BUG)
{"tls_rollback_bug", SSL_OP_TLS_ROLLBACK_BUG},
#endif
{NULL, 0L}
};
#endif

93
src/options.lua Normal file
View File

@ -0,0 +1,93 @@
local function usage()
print("Usage:")
print("* Generate options of your system:")
print(" lua options.lua -g /path/to/ssl.h [verion] > options.h")
print("* Examples:")
print(" lua options.lua -g /usr/include/openssl/ssl.h > options.h\n")
print(" lua options.lua -g /usr/include/openssl/ssl.h \"OpenSSL 1.0.1 14\" > options.h\n")
print("* List options of your system:")
print(" lua options.lua -l /path/to/ssl.h\n")
end
--
local function printf(str, ...)
print(string.format(str, ...))
end
local function generate(options, version)
print([[
#ifndef LSEC_OPTIONS_H
#define LSEC_OPTIONS_H
/*--------------------------------------------------------------------------
* LuaSec 0.5.1
* Copyright (C) 2006-2015 Bruno Silvestre
*
*--------------------------------------------------------------------------*/
#include <openssl/ssl.h>
/* If you need to generate these options again, see options.lua */
]])
printf([[
/*
OpenSSL version: %s
*/
]], version)
print([[
struct ssl_option_s {
const char *name;
unsigned long code;
};
typedef struct ssl_option_s ssl_option_t;
]])
print([[static ssl_option_t ssl_options[] = {]])
for k, option in ipairs(options) do
local name = string.lower(string.sub(option, 8))
print(string.format([[#if defined(%s)]], option))
print(string.format([[ {"%s", %s},]], name, option))
print([[#endif]])
end
print([[ {NULL, 0L}]])
print([[
};
#endif
]])
end
local function loadoptions(file)
local options = {}
local f = assert(io.open(file, "r"))
for line in f:lines() do
local op = string.match(line, "define%s+(SSL_OP_%S+)")
if op then
table.insert(options, op)
end
end
table.sort(options, function(a,b) return a<b end)
return options
end
--
local options
local flag, file, version = ...
version = version or "Unknown"
if not file then
usage()
elseif flag == "-g" then
options = loadoptions(file)
generate(options, version)
elseif flag == "-l" then
options = loadoptions(file)
for k, option in ipairs(options) do
print(option)
end
else
usage()
end

548
src/ssl.c
View File

@ -1,30 +1,53 @@
/*--------------------------------------------------------------------------
* LuaSec 0.3.2
* Copyright (C) 2006-2009 Bruno Silvestre
* LuaSec 0.5.1
*
* Copyright (C) 2014-2015 Kim Alvefur, Paul Aurich, Tobias Markmann,
* Matthew Wild.
* Copyright (C) 2006-2014 Bruno Silvestre.
*
*--------------------------------------------------------------------------*/
#include <errno.h>
#include <string.h>
#if defined(WIN32)
#include <Winsock2.h>
#endif
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#include <openssl/x509_vfy.h>
#include <openssl/err.h>
#include <lua.h>
#include <lauxlib.h>
#include "io.h"
#include "buffer.h"
#include "timeout.h"
#include "socket.h"
#include "context.h"
#include <luasocket/io.h>
#include <luasocket/buffer.h>
#include <luasocket/timeout.h>
#include <luasocket/socket.h>
#include "x509.h"
#include "ssl.h"
/**
* Underline socket error.
*/
static int lsec_socket_error()
{
#if defined(WIN32)
return WSAGetLastError();
#else
return errno;
#endif
}
/**
* Map error code into string.
*/
static const char *ssl_ioerror(void *ctx, int err)
{
if (err == IO_SSL) {
if (err == LSEC_IO_SSL) {
p_ssl ssl = (p_ssl) ctx;
switch(ssl->error) {
case SSL_ERROR_NONE: return "No error";
@ -47,11 +70,22 @@ static const char *ssl_ioerror(void *ctx, int err)
*/
static int meth_destroy(lua_State *L)
{
p_ssl ssl = (p_ssl) lua_touserdata(L, 1);
if (ssl->ssl) {
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
if (ssl->state == LSEC_STATE_CONNECTED) {
socket_setblocking(&ssl->sock);
SSL_shutdown(ssl->ssl);
}
if (ssl->sock != SOCKET_INVALID) {
socket_destroy(&ssl->sock);
}
ssl->state = LSEC_STATE_CLOSED;
if (ssl->ssl) {
/* Clear the registry */
luaL_getmetatable(L, "SSL:Verify:Registry");
lua_pushlightuserdata(L, (void*)ssl->ssl);
lua_pushnil(L);
lua_settable(L, -3);
/* Destroy the object */
SSL_free(ssl->ssl);
ssl->ssl = NULL;
}
@ -63,36 +97,38 @@ static int meth_destroy(lua_State *L)
*/
static int handshake(p_ssl ssl)
{
int err;
p_timeout tm = timeout_markstart(&ssl->tm);
if (ssl->state == ST_SSL_CLOSED)
if (ssl->state == LSEC_STATE_CLOSED)
return IO_CLOSED;
for ( ; ; ) {
int err = SSL_do_handshake(ssl->ssl);
ERR_clear_error();
err = SSL_do_handshake(ssl->ssl);
ssl->error = SSL_get_error(ssl->ssl, err);
switch(ssl->error) {
switch (ssl->error) {
case SSL_ERROR_NONE:
ssl->state = ST_SSL_CONNECTED;
ssl->state = LSEC_STATE_CONNECTED;
return IO_DONE;
case SSL_ERROR_WANT_READ:
err = socket_waitfd(&ssl->sock, WAITFD_R, tm);
if (err == IO_TIMEOUT) return IO_SSL;
if (err == IO_TIMEOUT) return LSEC_IO_SSL;
if (err != IO_DONE) return err;
break;
case SSL_ERROR_WANT_WRITE:
err = socket_waitfd(&ssl->sock, WAITFD_W, tm);
if (err == IO_TIMEOUT) return IO_SSL;
if (err == IO_TIMEOUT) return LSEC_IO_SSL;
if (err != IO_DONE) return err;
break;
case SSL_ERROR_SYSCALL:
if (ERR_peek_error()) {
ssl->error = SSL_ERROR_SSL;
return IO_SSL;
return LSEC_IO_SSL;
}
if (err == 0)
return IO_CLOSED;
return socket_error();
return lsec_socket_error();
default:
return IO_SSL;
return LSEC_IO_SSL;
}
}
return IO_UNKNOWN;
@ -104,37 +140,39 @@ static int handshake(p_ssl ssl)
static int ssl_send(void *ctx, const char *data, size_t count, size_t *sent,
p_timeout tm)
{
p_ssl ssl = (p_ssl) ctx;
if (ssl->state == ST_SSL_CLOSED)
int err;
p_ssl ssl = (p_ssl)ctx;
if (ssl->state != LSEC_STATE_CONNECTED)
return IO_CLOSED;
*sent = 0;
for ( ; ; ) {
int err = SSL_write(ssl->ssl, data, (int) count);
ERR_clear_error();
err = SSL_write(ssl->ssl, data, (int)count);
ssl->error = SSL_get_error(ssl->ssl, err);
switch(ssl->error) {
switch (ssl->error) {
case SSL_ERROR_NONE:
*sent = err;
return IO_DONE;
case SSL_ERROR_WANT_READ:
err = socket_waitfd(&ssl->sock, WAITFD_R, tm);
if (err == IO_TIMEOUT) return IO_SSL;
if (err == IO_TIMEOUT) return LSEC_IO_SSL;
if (err != IO_DONE) return err;
break;
case SSL_ERROR_WANT_WRITE:
err = socket_waitfd(&ssl->sock, WAITFD_W, tm);
if (err == IO_TIMEOUT) return IO_SSL;
if (err == IO_TIMEOUT) return LSEC_IO_SSL;
if (err != IO_DONE) return err;
break;
case SSL_ERROR_SYSCALL:
if (ERR_peek_error()) {
ssl->error = SSL_ERROR_SSL;
return IO_SSL;
return LSEC_IO_SSL;
}
if (err == 0)
return IO_CLOSED;
return socket_error();
return lsec_socket_error();
default:
return IO_SSL;
return LSEC_IO_SSL;
}
}
return IO_UNKNOWN;
@ -146,14 +184,16 @@ static int ssl_send(void *ctx, const char *data, size_t count, size_t *sent,
static int ssl_recv(void *ctx, char *data, size_t count, size_t *got,
p_timeout tm)
{
p_ssl ssl = (p_ssl) ctx;
if (ssl->state == ST_SSL_CLOSED)
int err;
p_ssl ssl = (p_ssl)ctx;
if (ssl->state != LSEC_STATE_CONNECTED)
return IO_CLOSED;
*got = 0;
for ( ; ; ) {
int err = SSL_read(ssl->ssl, data, (int) count);
ERR_clear_error();
err = SSL_read(ssl->ssl, data, (int)count);
ssl->error = SSL_get_error(ssl->ssl, err);
switch(ssl->error) {
switch (ssl->error) {
case SSL_ERROR_NONE:
*got = err;
return IO_DONE;
@ -162,24 +202,24 @@ static int ssl_recv(void *ctx, char *data, size_t count, size_t *got,
return IO_CLOSED;
case SSL_ERROR_WANT_READ:
err = socket_waitfd(&ssl->sock, WAITFD_R, tm);
if (err == IO_TIMEOUT) return IO_SSL;
if (err == IO_TIMEOUT) return LSEC_IO_SSL;
if (err != IO_DONE) return err;
break;
case SSL_ERROR_WANT_WRITE:
err = socket_waitfd(&ssl->sock, WAITFD_W, tm);
if (err == IO_TIMEOUT) return IO_SSL;
if (err == IO_TIMEOUT) return LSEC_IO_SSL;
if (err != IO_DONE) return err;
break;
case SSL_ERROR_SYSCALL:
if (ERR_peek_error()) {
ssl->error = SSL_ERROR_SSL;
return IO_SSL;
return LSEC_IO_SSL;
}
if (err == 0)
return IO_CLOSED;
return socket_error();
return lsec_socket_error();
default:
return IO_SSL;
return LSEC_IO_SSL;
}
}
return IO_UNKNOWN;
@ -191,15 +231,15 @@ static int ssl_recv(void *ctx, char *data, size_t count, size_t *got,
static int meth_create(lua_State *L)
{
p_ssl ssl;
int mode = ctx_getmode(L, 1);
SSL_CTX *ctx = ctx_getcontext(L, 1);
int mode = lsec_getmode(L, 1);
SSL_CTX *ctx = lsec_checkcontext(L, 1);
if (mode == MD_CTX_INVALID) {
if (mode == LSEC_MODE_INVALID) {
lua_pushnil(L);
lua_pushstring(L, "invalid mode");
return 2;
}
ssl = (p_ssl) lua_newuserdata(L, sizeof(t_ssl));
ssl = (p_ssl)lua_newuserdata(L, sizeof(t_ssl));
if (!ssl) {
lua_pushnil(L);
lua_pushstring(L, "error creating SSL object");
@ -208,19 +248,23 @@ static int meth_create(lua_State *L)
ssl->ssl = SSL_new(ctx);
if (!ssl->ssl) {
lua_pushnil(L);
lua_pushstring(L, "error creating SSL object");
return 2;;
lua_pushfstring(L, "error creating SSL object (%s)",
ERR_reason_error_string(ERR_get_error()));
return 2;
}
ssl->state = ST_SSL_NEW;
SSL_set_fd(ssl->ssl, (int) SOCKET_INVALID);
ssl->state = LSEC_STATE_NEW;
SSL_set_fd(ssl->ssl, (int)SOCKET_INVALID);
SSL_set_mode(ssl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE |
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
if (mode == MD_CTX_SERVER)
#if defined(SSL_MODE_RELEASE_BUFFERS)
SSL_set_mode(ssl->ssl, SSL_MODE_RELEASE_BUFFERS);
#endif
if (mode == LSEC_MODE_SERVER)
SSL_set_accept_state(ssl->ssl);
else
SSL_set_connect_state(ssl->ssl);
io_init(&ssl->io, (p_send) ssl_send, (p_recv) ssl_recv,
io_init(&ssl->io, (p_send)ssl_send, (p_recv)ssl_recv,
(p_error) ssl_ioerror, ssl);
timeout_init(&ssl->tm, -1, -1);
buffer_init(&ssl->buf, &ssl->io, &ssl->tm);
@ -234,7 +278,7 @@ static int meth_create(lua_State *L)
* Buffer send function
*/
static int meth_send(lua_State *L) {
p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection");
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
return buffer_meth_send(L, &ssl->buf);
}
@ -242,28 +286,44 @@ static int meth_send(lua_State *L) {
* Buffer receive function
*/
static int meth_receive(lua_State *L) {
p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection");
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
return buffer_meth_receive(L, &ssl->buf);
}
/**
* Get the buffer's statistics.
*/
static int meth_getstats(lua_State *L) {
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
return buffer_meth_getstats(L, &ssl->buf);
}
/**
* Set the buffer's statistics.
*/
static int meth_setstats(lua_State *L) {
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
return buffer_meth_setstats(L, &ssl->buf);
}
/**
* Select support methods
*/
static int meth_getfd(lua_State *L)
{
p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection");
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
lua_pushnumber(L, ssl->sock);
return 1;
}
/**
* Set the TLS/SSL file descriptor.
* This is done *before* the handshake.
* Call it *before* the handshake.
*/
static int meth_setfd(lua_State *L)
{
p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection");
if (ssl->state != ST_SSL_NEW)
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
if (ssl->state != LSEC_STATE_NEW)
luaL_argerror(L, 1, "invalid SSL object state");
ssl->sock = luaL_checkint(L, 2);
socket_setnonblocking(&ssl->sock);
@ -276,7 +336,7 @@ static int meth_setfd(lua_State *L)
*/
static int meth_handshake(lua_State *L)
{
p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection");
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
int err = handshake(ssl);
if (err == IO_DONE) {
lua_pushboolean(L, 1);
@ -292,9 +352,7 @@ static int meth_handshake(lua_State *L)
*/
static int meth_close(lua_State *L)
{
p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection");
meth_destroy(L);
ssl->state = ST_SSL_CLOSED;
return 0;
}
@ -303,7 +361,7 @@ static int meth_close(lua_State *L)
*/
static int meth_settimeout(lua_State *L)
{
p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection");
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
return timeout_meth_settimeout(L, &ssl->tm);
}
@ -313,8 +371,8 @@ static int meth_settimeout(lua_State *L)
static int meth_dirty(lua_State *L)
{
int res = 0;
p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection");
if (ssl->state != ST_SSL_CLOSED)
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
if (ssl->state != LSEC_STATE_CLOSED)
res = !buffer_isempty(&ssl->buf) || SSL_pending(ssl->ssl);
lua_pushboolean(L, res);
return 1;
@ -325,8 +383,10 @@ static int meth_dirty(lua_State *L)
*/
static int meth_want(lua_State *L)
{
p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection");
int code = (ssl->state == ST_SSL_CLOSED) ? SSL_NOTHING : SSL_want(ssl->ssl);
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
int code = (ssl->state == LSEC_STATE_CLOSED)
? SSL_NOTHING
: SSL_want(ssl->ssl);
switch(code) {
case SSL_NOTHING: lua_pushstring(L, "nothing"); break;
case SSL_READING: lua_pushstring(L, "read"); break;
@ -337,65 +397,344 @@ static int meth_want(lua_State *L)
}
/**
* Return a pointer to SSL structure.
* Return the compression method used.
*/
static int meth_rawconn(lua_State *L)
static int meth_compression(lua_State *L)
{
const COMP_METHOD *comp;
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
if (ssl->state != LSEC_STATE_CONNECTED) {
lua_pushnil(L);
lua_pushstring(L, "closed");
return 2;
}
comp = SSL_get_current_compression(ssl->ssl);
if (comp)
lua_pushstring(L, SSL_COMP_get_name(comp));
else
lua_pushnil(L);
return 1;
}
/**
* Return the nth certificate of the peer's chain.
*/
static int meth_getpeercertificate(lua_State *L)
{
int n;
X509 *cert;
STACK_OF(X509) *certs;
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
if (ssl->state != LSEC_STATE_CONNECTED) {
lua_pushnil(L);
lua_pushstring(L, "closed");
return 2;
}
/* Default to the first cert */
n = luaL_optint(L, 2, 1);
/* This function is 1-based, but OpenSSL is 0-based */
--n;
if (n < 0) {
lua_pushnil(L);
lua_pushliteral(L, "invalid certificate index");
return 2;
}
if (n == 0) {
cert = SSL_get_peer_certificate(ssl->ssl);
if (cert)
lsec_pushx509(L, cert);
else
lua_pushnil(L);
return 1;
}
/* In a server-context, the stack doesn't contain the peer cert,
* so adjust accordingly.
*/
if (ssl->ssl->server)
--n;
certs = SSL_get_peer_cert_chain(ssl->ssl);
if (n >= sk_X509_num(certs)) {
lua_pushnil(L);
return 1;
}
cert = sk_X509_value(certs, n);
/* Increment the reference counting of the object. */
/* See SSL_get_peer_certificate() source code. */
CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
lsec_pushx509(L, cert);
return 1;
}
/**
* Return the chain of certificate of the peer.
*/
static int meth_getpeerchain(lua_State *L)
{
int i;
int idx = 1;
int n_certs;
X509 *cert;
STACK_OF(X509) *certs;
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
if (ssl->state != LSEC_STATE_CONNECTED) {
lua_pushnil(L);
lua_pushstring(L, "closed");
return 2;
}
lua_newtable(L);
if (ssl->ssl->server) {
lsec_pushx509(L, SSL_get_peer_certificate(ssl->ssl));
lua_rawseti(L, -2, idx++);
}
certs = SSL_get_peer_cert_chain(ssl->ssl);
n_certs = sk_X509_num(certs);
for (i = 0; i < n_certs; i++) {
cert = sk_X509_value(certs, i);
/* Increment the reference counting of the object. */
/* See SSL_get_peer_certificate() source code. */
CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
lsec_pushx509(L, cert);
lua_rawseti(L, -2, idx++);
}
return 1;
}
/**
* Copy the table src to the table dst.
*/
static void copy_error_table(lua_State *L, int src, int dst)
{
lua_pushnil(L);
while (lua_next(L, src) != 0) {
if (lua_istable(L, -1)) {
/* Replace the table with its copy */
lua_newtable(L);
copy_error_table(L, dst+2, dst+3);
lua_remove(L, dst+2);
}
lua_pushvalue(L, -2);
lua_pushvalue(L, -2);
lua_rawset(L, dst);
/* Remove the value and leave the key */
lua_pop(L, 1);
}
}
/**
* Return the verification state of the peer chain.
*/
static int meth_getpeerverification(lua_State *L)
{
long err;
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
if (ssl->state != LSEC_STATE_CONNECTED) {
lua_pushboolean(L, 0);
lua_pushstring(L, "closed");
return 2;
}
err = SSL_get_verify_result(ssl->ssl);
if (err == X509_V_OK) {
lua_pushboolean(L, 1);
return 1;
}
luaL_getmetatable(L, "SSL:Verify:Registry");
lua_pushlightuserdata(L, (void*)ssl->ssl);
lua_gettable(L, -2);
if (lua_isnil(L, -1))
lua_pushstring(L, X509_verify_cert_error_string(err));
else {
/* Copy the table of errors to avoid modifications */
lua_newtable(L);
copy_error_table(L, lua_gettop(L)-1, lua_gettop(L));
}
lua_pushboolean(L, 0);
lua_pushvalue(L, -2);
return 2;
}
/**
* Get the latest "Finished" message sent out.
*/
static int meth_getfinished(lua_State *L)
{
size_t len = 0;
char *buffer = NULL;
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
if (ssl->state != LSEC_STATE_CONNECTED) {
lua_pushnil(L);
lua_pushstring(L, "closed");
return 2;
}
if ((len = SSL_get_finished(ssl->ssl, NULL, 0)) == 0)
return 0;
buffer = (char*)malloc(len);
if (!buffer) {
lua_pushnil(L);
lua_pushstring(L, "out of memory");
return 2;
}
SSL_get_finished(ssl->ssl, buffer, len);
lua_pushlstring(L, buffer, len);
free(buffer);
return 1;
}
/**
* Gets the latest "Finished" message received.
*/
static int meth_getpeerfinished(lua_State *L)
{
size_t len = 0;
char *buffer = NULL;
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
if (ssl->state != LSEC_STATE_CONNECTED) {
lua_pushnil(L);
lua_pushstring(L, "closed");
return 0;
}
if ((len = SSL_get_peer_finished(ssl->ssl, NULL, 0)) == 0)
return 0;
buffer = (char*)malloc(len);
if (!buffer) {
lua_pushnil(L);
lua_pushstring(L, "out of memory");
return 2;
}
SSL_get_peer_finished(ssl->ssl, buffer, len);
lua_pushlstring(L, buffer, len);
free(buffer);
return 1;
}
/**
* Object information -- tostring metamethod
*/
static int meth_tostring(lua_State *L)
{
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
lua_pushlightuserdata(L, (void*)ssl->ssl);
lua_pushfstring(L, "SSL connection: %p%s", ssl,
ssl->state == LSEC_STATE_CLOSED ? " (closed)" : "");
return 1;
}
/**
* Add a method in the SSL metatable.
*/
static int meth_setmethod(lua_State *L)
{
luaL_getmetatable(L, "SSL:Connection");
lua_pushstring(L, "__index");
lua_gettable(L, -2);
lua_pushvalue(L, 1);
lua_pushvalue(L, 2);
lua_settable(L, -3);
return 0;
}
/**
* Return information about the connection.
*/
static int meth_info(lua_State *L)
{
int bits = 0;
int algbits = 0;
char buf[256] = {0};
const SSL_CIPHER *cipher;
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
cipher = SSL_get_current_cipher(ssl->ssl);
if (!cipher)
return 0;
SSL_CIPHER_description(cipher, buf, sizeof(buf));
bits = SSL_CIPHER_get_bits(cipher, &algbits);
lua_pushstring(L, buf);
lua_pushnumber(L, bits);
lua_pushnumber(L, algbits);
lua_pushstring(L, SSL_get_version(ssl->ssl));
return 4;
}
static int meth_copyright(lua_State *L)
{
lua_pushstring(L, "LuaSec 0.5.1 - Copyright (C) 2006-2015 Bruno Silvestre"
#if defined(WITH_LUASOCKET)
"\nLuaSocket 3.0-RC1 - Copyright (C) 2004-2013 Diego Nehab"
#endif
);
return 1;
}
/*---------------------------------------------------------------------------*/
/**
* SSL methods
*/
static luaL_Reg methods[] = {
{"close", meth_close},
{"getfd", meth_getfd},
{"getfinished", meth_getfinished},
{"getpeercertificate", meth_getpeercertificate},
{"getpeerchain", meth_getpeerchain},
{"getpeerverification", meth_getpeerverification},
{"getpeerfinished", meth_getpeerfinished},
{"getstats", meth_getstats},
{"setstats", meth_setstats},
{"dirty", meth_dirty},
{"dohandshake", meth_handshake},
{"receive", meth_receive},
{"send", meth_send},
{"settimeout", meth_settimeout},
{"want", meth_want},
{NULL, NULL}
};
/**
* SSL metamethods
* SSL metamethods.
*/
static luaL_Reg meta[] = {
{"close", meth_close},
{"getfd", meth_getfd},
{"dirty", meth_dirty},
{"dohandshake", meth_handshake},
{"receive", meth_receive},
{"send", meth_send},
{"settimeout", meth_settimeout},
{"want", meth_want},
{"__gc", meth_destroy},
{"__tostring", meth_tostring},
{NULL, NULL}
};
/**
* SSL functions.
*/
static luaL_Reg funcs[] = {
{"compression", meth_compression},
{"create", meth_create},
{"info", meth_info},
{"setfd", meth_setfd},
{"setmethod", meth_setmethod},
{"copyright", meth_copyright},
{NULL, NULL}
};
/**
* SSL functions
* Initialize modules.
*/
static luaL_Reg funcs[] = {
{"create", meth_create},
{"setfd", meth_setfd},
{"rawconnection", meth_rawconn},
{NULL, NULL}
};
/**
* Initialize modules
*/
LUASEC_API int luaopen_ssl_core(lua_State *L)
#if (LUA_VERSION_NUM == 501)
LSEC_API int luaopen_ssl_core(lua_State *L)
{
/* Initialize SSL */
if (!SSL_library_init()) {
lua_pushstring(L, "unable to initialize SSL library");
lua_error(L);
}
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
#if defined(WITH_LUASOCKET)
/* Initialize internal library */
socket_open();
#endif
/* Registre the functions and tables */
/* Register the functions and tables */
luaL_newmetatable(L, "SSL:Connection");
lua_newtable(L);
luaL_register(L, NULL, meta);
lua_newtable(L);
luaL_register(L, NULL, methods);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, meth_destroy);
lua_setfield(L, -2, "__gc");
luaL_register(L, "ssl.core", funcs);
lua_pushnumber(L, SOCKET_INVALID);
@ -403,4 +742,35 @@ LUASEC_API int luaopen_ssl_core(lua_State *L)
return 1;
}
#else
LSEC_API int luaopen_ssl_core(lua_State *L)
{
/* Initialize SSL */
if (!SSL_library_init()) {
lua_pushstring(L, "unable to initialize SSL library");
lua_error(L);
}
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
#if defined(WITH_LUASOCKET)
/* Initialize internal library */
socket_open();
#endif
/* Register the functions and tables */
luaL_newmetatable(L, "SSL:Connection");
luaL_setfuncs(L, meta, 0);
lua_newtable(L);
luaL_setfuncs(L, methods, 0);
lua_setfield(L, -2, "__index");
lua_newtable(L);
luaL_setfuncs(L, funcs, 0);
lua_pushnumber(L, SOCKET_INVALID);
lua_setfield(L, -2, "invalidfd");
return 1;
}
#endif

View File

@ -1,26 +1,28 @@
#ifndef __SSL_H__
#define __SSL_H__
#ifndef LSEC_SSL_H
#define LSEC_SSL_H
/*--------------------------------------------------------------------------
* LuaSec 0.3.2
* Copyright (C) 2006-2009 Bruno Silvestre
* LuaSec 0.5.1
* Copyright (C) 2006-2015 Bruno Silvestre
*
*--------------------------------------------------------------------------*/
#include <openssl/ssl.h>
#include <lua.h>
#include "io.h"
#include "buffer.h"
#include "timeout.h"
#include <luasocket/io.h>
#include <luasocket/buffer.h>
#include <luasocket/timeout.h>
#include <luasocket/socket.h>
#ifndef LUASEC_API
#define LUASEC_API extern
#endif
#include "config.h"
#include "context.h"
#define ST_SSL_NEW 1
#define ST_SSL_CONNECTED 2
#define ST_SSL_CLOSED 3
#define LSEC_STATE_NEW 1
#define LSEC_STATE_CONNECTED 2
#define LSEC_STATE_CLOSED 3
#define LSEC_IO_SSL -100
typedef struct t_ssl_ {
t_socket sock;
@ -28,11 +30,11 @@ typedef struct t_ssl_ {
t_buffer buf;
t_timeout tm;
SSL *ssl;
char state;
int state;
int error;
} t_ssl;
typedef t_ssl* p_ssl;
LUASEC_API int luaopen_ssl_core(lua_State *L);
LSEC_API int luaopen_ssl_core(lua_State *L);
#endif

View File

@ -1,22 +1,24 @@
------------------------------------------------------------------------------
-- LuaSec 0.3.2
-- Copyright (C) 2006-2008 Bruno Silvestre
-- LuaSec 0.5.1
-- Copyright (C) 2006-2015 Bruno Silvestre
--
------------------------------------------------------------------------------
local core = require("ssl.core")
local context = require("ssl.context")
local x509 = require("ssl.x509")
module("ssl", package.seeall)
require("ssl.core")
require("ssl.context")
_VERSION = "0.5.1"
_COPYRIGHT = core.copyright()
-- Export
loadcertificate = x509.load
_VERSION = "0.3.2"
_COPYRIGHT = "LuaSec 0.3.2 - Copyright (C) 2006-2009 Bruno Silvestre\n" ..
"LuaSocket 2.0.2 - Copyright (C) 2004-2007 Diego Nehab"
-- Export functions
rawconnection = core.rawconnection
rawcontext = context.rawcontext
-- We must prevent the contexts to be collected before the connections,
-- otherwise the C registry will be cleared.
local registry = setmetatable({}, {__mode="k"})
--
--
@ -45,6 +47,12 @@ function newcontext(cfg)
if not succ then return nil, msg end
-- Load the key
if cfg.key then
if cfg.password and
type(cfg.password) ~= "function" and
type(cfg.password) ~= "string"
then
return nil, "invalid password type"
end
succ, msg = context.loadkey(ctx, cfg.key, cfg.password)
if not succ then return nil, msg end
end
@ -58,6 +66,11 @@ function newcontext(cfg)
succ, msg = context.locations(ctx, cfg.cafile, cfg.capath)
if not succ then return nil, msg end
end
-- Set SSL ciphers
if cfg.ciphers then
succ, msg = context.setcipher(ctx, cfg.ciphers)
if not succ then return nil, msg end
end
-- Set the verification options
succ, msg = optexec(context.setverify, cfg.verify, ctx)
if not succ then return nil, msg end
@ -69,6 +82,29 @@ function newcontext(cfg)
succ, msg = context.setdepth(ctx, cfg.depth)
if not succ then return nil, msg end
end
-- NOTE: Setting DH parameters and elliptic curves needs to come after
-- setoptions(), in case the user has specified the single_{dh,ecdh}_use
-- options.
-- Set DH parameters
if cfg.dhparam then
if type(cfg.dhparam) ~= "function" then
return nil, "invalid DH parameter type"
end
context.setdhparam(ctx, cfg.dhparam)
end
-- Set elliptic curve
if cfg.curve then
succ, msg = context.setcurve(ctx, cfg.curve)
if not succ then return nil, msg end
end
-- Set extra verification options
if cfg.verifyext and ctx.setverifyext then
succ, msg = optexec(ctx.setverifyext, cfg.verifyext, ctx)
if not succ then return nil, msg end
end
return ctx
end
@ -87,7 +123,46 @@ function wrap(sock, cfg)
if s then
core.setfd(s, sock:getfd())
sock:setfd(core.invalidfd)
registry[s] = ctx
return s
end
return nil, msg
end
--
-- Extract connection information.
--
local function info(ssl, field)
local str, comp, err, protocol
comp, err = core.compression(ssl)
if err then
return comp, err
end
-- Avoid parser
if field == "compression" then
return comp
end
local info = {compression = comp}
str, info.bits, info.algbits, protocol = core.info(ssl)
if str then
info.cipher, info.protocol, info.key,
info.authentication, info.encryption, info.mac =
string.match(str,
"^(%S+)%s+(%S+)%s+Kx=(%S+)%s+Au=(%S+)%s+Enc=(%S+)%s+Mac=(%S+)")
info.export = (string.match(str, "%sexport%s*$") ~= nil)
end
if protocol then
info.protocol = protocol
end
if field then
return info[field]
end
-- Empty?
return ( (next(info)) and info )
end
--
-- Set method for SSL connections.
--
core.setmethod("info", info)

View File

@ -1,145 +0,0 @@
/*=========================================================================*\
* LuaSocket 2.0.2
* Copyright (C) 2004-2007 Diego Nehab
*
* Socket compatibilization module for Unix
*
* The code is now interrupt-safe.
* The penalty of calling select to avoid busy-wait is only paid when
* the I/O call fail in the first place.
*
* RCS ID: $Id: usocket.c,v 1.38 2007/10/13 23:55:20 diego Exp $
\*=========================================================================*/
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include "socket.h"
#include "usocket.h"
/*-------------------------------------------------------------------------*\
* Wait for readable/writable/connected socket with timeout
\*-------------------------------------------------------------------------*/
#ifdef SOCKET_POLL
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
int ret;
struct pollfd pfd;
pfd.fd = *ps;
pfd.events = sw;
pfd.revents = 0;
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
do {
int t = (int)(timeout_getretry(tm)*1e3);
ret = poll(&pfd, 1, t >= 0? t: -1);
} while (ret == -1 && errno == EINTR);
if (ret == -1) return errno;
if (ret == 0) return IO_TIMEOUT;
if (sw == WAITFD_C && (pfd.revents & (POLLIN|POLLERR))) return IO_CLOSED;
return IO_DONE;
}
#else
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
int ret;
fd_set rfds, wfds, *rp, *wp;
struct timeval tv, *tp;
double t;
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
do {
/* must set bits within loop, because select may have modifed them */
rp = wp = NULL;
if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(*ps, &rfds); rp = &rfds; }
if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
t = timeout_getretry(tm);
tp = NULL;
if (t >= 0.0) {
tv.tv_sec = (int)t;
tv.tv_usec = (int)((t-tv.tv_sec)*1.0e6);
tp = &tv;
}
ret = select(*ps+1, rp, wp, NULL, tp);
} while (ret == -1 && errno == EINTR);
if (ret == -1) return errno;
if (ret == 0) return IO_TIMEOUT;
if (sw == WAITFD_C && FD_ISSET(*ps, &rfds)) return IO_CLOSED;
return IO_DONE;
}
#endif
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int socket_open(void) {
/* instals a handler to ignore sigpipe or it will crash us */
signal(SIGPIPE, SIG_IGN);
return 1;
}
/*-------------------------------------------------------------------------*\
* Close module
\*-------------------------------------------------------------------------*/
int socket_close(void) {
return 1;
}
/*-------------------------------------------------------------------------*\
* Close and inutilize socket
\*-------------------------------------------------------------------------*/
void socket_destroy(p_socket ps) {
if (*ps != SOCKET_INVALID) {
socket_setblocking(ps);
close(*ps);
*ps = SOCKET_INVALID;
}
}
/*-------------------------------------------------------------------------*\
* Put socket into blocking mode
\*-------------------------------------------------------------------------*/
void socket_setblocking(p_socket ps) {
int flags = fcntl(*ps, F_GETFL, 0);
flags &= (~(O_NONBLOCK));
fcntl(*ps, F_SETFL, flags);
}
/*-------------------------------------------------------------------------*\
* Put socket into non-blocking mode
\*-------------------------------------------------------------------------*/
void socket_setnonblocking(p_socket ps) {
int flags = fcntl(*ps, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(*ps, F_SETFL, flags);
}
/*-------------------------------------------------------------------------*\
* Error translation functions
* Make sure important error messages are standard
\*-------------------------------------------------------------------------*/
const char *socket_strerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case EADDRINUSE: return "address already in use";
case EISCONN: return "already connected";
case EACCES: return "permission denied";
case ECONNREFUSED: return "connection refused";
case ECONNABORTED: return "closed";
case ECONNRESET: return "closed";
case EPIPE: return "closed";
case ETIMEDOUT: return "timeout";
default: return strerror(errno);
}
}
/*-------------------------------------------------------------------------*\
* Underline error code.
\*-------------------------------------------------------------------------*/
int socket_error()
{
return errno;
}

View File

@ -1,28 +0,0 @@
#ifndef USOCKET_H
#define USOCKET_H
/*=========================================================================*\
* LuaSocket 2.0.2
* Copyright (C) 2004-2007 Diego Nehab
*
* Socket compatibilization module for Unix
*
* RCS ID: $Id: usocket.h 6 2006-04-30 20:33:05Z brunoos $
\*=========================================================================*/
#ifdef SOCKET_POLL
#include <sys/poll.h>
#define WAITFD_R POLLIN
#define WAITFD_W POLLOUT
#define WAITFD_C (POLLIN|POLLOUT)
#else
#define WAITFD_R 1
#define WAITFD_W 2
#define WAITFD_C (WAITFD_R|WAITFD_W)
#endif
typedef int t_socket;
typedef t_socket *p_socket;
#define SOCKET_INVALID (-1)
#endif /* USOCKET_H */

View File

@ -1,169 +0,0 @@
/*=========================================================================*\
* LuaSocket 2.0.2
* Copyright (C) 2004-2007 Diego Nehab
*
* Socket compatibilization module for Win32
*
* The penalty of calling select to avoid busy-wait is only paid when
* the I/O call fail in the first place.
*
* RCS ID: $Id: wsocket.c,v 1.36 2007/06/11 23:44:54 diego Exp $
\*=========================================================================*/
#include <string.h>
#include "socket.h"
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int socket_open(void) {
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 0);
int err = WSAStartup(wVersionRequested, &wsaData );
if (err != 0) return 0;
if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) &&
(LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) {
WSACleanup();
return 0;
}
return 1;
}
/*-------------------------------------------------------------------------*\
* Close module
\*-------------------------------------------------------------------------*/
int socket_close(void) {
WSACleanup();
return 1;
}
/*-------------------------------------------------------------------------*\
* Wait for readable/writable/connected socket with timeout
\*-------------------------------------------------------------------------*/
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
int ret;
fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL;
struct timeval tv, *tp = NULL;
double t;
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
if (sw & WAITFD_R) {
FD_ZERO(&rfds);
FD_SET(*ps, &rfds);
rp = &rfds;
}
if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; }
if ((t = timeout_get(tm)) >= 0.0) {
tv.tv_sec = (int) t;
tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6);
tp = &tv;
}
ret = select(0, rp, wp, ep, tp);
if (ret == -1) return WSAGetLastError();
if (ret == 0) return IO_TIMEOUT;
if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED;
return IO_DONE;
}
/*-------------------------------------------------------------------------*\
* Close and inutilize socket
\*-------------------------------------------------------------------------*/
void socket_destroy(p_socket ps) {
if (*ps != SOCKET_INVALID) {
socket_setblocking(ps); /* close can take a long time on WIN32 */
closesocket(*ps);
*ps = SOCKET_INVALID;
}
}
/*-------------------------------------------------------------------------*\
* Put socket into blocking mode
\*-------------------------------------------------------------------------*/
void socket_setblocking(p_socket ps) {
u_long argp = 0;
ioctlsocket(*ps, FIONBIO, &argp);
}
/*-------------------------------------------------------------------------*\
* Put socket into non-blocking mode
\*-------------------------------------------------------------------------*/
void socket_setnonblocking(p_socket ps) {
u_long argp = 1;
ioctlsocket(*ps, FIONBIO, &argp);
}
/*-------------------------------------------------------------------------*\
* Error translation functions
\*-------------------------------------------------------------------------*/
/* WinSock doesn't have a strerror... */
static const char *wstrerror(int err) {
switch (err) {
case WSAEINTR: return "Interrupted function call";
case WSAEACCES: return "Permission denied";
case WSAEFAULT: return "Bad address";
case WSAEINVAL: return "Invalid argument";
case WSAEMFILE: return "Too many open files";
case WSAEWOULDBLOCK: return "Resource temporarily unavailable";
case WSAEINPROGRESS: return "Operation now in progress";
case WSAEALREADY: return "Operation already in progress";
case WSAENOTSOCK: return "Socket operation on nonsocket";
case WSAEDESTADDRREQ: return "Destination address required";
case WSAEMSGSIZE: return "Message too long";
case WSAEPROTOTYPE: return "Protocol wrong type for socket";
case WSAENOPROTOOPT: return "Bad protocol option";
case WSAEPROTONOSUPPORT: return "Protocol not supported";
case WSAESOCKTNOSUPPORT: return "Socket type not supported";
case WSAEOPNOTSUPP: return "Operation not supported";
case WSAEPFNOSUPPORT: return "Protocol family not supported";
case WSAEAFNOSUPPORT:
return "Address family not supported by protocol family";
case WSAEADDRINUSE: return "Address already in use";
case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
case WSAENETDOWN: return "Network is down";
case WSAENETUNREACH: return "Network is unreachable";
case WSAENETRESET: return "Network dropped connection on reset";
case WSAECONNABORTED: return "Software caused connection abort";
case WSAECONNRESET: return "Connection reset by peer";
case WSAENOBUFS: return "No buffer space available";
case WSAEISCONN: return "Socket is already connected";
case WSAENOTCONN: return "Socket is not connected";
case WSAESHUTDOWN: return "Cannot send after socket shutdown";
case WSAETIMEDOUT: return "Connection timed out";
case WSAECONNREFUSED: return "Connection refused";
case WSAEHOSTDOWN: return "Host is down";
case WSAEHOSTUNREACH: return "No route to host";
case WSAEPROCLIM: return "Too many processes";
case WSASYSNOTREADY: return "Network subsystem is unavailable";
case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range";
case WSANOTINITIALISED:
return "Successful WSAStartup not yet performed";
case WSAEDISCON: return "Graceful shutdown in progress";
case WSAHOST_NOT_FOUND: return "Host not found";
case WSATRY_AGAIN: return "Nonauthoritative host not found";
case WSANO_RECOVERY: return "Nonrecoverable name lookup error";
case WSANO_DATA: return "Valid name, no data record of requested type";
default: return "Unknown error";
}
}
const char *socket_strerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case WSAEADDRINUSE: return "address already in use";
case WSAECONNREFUSED: return "connection refused";
case WSAEISCONN: return "already connected";
case WSAEACCES: return "permission denied";
case WSAECONNABORTED: return "closed";
case WSAECONNRESET: return "closed";
case WSAETIMEDOUT: return "timeout";
default: return wstrerror(err);
}
}
/* Socket error code */
int socket_error()
{
return WSAGetLastError();
}

527
src/x509.c Normal file
View File

@ -0,0 +1,527 @@
/*--------------------------------------------------------------------------
* LuaSec 0.5.1
*
* Copyright (C) 2014-2015 Kim Alvefur, Paul Aurich, Tobias Markmann
* Matthew Wild, Bruno Silvestre.
*
*--------------------------------------------------------------------------*/
#include <string.h>
#if defined(WIN32)
#include <windows.h>
#endif
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <lua.h>
#include <lauxlib.h>
#include "x509.h"
static const char* hex_tab = "0123456789abcdef";
/**
* Push the certificate on the stack.
*/
void lsec_pushx509(lua_State* L, X509 *cert)
{
p_x509 cert_obj = (p_x509)lua_newuserdata(L, sizeof(t_x509));
cert_obj->cert = cert;
cert_obj->encode = LSEC_AI5_STRING;
luaL_getmetatable(L, "SSL:Certificate");
lua_setmetatable(L, -2);
}
/**
* Return the OpenSSL certificate X509.
*/
X509* lsec_checkx509(lua_State* L, int idx)
{
return ((p_x509)luaL_checkudata(L, idx, "SSL:Certificate"))->cert;
}
/**
* Return LuaSec certificate X509 representation.
*/
p_x509 lsec_checkp_x509(lua_State* L, int idx)
{
return (p_x509)luaL_checkudata(L, idx, "SSL:Certificate");
}
/*---------------------------------------------------------------------------*/
/**
* Convert the buffer 'in' to hexadecimal.
*/
static void to_hex(const char* in, int length, char* out)
{
int i;
for (i = 0; i < length; i++) {
out[i*2] = hex_tab[(in[i] >> 4) & 0xF];
out[i*2+1] = hex_tab[(in[i]) & 0xF];
}
}
/**
* Converts the ASN1_OBJECT into a textual representation and put it
* on the Lua stack.
*/
static void push_asn1_objname(lua_State* L, ASN1_OBJECT *object, int no_name)
{
char buffer[256];
int len = OBJ_obj2txt(buffer, sizeof(buffer), object, no_name);
len = (len < sizeof(buffer)) ? len : sizeof(buffer);
lua_pushlstring(L, buffer, len);
}
/**
* Push the ASN1 string on the stack.
*/
static void push_asn1_string(lua_State* L, ASN1_STRING *string, int encode)
{
int len;
unsigned char *data;
if (!string) {
lua_pushnil(L);
return;
}
switch (encode) {
case LSEC_AI5_STRING:
lua_pushlstring(L, (char*)ASN1_STRING_data(string),
ASN1_STRING_length(string));
break;
case LSEC_UTF8_STRING:
len = ASN1_STRING_to_UTF8(&data, string);
if (len >= 0) {
lua_pushlstring(L, (char*)data, len);
OPENSSL_free(data);
}
else
lua_pushnil(L);
}
}
/**
* Return a human readable time.
*/
static int push_asn1_time(lua_State *L, ASN1_UTCTIME *tm)
{
char *tmp;
long size;
BIO *out = BIO_new(BIO_s_mem());
ASN1_TIME_print(out, tm);
size = BIO_get_mem_data(out, &tmp);
lua_pushlstring(L, tmp, size);
BIO_free(out);
return 1;
}
/**
*
*/
static int push_subtable(lua_State* L, int idx)
{
lua_pushvalue(L, -1);
lua_gettable(L, idx-1);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -2);
lua_pushvalue(L, -2);
lua_settable(L, idx-3);
lua_replace(L, -2); /* Replace key with table */
return 1;
}
lua_replace(L, -2); /* Replace key with table */
return 0;
}
/**
* Retrive the general names from the object.
*/
static int push_x509_name(lua_State* L, X509_NAME *name, int encode)
{
int i;
int n_entries;
ASN1_OBJECT *object;
X509_NAME_ENTRY *entry;
lua_newtable(L);
n_entries = X509_NAME_entry_count(name);
for (i = 0; i < n_entries; i++) {
entry = X509_NAME_get_entry(name, i);
object = X509_NAME_ENTRY_get_object(entry);
lua_newtable(L);
push_asn1_objname(L, object, 1);
lua_setfield(L, -2, "oid");
push_asn1_objname(L, object, 0);
lua_setfield(L, -2, "name");
push_asn1_string(L, X509_NAME_ENTRY_get_data(entry), encode);
lua_setfield(L, -2, "value");
lua_rawseti(L, -2, i+1);
}
return 1;
}
/*---------------------------------------------------------------------------*/
/**
* Retrive the Subject from the certificate.
*/
static int meth_subject(lua_State* L)
{
p_x509 px = lsec_checkp_x509(L, 1);
return push_x509_name(L, X509_get_subject_name(px->cert), px->encode);
}
/**
* Retrive the Issuer from the certificate.
*/
static int meth_issuer(lua_State* L)
{
p_x509 px = lsec_checkp_x509(L, 1);
return push_x509_name(L, X509_get_issuer_name(px->cert), px->encode);
}
/**
* Retrieve the extensions from the certificate.
*/
int meth_extensions(lua_State* L)
{
int j;
int i = -1;
int n_general_names;
OTHERNAME *otherName;
X509_EXTENSION *extension;
GENERAL_NAME *general_name;
STACK_OF(GENERAL_NAME) *values;
p_x509 px = lsec_checkp_x509(L, 1);
X509 *peer = px->cert;
/* Return (ret) */
lua_newtable(L);
while ((i = X509_get_ext_by_NID(peer, NID_subject_alt_name, i)) != -1) {
extension = X509_get_ext(peer, i);
if (extension == NULL)
break;
values = X509V3_EXT_d2i(extension);
if (values == NULL)
break;
/* Push ret[oid] */
push_asn1_objname(L, extension->object, 1);
push_subtable(L, -2);
/* Set ret[oid].name = name */
push_asn1_objname(L, extension->object, 0);
lua_setfield(L, -2, "name");
n_general_names = sk_GENERAL_NAME_num(values);
for (j = 0; j < n_general_names; j++) {
general_name = sk_GENERAL_NAME_value(values, j);
switch (general_name->type) {
case GEN_OTHERNAME:
otherName = general_name->d.otherName;
push_asn1_objname(L, otherName->type_id, 1);
if (push_subtable(L, -2)) {
push_asn1_objname(L, otherName->type_id, 0);
lua_setfield(L, -2, "name");
}
push_asn1_string(L, otherName->value->value.asn1_string, px->encode);
lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
lua_pop(L, 1);
break;
case GEN_DNS:
lua_pushstring(L, "dNSName");
push_subtable(L, -2);
push_asn1_string(L, general_name->d.dNSName, px->encode);
lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
lua_pop(L, 1);
break;
case GEN_EMAIL:
lua_pushstring(L, "rfc822Name");
push_subtable(L, -2);
push_asn1_string(L, general_name->d.rfc822Name, px->encode);
lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
lua_pop(L, 1);
break;
case GEN_URI:
lua_pushstring(L, "uniformResourceIdentifier");
push_subtable(L, -2);
push_asn1_string(L, general_name->d.uniformResourceIdentifier, px->encode);
lua_rawseti(L, -2, lua_rawlen(L, -2)+1);
lua_pop(L, 1);
break;
case GEN_IPADD:
lua_pushstring(L, "iPAddress");
push_subtable(L, -2);
push_asn1_string(L, general_name->d.iPAddress, px->encode);
lua_rawseti(L, -2, lua_rawlen(L, -2)+1);
lua_pop(L, 1);
break;
case GEN_X400:
/* x400Address */
/* not supported */
break;
case GEN_DIRNAME:
/* directoryName */
/* not supported */
break;
case GEN_EDIPARTY:
/* ediPartyName */
/* not supported */
break;
case GEN_RID:
/* registeredID */
/* not supported */
break;
}
}
lua_pop(L, 1); /* ret[oid] */
i++; /* Next extension */
}
return 1;
}
/**
* Convert the certificate to PEM format.
*/
static int meth_pem(lua_State* L)
{
char* data;
long bytes;
X509* cert = lsec_checkx509(L, 1);
BIO *bio = BIO_new(BIO_s_mem());
if (!PEM_write_bio_X509(bio, cert)) {
lua_pushnil(L);
return 1;
}
bytes = BIO_get_mem_data(bio, &data);
if (bytes > 0)
lua_pushlstring(L, data, bytes);
else
lua_pushnil(L);
BIO_free(bio);
return 1;
}
/**
* Compute the fingerprint.
*/
static int meth_digest(lua_State* L)
{
unsigned int bytes;
const EVP_MD *digest = NULL;
unsigned char buffer[EVP_MAX_MD_SIZE];
char hex_buffer[EVP_MAX_MD_SIZE*2];
X509 *cert = lsec_checkx509(L, 1);
const char *str = luaL_optstring(L, 2, NULL);
if (!str)
digest = EVP_sha1();
else {
if (!strcmp(str, "sha1"))
digest = EVP_sha1();
else if (!strcmp(str, "sha256"))
digest = EVP_sha256();
else if (!strcmp(str, "sha512"))
digest = EVP_sha512();
}
if (!digest) {
lua_pushnil(L);
lua_pushfstring(L, "digest algorithm not supported (%s)", str);
return 2;
}
if (!X509_digest(cert, digest, buffer, &bytes)) {
lua_pushnil(L);
lua_pushfstring(L, "error processing the certificate (%s)",
ERR_reason_error_string(ERR_get_error()));
return 2;
}
to_hex((char*)buffer, bytes, hex_buffer);
lua_pushlstring(L, hex_buffer, bytes*2);
return 1;
}
/**
* Check if the certificate is valid in a given time.
*/
static int meth_valid_at(lua_State* L)
{
X509* cert = lsec_checkx509(L, 1);
time_t time = luaL_checkinteger(L, 2);
lua_pushboolean(L, (X509_cmp_time(X509_get_notAfter(cert), &time) >= 0
&& X509_cmp_time(X509_get_notBefore(cert), &time) <= 0));
return 1;
}
/**
* Return the serial number.
*/
static int meth_serial(lua_State *L)
{
char *tmp;
BIGNUM *bn;
ASN1_INTEGER *serial;
X509* cert = lsec_checkx509(L, 1);
serial = X509_get_serialNumber(cert);
bn = ASN1_INTEGER_to_BN(serial, NULL);
tmp = BN_bn2hex(bn);
lua_pushstring(L, tmp);
BN_free(bn);
OPENSSL_free(tmp);
return 1;
}
/**
* Return not before date.
*/
static int meth_notbefore(lua_State *L)
{
X509* cert = lsec_checkx509(L, 1);
return push_asn1_time(L, X509_get_notBefore(cert));
}
/**
* Return not after date.
*/
static int meth_notafter(lua_State *L)
{
X509* cert = lsec_checkx509(L, 1);
return push_asn1_time(L, X509_get_notAfter(cert));
}
/**
* Collect X509 objects.
*/
static int meth_destroy(lua_State* L)
{
X509_free(lsec_checkx509(L, 1));
return 0;
}
static int meth_tostring(lua_State *L)
{
X509* cert = lsec_checkx509(L, 1);
lua_pushfstring(L, "X509 certificate: %p", cert);
return 1;
}
/**
* Set the encode for ASN.1 string.
*/
static int meth_set_encode(lua_State* L)
{
int succ = 0;
p_x509 px = lsec_checkp_x509(L, 1);
const char *enc = luaL_checkstring(L, 2);
if (strncmp(enc, "ai5", 3) == 0) {
succ = 1;
px->encode = LSEC_AI5_STRING;
} else if (strncmp(enc, "utf8", 4) == 0) {
succ = 1;
px->encode = LSEC_UTF8_STRING;
}
lua_pushboolean(L, succ);
return 1;
}
/*---------------------------------------------------------------------------*/
static int load_cert(lua_State* L)
{
X509 *cert;
size_t bytes;
const char* data;
BIO *bio = BIO_new(BIO_s_mem());
data = luaL_checklstring(L, 1, &bytes);
BIO_write(bio, data, bytes);
cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
if (cert)
lsec_pushx509(L, cert);
else
lua_pushnil(L);
BIO_free(bio);
return 1;
}
/*---------------------------------------------------------------------------*/
/**
* Certificate methods.
*/
static luaL_Reg methods[] = {
{"digest", meth_digest},
{"setencode", meth_set_encode},
{"extensions", meth_extensions},
{"issuer", meth_issuer},
{"notbefore", meth_notbefore},
{"notafter", meth_notafter},
{"pem", meth_pem},
{"serial", meth_serial},
{"subject", meth_subject},
{"validat", meth_valid_at},
{NULL, NULL}
};
/**
* X509 metamethods.
*/
static luaL_Reg meta[] = {
{"__gc", meth_destroy},
{"__tostring", meth_tostring},
{NULL, NULL}
};
/**
* X509 functions.
*/
static luaL_Reg funcs[] = {
{"load", load_cert},
{NULL, NULL}
};
/*--------------------------------------------------------------------------*/
#if (LUA_VERSION_NUM == 501)
LSEC_API int luaopen_ssl_x509(lua_State *L)
{
/* Register the functions and tables */
luaL_newmetatable(L, "SSL:Certificate");
luaL_register(L, NULL, meta);
lua_newtable(L);
luaL_register(L, NULL, methods);
lua_setfield(L, -2, "__index");
luaL_register(L, "ssl.x509", funcs);
return 1;
}
#else
LSEC_API int luaopen_ssl_x509(lua_State *L)
{
/* Register the functions and tables */
luaL_newmetatable(L, "SSL:Certificate");
luaL_setfuncs(L, meta, 0);
lua_newtable(L);
luaL_setfuncs(L, methods, 0);
lua_setfield(L, -2, "__index");
lua_newtable(L);
luaL_setfuncs(L, funcs, 0);
return 1;
}
#endif

31
src/x509.h Normal file
View File

@ -0,0 +1,31 @@
/*--------------------------------------------------------------------------
* LuaSec 0.5.1
*
* Copyright (C) 2014-2015 Kim Alvefur, Paul Aurich, Tobias Markmann
* Matthew Wild, Bruno Silvestre.
*
*--------------------------------------------------------------------------*/
#ifndef LSEC_X509_H
#define LSEC_X509_H
#include <openssl/x509v3.h>
#include <lua.h>
#include "config.h"
/* We do not support UniversalString nor BMPString as ASN.1 String types */
enum { LSEC_AI5_STRING, LSEC_UTF8_STRING };
typedef struct t_x509_ {
X509 *cert;
int encode;
} t_x509;
typedef t_x509* p_x509;
void lsec_pushx509(lua_State* L, X509* cert);
X509* lsec_checkx509(lua_State* L, int idx);
LSEC_API int luaopen_ssl_x509(lua_State *L);
#endif