diff --git a/lib/resty/openssl.lua b/lib/resty/openssl.lua index 9d7e4c48..3e8119a0 100644 --- a/lib/resty/openssl.lua +++ b/lib/resty/openssl.lua @@ -12,6 +12,7 @@ local _M = { digest = require("resty.openssl.digest"), hmac = require("resty.openssl.hmac"), pkey = require("resty.openssl.pkey"), + objects = require("resty.openssl.objects"), rand = require("resty.openssl.rand"), version = require("resty.openssl.version"), x509 = require("resty.openssl.x509"), @@ -73,6 +74,7 @@ function _M.luaossl_compat() _M.x509.getSubject = _M.x509.get_subject_name _M.x509.setIssuer = _M.x509.set_issuer_name _M.x509.getIssuer = _M.x509.get_issuer_name + _M.x509.getOCSP = _M.x509.get_ocsp_url _M.cipher.encrypt = function(self, key, iv, padding) return self, _M.cipher.init(self, key, iv, true, not padding) diff --git a/lib/resty/openssl/include/stack.lua b/lib/resty/openssl/include/stack.lua index 81c064e1..7e371910 100644 --- a/lib/resty/openssl/include/stack.lua +++ b/lib/resty/openssl/include/stack.lua @@ -14,6 +14,10 @@ local OPENSSL_11 = require("resty.openssl.version").OPENSSL_11 local _M = {} +ffi.cdef [[ + typedef char *OPENSSL_STRING; +]] + if OPENSSL_11 then ffi.cdef [[ typedef struct stack_st OPENSSL_STACK; diff --git a/lib/resty/openssl/include/x509/init.lua b/lib/resty/openssl/include/x509/init.lua index ab8b771c..7cd2a26b 100644 --- a/lib/resty/openssl/include/x509/init.lua +++ b/lib/resty/openssl/include/x509/init.lua @@ -28,6 +28,7 @@ ffi.cdef [[ int X509_EXTENSION_get_critical(const X509_EXTENSION *ex); ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *ex); ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ne); + X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc); // needed by pkey EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a); diff --git a/lib/resty/openssl/include/x509v3.lua b/lib/resty/openssl/include/x509v3.lua index c9c735f6..289a039f 100644 --- a/lib/resty/openssl/include/x509v3.lua +++ b/lib/resty/openssl/include/x509v3.lua @@ -10,6 +10,10 @@ local BASIC_CONSTRAINTS = { } ffi.cdef [[ + // STACK_OF(OPENSSL_STRING) + OPENSSL_STACK *X509_get1_ocsp(X509 *x); + void X509_email_free(OPENSSL_STACK *sk); + typedef struct EDIPartyName_st EDIPARTYNAME; typedef struct otherName_st OTHERNAME; diff --git a/lib/resty/openssl/x509/extension.lua b/lib/resty/openssl/x509/extension.lua index 8c46117c..c90f8cf0 100644 --- a/lib/resty/openssl/x509/extension.lua +++ b/lib/resty/openssl/x509/extension.lua @@ -79,6 +79,26 @@ function _M.dup(ctx) return self, nil end +function _M.from_data(any, nid, crit) + if type(any) ~= "table" or type(any.ctx) ~= "cdata" then + return nil, "expect a table with ctx at #1" + elseif type(nid) ~= "number" then + return nil, "expect a table at #2" + end + + local ctx = C.X509V3_EXT_i2d(nid, crit and 1 or 0, any.ctx) + if ctx == nil then + return nil, format_error("extension:from_data: X509V3_EXT_i2d") + end + ffi_gc(ctx, C.X509_EXTENSION_free) + + local self = setmetatable({ + ctx = ctx, + }, mt) + + return self, nil +end + function _M:get_object() -- retruns the internal pointer local asn1 = C.X509_EXTENSION_get_object(self.ctx) diff --git a/lib/resty/openssl/x509/init.lua b/lib/resty/openssl/x509/init.lua index 5b942b9b..13ed19aa 100644 --- a/lib/resty/openssl/x509/init.lua +++ b/lib/resty/openssl/x509/init.lua @@ -9,6 +9,7 @@ require "resty.openssl.include.x509" require "resty.openssl.include.x509v3" require "resty.openssl.include.evp" require "resty.openssl.include.objects" +local stack_macro = require("resty.openssl.include.stack") local stack_lib = require("resty.openssl.stack") local asn1_lib = require("resty.openssl.asn1") local digest_lib = require("resty.openssl.digest") @@ -166,15 +167,89 @@ function _M:get_lifetime() return not_before, not_after, nil end +-- note: index is 0 based +local OPENSSL_STRING_value_at = function(ctx, i) + local ct = ffi_cast("OPENSSL_STRING", stack_macro.OPENSSL_sk_value(ctx, i)) + if ct == nil then + return nil + end + return ffi_str(ct) +end + +function _M:get_ocsp_url(return_all) + local st = C.X509_get1_ocsp(self.ctx) + local ret + if return_all then + ret = {} + local count = stack_macro.OPENSSL_sk_num(st) + for i=0,count do + ret[i+1] = OPENSSL_STRING_value_at(st, i) + end + else + ret = OPENSSL_STRING_value_at(st, 0) + end + + C.X509_email_free(st) + return ret +end + +function _M:get_ocsp_request() + +end + +function _M:get_crl_url(return_all) + local cdp, err = self:get_crl_distribution_points() + if err then + return nil, err + end + + if cdp:count() == 0 then + return + end + + if return_all then + local ret = {} + local cdp_iter = cdp:each() + while true do + local _, gn = cdp_iter() + if not gn then + break + end + local gn_iter = gn:each() + while true do + local k, v = gn_iter() + if not k then + break + elseif k == "URI" then + table.insert(ret, v) + end + end + end + return ret + else + local gn, err = cdp:index(1) + if err then + return nil, err + end + local iter = gn:each() + while true do + local k, v = iter() + if not k then + break + elseif k == "URI" then + return v + end + end + end +end + function _M:sign(pkey, digest) local pkey_lib = require("resty.openssl.pkey") if not pkey_lib.istype(pkey) then return false, "expect a pkey instance at #1" end - if digest then - if not digest_lib.istype(digest) then - return false, "expect a digest instance at #2" - end + if digest and not digest_lib.istype(digest) then + return false, "expect a digest instance at #2" end -- returns size of signature if success @@ -301,6 +376,7 @@ else error("X509_delete_ext undefined") end end + function _M:set_extension(extension, last_pos) if not extension_lib.istype(extension) then return false, "expect a x509.extension instance at #1" diff --git a/t/openssl/x509.t b/t/openssl/x509.t index 1d46a612..e901296d 100644 --- a/t/openssl/x509.t +++ b/t/openssl/x509.t @@ -452,9 +452,74 @@ OCSP - URI:http://somedomain.com } --- request GET /t ---- response_body_like eval +--- response_body eval "URI http://crl3.digicert.com/sha2-ev-server-g2.crl URI http://crl4.digicert.com/sha2-ev-server-g2.crl " --- no_error_log +[error] + +=== TEST 18: Set CRL distribution points +--- http_config eval: $::HttpConfig +--- config + location =/t { + content_by_lua_block { + -- NYI + } + } +--- request + GET /t +--- no_error_log +[error] + +=== TEST 19: Get OCSP url +--- http_config eval: $::HttpConfig +--- config + location =/t { + content_by_lua_block { + local f = io.open("t/fixtures/Github.pem"):read("*a") + local c, err = require("resty.openssl.x509").new(f) + + local ocsp, err = c:get_ocsp_url() + if err then ngx.log(ngx.ERR, err) end + ngx.say(ocsp) + + local ocsp, err = c:get_ocsp_url(true) + if err then ngx.log(ngx.ERR, err) end + ngx.say(require("cjson").encode(ocsp)) + } + } +--- request + GET /t +--- response_body eval +'http://ocsp.digicert.com +["http:\/\/ocsp.digicert.com"] +' +--- no_error_log +[error] + +=== TEST 20: Get CRL url +--- http_config eval: $::HttpConfig +--- config + location =/t { + content_by_lua_block { + local f = io.open("t/fixtures/Github.pem"):read("*a") + local c, err = require("resty.openssl.x509").new(f) + + local crl, err = c:get_crl_url() + if err then ngx.log(ngx.ERR, err) end + ngx.say(crl) + + local crl, err = c:get_crl_url(true) + if err then ngx.log(ngx.ERR, err) end + ngx.say(require("cjson").encode(crl)) + } + } +--- request + GET /t +--- response_body eval +'http://crl3.digicert.com/sha2-ev-server-g2.crl +["http:\/\/crl3.digicert.com\/sha2-ev-server-g2.crl","http:\/\/crl4.digicert.com\/sha2-ev-server-g2.crl"] +' +--- no_error_log [error] \ No newline at end of file diff --git a/t/openssl/x509/altname.t b/t/openssl/x509/altname.t index 27a24871..8c0b9daf 100644 --- a/t/openssl/x509/altname.t +++ b/t/openssl/x509/altname.t @@ -55,7 +55,7 @@ __DATA__ end end ngx.say(#c) - ngx.say(#c:all()) + ngx.say(c:count()) } } --- request diff --git a/t/openssl/x509/extension.t b/t/openssl/x509/extension.t index 35c7b12e..aeb9975a 100644 --- a/t/openssl/x509/extension.t +++ b/t/openssl/x509/extension.t @@ -191,3 +191,29 @@ CA Issuers - URI:http://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServe --- no_error_log [error] +=== TEST 7: Creates extension by data +--- http_config eval: $::HttpConfig +--- config + location =/t { + content_by_lua_block { + local altname = require("resty.openssl.x509.altname").new() + altname:add("DNS", "test.com") + altname:add("DNS", "test2.com") + local extension = require("resty.openssl.x509.extension") + local c, err = extension.from_data(altname, 85, false) + if err then + ngx.log(ngx.ERR, err) + return + end + ngx.say(require("cjson").encode(c:get_object())) + ngx.say(tostring(c)) + } + } +--- request + GET /t +--- response_body_like eval +'{"ln":"X509v3 Subject Alternative Name","nid":85,"sn":"subjectAltName","id":"2.5.29.17"} +DNS:test.com, DNS:test2.com +' +--- no_error_log +[error]