fffonion / lua-resty-openssl

FFI-based OpenSSL binding for OpenResty
BSD 2-Clause "Simplified" License
130 stars 43 forks source link

PKCS1 error #170

Closed iakuf closed 1 month ago

iakuf commented 1 month ago

want to use my own CA certificate for self-signing. Then have my clients import my CA certificate to become their root certificate. Then let it access my nginx.

At this time, nginx can proxy any https domain name, similar to a man-in-the-middle attack, which is very useful for intranet caching such as game content.

Certificates for these domain names will automatically generate corresponding SSL certificates based on the domain names when requested. So I first generated a self-signed CA certificate and CA key, as follows.

openssl genpkey -algorithm RSA -out www.test.com.key -pkeyopt rsa_keygen_bits:2048 

openssl req -new -key www.test.com.key -out www.test.com.csr -subj "/C=CN/ST=Beijing/L=Beijing/O=Example Corp/CN=www.test.com"

openssl x509 -req -in www.test.com.csr -CA  ../ssl_cert/nginx-self-signed.pem  -CAkey ../ssl_cert/nginx-self-signed.key -CAcreateserial -out www.test.com.crt -days 365 -sha256 -extfile test.cnf 

Then I used the openssl command to test

openssl verify -verbose -CAfile ../ssl_cert/nginx-self-signed.crt www.test.com.crt
www.test.com.crt: OK

this is test.cnf

[req]
default_bits       = 2048
distinguished_name = req_distinguished_name
x509_extensions    = v3_req
prompt             = no

[req_distinguished_name]
C  = CN
ST = Beijing
L  = Beijing
O  = Example Corp
CN = www.test.com

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = www.test.com
DNS.2 = test.com

I use lua-resty-openssl to achieve the same function, the code is as follows

local openssl_pkey = require("resty.openssl.pkey")
local openssl_x509 = require("resty.openssl.x509")
local openssl_x509_name = require("resty.openssl.x509.name")
local openssl_digest = require("resty.openssl.digest")

local function readFile(path)
    local file, err = io.open(path, "r")
    if not file then
        return nil, "Failed to open file: " .. (err or "unknown error")
    end 
    local content = file:read("*a")
    file:close()
    return content, nil 
end

local ca_cert_pem, err = readFile("nginx-self-signed.pem")
if not ca_cert_pem then
    error(err)
end

local ca_key_pem, err = readFile("nginx-self-signed.key")
if not ca_key_pem then
    error(err)
end

local ca_cert, err = openssl_x509.new(ca_cert_pem, "PEM")
if not ca_cert then
    error("Failed to parse CA certificate: " .. err)
end

local ca_key, err = openssl_pkey.new({ pem = ca_key_pem, format = "PEM" })
if not ca_key then
    error("Failed to parse CA private key: " .. err)
end

local function generateCert(domain)

    local key, err = openssl_pkey.new({ 
            type = 'RSA',
            bits = 2048
        })  
    if  err then
        ngx.log(ngx.ERR, "Failed to new private key: ", err)
    end 

    local cert = openssl_x509.new()
    local name = openssl_x509_name.new()

    name:add("CN", domain)
    cert:set_subject_name(name)
    cert:set_pubkey(key)

    cert:set_issuer_name(ca_cert:get_subject_name())  

    cert:set_not_before(ngx.time())
    cert:set_not_after(ngx.time() + 365 * 24 * 60 * 60)  

    local digest = openssl_digest.new("sha256")

    local ok, err = cert:sign(ca_key)
    if not ok then
        ngx.log(ngx.ERR, "Error signing certificate: ", err)
    end 

    local ok, err = cert:verify(ca_key)
    if not ok then
        ngx.log(ngx.ERR, "Error verify certificate: ", err)
    end 

    local cert_pem, err = cert:to_PEM()
    if not cert_pem then
        ngx.log(ngx.ERR, "Failed to convert certificate to PEM: ", err)
    end 

    local key_pem, err = key:to_PEM("private")
    ngx.log(ngx.ERR, "Key type is ", key:is_private())
    if not key_pem then
        ngx.log(ngx.ERR, "Failed to convert private key to PEM: ", err)
    end 

    return cert_pem, key_pem
end

local cert_pem, key_pem = generateCert("www.test.com")
-- Save to files
local cert_file = io.open("generated_cert1.pem", "w")
cert_file:write(cert_pem)
cert_file:close()

