lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi,

     I googled openssl binding for Lua, but I can't found a fit version for me. They all missing some thing for me. So I decided wirte a new version.

     The job is begin now, and I think it will till to the end of this year (according to my free time), and welcome any advice.

     Source code can be fetch from https://github.com/zhaozg/lua-openssl or http://code.google.com/p/lua-openssl/.

     Get more from lua, I hope to do some contribution for Lua.
     Below is document(Not completely)
---------------------------------------------------------------------------------------------------------------------------------------------------------

OpenSSL binding for Lua

$Id: README 2011/7/19  zhiguo.zhao $

Index
-----
1. Introduce
2. Certificate
3. Public/Private Key
4. Cipher
5. Message Digest
6. PKCS7 SMIME
7. CSR & CRL
8. Pkcs12
9. Misc

I.   Howto.
II.  Examples
III. Contacts

1. Introduction
---------------

NEW: support for S/MIME encrypt/decrypt/sign/verify, as well as more
flexibility for specifying certificates/keys.

The functions implemented so far make it possible to seal and open data, and
also create and verify signatures.

Most of the functions require a key or a certificate as a parameter; to make
things easy for you to use openssl, this extension allows you to specify 
certificates or key in the following way:

1. As an openssl.x509 object returned from openssl.x509_read
2. As an openssl.evp_pkey object return from openssl.pkey_read 
   or openssl.pkey_new

Similarly, you can use the following methods of specifying a public key:

1. As a key object returned from object:get_public

There are many important lua object type: 
openssl.bio,
openssl.x509, 
openssl.stack_of_x509,
openssl.x509_req,
openssl.evp_pkey, 
openssl.digest, 
openssl.cipher,
openssl.engine
openssl.evp_cipher_ctx
openssl.evp_digest_ctx
...
They are short write as bio, x509, sk_x509, x509_req, evp_pkey,digest, cipher,
engine(not used now!), cipher_ctx,  digest_ctx

Notes, In next section of this document,

    => means return a lua_openssl object
    -> means return a basic type of lua

If function return a nil, it will be follow by a error number and string

2. Certificate
--------------

openssl.x509_read(string val) => x509
    val is a string containing the data from the certificate file

x509:export([bool notext=true]) -> string
    export x509 as certificate content data

x509:parse([bool shortnames=true]) -> table
    return a table which contain all x509 information

x509:check_private_key(evp_pkey pkey) -> boolean

x509:get_public() => evp_pkey

x509:checkpurpose(string purpose, sk_x509 ca [,sk_x509 untrusted])->boolean
    purpose canbe one of: ssl_client, ssl_server, ns_ssl_server, smime_sign,
    smime_encrypt, crl_sign, any, ocsp_helper, timestamp_sign

    ca is an openssl.stack_of_x509 object contain certchain.
    untrusted is an openssl.stack_of_x509 object containing a bunch of certs
    that are not trusted but may be useful in validating the certificate.

openssl.stack_of_x509 is an important object ina lua-openssl, it can be used
as a certchaina, trusted CA files or unstrustcerts.

openssl.sk_x509_read(filename) => sk_x509
openssl.sk_x509_new([table array={}]} ->sk_x509

sk_x509:push(openssl.x509 cert) => sk_x509
sk_x509:pop() => x509

sk_x509:set(number i, x509 cert) =>sk_x509
sk_x509:get(number i) => x509

sk_x509:insert(x509 cert,number i, ) =>sk_x509
sk_x509:delete(number i) => x509

sk_x509:totable() -> table 
    tableas array contain x509 from index 1

sk_x509:sort()

#sk_x509  -> number
    return number of certs in stack_of_x509

3. Public/Private key functions
-------------------------------

openssl.evp_new([string alg='rsa' [,int bits=1024|512, [...]]]) => evp_pkey
    
    default generate RSA key, bits=1024, 3rd paramater e default is 0x10001
    dsa,with bits default 1024 ,and seed data default have no data
    dh, with bits(prime_len) default 512, and generator default is 
    ec, not use any paramater, not fully support

openssl.pkey_new([table args]) =>  evp_pkey
    args = {dsa={n=,e=,...}|dh={}|dsa={}}

openssl.evp_read(string data|x509 cert [,bool public_key=true 
    [,string passphrase]]) => evp_pkey

   Read from a file or a data, coerce it into a EVP_PKEY object.
   It can be:
       1. X509 object -> public key will be extracted from it
       2. interpreted as the data from the cert/key file and interpreted in
       same way as openssl_get_privatekey()

    NOTE: If you are requesting a private key but have not specified a 
    passphrase, you should use an empty string rather than NULL for the 
    passphrase - NULL causes a passphrase prompt to be emitted Lua error !

