diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..94f4b9d --- /dev/null +++ b/INSTALL @@ -0,0 +1,23 @@ +LuaSec 0.2 +----------- + +* On Linux, BSD, and Mac OS X: + + - Edit 'Makefile' + * Inform the path to install the modules. + * 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. + + - Use 'make ' to compile + * Platforms: linux, bsd, or macosx + + - Use 'make install' to install the modules. + +* On Windows: + + - Use the Visual C++ project to compile the library. + + - Copy the 'ssl.lua' file to some place in your LUA_PATH. + + - Copy the 'ssl.dll' file to some place in your LUA_CPATH. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..959e081 --- /dev/null +++ b/LICENSE @@ -0,0 +1,44 @@ +LuaSec 0.2 license +Copyright (C) 2006-2007 Bruno Silvestre + +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. + +---------------------------------------------------------------------------- + +LuaSocket 2.0.2 license +Copyright © 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. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..75917c7 --- /dev/null +++ b/Makefile @@ -0,0 +1,50 @@ +# Inform the location to intall the modules +LUAPATH=/usr/local/share/lua/5.1 +CPATH=/usr/local/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 + +# For Mac OS X: set the system version +MACOSX_VERSION=10.4 + +DEFS=-DBUFFER_DEBUG + +#---------------------- +# Do not edit this part + +.PHONY: all clean install none linux bsd macosx + +all: none + +none: + @echo "Usage: $(MAKE) " + @echo " * linux" + @echo " * bsd" + @echo " * macosx" + +install: + @cd src ; $(MAKE) CPATH="$(CPATH)" LUAPATH="$(LUAPATH)" install + +linux: + @echo "---------------------" + @echo "** Build for Linux **" + @echo "---------------------" + @cd src ; $(MAKE) INCDIR="$(INCDIR)" LIBDIR="$(LIBDIR)" DEFS="$(DEFS)" $@ + +bsd: + @echo "-------------------" + @echo "** Build for BSD **" + @echo "-------------------" + @cd src ; $(MAKE) INCDIR="$(INCDIR)" LIBDIR="$(LIBDIR)" DEFS="$(DEFS)" $@ + +macosx: + @echo "------------------------------" + @echo "** Build for Mac OS X $(MACOSX_VERSION) **" + @echo "------------------------------" + @cd src ; $(MAKE) INCDIR="$(INCDIR)" LIBDIR="$(LIBDIR)" DEFS="$(DEFS)" MACVER="$(MACOSX_VERSION)" $@ + +clean: + @cd src ; $(MAKE) clean diff --git a/luasec.ncb b/luasec.ncb new file mode 100644 index 0000000..a3569d5 Binary files /dev/null and b/luasec.ncb differ diff --git a/luasec.sln b/luasec.sln new file mode 100644 index 0000000..a8f9164 --- /dev/null +++ b/luasec.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luasec", "luasec.vcproj", "{A629932F-8819-4C0B-8835-CBF1FEED6376}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {A629932F-8819-4C0B-8835-CBF1FEED6376}.Debug.ActiveCfg = Debug|Win32 + {A629932F-8819-4C0B-8835-CBF1FEED6376}.Debug.Build.0 = Debug|Win32 + {A629932F-8819-4C0B-8835-CBF1FEED6376}.Release.ActiveCfg = Release|Win32 + {A629932F-8819-4C0B-8835-CBF1FEED6376}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/luasec.suo b/luasec.suo new file mode 100644 index 0000000..a8a9000 Binary files /dev/null and b/luasec.suo differ diff --git a/luasec.vcproj b/luasec.vcproj new file mode 100644 index 0000000..b76b049 --- /dev/null +++ b/luasec.vcproj @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/README b/samples/README new file mode 100644 index 0000000..a0d8725 --- /dev/null +++ b/samples/README @@ -0,0 +1,31 @@ +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. + +* oneshot + A simple connection example. + +* loop + Test successive connections between the server and the client + (to check memory leak). + +* loop-gc + Same of above, but the connection is not explicit closed, the gabage + collector is encharge of it. + +* wantread + Test timeout in handshake() and receive(). + +* wantwrite + Test timeout in send(). + +* want + Test want(). diff --git a/samples/certs/clientA.cnf b/samples/certs/clientA.cnf new file mode 100644 index 0000000..f938d90 --- /dev/null +++ b/samples/certs/clientA.cnf @@ -0,0 +1,316 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca' and 'req'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem # The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = sha1 # which md to use. +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString. +# utf8only: only UTF8Strings. +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings +# so use this option with caution! +string_mask = nombstr + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = BR +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State +stateOrProvinceName_default = Espirito Santo + +localityName = Locality Name (eg, city) +localityName_default = Santo Antonio do Canaa + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Sao Tonico Ltda + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = Department of Computer Science + +commonName = Common Name (eg, YOUR name) +commonName_default = Client A +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer:always + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always,issuer:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo diff --git a/samples/certs/clientA.sh b/samples/certs/clientA.sh new file mode 100755 index 0000000..0350ede --- /dev/null +++ b/samples/certs/clientA.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +openssl req -newkey rsa:1024 -sha1 -keyout clientAkey.pem -out clientAreq.pem \ + -nodes -config ./clientA.cnf -days 365 -batch + +openssl x509 -req -in clientAreq.pem -sha1 -extfile ./clientA.cnf \ + -extensions usr_cert -CA rootA.pem -CAkey rootAkey.pem -CAcreateserial \ + -out clientAcert.pem -days 365 + +cat clientAcert.pem rootA.pem > clientA.pem + +openssl x509 -subject -issuer -noout -in clientA.pem diff --git a/samples/certs/clientB.cnf b/samples/certs/clientB.cnf new file mode 100644 index 0000000..40405d1 --- /dev/null +++ b/samples/certs/clientB.cnf @@ -0,0 +1,316 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca' and 'req'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem # The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = sha1 # which md to use. +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString. +# utf8only: only UTF8Strings. +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings +# so use this option with caution! +string_mask = nombstr + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = BR +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State +stateOrProvinceName_default = Espirito Santo + +localityName = Locality Name (eg, city) +localityName_default = Santo Antonio do Canaa + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Sao Tonico Ltda + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = Department of Computer Science + +commonName = Common Name (eg, YOUR name) +commonName_default = Client B +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer:always + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always,issuer:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo diff --git a/samples/certs/clientB.sh b/samples/certs/clientB.sh new file mode 100755 index 0000000..94f8986 --- /dev/null +++ b/samples/certs/clientB.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +openssl req -newkey rsa:1024 -sha1 -keyout clientBkey.pem -out clientBreq.pem \ + -nodes -config ./clientB.cnf -days 365 -batch + +openssl x509 -req -in clientBreq.pem -sha1 -extfile ./clientB.cnf \ + -extensions usr_cert -CA rootB.pem -CAkey rootBkey.pem -CAcreateserial \ + -out clientBcert.pem -days 365 + +cat clientBcert.pem rootB.pem > clientB.pem + +openssl x509 -subject -issuer -noout -in clientB.pem diff --git a/samples/certs/rootA.cnf b/samples/certs/rootA.cnf new file mode 100644 index 0000000..a16a6de --- /dev/null +++ b/samples/certs/rootA.cnf @@ -0,0 +1,315 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca' and 'req'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem # The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = sha1 # which md to use. +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString. +# utf8only: only UTF8Strings. +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings +# so use this option with caution! +string_mask = nombstr + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = BR +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Espirito Santo + +localityName = Locality Name (eg, city) +localityName_default = Santo Antonio do Canaa + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Santo Tonico Ltda + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = Department of Computer Science + +commonName = Common Name (eg, YOUR name) +commonName_max = 64 +commonName_default = Root A + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer:always + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always,issuer:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo diff --git a/samples/certs/rootA.sh b/samples/certs/rootA.sh new file mode 100755 index 0000000..1a93e42 --- /dev/null +++ b/samples/certs/rootA.sh @@ -0,0 +1,5 @@ +openssl req -newkey rsa:1024 -sha1 -keyout rootAkey.pem -out rootAreq.pem -nodes -config ./rootA.cnf -days 365 -batch + +openssl x509 -req -in rootAreq.pem -sha1 -extfile ./rootA.cnf -extensions v3_ca -signkey rootAkey.pem -out rootA.pem -days 365 + +openssl x509 -subject -issuer -noout -in rootA.pem diff --git a/samples/certs/rootB.cnf b/samples/certs/rootB.cnf new file mode 100644 index 0000000..3627abc --- /dev/null +++ b/samples/certs/rootB.cnf @@ -0,0 +1,315 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca' and 'req'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem # The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = sha1 # which md to use. +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString. +# utf8only: only UTF8Strings. +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings +# so use this option with caution! +string_mask = nombstr + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = BR +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Espirito Santo + +localityName = Locality Name (eg, city) +localityName_default = Santo Antonio do Canaa + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Sao Tonico Ltda + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = Department of Computer Science + +commonName = Common Name (eg, YOUR name) +commonName_default = Root B +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer:always + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always,issuer:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo diff --git a/samples/certs/rootB.sh b/samples/certs/rootB.sh new file mode 100755 index 0000000..9081188 --- /dev/null +++ b/samples/certs/rootB.sh @@ -0,0 +1,5 @@ +openssl req -newkey rsa:1024 -sha1 -keyout rootBkey.pem -out rootBreq.pem -nodes -config ./rootB.cnf -days 365 -batch + +openssl x509 -req -in rootBreq.pem -sha1 -extfile ./rootB.cnf -extensions v3_ca -signkey rootBkey.pem -out rootB.pem -days 365 + +openssl x509 -subject -issuer -noout -in rootB.pem diff --git a/samples/certs/serverA.cnf b/samples/certs/serverA.cnf new file mode 100644 index 0000000..f86b6b6 --- /dev/null +++ b/samples/certs/serverA.cnf @@ -0,0 +1,316 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca' and 'req'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem # The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = sha1 # which md to use. +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString. +# utf8only: only UTF8Strings. +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings +# so use this option with caution! +string_mask = nombstr + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = BR +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State +stateOrProvinceName_default = Espirito Santo + +localityName = Locality Name (eg, city) +localityName_default = Santo Antonio do Canaa + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Sao Tonico Ltda + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = Department of Computer Science + +commonName = Common Name (eg, YOUR name) +commonName_default = Server A +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer:always + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always,issuer:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo diff --git a/samples/certs/serverA.sh b/samples/certs/serverA.sh new file mode 100755 index 0000000..7fa04e0 --- /dev/null +++ b/samples/certs/serverA.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +openssl req -newkey rsa:1024 -keyout serverAkey.pem -out serverAreq.pem \ + -config ./serverA.cnf -nodes -days 365 -batch + +openssl x509 -req -in serverAreq.pem -sha1 -extfile ./serverA.cnf \ + -extensions usr_cert -CA rootA.pem -CAkey rootAkey.pem -CAcreateserial \ + -out serverAcert.pem -days 365 + +cat serverAcert.pem rootA.pem > serverA.pem + +openssl x509 -subject -issuer -noout -in serverA.pem diff --git a/samples/certs/serverB.cnf b/samples/certs/serverB.cnf new file mode 100644 index 0000000..2a1426a --- /dev/null +++ b/samples/certs/serverB.cnf @@ -0,0 +1,316 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca' and 'req'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem # The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = sha1 # which md to use. +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString. +# utf8only: only UTF8Strings. +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings +# so use this option with caution! +string_mask = nombstr + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = BR +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State +stateOrProvinceName_default = Espirito Santo + +localityName = Locality Name (eg, city) +localityName_default = Santo Antonio do Canaa + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Sao Tonico Ltda + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = Department of Computer Science + +commonName = Common Name (eg, YOUR name) +commonName_default = Server B +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer:always + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always,issuer:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo diff --git a/samples/certs/serverB.sh b/samples/certs/serverB.sh new file mode 100755 index 0000000..c75b00a --- /dev/null +++ b/samples/certs/serverB.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +openssl req -newkey rsa:1024 -keyout serverBkey.pem -out serverBreq.pem \ + -config ./serverB.cnf -nodes -days 365 -batch + +openssl x509 -req -in serverBreq.pem -sha1 -extfile ./serverB.cnf \ + -extensions usr_cert -CA rootB.pem -CAkey rootBkey.pem -CAcreateserial \ + -out serverBcert.pem -days 365 + +cat serverBcert.pem rootB.pem > serverB.pem + +openssl x509 -subject -issuer -noout -in serverB.pem diff --git a/samples/loop-gc/client.lua b/samples/loop-gc/client.lua new file mode 100644 index 0000000..bcf5f8d --- /dev/null +++ b/samples/loop-gc/client.lua @@ -0,0 +1,27 @@ +-- +-- Public domain +-- +require("socket") +require("ssl") + +local params = { + mode = "client", + protocol = "sslv3", + key = "../certs/clientAkey.pem", + certificate = "../certs/clientA.pem", + cafile = "../certs/rootA.pem", + verify = {"peer", "fail_if_no_peer_cert"}, + options = {"all", "no_sslv2"}, +} + +while true do + local peer = socket.tcp() + assert( peer:connect("127.0.0.1", 8888) ) + + -- [[ SSL wrapper + peer = assert( ssl.wrap(peer, params) ) + assert( peer:dohandshake() ) + --]] + + print(peer:receive("*l")) +end diff --git a/samples/loop-gc/server.lua b/samples/loop-gc/server.lua new file mode 100644 index 0000000..32e48f9 --- /dev/null +++ b/samples/loop-gc/server.lua @@ -0,0 +1,35 @@ +-- +-- Public domain +-- +require("socket") +require("ssl") + +local params = { + mode = "server", + protocol = "sslv3", + key = "../certs/serverAkey.pem", + certificate = "../certs/serverA.pem", + cafile = "../certs/rootA.pem", + verify = {"peer", "fail_if_no_peer_cert"}, + options = {"all", "no_sslv2"}, +} + +-- [[ 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() + +while true do + local peer = server:accept() + + -- [[ SSL wrapper + peer = assert( ssl.wrap(peer, ctx) ) + assert( peer:dohandshake() ) + --]] + + peer:send("loop test\n") +end diff --git a/samples/loop/client.lua b/samples/loop/client.lua new file mode 100644 index 0000000..13cd720 --- /dev/null +++ b/samples/loop/client.lua @@ -0,0 +1,28 @@ +-- +-- Public domain +-- +require("socket") +require("ssl") + +local params = { + mode = "client", + protocol = "sslv3", + key = "../certs/clientAkey.pem", + certificate = "../certs/clientA.pem", + cafile = "../certs/rootA.pem", + verify = {"peer", "fail_if_no_peer_cert"}, + options = {"all", "no_sslv2"}, +} + +while true do + local peer = socket.tcp() + assert( peer:connect("127.0.0.1", 8888) ) + + -- [[ SSL wrapper + peer = assert( ssl.wrap(peer, params) ) + assert( peer:dohandshake() ) + --]] + + print(peer:receive("*l")) + peer:close() +end diff --git a/samples/loop/server.lua b/samples/loop/server.lua new file mode 100644 index 0000000..f35b8a9 --- /dev/null +++ b/samples/loop/server.lua @@ -0,0 +1,36 @@ +-- +-- Public domain +-- +require("socket") +require("ssl") + +local params = { + mode = "server", + protocol = "sslv3", + key = "../certs/serverAkey.pem", + certificate = "../certs/serverA.pem", + cafile = "../certs/rootA.pem", + verify = {"peer", "fail_if_no_peer_cert"}, + options = {"all", "no_sslv2"}, +} + +-- [[ 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() + +while true do + local peer = server:accept() + + -- [[ SSL wrapper + peer = assert( ssl.wrap(peer, ctx) ) + assert( peer:dohandshake() ) + --]] + + peer:send("loop test\n") + peer:close() +end diff --git a/samples/oneshot/client.lua b/samples/oneshot/client.lua new file mode 100644 index 0000000..5ecf492 --- /dev/null +++ b/samples/oneshot/client.lua @@ -0,0 +1,26 @@ +-- +-- Public domain +-- +require("socket") +require("ssl") + +local params = { + mode = "client", + protocol = "sslv3", + key = "../certs/clientAkey.pem", + certificate = "../certs/clientA.pem", + cafile = "../certs/rootA.pem", + verify = {"peer", "fail_if_no_peer_cert"}, + options = {"all", "no_sslv2"}, +} + +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() diff --git a/samples/oneshot/server.lua b/samples/oneshot/server.lua new file mode 100644 index 0000000..93261e2 --- /dev/null +++ b/samples/oneshot/server.lua @@ -0,0 +1,35 @@ +-- +-- Public domain +-- +require("socket") +require("ssl") + +local params = { + mode = "server", + protocol = "sslv3", + key = "../certs/serverAkey.pem", + certificate = "../certs/serverA.pem", + cafile = "../certs/rootA.pem", + verify = {"peer", "fail_if_no_peer_cert"}, + options = {"all", "no_sslv2"}, +} + + +-- [[ 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() diff --git a/samples/want/client.lua b/samples/want/client.lua new file mode 100644 index 0000000..586f0a4 --- /dev/null +++ b/samples/want/client.lua @@ -0,0 +1,66 @@ +-- +-- Test the conn:want() function +-- +-- Public domain +-- +require("socket") +require("ssl") + +local params = { + mode = "client", + protocol = "sslv3", + key = "../certs/clientAkey.pem", + certificate = "../certs/clientA.pem", + cafile = "../certs/rootA.pem", + verify = {"peer", "fail_if_no_peer_cert"}, + options = {"all", "no_sslv2"}, +} + +-- Wait until socket is ready (for reading or writing) +local function wait(peer) + -- What event blocked us? + local err + if peer.want then -- Is it an SSL connection? + err = peer:want() + print("Want? ", err) + else + -- No, it's a normal TCP connection... + err = "timeout" + end + + if err == "read" or err == "timeout" then + socket.select({peer}, nil) + elseif err == "write" then + socket.select(nil, {peer}) + else + peer:close() + os.exit(1) + end +end + +-- Start the TCP connection +local peer = socket.tcp() +assert( peer:connect("127.0.0.1", 8888) ) + +-- [[ SSL wrapper +peer = assert( ssl.wrap(peer, params) ) +peer:settimeout(0.3) +local succ = peer:dohandshake() +while not succ do + wait(peer) + succ = peer:dohandshake() +end +print("** Handshake done") +--]] + +-- If the section above is commented, the timeout is not set. +-- We set it again for safetiness. +peer:settimeout(0.3) + +-- Try to receive a line +local str = peer:receive("*l") +while not str do + wait(peer) + str = peer:receive("*l") +end +peer:close() diff --git a/samples/want/server.lua b/samples/want/server.lua new file mode 100644 index 0000000..4a874b6 --- /dev/null +++ b/samples/want/server.lua @@ -0,0 +1,43 @@ +-- +-- Public domain +-- +require("socket") +require("ssl") + +local params = { + mode = "server", + protocol = "sslv3", + key = "../certs/serverAkey.pem", + certificate = "../certs/serverA.pem", + cafile = "../certs/rootA.pem", + verify = {"peer", "fail_if_no_peer_cert"}, + options = {"all", "no_sslv2"}, +} + +-- [[ 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) ) +socket.sleep(2) -- force the timeout in the client dohandshake() +assert( peer:dohandshake() ) +--]] + +for i = 1, 10 do + local v = tostring(i) + io.write(v) + io.flush() + peer:send(v) + socket.sleep(1) -- force the timeout in the client receive() +end +io.write("\n") +peer:send("\n") +peer:close() diff --git a/samples/wantread/client.lua b/samples/wantread/client.lua new file mode 100644 index 0000000..36112df --- /dev/null +++ b/samples/wantread/client.lua @@ -0,0 +1,55 @@ +-- +-- Public domain +-- +require("socket") +require("ssl") + +local params = { + mode = "client", + protocol = "sslv3", + key = "../certs/clientAkey.pem", + certificate = "../certs/clientA.pem", + cafile = "../certs/rootA.pem", + verify = {"peer", "fail_if_no_peer_cert"}, + options = {"all", "no_sslv2"}, +} + + +local function wait(peer, err) + if err == "timeout" or err == "wantread" then + socket.select({peer}, nil) + elseif err == "wantwrite" then + socket.select(nil, {peer}) + else + peer:close() + os.exit(1) + end +end + + +local peer = socket.tcp() +assert( peer:connect("127.0.0.1", 8888) ) + +-- [[ SSL wrapper +peer = assert( ssl.wrap(peer, params) ) +peer:settimeout(0.3) +local succ, err = peer:dohandshake() +while not succ do + print("handshake", err) + wait(peer, err) + succ, err = peer:dohandshake() +end +print("** Handshake done") +--]] + +-- If the section above is commented, the timeout is not set. +-- We set it again for safetiness. +peer:settimeout(0.3) + +local str, err, part = peer:receive("*l") +while not str do + print(part, err) + wait(peer, err) + str, err, part = peer:receive("*l") +end +peer:close() diff --git a/samples/wantread/server.lua b/samples/wantread/server.lua new file mode 100644 index 0000000..0be23a5 --- /dev/null +++ b/samples/wantread/server.lua @@ -0,0 +1,45 @@ +-- +-- Test the conn:want() function. +-- +-- Public domain +-- +require("socket") +require("ssl") + +local params = { + mode = "server", + protocol = "sslv3", + key = "../certs/serverAkey.pem", + certificate = "../certs/serverA.pem", + cafile = "../certs/rootA.pem", + verify = {"peer", "fail_if_no_peer_cert"}, + options = {"all", "no_sslv2"}, +} + +-- [[ 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) ) +socket.sleep(2) -- force the timeout in the client dohandshake() +assert( peer:dohandshake() ) +--]] + +for i = 1, 10 do + local v = tostring(i) + io.write(v) + io.flush() + peer:send(v) + socket.sleep(1) -- force the timeout in the client receive() +end +io.write("\n") +peer:send("\n") +peer:close() diff --git a/samples/wantwrite/client.lua b/samples/wantwrite/client.lua new file mode 100644 index 0000000..c0e7be1 --- /dev/null +++ b/samples/wantwrite/client.lua @@ -0,0 +1,49 @@ +-- +-- Public domain +-- +require("socket") +require("ssl") + +local params = { + mode = "client", + protocol = "sslv3", + key = "../certs/clientAkey.pem", + certificate = "../certs/clientA.pem", + cafile = "../certs/rootA.pem", + verify = {"peer", "fail_if_no_peer_cert"}, + options = {"all", "no_sslv2"}, +} + +local function wait(peer, err) + if err == "wantread" then + socket.select({peer}, nil) + elseif err == "timeout" or err == "wantwrite" then + socket.select(nil, {peer}) + else + peer:close() + os.exit(1) + end +end + + +local peer = socket.tcp() +assert( peer:connect("127.0.0.1", 8888) ) + +-- [[ SSL wrapper +peer = assert( ssl.wrap(peer, params) ) +assert( peer:dohandshake() ) +--]] + +peer:settimeout(0.3) + +local str = "a rose is a rose is a rose is a...\n" +while true do + print("Sending...") + local succ, err = peer:send(str) + while succ do + succ, err = peer:send(str) + end + print("Waiting...", err) + wait(peer, err) +end +peer:close() diff --git a/samples/wantwrite/server.lua b/samples/wantwrite/server.lua new file mode 100644 index 0000000..7d73dce --- /dev/null +++ b/samples/wantwrite/server.lua @@ -0,0 +1,40 @@ +-- +-- Public domain +-- +require("socket") +require("ssl") + +print("Use Ctrl+S and Ctrl+Q to suspend and resume the server.") + +local params = { + mode = "server", + protocol = "sslv3", + key = "../certs/serverAkey.pem", + certificate = "../certs/serverA.pem", + cafile = "../certs/rootA.pem", + verify = {"peer", "fail_if_no_peer_cert"}, + options = {"all", "no_sslv2"}, +} + + +-- [[ 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() ) +--]] + +while true do + local str = peer:receive("*l") + print(str) +end +peer:close() diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..cc53eb0 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,61 @@ +CMOD=ssl.so +LMOD=ssl.lua + +OBJS= \ + timeout.o \ + buffer.o \ + io.o \ + usocket.o \ + context.o \ + ssl.o + +LIBS=-lssl -lcrypto + +WARN=-Wall -pedantic + +BSD_CFLAGS=-O2 -fpic $(WARN) $(INCDIR) $(DEFS) +BSD_LDFLAGS=-O -shared -fpic $(LIBDIR) + +LNX_CFLAGS=-O2 -fpic $(WARN) $(INCDIR) $(DEFS) +LNX_LDFLAGS=-O -shared -fpic $(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) + +.PHONY: all clean install none linux bsd macosx + +all: + +install: $(CMOD) $(LMOD) + $(CP) $(CMOD) $(CPATH) + $(CP) $(LMOD) $(LUAPATH) + +linux: + @make $(CMOD) MYCFLAGS="$(LNX_CFLAGS)" MYLDFLAGS="$(LNX_LDFLAGS)" + +bsd: + @make $(CMOD) MYCFLAGS="$(BSD_CFLAGS)" MYLDFLAGS="$(BSD_LDFLAGS)" + +macosx: + @make $(CMOD) MYCFLAGS="$(MAC_CFLAGS)" MYLDFLAGS="$(MAC_LDFLAGS)" MYENV="$(MAC_ENV)" + + +$(CMOD): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +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 diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 0000000..673fd6f --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,237 @@ +/*=========================================================================*\ +* 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 $ +\*=========================================================================*/ +#include "lua.h" +#include "lauxlib.h" + +#include "buffer.h" + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b); +static int recvline(p_buffer buf, luaL_Buffer *b); +static int recvall(p_buffer buf, luaL_Buffer *b); +static int buffer_get(p_buffer buf, const char **data, size_t *count); +static void buffer_skip(p_buffer buf, size_t count); +static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent); + +/* min and max macros */ +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? x : y) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? x : y) +#endif + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes C structure +\*-------------------------------------------------------------------------*/ +void buffer_init(p_buffer buf, p_io io, p_timeout tm) { + buf->first = buf->last = 0; + buf->io = io; + buf->tm = tm; +} + +/*-------------------------------------------------------------------------*\ +* object:send() interface +\*-------------------------------------------------------------------------*/ +int buffer_meth_send(lua_State *L, p_buffer buf) { + int top = lua_gettop(L); + int err = IO_DONE; + size_t size = 0, sent = 0; + const char *data = luaL_checklstring(L, 2, &size); + long start = (long) luaL_optnumber(L, 3, 1); + long end = (long) luaL_optnumber(L, 4, -1); + p_timeout tm = timeout_markstart(buf->tm); + if (start < 0) start = (long) (size+start+1); + if (end < 0) end = (long) (size+end+1); + if (start < 1) start = (long) 1; + if (end > (long) size) end = (long) size; + if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent); + /* check if there was an error */ + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, buf->io->error(buf->io->ctx, err)); + lua_pushnumber(L, sent+start-1); + } else { + lua_pushnumber(L, sent+start-1); + lua_pushnil(L); + lua_pushnil(L); + } +#ifdef BUFFER_DEBUG + /* push time elapsed during operation as the last return value */ + lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm)); +#endif + return lua_gettop(L) - top; +} + +/*-------------------------------------------------------------------------*\ +* object:receive() interface +\*-------------------------------------------------------------------------*/ +int buffer_meth_receive(lua_State *L, p_buffer buf) { + int err = IO_DONE, top = lua_gettop(L); + luaL_Buffer b; + size_t size; + const char *part = luaL_optlstring(L, 3, "", &size); + p_timeout tm = timeout_markstart(buf->tm); + /* initialize buffer with optional extra prefix + * (useful for concatenating previous partial results) */ + luaL_buffinit(L, &b); + luaL_addlstring(&b, part, size); + /* receive new patterns */ + if (!lua_isnumber(L, 2)) { + const char *p= luaL_optstring(L, 2, "*l"); + 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); + /* check if there was an error */ + if (err != IO_DONE) { + /* we can't push anyting in the stack before pushing the + * contents of the buffer. this is the reason for the complication */ + luaL_pushresult(&b); + lua_pushstring(L, buf->io->error(buf->io->ctx, err)); + lua_pushvalue(L, -2); + lua_pushnil(L); + lua_replace(L, -4); + } else { + luaL_pushresult(&b); + lua_pushnil(L); + lua_pushnil(L); + } +#ifdef BUFFER_DEBUG + /* push time elapsed during operation as the last return value */ + lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm)); +#endif + return lua_gettop(L) - top; +} + +/*-------------------------------------------------------------------------*\ +* Determines if there is any data in the read buffer +\*-------------------------------------------------------------------------*/ +int buffer_isempty(p_buffer buf) { + return buf->first >= buf->last; +} + +/*=========================================================================*\ +* Internal functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Sends a block of data (unbuffered) +\*-------------------------------------------------------------------------*/ +#define STEPSIZE 8192 +static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) { + p_io io = buf->io; + p_timeout tm = buf->tm; + size_t total = 0; + int err = IO_DONE; + while (total < count && err == IO_DONE) { + size_t done; + size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE; + err = io->send(io->ctx, data+total, step, &done, tm); + total += done; + } + *sent = total; + return err; +} + +/*-------------------------------------------------------------------------*\ +* Reads a fixed number of bytes (buffered) +\*-------------------------------------------------------------------------*/ +static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) { + int err = IO_DONE; + size_t total = 0; + while (err == IO_DONE) { + size_t count; const char *data; + err = buffer_get(buf, &data, &count); + count = MIN(count, wanted - total); + luaL_addlstring(b, data, count); + buffer_skip(buf, count); + total += count; + if (total >= wanted) break; + } + return err; +} + +/*-------------------------------------------------------------------------*\ +* Reads everything until the connection is closed (buffered) +\*-------------------------------------------------------------------------*/ +static int recvall(p_buffer buf, luaL_Buffer *b) { + int err = IO_DONE; + size_t total = 0; + while (err == IO_DONE) { + const char *data; size_t count; + err = buffer_get(buf, &data, &count); + total += count; + luaL_addlstring(b, data, count); + buffer_skip(buf, count); + } + if (err == IO_CLOSED) { + if (total > 0) return IO_DONE; + else return IO_CLOSED; + } else return err; +} + +/*-------------------------------------------------------------------------*\ +* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF +* are not returned by the function and are discarded from the buffer +\*-------------------------------------------------------------------------*/ +static int recvline(p_buffer buf, luaL_Buffer *b) { + int err = IO_DONE; + while (err == IO_DONE) { + size_t count, pos; const char *data; + err = buffer_get(buf, &data, &count); + pos = 0; + while (pos < count && data[pos] != '\n') { + /* we ignore all \r's */ + if (data[pos] != '\r') luaL_putchar(b, data[pos]); + pos++; + } + if (pos < count) { /* found '\n' */ + buffer_skip(buf, pos+1); /* skip '\n' too */ + break; /* we are done */ + } else /* reached the end of the buffer */ + buffer_skip(buf, pos); + } + return err; +} + +/*-------------------------------------------------------------------------*\ +* Skips a given number of bytes from read buffer. No data is read from the +* transport layer +\*-------------------------------------------------------------------------*/ +static void buffer_skip(p_buffer buf, size_t count) { + buf->first += count; + if (buffer_isempty(buf)) + buf->first = buf->last = 0; +} + +/*-------------------------------------------------------------------------*\ +* Return any data available in buffer, or get more data from transport layer +* if buffer is empty +\*-------------------------------------------------------------------------*/ +static int buffer_get(p_buffer buf, const char **data, size_t *count) { + int err = IO_DONE; + p_io io = buf->io; + p_timeout tm = buf->tm; + if (buffer_isempty(buf)) { + size_t got; + err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm); + buf->first = 0; + buf->last = got; + } + *count = buf->last - buf->first; + *data = buf->data + buf->first; + return err; +} diff --git a/src/buffer.h b/src/buffer.h new file mode 100644 index 0000000..61d2798 --- /dev/null +++ b/src/buffer.h @@ -0,0 +1,45 @@ +#ifndef BUF_H +#define BUF_H +/*=========================================================================*\ +* LuaSocket 2.0.2 +* Copyright (C) 2004-2007 Diego Nehab +* +* Input/Output interface for Lua programs +* +* Line patterns require buffering. Reading one character at a time involves +* too many system calls and is very slow. This module implements the +* LuaSocket interface for input/output on connected objects, as seen by +* Lua programs. +* +* Input is buffered. Output is *not* buffered because there was no simple +* way of making sure the buffered output data would ever be sent. +* +* 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 + +#include "io.h" +#include "timeout.h" + +/* buffer size in bytes */ +#define BUF_SIZE 8192 + +/* buffer control structure */ +typedef struct t_buffer_ { + 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 */ + char data[BUF_SIZE]; /* storage space for buffer data */ +} t_buffer; +typedef t_buffer *p_buffer; + +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_isempty(p_buffer buf); + +#endif /* BUF_H */ diff --git a/src/context.c b/src/context.c new file mode 100644 index 0000000..dca8c9e --- /dev/null +++ b/src/context.c @@ -0,0 +1,387 @@ +/*-------------------------------------------------------------------------- + * LuaSec 0.2 + * Copyright (C) 2006-2007 Bruno Silvestre + * + *--------------------------------------------------------------------------*/ + +#include +#include +#include + +#include +#include + +#include "context.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}, +#endif + {NULL, 0L} +}; + +/*--------------------------- Auxiliary Functions ----------------------------*/ + +/** + * Return the context. + */ +static p_context checkctx(lua_State *L, int idx) +{ + return (p_context)luaL_checkudata(L, idx, "SSL:Context"); +} + +/** + * Prepare the SSL options flag. + */ +static int set_option_flag(const char *opt, unsigned long *flag) +{ + ssl_option_t *p; + for (p = ssl_options; p->name; p++) { + if (!strcmp(opt, p->name)) { + *flag |= p->code; + return 1; + } + } + return 0; +} + +/** + * Find the protocol. + */ +static 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(); + return NULL; +} + +/** + * Prepare the SSL handshake verify flag. + */ +static int set_verify_flag(const char *str, int *flag) +{ + if (!strcmp(str, "none")) { + *flag |= SSL_VERIFY_NONE; + return 1; + } + if (!strcmp(str, "peer")) { + *flag |= SSL_VERIFY_PEER; + return 1; + } + if (!strcmp(str, "client_once")) { + *flag |= SSL_VERIFY_CLIENT_ONCE; + return 1; + } + if (!strcmp(str, "fail_if_no_peer_cert")) { + *flag |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + return 1; + } + return 0; +} + +/*------------------------------ Lua Functions -------------------------------*/ + +/** + * Create a SSL context. + */ +static int create(lua_State *L) +{ + p_context ctx; + SSL_METHOD *method; + + method = str2method(luaL_checkstring(L, 1)); + if (!method) { + lua_pushnil(L); + lua_pushstring(L, "invalid protocol"); + return 2; + } + ctx = (p_context) lua_newuserdata(L, sizeof(t_context)); + if (!ctx) { + lua_pushnil(L); + lua_pushstring(L, "error creating context"); + return 2; + } + ctx->context = SSL_CTX_new(method); + if (!ctx->context) { + lua_pushnil(L); + lua_pushstring(L, "error creating context"); + return 2; + } + ctx->mode = MD_CTX_INVALID; + /* No session support */ + SSL_CTX_set_session_cache_mode(ctx->context, SSL_SESS_CACHE_OFF); + luaL_getmetatable(L, "SSL:Context"); + lua_setmetatable(L, -2); + return 1; +} + +/** + * Load the trusting certificates. + */ +static int load_locations(lua_State *L) +{ + SSL_CTX *ctx = ctx_getcontext(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) { + lua_pushboolean(L, 0); + lua_pushfstring(L, "error loading CA locations (%s)", + ERR_reason_error_string(ERR_get_error())); + return 2; + } + lua_pushboolean(L, 1); + return 1; +} + +/** + * Load the certificate file. + */ +static int load_cert(lua_State *L) +{ + SSL_CTX *ctx = ctx_getcontext(L, 1); + const char *filename = luaL_checkstring(L, 2); + if (SSL_CTX_use_certificate_chain_file(ctx, filename) != 1) { + lua_pushboolean(L, 0); + lua_pushfstring(L, "error loading certificate (%s)", + ERR_reason_error_string(ERR_get_error())); + return 2; + } + lua_pushboolean(L, 1); + return 1; +} + +/** + * Load the key file -- only in PEM format. + */ +static int load_key(lua_State *L) +{ + SSL_CTX *ctx = ctx_getcontext(L, 1); + const char *filename = luaL_checkstring(L, 2); + + if (SSL_CTX_use_PrivateKey_file(ctx, filename, SSL_FILETYPE_PEM) != 1) { + lua_pushboolean(L, 0); + lua_pushfstring(L, "error loading private key (%s)", + ERR_reason_error_string(ERR_get_error())); + return 2; + } + lua_pushboolean(L, 1); + return 1; +} + +/** + * Set the cipher list. + */ +static int set_cipher(lua_State *L) +{ + SSL_CTX *ctx = ctx_getcontext(L, 1); + const char *list = luaL_checkstring(L, 2); + if (SSL_CTX_set_cipher_list(ctx, list) != 1) { + lua_pushboolean(L, 0); + lua_pushfstring(L, "error setting cipher list (%s)", + ERR_reason_error_string(ERR_get_error())); + return 2; + } + lua_pushboolean(L, 1); + return 1; +} + +/** + * Set the depth for certificate checking. + */ +static int set_depth(lua_State *L) +{ + SSL_CTX *ctx = ctx_getcontext(L, 1); + SSL_CTX_set_verify_depth(ctx, luaL_checkint(L, 2)); + lua_pushboolean(L, 1); + return 1; +} + +/** + * Set the handshake verify options. + */ +static int set_verify(lua_State *L) +{ + int i; + int flag = 0; + SSL_CTX *ctx = ctx_getcontext(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; + } + } + SSL_CTX_set_verify(ctx, flag, NULL); + } + lua_pushboolean(L, 1); + return 1; +} + +/** + * Set the protocol options. + */ +static int set_options(lua_State *L) +{ + int i; + unsigned long flag = 0L; + SSL_CTX *ctx = ctx_getcontext(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)) { + lua_pushboolean(L, 0); + lua_pushstring(L, "invalid option"); + return 2; + } + } + SSL_CTX_set_options(ctx, flag); + } + lua_pushboolean(L, 1); + return 1; +} + +/** + * Set the context mode. + */ +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; + lua_pushboolean(L, 1); + return 1; + } + if(!strcmp("client", str)) { + ctx->mode = MD_CTX_CLIENT; + lua_pushboolean(L, 1); + return 1; + } + lua_pushboolean(L, 0); + lua_pushstring(L, "invalid mode"); + return 1; +} + +/** + * 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}, + {NULL, NULL} +}; + +/*-------------------------------- Metamethods -------------------------------*/ + +/** + * Collect SSL context -- GC metamethod. + */ +static int meth_destroy(lua_State *L) +{ + p_context ctx = checkctx(L, 1); + if (ctx->context) { + SSL_CTX_free(ctx->context); + ctx->context = NULL; + } + return 0; +} + +/** + * Object information -- tostring metamethod. + */ +static int meth_tostring(lua_State *L) +{ + p_context ctx = checkctx(L, 1); + lua_pushfstring(L, "SSL context: %p", ctx); + return 1; +} + +/** + * Context metamethods. + */ +static luaL_Reg meta[] = { + {"__gc", meth_destroy}, + {"__tostring", meth_tostring}, + {NULL, NULL} +}; + + +/*----------------------------- Public Functions ---------------------------*/ + +/** + * Retrieve the SSL context from the Lua stack. + */ +SSL_CTX* ctx_getcontext(lua_State *L, int idx) +{ + p_context ctx = checkctx(L, idx); + return ctx->context; +} + +/** + * Retrieve the mode from the context in the Lua stack. + */ +char ctx_getmode(lua_State *L, int idx) +{ + p_context ctx = checkctx(L, idx); + return ctx->mode; +} + +/*------------------------------ Initialization ------------------------------*/ + +/** + * Registre the module. + */ +int luaopen_ssl_context(lua_State *L) +{ + luaL_newmetatable(L, "SSL:Context"); + luaL_register(L, NULL, meta); + luaL_register(L, "ssl.context", funcs); + return 1; +} diff --git a/src/context.h b/src/context.h new file mode 100644 index 0000000..8544200 --- /dev/null +++ b/src/context.h @@ -0,0 +1,35 @@ +#ifndef __CONTEXT_H__ +#define __CONTEXT_H__ + +/*-------------------------------------------------------------------------- + * LuaSec 0.2 + * Copyright (C) 2006-2007 Bruno Silvestre + * + *--------------------------------------------------------------------------*/ + +#include +#include + +#ifndef LUASEC_API +#define LUASEC_API extern +#endif + +#define MD_CTX_INVALID 0 +#define MD_CTX_SERVER 1 +#define MD_CTX_CLIENT 2 + +typedef struct t_context_ { + SSL_CTX *context; + char 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); +/* Retrieve the mode from the context in the Lua stack */ +char ctx_getmode(lua_State *L, int idx); + +/* Registre the module. */ +LUASEC_API int luaopen_ssl_context(lua_State *L); + +#endif diff --git a/src/io.c b/src/io.c new file mode 100644 index 0000000..ff2e7ad --- /dev/null +++ b/src/io.c @@ -0,0 +1,34 @@ +/*=========================================================================*\ +* 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 $ +\*=========================================================================*/ +#include "io.h" + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes C structure +\*-------------------------------------------------------------------------*/ +void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx) { + io->send = send; + io->recv = recv; + io->error = error; + io->ctx = ctx; +} + +/*-------------------------------------------------------------------------*\ +* I/O error strings +\*-------------------------------------------------------------------------*/ +const char *io_strerror(int err) { + switch (err) { + case IO_DONE: return NULL; + case IO_CLOSED: return "closed"; + case IO_TIMEOUT: return "timeout"; + default: return "unknown error"; + } +} diff --git a/src/io.h b/src/io.h new file mode 100644 index 0000000..b5942d3 --- /dev/null +++ b/src/io.h @@ -0,0 +1,70 @@ +#ifndef IO_H +#define IO_H +/*=========================================================================*\ +* LuaSocket 2.0.2 +* Copyright (C) 2004-2007 Diego Nehab +* +* Input/Output abstraction +* +* This module defines the interface that LuaSocket expects from the +* transport layer for streamed input/output. The idea is that if any +* transport implements this interface, then the buffer.c functions +* automatically work on it. +* +* 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 +#include + +#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 */ +}; + +/* interface to error message function */ +typedef const char *(*p_error) ( + void *ctx, /* context needed by send */ + int err /* error code */ +); + +/* interface to send function */ +typedef int (*p_send) ( + void *ctx, /* context needed by send */ + const char *data, /* pointer to buffer with data to send */ + size_t count, /* number of bytes to send from buffer */ + size_t *sent, /* number of bytes sent uppon return */ + p_timeout tm /* timeout control */ +); + +/* interface to recv function */ +typedef int (*p_recv) ( + void *ctx, /* context needed by recv */ + char *data, /* pointer to buffer where data will be writen */ + size_t count, /* number of bytes to receive into buffer */ + size_t *got, /* number of bytes received uppon return */ + p_timeout tm /* timeout control */ +); + +/* IO driver definition */ +typedef struct t_io_ { + void *ctx; /* context needed by send/recv */ + p_send send; /* send function pointer */ + p_recv recv; /* receive function pointer */ + p_error error; /* strerror function */ +} t_io; +typedef t_io *p_io; + +void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx); +const char *io_strerror(int err); + +#endif /* IO_H */ + diff --git a/src/socket.h b/src/socket.h new file mode 100644 index 0000000..8a5b1f2 --- /dev/null +++ b/src/socket.h @@ -0,0 +1,47 @@ +#ifndef SOCKET_H +#define SOCKET_H +/*=========================================================================*\ +* LuaSocket 2.0.2 +* Copyright (C) 2004-2007 Diego Nehab +* +* Socket compatibilization module +* +* 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" + +/*=========================================================================*\ +* Platform specific compatibilization +\*=========================================================================*/ +#ifdef _WIN32 +#include "wsocket.h" +#else +#include "usocket.h" +#endif + +/*=========================================================================*\ +* The connect and accept functions accept a timeout and their +* implementations are somewhat complicated. We chose to move +* the timeout control into this module for these functions in +* order to simplify the modules that use them. +\*=========================================================================*/ +#include "timeout.h" + +/*=========================================================================*\ +* Functions bellow implement a comfortable platform independent +* interface to sockets +\*=========================================================================*/ +int socket_open(void); +int socket_close(void); +void socket_destroy(p_socket ps); +void socket_setnonblocking(p_socket ps); +void socket_setblocking(p_socket ps); +int socket_waitfd(p_socket ps, int sw, p_timeout tm); +const char *socket_strerror(int err); + +#endif /* SOCKET_H */ diff --git a/src/ssl.c b/src/ssl.c new file mode 100644 index 0000000..f8d6cda --- /dev/null +++ b/src/ssl.c @@ -0,0 +1,393 @@ +/*-------------------------------------------------------------------------- + * LuaSec 0.2 + * Copyright (C) 2006-2007 Bruno Silvestre + * + *--------------------------------------------------------------------------*/ + +#include +#include + +#include +#include + +#include +#include + +#include "io.h" +#include "buffer.h" +#include "timeout.h" +#include "socket.h" +#include "context.h" +#include "ssl.h" + +/** + * Map error code into string. + */ +static const char *ssl_ioerror(void *ctx, int err) +{ + if (err == IO_SSL) { + p_ssl ssl = (p_ssl) ctx; + switch(ssl->error) { + case SSL_ERROR_NONE: return "No error"; + case SSL_ERROR_ZERO_RETURN: return "closed"; + case SSL_ERROR_WANT_READ: return "wantread"; + case SSL_ERROR_WANT_WRITE: return "wantwrite"; + case SSL_ERROR_WANT_CONNECT: return "'connect' not completed"; + case SSL_ERROR_WANT_ACCEPT: return "'accept' not completed"; + case SSL_ERROR_WANT_X509_LOOKUP: return "Waiting for callback"; + case SSL_ERROR_SYSCALL: return "System error"; + case SSL_ERROR_SSL: return ERR_reason_error_string(ERR_get_error()); + default: return "Unknown SSL error"; + } + } + return socket_strerror(err); +} + +/** + * Close the connection before the GC collect the object. + */ +static int meth_destroy(lua_State *L) +{ + p_ssl ssl = (p_ssl) lua_touserdata(L, 1); + if (ssl->ssl) { + socket_setblocking(&ssl->sock); + SSL_shutdown(ssl->ssl); + socket_destroy(&ssl->sock); + SSL_free(ssl->ssl); + ssl->ssl = NULL; + } + return 0; +} + +/** + * Perform the TLS/SSL handshake + */ +static int handshake(p_ssl ssl) +{ + p_timeout tm = timeout_markstart(&ssl->tm); + if (ssl->state == ST_SSL_CLOSED) + return IO_CLOSED; + for ( ; ; ) { + int err = SSL_do_handshake(ssl->ssl); + ssl->error = SSL_get_error(ssl->ssl, err); + switch(ssl->error) { + case SSL_ERROR_NONE: + ssl->state = ST_SSL_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_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_DONE) return err; + break; + case SSL_ERROR_SYSCALL: + if (ERR_peek_error()) { + ssl->error = SSL_ERROR_SSL; + return IO_SSL; + } + if (err == 0) + return IO_CLOSED; + return errno; + default: + return IO_SSL; + } + } + return IO_UNKNOWN; +} + +/** + * Send data + */ +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) + return IO_CLOSED; + *sent = 0; + for ( ; ; ) { + int err = SSL_write(ssl->ssl, data, (int) count); + ssl->error = SSL_get_error(ssl->ssl, err); + 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_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_DONE) return err; + break; + case SSL_ERROR_SYSCALL: + if (ERR_peek_error()) { + ssl->error = SSL_ERROR_SSL; + return IO_SSL; + } + if (err == 0) + return IO_CLOSED; + return errno; + default: + return IO_SSL; + } + } + return IO_UNKNOWN; +} + +/** + * Receive data + */ +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) + return IO_CLOSED; + *got = 0; + for ( ; ; ) { + int err = SSL_read(ssl->ssl, data, (int) count); + ssl->error = SSL_get_error(ssl->ssl, err); + switch(ssl->error) { + case SSL_ERROR_NONE: + *got = 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_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_DONE) return err; + break; + case SSL_ERROR_SYSCALL: + if (ERR_peek_error()) { + ssl->error = SSL_ERROR_SSL; + return IO_SSL; + } + if (err == 0) + return IO_CLOSED; + return errno; + default: + return IO_SSL; + } + } + return IO_UNKNOWN; +} + +/** + * Create a new TLS/SSL object and mark it as new. + */ +static int meth_create(lua_State *L) +{ + p_ssl ssl; + int mode = ctx_getmode(L, 1); + SSL_CTX *ctx = ctx_getcontext(L, 1); + + if (mode == MD_CTX_INVALID) { + lua_pushnil(L); + lua_pushstring(L, "invalid mode"); + return 2; + } + ssl = (p_ssl) lua_newuserdata(L, sizeof(t_ssl)); + if (!ssl) { + lua_pushnil(L); + lua_pushstring(L, "error creating SSL object"); + return 2; + } + ssl->ssl = SSL_new(ctx); + if (!ssl->ssl) { + lua_pushnil(L); + lua_pushstring(L, "error creating SSL object"); + return 2;; + } + ssl->state = ST_SSL_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) + 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, + (p_error) ssl_ioerror, ssl); + timeout_init(&ssl->tm, -1, -1); + buffer_init(&ssl->buf, &ssl->io, &ssl->tm); + + luaL_getmetatable(L, "SSL:Connection"); + lua_setmetatable(L, -2); + return 1; +} + +/** + * Buffer send function + */ +static int meth_send(lua_State *L) { + p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection"); + return buffer_meth_send(L, &ssl->buf); +} + +/** + * Buffer receive function + */ +static int meth_receive(lua_State *L) { + p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection"); + return buffer_meth_receive(L, &ssl->buf); +} + +/** + * Select support methods + */ +static int meth_getfd(lua_State *L) +{ + 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. + */ +static int meth_setfd(lua_State *L) +{ + p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection"); + if (ssl->state != ST_SSL_NEW) + luaL_argerror(L, 1, "invalid SSL object state"); + ssl->sock = luaL_checkint(L, 2); + socket_setnonblocking(&ssl->sock); + SSL_set_fd(ssl->ssl, (int)ssl->sock); + return 0; +} + +/** + * Lua handshake function. + */ +static int meth_handshake(lua_State *L) +{ + p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection"); + int err = handshake(ssl); + if (err == IO_DONE) { + lua_pushboolean(L, 1); + return 1; + } + lua_pushboolean(L, 0); + lua_pushstring(L, ssl_ioerror((void*)ssl, err)); + return 2; +} + +/** + * Close the connection. + */ +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; +} + +/** + * Set timeout. + */ +static int meth_settimeout(lua_State *L) +{ + p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection"); + return timeout_meth_settimeout(L, &ssl->tm); +} + +/** + * Check if there is data in the buffer. + */ +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) + res = !buffer_isempty(&ssl->buf) || SSL_pending(ssl->ssl); + lua_pushboolean(L, res); + return 1; +} + +/** + * Return the state information about the SSL object. + */ +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); + switch(code) { + case SSL_NOTHING: lua_pushstring(L, "nothing"); break; + case SSL_READING: lua_pushstring(L, "read"); break; + case SSL_WRITING: lua_pushstring(L, "write"); break; + case SSL_X509_LOOKUP: lua_pushstring(L, "x509lookup"); break; + } + return 1; +} + +/*---------------------------------------------------------------------------*/ + + +/** + * 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}, + {NULL, NULL} +}; + +/** + * SSL functions + */ +static luaL_Reg funcs[] = { + {"create", meth_create}, + {"setfd", meth_setfd}, + {NULL, NULL} +}; + +/** + * Initialize modules + */ +LUASEC_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); + } + SSL_load_error_strings(); + + /* Initialize internal library */ + socket_open(); + + /* Registre the functions and tables */ + luaL_newmetatable(L, "SSL:Connection"); + lua_newtable(L); + luaL_register(L, NULL, meta); + 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); + lua_setfield(L, -2, "invalidfd"); + + return 1; +} + diff --git a/src/ssl.h b/src/ssl.h new file mode 100644 index 0000000..98593bd --- /dev/null +++ b/src/ssl.h @@ -0,0 +1,38 @@ +#ifndef __SSL_H__ +#define __SSL_H__ + +/*-------------------------------------------------------------------------- + * LuaSec 0.2 + * Copyright (C) 2006-2007 Bruno Silvestre + * + *--------------------------------------------------------------------------*/ + +#include +#include + +#include "io.h" +#include "buffer.h" +#include "timeout.h" + +#ifndef LUASEC_API +#define LUASEC_API extern +#endif + +#define ST_SSL_NEW 1 +#define ST_SSL_CONNECTED 2 +#define ST_SSL_CLOSED 3 + +typedef struct t_ssl_ { + t_socket sock; + t_io io; + t_buffer buf; + t_timeout tm; + SSL *ssl; + char state; + int error; +} t_ssl; +typedef t_ssl* p_ssl; + +LUASEC_API int luaopen_ssl_core(lua_State *L); + +#endif diff --git a/src/ssl.lua b/src/ssl.lua new file mode 100644 index 0000000..5e2c070 --- /dev/null +++ b/src/ssl.lua @@ -0,0 +1,84 @@ +------------------------------------------------------------------------------ +-- LuaSec 0.2 +-- Copyright (C) 2006-2007 Bruno Silvestre +-- +------------------------------------------------------------------------------ + +module("ssl", package.seeall) + +require("ssl.core") +require("ssl.context") + + +_COPYRIGHT = "LuaSec 0.2 - Copyright (C) 2006-2007 Bruno Silvestre\n" .. + "LuaSocket 2.0.2 - Copyright (C) 2004-2007 Diego Nehab" + +-- +-- +-- +local function optexec(func, param, ctx) + if param then + if type(param) == "table" then + return func(ctx, unpack(param)) + else + return func(ctx, param) + end + end + return true +end + +-- +-- +-- +function newcontext(cfg) + local succ, msg, ctx + -- Create the context + ctx, msg = context.create(cfg.protocol) + if not ctx then return nil, msg end + -- Mode + succ, msg = context.setmode(ctx, cfg.mode) + if not succ then return nil, msg end + -- Load the key + succ, msg = context.loadkey(ctx, cfg.key) + if not succ then return nil, msg end + -- Load the certificate + succ, msg = context.loadcert(ctx, cfg.certificate) + if not succ then return nil, msg end + -- Load the CA certificates + if cfg.cafile or cfg.capath then + succ, msg = context.locations(ctx, cfg.cafile, cfg.capath) + 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 + -- Set SSL options + succ, msg = optexec(context.setoptions, cfg.options, ctx) + if not succ then return nil, msg end + -- Set the depth for certificate verification + if cfg.depth then + succ, msg = context.setdepth(ctx, cfg.depth) + if not succ then return nil, msg end + end + return ctx +end + +-- +-- +-- +function wrap(sock, cfg) + local ctx, msg + if type(cfg) == "table" then + ctx, msg = newcontext(cfg) + if not ctx then return nil, msg end + else + ctx = cfg + end + local s, msg = core.create(ctx) + if s then + core.setfd(s, sock:getfd()) + sock:setfd(core.invalidfd) + return s + end + return nil, msg +end diff --git a/src/timeout.c b/src/timeout.c new file mode 100644 index 0000000..d141213 --- /dev/null +++ b/src/timeout.c @@ -0,0 +1,155 @@ +/*=========================================================================*\ +* 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 $ +\*=========================================================================*/ +#include + +#ifdef _WIN32 +#include +#else +#include +#include +#endif + +#include +#include + +#include "timeout.h" + +/* min and max macros */ +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? x : y) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? x : y) +#endif + +/*=========================================================================*\ +* Exported functions. +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initialize structure +\*-------------------------------------------------------------------------*/ +void timeout_init(p_timeout tm, double block, double total) { + tm->block = block; + tm->total = total; +} + +/*-------------------------------------------------------------------------*\ +* Determines how much time we have left for the next system call, +* if the previous call was successful +* Input +* tm: timeout control structure +* Returns +* the number of ms left or -1 if there is no time limit +\*-------------------------------------------------------------------------*/ +double timeout_get(p_timeout tm) { + if (tm->block < 0.0 && tm->total < 0.0) { + return -1; + } else if (tm->block < 0.0) { + double t = tm->total - timeout_gettime() + tm->start; + return MAX(t, 0.0); + } else if (tm->total < 0.0) { + return tm->block; + } else { + double t = tm->total - timeout_gettime() + tm->start; + return MIN(tm->block, MAX(t, 0.0)); + } +} + +/*-------------------------------------------------------------------------*\ +* Returns time since start of operation +* Input +* tm: timeout control structure +* Returns +* start field of structure +\*-------------------------------------------------------------------------*/ +double timeout_getstart(p_timeout tm) { + return tm->start; +} + +/*-------------------------------------------------------------------------*\ +* Determines how much time we have left for the next system call, +* if the previous call was a failure +* Input +* tm: timeout control structure +* Returns +* the number of ms left or -1 if there is no time limit +\*-------------------------------------------------------------------------*/ +double timeout_getretry(p_timeout tm) { + if (tm->block < 0.0 && tm->total < 0.0) { + return -1; + } else if (tm->block < 0.0) { + double t = tm->total - timeout_gettime() + tm->start; + return MAX(t, 0.0); + } else if (tm->total < 0.0) { + double t = tm->block - timeout_gettime() + tm->start; + return MAX(t, 0.0); + } else { + double t = tm->total - timeout_gettime() + tm->start; + return MIN(tm->block, MAX(t, 0.0)); + } +} + +/*-------------------------------------------------------------------------*\ +* Marks the operation start time in structure +* Input +* tm: timeout control structure +\*-------------------------------------------------------------------------*/ +p_timeout timeout_markstart(p_timeout tm) { + tm->start = timeout_gettime(); + return tm; +} + +/*-------------------------------------------------------------------------*\ +* Gets time in s, relative to January 1, 1970 (UTC) +* Returns +* time in s. +\*-------------------------------------------------------------------------*/ +#ifdef _WIN32 +double timeout_gettime(void) { + FILETIME ft; + double t; + GetSystemTimeAsFileTime(&ft); + /* Windows file time (time since January 1, 1601 (UTC)) */ + t = ft.dwLowDateTime/1.0e7 + ft.dwHighDateTime*(4294967296.0/1.0e7); + /* convert to Unix Epoch time (time since January 1, 1970 (UTC)) */ + return (t - 11644473600.0); +} +#else +double timeout_gettime(void) { + struct timeval v; + gettimeofday(&v, (struct timezone *) NULL); + /* Unix Epoch time (time since January 1, 1970 (UTC)) */ + return v.tv_sec + v.tv_usec/1.0e6; +} +#endif + +/*-------------------------------------------------------------------------*\ +* Sets timeout values for IO operations +* Lua Input: base, time [, mode] +* time: time out value in seconds +* mode: "b" for block timeout, "t" for total timeout. (default: b) +\*-------------------------------------------------------------------------*/ +int timeout_meth_settimeout(lua_State *L, p_timeout tm) { + double t = luaL_optnumber(L, 2, -1); + const char *mode = luaL_optstring(L, 3, "b"); + switch (*mode) { + case 'b': + tm->block = t; + break; + case 'r': case 't': + tm->total = t; + break; + default: + luaL_argcheck(L, 0, 3, "invalid timeout mode"); + break; + } + lua_pushnumber(L, 1); + return 1; +} + diff --git a/src/timeout.h b/src/timeout.h new file mode 100644 index 0000000..1157d43 --- /dev/null +++ b/src/timeout.h @@ -0,0 +1,32 @@ +#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 $ +\*=========================================================================*/ +#include + +/* timeout control structure */ +typedef struct t_timeout_ { + double block; /* maximum time for blocking calls */ + double total; /* total number of miliseconds for operation */ + double start; /* time of start of operation */ +} t_timeout; +typedef t_timeout *p_timeout; + +int timeout_open(lua_State *L); +void timeout_init(p_timeout tm, double block, double total); +double timeout_get(p_timeout tm); +double timeout_getretry(p_timeout tm); +p_timeout timeout_markstart(p_timeout tm); +double timeout_getstart(p_timeout tm); +double timeout_gettime(void); +int timeout_meth_settimeout(lua_State *L, p_timeout tm); + +#define timeout_iszero(tm) ((tm)->block == 0.0) + +#endif /* TIMEOUT_H */ diff --git a/src/usocket.c b/src/usocket.c new file mode 100644 index 0000000..9ead9f4 --- /dev/null +++ b/src/usocket.c @@ -0,0 +1,137 @@ +/*=========================================================================*\ +* 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 +#include +#include +#include +#include +#include +#include +#include + +#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); + } +} + diff --git a/src/usocket.h b/src/usocket.h new file mode 100644 index 0000000..de8a4a9 --- /dev/null +++ b/src/usocket.h @@ -0,0 +1,28 @@ +#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 +#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 */ diff --git a/src/wsocket.c b/src/wsocket.c new file mode 100644 index 0000000..9f99138 --- /dev/null +++ b/src/wsocket.c @@ -0,0 +1,164 @@ +/*=========================================================================*\ +* 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 + +#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 ERROR_FILE_NOT_FOUND: return "closed"; + 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); + } +} + diff --git a/src/wsocket.h b/src/wsocket.h new file mode 100644 index 0000000..b977df6 --- /dev/null +++ b/src/wsocket.h @@ -0,0 +1,28 @@ +#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 $ +\*=========================================================================*/ + +/*=========================================================================*\ +* WinSock include files +\*=========================================================================*/ +#include + +#define WAITFD_R 1 +#define WAITFD_W 2 +#define WAITFD_E 4 +#define WAITFD_C (WAITFD_E|WAITFD_W) + +#define SOCKET_INVALID (INVALID_SOCKET) + +typedef int socklen_t; +typedef SOCKET t_socket; +typedef t_socket *p_socket; + +#endif /* WSOCKET_H */