Skip to content

Commit

Permalink
feat(x509.altname) support set and get IP addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
fffonion committed Oct 13, 2022
1 parent 6bb233c commit 845dced
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 46 deletions.
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:sb@sb.local,IP.1:1.2.3.4,DNS:example.com,email:test@test.com,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:sb@sb.local,IP.1:255.255.255.255,IP.2:1111:1111:1111:1111:1111:1111:1111:1111,DNS:example.com,email:test@test.com,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:test@test.com
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]

0 comments on commit 845dced

Please sign in to comment.