evp_pkey:export(epv_pkey key [,boolean raw_key=false [, string passphrase]]) 
   -> string

   If raw_key is true, export will export rsa,dsa or dh data
evp_peky:parse(evp_pkey key) -> table
    returns an table with the key details (bits, pkey, type)

evp_pkey:is_private() -> boolean
    Check whether the supplied key is a private key by checking if the secret
    prime factors are set

About padding

    Now supporting 6 padding mode, they are:
pkcs1: RSA_PKCS1_PADDING 1
sslv23: RSA_SSLV23_PADDING 2
no: RSA_NO_PADDING 3
oaep: RSA_PKCS1_OAEP_PADDING 4
x931: RSA_X931_PADDING 5
pss: RSA_PKCS1_PSS_PADDING 6

   If input other padding string value other(ingore capatical) than above,
   will raise lua error.

evp_pkey:encrypt(string data [,string padding=pkcs1]) -> string
evp_pkey:decrypt(string data [,string padding=pkcs1]) -> string

4. Cipher
---------

openssl.get_cipher(string alg|number alg_id) => evp_pkey
    return a cipher method
openssl.get_cipher([bool aliases = true]) ->table
    return all ciphers methods default with alias, 

evp_cipher:info() ->table
    result with name, block_size,key_length,iv_length,flags,mode keys
   
evp_cipher:encrypt_init([ string key [,string iv [,engine engimp]]]) 
    => cipher_ctx
evp_cipher:decrypt_init([ string key [,string iv [,engine engimp]]]) 
    => cipher_ctx
evp_cipher:cipher_init(bool enc, [, string key [,string iv 
    [,engine engimp]]]) => cipher_ctx

cipher_ctx:info() ->table
    result with block_size,key_length,iv_length,flags,mode,nid,type 
    and cipher object keys
cipher_ctx:encrypt_update(string data)->string
    return string may be 0 length
cipher_ctx:encrypt_final()->string
cipher_ctx:decrypt_update(string data)->string
    return string may be 0 length
cipher_ctx:decrypt_final()->string

cipher_ctx:update(string data)->string
    return string may be 0 length
cipher_ctx:final()->string

cipher_ctx:cleanup() -> boolean
    reset state make object resulable.

5. Message Digest
-----------------

openssl.get_digest(string alg|int alg_id) => digest_ctx
    return a evp_digest object
openssl.get_digest([bool alias=true]) -> table
    return all md methods default with alias

evp_digest:info() -> table
    return a table with key nid,name, size, block_size, pkey_type, flags
evp_digest:digest(string in) -> string
    return binary digest result

evp_digest:init() => digest_ctx

digest_ctx:info() -> table
    return a table with key block_size, size, type and diget object
digest_ctx:update(string data) -> boolean
digest_ctx:final() -> string
digest_ctx:cleanup() ->boolean

6. PKCS7 (S/MIME) Sign/Verify/Encrypt/Decrypt Functions:
-------------------------------------------------------

These functions allow you to manipulate S/MIME messages!

They are based on apps/smime.c from the openssl dist, so for information,
see the documentation for openssl.

Strings "detached", "nodetached", "text", "nointern", "noverify",  "nochain",
"nocerts", "noattr", "binary", "nosigs" are supported

Decrypts the S/MIME message in the BIO object and and output the results to
BIO object. recipcert is a CERT for one of the recipients. recipkey 
specifies the private key matching recipcert.

headers is an array of headers to prepend to the message: they will
not be included in the encoded section.
flags is flag information as described above.
Hint: you will want to put "To", "From", and "Subject" headers in headers.
Headers can be either an assoc array keyed by header named, or can be
and indexed array containing a single header line per value.

openssl.pkcs7_sign(bio in, bio out, x509 signcert, evp_pkey signkey, 
table headers [, string flags [,stack_of_x509 extracerts]])->boolean

   Signs the MIME message in the BIO in with signcert/signkey and output the 
   result to BIO out. 
   headers lists plain text headers to exclude from the signed portion of the
   message, and should include to, from and subject as a minimum 

