Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(x509.altname) support set and get IP addresses #74

Merged
merged 1 commit into from
Oct 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3209,6 +3209,8 @@ Adds a name to altname stack, first argument is case-insensitive and can be one
URI
DNSName
DNS
IP
IPAddress

This function can be called multiple times in a chained fashion.

Expand Down
2 changes: 2 additions & 0 deletions lib/resty/openssl/include/asn1.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ ffi.cdef [[
int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v);

int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v);

int ASN1_STRING_length(const ASN1_STRING *x);
]]

local function declare_asn1_functions(typ, has_ex)
Expand Down
38 changes: 36 additions & 2 deletions lib/resty/openssl/x509/altname.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,25 @@ local dup = stack_lib.dup_of(STACK)

local types = altname_macro.types

local AF_INET = 2
local AF_INET6 = 10
if ffi.os == "OSX" then
AF_INET6 = 30
elseif ffi.os == "BSD" then
AF_INET6 = 28
elseif ffi.os == "Windows" then
AF_INET6 = 23
end

ffi.cdef [[
typedef int socklen_t;
int inet_pton(int af, const char *restrict src, void *restrict dst);
const char *inet_ntop(int af, const void *restrict src,
char *restrict dst, socklen_t size);
]]

local ip_buffer = ffi.new("unsigned char [46]") -- 46 bytes enough for both string ipv6 and binary ipv6

-- similar to GENERAL_NAME_print, but returns value instead of print
local gn_decode = function(ctx)
local typ = ctx.type
Expand All @@ -42,7 +61,13 @@ local gn_decode = function(ctx)
elseif typ == types.URI then
v = ffi_str(asn1_macro.ASN1_STRING_get0_data(ctx.d.uniformResourceIdentifier))
elseif typ == types.IP then
v = "IP:<unsupported>"
v = asn1_macro.ASN1_STRING_get0_data(ctx.d.iPAddress)
local l = tonumber(C.ASN1_STRING_length(ctx.d.iPAddress))
if l ~= 4 and l ~= 16 then
error("Unknown IP address type")
end
v = C.inet_ntop(l == 4 and AF_INET or AF_INET6, v, ip_buffer, 46)
v = ffi_str(v)
elseif typ == types.RID then
v = "RID:<unsupported>"
else
Expand Down Expand Up @@ -119,7 +144,16 @@ local function gn_set(gn, typ, value)
return "x509.altname:gn_set: unknown type " .. typ
end

if gn_type ~= types.Email and
if gn_type == types.IP then
if C.inet_pton(AF_INET, txt, ip_buffer) == 1 then
txt = ffi_str(ip_buffer, 4)
elseif C.inet_pton(AF_INET6, txt, ip_buffer) == 1 then
txt = ffi_str(ip_buffer, 16)
else
return "x509.altname:gn_set: invalid IP address " .. txt
end

elseif gn_type ~= types.Email and
gn_type ~= types.URI and
gn_type ~= types.DNS then
return "x509.altname:gn_set: setting type " .. typ .. " is currently not supported"
Expand Down
34 changes: 0 additions & 34 deletions t/fixtures/x509_sans.crt

This file was deleted.

53 changes: 43 additions & 10 deletions t/openssl/x509/altname.t
Original file line number Diff line number Diff line change
Expand Up @@ -178,17 +178,18 @@ DNS example.com
location =/t {
content_by_lua_block {
local x509 = require("resty.openssl.x509")
--[[
openssl req -x509 -nodes -newkey rsa:4096 -keyout x509_sans.key -out x509_sans.cer -days 36500 \
-subj '/OU=EFS File Encryption Certificate/L=EFS/CN=efs' \
-addext 'extendedKeyUsage=1.3.6.1.4.1.311.10.3.4.1' -addext 'basicConstraints=CA:FALSE' \
-addext 'subjectAltName=otherName:msUPN;UTF8:[email protected],IP.1:1.2.3.4,DNS:example.com,email:[email protected],RID:1.2.3.4'
]]--
local x = myassert(x509.new(io.open("t/fixtures/x509_sans.crt"):read("*a")))

local c = myassert(x:get_subject_alt_name())
local extension = require "resty.openssl.x509.extension"

for k, v in pairs(c) do
local ext, err = myassert(extension.new("subjectAltName", "otherName:msUPN;UTF8:[email protected],IP.1:255.255.255.255,IP.2:1111:1111:1111:1111:1111:1111:1111:1111,DNS:example.com,email:[email protected],RID:1.2.3.4"))

local c = x509.new()

myassert(c:add_extension(ext))

local alts = myassert(c:get_subject_alt_name())

for k, v in pairs(alts) do
ngx.say(k, ":", v)
end
}
Expand All @@ -197,9 +198,41 @@ DNS example.com
GET /t
--- response_body
OtherName:OtherName:<unsupported>
IP:IP:<unsupported>
IP:255.255.255.255
IP:1111:1111:1111:1111:1111:1111:1111:1111
DNS:example.com
email:[email protected]
RID:RID:<unsupported>
--- no_error_log
[error]

=== TEST 8: IP addresses are validated and parsed
--- http_config eval: $::HttpConfig
--- config
location =/t {
content_by_lua_block {
local altname = require("resty.openssl.x509.altname")
local c = myassert(altname.new())

myassert(c:add("IP", "1.2.3.4"))
myassert(c:add("IPAddress", "100.100.100.100"))
myassert(c:add("IP", "255.255.255.255"))
myassert(c:add("IP", "::1"))
myassert(c:add("IP", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))
for _, v in ipairs({"1", ":::", "ffff:", "256.1.1.1"}) do
local _, err = c:add("IP", v)
if err == nil then
ngx.say("should error on " .. v)
end
end

ngx.say(c:tostring())

}
}
--- request
GET /t
--- response_body
IP=1.2.3.4/IP=100.100.100.100/IP=255.255.255.255/IP=::1/IP=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
--- no_error_log
[error]