snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
This commit is contained in:
154
tests/prosody/lua/jwk_spec.lua
Normal file
154
tests/prosody/lua/jwk_spec.lua
Normal file
@@ -0,0 +1,154 @@
|
||||
-- Unit tests for token/jwk.lib.lua
|
||||
-- Run with busted from resources/prosody-plugins/:
|
||||
-- busted spec/lua/
|
||||
-- Requires: basexx (luarocks install basexx)
|
||||
|
||||
-- dofile resolves relative to CWD, so run from resources/prosody-plugins/.
|
||||
-- The module sets ASN1, base64_encode, and base64url_decode as globals.
|
||||
local M = dofile("token/jwk.lib.lua")
|
||||
local ASN1 = M.ASN1
|
||||
|
||||
describe("jwk.lib", function()
|
||||
|
||||
describe("ASN1", function()
|
||||
|
||||
describe("encode_length", function()
|
||||
it("encodes single-byte length for 0", function()
|
||||
assert.equal(string.char(0x00), ASN1.encode_length(0))
|
||||
end)
|
||||
|
||||
it("encodes single-byte length for 127", function()
|
||||
assert.equal(string.char(0x7F), ASN1.encode_length(127))
|
||||
end)
|
||||
|
||||
it("encodes two-byte form for 128", function()
|
||||
assert.equal(string.char(0x81, 0x80), ASN1.encode_length(128))
|
||||
end)
|
||||
|
||||
it("encodes two-byte form for 255", function()
|
||||
assert.equal(string.char(0x81, 0xFF), ASN1.encode_length(255))
|
||||
end)
|
||||
|
||||
it("encodes three-byte form for 256", function()
|
||||
assert.equal(string.char(0x82, 0x01, 0x00), ASN1.encode_length(256))
|
||||
end)
|
||||
|
||||
it("encodes three-byte form for 65535", function()
|
||||
assert.equal(string.char(0x82, 0xFF, 0xFF), ASN1.encode_length(65535))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("encode_null", function()
|
||||
it("returns NULL tag (0x05) with zero length", function()
|
||||
assert.equal(string.char(0x05, 0x00), ASN1.encode_null())
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("encode_integer", function()
|
||||
it("tags with 0x02 and does not pad when high bit is clear", function()
|
||||
assert.equal(string.char(0x02, 0x01, 0x7F), ASN1.encode_integer(string.char(0x7F)))
|
||||
end)
|
||||
|
||||
it("prepends 0x00 when high bit is set to indicate positive number", function()
|
||||
assert.equal(string.char(0x02, 0x02, 0x00, 0x80), ASN1.encode_integer(string.char(0x80)))
|
||||
end)
|
||||
|
||||
it("prepends 0x00 when first byte is 0xFF", function()
|
||||
assert.equal(string.char(0x02, 0x02, 0x00, 0xFF), ASN1.encode_integer(string.char(0xFF)))
|
||||
end)
|
||||
|
||||
it("handles multi-byte integer without high bit", function()
|
||||
assert.equal(string.char(0x02, 0x02, 0x01, 0x00), ASN1.encode_integer(string.char(0x01, 0x00)))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("encode_sequence", function()
|
||||
it("wraps content with SEQUENCE tag 0x30", function()
|
||||
assert.equal(string.char(0x30, 0x02, 0xAB, 0xCD), ASN1.encode_sequence(string.char(0xAB, 0xCD)))
|
||||
end)
|
||||
|
||||
it("handles empty content", function()
|
||||
assert.equal(string.char(0x30, 0x00), ASN1.encode_sequence(""))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("encode_bit_string", function()
|
||||
it("wraps with BIT STRING tag (0x03) and prepends unused-bits byte (0x00)", function()
|
||||
-- tag=0x03, length=2 (0x00 + one content byte), 0x00 unused bits, 0xAB
|
||||
assert.equal(string.char(0x03, 0x02, 0x00, 0xAB), ASN1.encode_bit_string(string.char(0xAB)))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("encode_oid", function()
|
||||
it("wraps bytes with OID tag 0x06", function()
|
||||
local oid_bytes = string.char(0x2A, 0x86, 0x48)
|
||||
assert.equal(string.char(0x06, 0x03) .. oid_bytes, ASN1.encode_oid(oid_bytes))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("der_to_pem", function()
|
||||
it("wraps DER bytes in PEM format with default PUBLIC KEY label", function()
|
||||
local der = string.char(0x30, 0x00)
|
||||
local pem = ASN1.der_to_pem(der)
|
||||
assert.truthy(pem:match("^-----BEGIN PUBLIC KEY-----\n"))
|
||||
assert.truthy(pem:match("-----END PUBLIC KEY-----\n$"))
|
||||
end)
|
||||
|
||||
it("uses custom label when provided", function()
|
||||
local der = string.char(0x30, 0x00)
|
||||
local pem = ASN1.der_to_pem(der, "RSA PUBLIC KEY")
|
||||
assert.truthy(pem:match("^-----BEGIN RSA PUBLIC KEY-----\n"))
|
||||
assert.truthy(pem:match("-----END RSA PUBLIC KEY-----\n$"))
|
||||
end)
|
||||
|
||||
it("breaks base64 into 64-character lines", function()
|
||||
-- 48 bytes of DER = 64 chars of base64 (exactly one line)
|
||||
local der = string.rep(string.char(0x00), 48)
|
||||
local pem = ASN1.der_to_pem(der)
|
||||
-- Should have exactly one data line between the markers
|
||||
local data = pem:match("-----BEGIN PUBLIC KEY-----\n(.-)\n-----END PUBLIC KEY-----")
|
||||
assert.falsy(data:match("\n")) -- no newline = single line
|
||||
assert.equal(64, #data)
|
||||
end)
|
||||
end)
|
||||
|
||||
end) -- ASN1
|
||||
|
||||
describe("jwk_to_pem", function()
|
||||
-- Test vectors computed independently with Python's cryptography primitives.
|
||||
-- n=0x0F (15), e=0x03 (3) — minimal key with no high-bit padding needed.
|
||||
it("converts a minimal RSA JWK (no 0x00 padding) to PEM", function()
|
||||
local pem = M.jwk_to_pem({ n = "Dw", e = "Aw" })
|
||||
local expected = "-----BEGIN PUBLIC KEY-----\n"
|
||||
.. "MBowDQYJKoZIhvcNAQEBBQADCQAwBgIBDwIBAw==\n"
|
||||
.. "-----END PUBLIC KEY-----\n"
|
||||
assert.equal(expected, pem)
|
||||
end)
|
||||
|
||||
-- n=0x8001, e=65537 — modulus has high bit set, so ASN.1 must prepend 0x00.
|
||||
it("converts a JWK with high-bit modulus (requires 0x00 padding) to PEM", function()
|
||||
local pem = M.jwk_to_pem({ n = "gAE", e = "AQAB" })
|
||||
local expected = "-----BEGIN PUBLIC KEY-----\n"
|
||||
.. "MB4wDQYJKoZIhvcNAQEBBQADDQAwCgIDAIABAgMBAAE=\n"
|
||||
.. "-----END PUBLIC KEY-----\n"
|
||||
assert.equal(expected, pem)
|
||||
end)
|
||||
|
||||
it("output begins and ends with correct PEM markers", function()
|
||||
local pem = M.jwk_to_pem({ n = "Dw", e = "Aw" })
|
||||
assert.truthy(pem:match("^-----BEGIN PUBLIC KEY-----\n"))
|
||||
assert.truthy(pem:match("-----END PUBLIC KEY-----\n$"))
|
||||
end)
|
||||
|
||||
it("returns nil when n is missing", function()
|
||||
local pem = M.jwk_to_pem({ e = "Aw" })
|
||||
assert.is_nil(pem)
|
||||
end)
|
||||
|
||||
it("returns nil when e is missing", function()
|
||||
local pem = M.jwk_to_pem({ n = "Dw" })
|
||||
assert.is_nil(pem)
|
||||
end)
|
||||
end) -- jwk_to_pem
|
||||
|
||||
end) -- jwk.lib
|
||||
Reference in New Issue
Block a user