File: //opt/imunify360-webshield/lualib/resty/openssl/pkcs12.lua
local ffi = require "ffi"
local C = ffi.C
local ffi_gc = ffi.gc
local ffi_str = ffi.string
require "resty.openssl.include.pkcs12"
require "resty.openssl.include.bio"
require "resty.openssl.include.stack"
local bio_util = require "resty.openssl.auxiliary.bio"
local format_error = require("resty.openssl.err").format_error
local pkey_lib = require "resty.openssl.pkey"
local x509_lib = require "resty.openssl.x509"
local stack_lib = require "resty.openssl.stack"
local objects_lib = require "resty.openssl.objects"
local ctx_lib = require "resty.openssl.ctx"
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
local stack_of_x509_new = stack_lib.new_of("X509")
local stack_of_x509_add = stack_lib.add_of("X509")
local stack_of_x509_iter = stack_lib.mt_of("X509", x509_lib.dup, {}).__ipairs
local ptr_ptr_of_pkey = ffi.typeof("EVP_PKEY*[1]")
local ptr_ptr_of_x509 = ffi.typeof("X509*[1]")
local ptr_ptr_of_stack = ffi.typeof("OPENSSL_STACK*[1]")
local function decode(p12, passphrase)
local bio = C.BIO_new_mem_buf(p12, #p12)
if bio == nil then
return nil, "pkcs12.decode: BIO_new_mem_buf() failed"
end
ffi_gc(bio, C.BIO_free)
local p12 = C.d2i_PKCS12_bio(bio, nil)
if p12 == nil then
return nil, format_error("pkcs12.decode: d2i_PKCS12_bio")
end
ffi_gc(p12, C.PKCS12_free)
local ppkey = ptr_ptr_of_pkey()
local px509 = ptr_ptr_of_x509()
local pstack = ptr_ptr_of_stack()
local stack = stack_of_x509_new()
if stack == nil then
return nil, "pkcs12.decode: OPENSSL_sk_new_null() failed"
end
-- assign a valid OPENSSL_STACK so gc is taken care of
pstack[0] = stack
local code = C.PKCS12_parse(p12, passphrase or "", ppkey, px509, pstack)
if code ~= 1 then
return nil, format_error("pkcs12.decode: PKCS12_parse")
end
local cacerts
local n = C.OPENSSL_sk_num(stack)
if n > 0 then
cacerts = {}
local iter = stack_of_x509_iter({ ctx = stack })
for i=1, n do
local _, c = iter()
cacerts[i] = c
end
end
local friendly_name = C.X509_alias_get0(px509[0], nil)
if friendly_name ~= nil then
friendly_name = ffi_str(friendly_name)
end
return {
key = pkey_lib.new(ppkey[0]),
cert = x509_lib.new(px509[0]),
friendly_name = friendly_name,
cacerts = cacerts,
-- store reference to the stack, so it's not GC'ed unexpectedly
_stack = stack,
}
end
local function encode(opts, passphrase, properties)
if passphrase and type(passphrase) ~= "string" then
return nil, "pkcs12.encode: expect passphrase to be a string"
end
local pkey = opts.key
if not pkey_lib.istype(pkey) then
return nil, "pkcs12.encode: expect key to be a pkey instance"
end
local cert = opts.cert
if not x509_lib.istype(cert) then
return nil, "pkcs12.encode: expect cert to be a x509 instance"
end
local ok, err = cert:check_private_key(pkey)
if not ok then
return nil, "pkcs12.encode: key doesn't match cert: " .. err
end
local nid_key = opts.nid_key
if nid_key then
nid_key, err = objects_lib.txtnid2nid(nid_key)
if err then
return nil, "pkcs12.encode: invalid nid_key"
end
end
local nid_cert = opts.nid_cert
if nid_cert then
nid_cert, err = objects_lib.txtnid2nid(nid_cert)
if err then
return nil, "pkcs12.encode: invalid nid_cert"
end
end
local x509stack
local cacerts = opts.cacerts
if cacerts then
if type(cacerts) ~= "table" then
return nil, "pkcs12.encode: expect cacerts to be a table"
end
if #cacerts > 0 then
-- stack lib handles gc
x509stack = stack_of_x509_new()
for _, c in ipairs(cacerts) do
if C.X509_up_ref(c.ctx) ~= 1 then
return nil, "pkcs12.encode: failed to add cacerts: X509_up_ref failed"
end
local ok, err = stack_of_x509_add(x509stack, c.ctx)
if not ok then
return nil, "pkcs12.encode: failed to add cacerts: " .. err
end
end
end
end
local p12
if OPENSSL_3X then
p12 = C.PKCS12_create_ex(passphrase or "", opts.friendly_name,
pkey.ctx, cert.ctx, x509stack,
nid_key or 0, nid_cert or 0,
opts.iter or 0, opts.mac_iter or 0, 0,
ctx_lib.get_libctx(), properties)
else
p12 = C.PKCS12_create(passphrase or "", opts.friendly_name,
pkey.ctx, cert.ctx, x509stack,
nid_key or 0, nid_cert or 0,
opts.iter or 0, opts.mac_iter or 0, 0)
end
if p12 == nil then
return nil, format_error("pkcs12.encode: PKCS12_create")
end
ffi_gc(p12, C.PKCS12_free)
return bio_util.read_wrap(C.i2d_PKCS12_bio, p12)
end
return {
decode = decode,
loads = decode,
encode = encode,
dumps = encode,
}