需求
在基于nginx做waf开发时,nginx lua c动态库是常见的开发模式,在lua生态无法满足需求时,就需要我们在lua代码中调用动态库的方式,进行扩展,下面以lua调用c语言 openssl动态库的方式,进行判断证书的创建时间和证书的过期时间为例,进行说明
由于lua没有openss sdk做证书检查校验工作,那么就需要我们基于c语言和openssl库些一个so动态库,以供lua调用去判断证书有效时间、合法性、证书签发者信息等。
c函数从lua获取参数
与lua交互的c函数,所有函数入参参数固定为lua_State *L。
在lua调用c函数时,通过lua_State *L向其传入参数,如果只有一个参数且类型为string,那么在c函数中通过lua_tostring(L,1),获取传来的一个string类型的参数。
若lua向c函数传参时,有两个参数,第一个参数为string类型,第二个参数为number类型。那么在c函数中,需要通过lua_tostring(L,1)和lua_tonumber(L,2),分别获取lua传来的两个参数(即:string类型和number类型)。
代码说明
例如在如下代码中,expire_cert_time函数为获取证书过期时间,create_cert_time函数为获取证书创建时间,函数的参数为证书的路径(即:string类型),那么就可以通过path = lua_tostring(L,1),获取lua传来的证书路径,随后在c语言的函数中调用openssl函数进行一些列的操作。
向lua返回结果
在c函数中处理函数的结尾,通过lua_pushstring(L, buf)向lua返回处理结果,在该例中函数的返回值分别为,证书的创建时间、证书的过期时间,均是字符串类型,所以通过lua_pushstring把返回值push到lua_State L中,如果返回的是数字可以通过lua_pushnumber来实现。
c文件名:libcert.c
代码语言:javascript复制#include <stdio.h>
#include <lua.h>
#include <lauxlib.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include<sys/time.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include "tools.h"
static int expire_cert_time(lua_State *L)
{
const char *path = NULL;
path = lua_tostring(L,1);
int reason_code;
BIO *in;
int ret = 0;
X509 *x = NULL;
in = BIO_new(BIO_s_file());
if (in == NULL) {
}
if (BIO_read_filename(in, path) <= 0) {
}
x = PEM_read_bio_X509(in, NULL, NULL, NULL);
long version;
X509_NAME *issuer = NULL;
int entriesNum;
int i;
ASN1_TIME *time;
//获取证书版本
version = X509_get_version(x);
//printf("X509 Version: %ldn", version);
//获取证书颁发者信息,X509_NAME结构体保存了多项信息,包括国家、组织、部门、通用名、mail等。
issuer = X509_get_issuer_name(x);
//获取X509_NAME条目个数
entriesNum = sk_X509_NAME_ENTRY_num(issuer->entries);
//printf("entriesNum : %dn", version);
time_t tmp; //保存证书时间
struct tm *p;
char buf[100];
char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
//获取证书过期日期
time = X509_get_notAfter(x);
tmp = asn1_time_transform(time);
p = gmtime(&tmp);
sprintf(buf, "%ddd d:d:d",(1900 p->tm_year), (1 p->tm_mon),p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
lua_pushstring(L, buf);
return 1;
}
static int create_cert_time(lua_State *L)
{
const char *path = NULL;
path = lua_tostring(L,1);
int reason_code;
BIO *in;
int ret = 0;
X509 *x = NULL;
in = BIO_new(BIO_s_file());
if (in == NULL) {
}
if (BIO_read_filename(in, path) <= 0) {
}
x = PEM_read_bio_X509(in, NULL, NULL, NULL);
long version;
X509_NAME *issuer = NULL;
int entriesNum;
unsigned char msginfo[1024];
long Nid;
int i;
X509_NAME_ENTRY *name_entry;
ASN1_TIME *time;
X509_NAME *subject = NULL; //X509_NAME结构体,保存证书拥有者信息
ASN1_INTEGER *Serial = NULL; //保存证书序列号
EVP_PKEY *pubKey; //保存证书公钥
unsigned char derpubkey[1024];
int derpubkeyLen;
int msginfoLen;
unsigned short *pUtf8 = NULL;
int nUtf8;
int rv;
//获取证书版本
version = X509_get_version(x);
//printf("X509 Version: %ldn", version);
//获取证书颁发者信息,X509_NAME结构体保存了多项信息,包括国家、组织、部门、通用名、mail等。
issuer = X509_get_issuer_name(x);
//获取X509_NAME条目个数
entriesNum = sk_X509_NAME_ENTRY_num(issuer->entries);
//printf("entriesNum : %dn", version);
time_t tmptmp;
//获取证书生效日期
time = X509_get_notBefore(x);
tmptmp = asn1_time_transform(time);
struct tm *p;
char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
p = gmtime(&tmptmp);
char buf[100], buf2[100];
sprintf(buf, "%ddd d:d:d",(1900 p->tm_year), (1 p->tm_mon),p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
lua_pushstring(L,buf);
return 1;
}
static const struct luaL_Reg lib[] =
{
{"create_cert_time", create_cert_time},
{"expire_cert_time", expire_cert_time},
{NULL,NULL}
};
int luaopen_libcert(lua_State *L)
{
luaL_register(L,"libcert",lib);
return 1;
}
c函数注册至lua
luaL_Reg列表,记录了要注册的函数信息,本例中只有两个函数create_cert_time和expire_cert_time,所以luaL_Reg如下
代码语言:javascript复制static const struct luaL_Reg lib[] =
{
{"create_cert_time", create_cert_time},
{"expire_cert_time", expire_cert_time},
{NULL,NULL}
};
c库入口函数
通过luaopen_xxx实现,xxx标识c函数封装so动态库的名称,该例中动态库名称为libcert.so,固函数名为luaopen_libcert,luaL_register参数为lua_State、动态库名称libcert、上面luaL_Reg lib。
代码语言:javascript复制int luaopen_libcert(lua_State *L)
{
luaL_register(L,"libcert",lib);
return 1;
}
lua代码调用c动态库
代码和说明如下
代码语言:javascript复制require("libcert")
--参数为证书路径
c = libcert.create_cert_time("./abc.cert")
e = libcert.expire_cert_time("./abc.cert")
--证书创建时间
print("create time: ",c);
--证书过期时间
print("expire time: ",e);
注意:
本文使用lua5.1版本,在 lua5.2里没有luaL_register函数了,据说是lua不鼓励将模块设置到全局域,可以使用luaL_newlib(L, c)来实现。