local key_file = io.open("generated_key2.pem", "w")
key_file:write(key_pem)
key_file:close()
-- print("Certificate PEM:\n" .. cert_pem)
-- print("Private Key PEM:\n" .. key_pem)

Report the following error

openssl verify -verbose -CAfile ../ssl_cert/nginx-self-signed.crt generated_cert1.pem

error 7 at 0 depth lookup: certificate signature failure
error generated_cert1.pem: verification failed
800BDEBAC17F0000:error:0200008A:rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding:../crypto/rsa/rsa_pk1.c:79:
800BDEBAC17F0000:error:02000072:rsa routines:rsa_ossl_public_decrypt:padding check failed:../crypto/rsa/rsa_ossl.c:697:
800BDEBAC17F0000:error:1C880004:Provider routines:rsa_verify:RSA lib:../providers/implementations/signature/rsa_sig.c:774:
800BDEBAC17F0000:error:06880006:asn1 encoding routines:ASN1_item_verify_ctx:EVP lib:../crypto/asn1/a_verify.c:217:

I don’t know much about openssl. Why does PKCS1 report an error?

iakuf commented 1 month ago

local openssl_pkey = require("resty.openssl.pkey") local openssl_bignum = require("resty.openssl.bn") local openssl_csr = require("resty.openssl.x509.csr") local openssl_name = require("resty.openssl.x509.name") local openssl_rand = require("resty.openssl.rand")

-- CA证书和私钥的PEM内容 local ca_cert_pem = [[

-----END CERTIFICATE----- ]] local ca_pkey_pem = [[ -----BEGIN PRIVATE KEY-----

-----END PRIVATE KEY----- ]]

-- 加载CA证书和私钥 local ca_cert, err = openssl_x509.new(ca_cert_pem) if not ca_cert then ngx.log(ngx.ERR, "failed to load CA cert: ", err) return end

local ca_pkey, err = openssl_pkey.new(ca_pkey_pem) if not ca_pkey then ngx.log(ngx.ERR, "failed to load CA pkey: ", err) return end

local _M = {}

-- 创建证书 function _M:generateCert(domain) -- 生成和签署 SSL 证书时 -- step1: 生成新的密钥对:为待签名的证书生成一个新的公钥和私钥。 -- 创建私钥 local pkey, err = openssl_pkey.new({ type = "RSA", bits = 2048 }) if not pkey then ngx.log(ngx.ERR, "failed to create pkey: ", err) return end

-- step2 生成 CSR(证书签名请求):使用新生成的私钥和相关信息(如域名、组织信息等)生成 CSR。
local csr, err = openssl_csr.new()
if not csr then
    ngx.log(ngx.ERR, "failed to create csr: ", err)
    return
end

local subject = openssl_name.new({
    { C = "CN" },
    { ST = "Beijing" },
    { L = "Beijing" },
    { O = "Example Corp" },
    { CN = domain },
})
csr:set_subject_name(subject)
csr:set_pubkey(pkey)

-- step3 使用 CA 签署 CSR:用 CA 的私钥签署这个 CSR,生成最终的证书。
local openssl_x509 = require "resty.openssl.x509"
local resty_random = require "resty.openssl.rand"
local cert, err = openssl_x509.new()
if not cert then
    ngx.log(ngx.ERR, "failed to create cert: ", err)
    return
end

cert:set_serial_number(openssl_bignum.from_binary(openssl_rand.bytes(16)))
cert:set_subject_name(csr:get_subject_name())
cert:set_pubkey(csr:get_pubkey())
cert:set_issuer_name(ca_cert:get_subject_name())
cert:set_not_before(ngx.time())
cert:set_not_after(ngx.time() + 365 * 24 * 60 * 60)  -- 一年有效期
cert:sign(ca_pkey)

-- 获取证书的PEM格式
local cert_pem, err = cert:to_PEM()
if not cert_pem then
    ngx.log(ngx.ERR, "failed to get cert PEM: ", err)
    return
end

-- 获取私钥的PEM格式
local pkey_pem, err = pkey:to_PEM("private")
if not pkey_pem then
    ngx.log(ngx.ERR, "failed to get pkey PEM: ", err)
    return
end

end return _M

local cert_pem, key_pem = generateCert("www.test.com") -- Save to files -- local cert_file = io.open("generated_cert1.pem", "w") -- cert_file:write(cert_pem) -- cert_file:close() -- -- local key_file = io.open("generated_key2.pem", "w") -- key_file:write(pkey_pem) -- key_file:close()

I am is ok