openssl.pkcs7_verify(bio in, string flags [, stack_of_x509 signerscerts,
   [, stack_of_x509 cacerts, [, stack_of_x509 extracerts [,bio content])
->boolean

   Verifys that the data block is intact, the signer is who they say they are,
   and returns the CERTs of the signers 

openssl.pkcs7_encrypt(bio in, bio out, stack_of_x509 recipcerts, table header
    [, string flags [,cipher md] -> boolean

    Encrypts the message in the file named infile with the certificates in 
    recipcerts and output the result to the file named outfile

openssl.pkcs7_decrypt(bio in, bio out, x509 recipcert [,evp_pkey recipkey])
->boolean

7. Certificate sign request and Certificate revocked list
---------------------------------------------------------

openssl.csr_new(evp_pkey privkey, table dn={} [,table args = nil])->x509_req
openssl.csr_read(string data) -> x509_req

csr:sign(x509 cert, evp_pkey privkey, table arg) -> x509
args must have serialNumber as hexecoded string, num_days as number
csr:export([boolean pem=true [, boolean noext=true]])->string
csr:get_public() -> evp_pkey


8. PKCS12 Function
------------------

openssl.pkcs12_read(string pkcs12data, string pass) -> table
Parses a PKCS12 data to an table
return a table which have cert, pkey, and extracerts three keys

openssl.pkcs12_export(x509 cert, evp_pkey pkey, string pass 
[[, string friendname ], table extracerts])) -> string
Creates and exports a PKCS12 data

friendname is options, if exist, must at 4th paramater
extracerts is options, it can be at 4th or 5th(if friendname exist) paramater


9. Misc Function
----------------

openssl.object_create(string oid, string name [, string alias] ) -> boolean
    Add one object.
openssl.object_create(tables args) -> boolean
    Add a lot of object, args must be array index start from 1, and every 
    node is a table have oid,name and optional alias key.

openssl.random_bytes(number length [, boolean strong=false]) 
    -> string, boolean
    Returns a string of the length specified filled with random bytes

openssl.error_string()-> number, string
    If found error, it will return a error number code, followedd by string 
    description or it will return nothing and clear error state,
    so you can call it twice.


openssl.sign(string data,  evp_pkey key [, digest md|string md_alg=SHA1])
    ->string
    Uses key to create signature for data, returns signed result

openssl.verify(string data, string signature, evp_pkey key 
    [, digest md|string md_alg=SHA1]) ->boolean
    Uses key to verify that the signature is correct for the given data.

openssl.seal(string data, table pubkeys [, cipher enc|string md_alg=RC4])
    -> string, table
    Encrypts data using pubkeys, so that only owners of the respective
    private keys and ekeys can decrypt and read the data. Returns the
    sealed data and table contain ekeys hold envelope keys on success, 
    else nil. 

openssl.open(string data, string ekey, int privkey, 
    [, cipher enc|string md_alg=RC4]) -> string

Opens (decrypts) sealed data using a private key and the corresponding
envelope key. Returns decrypted data on success and nil on failure. 


openssl.bio_new_mem([string data]) => bio
    If data is none or nil, that will be a output object or input.

openssl.bio_new_file(string file [,string mode=r]) => bio
    If mode not gived, will return a input bio object.

openssl.bio_new_mem([string data]) => bio
    Create a memory bio, if data gived, that will be memory buffer data
openssl.bio_new_file(string file, [string mode='r'])->bio
    Create a file bio, if mode not gived, that default is 'r'

BIO object
bio:read(number len) -> string
bio:gets([number len=256]) -> string
bio:write(string data)->number
bio:puts(string data)->number

bio:get_mem()->string
    only support bio mem bio
bio:close()
bio:type()->string
bio:reset()

I.   HOWTO
----------

Howto 1: Build on Linux/Unix System.

Howto 2: Build on Windows with MSVC.

Howto 3: Build on Windows with mingw.


II.  Example usage
------------------

Example 1:  Iterator a openssl.stack_of_x509(sk_x509) object

    n = #sk
    for i=1, n do
x = sk:get(i)
    end

Example 2: read and parse certificate

local openssl = require('openssl')

function dump(t,i)
for k,v in pairs(t) do
if(type(v)=='table') then
print( string.rep('\t',i),k..'={')
dump(v,i+1)
print( string.rep('\t',i),k..'=}')
else
print( string.rep('\t',i),k..'='..tostring(v))
end
end
end

function test_x509()
local x = openssl.x509_read(certasstring)
print(x)
t = x:parse()
dump(t,0)
print(t)
end

test_x509()