Comparison

mod_push2/mod_push2.lua @ 6033:8cb37a497e4c

mod_push2: Switch from patched luaossl to prosody-trunk methods
author Stephen Paul Weber <singpolyma@singpolyma.net>
date Fri, 01 Nov 2024 11:07:23 -0500
parent 5998:fd1927e51791
child 6034:b4bf44765ce6
comparison
equal deleted inserted replaced
6032:a9fe4a50f935 6033:8cb37a497e4c
4 local hashes = require"util.hashes"; 4 local hashes = require"util.hashes";
5 local random = require"util.random"; 5 local random = require"util.random";
6 local watchdog = require "util.watchdog"; 6 local watchdog = require "util.watchdog";
7 local uuid = require "util.uuid"; 7 local uuid = require "util.uuid";
8 local base64 = require "util.encodings".base64; 8 local base64 = require "util.encodings".base64;
9 local ciphers = require "openssl.cipher"; 9 local crypto = require "util.crypto";
10 local pkey = require "openssl.pkey";
11 local kdf = require "openssl.kdf";
12 local jwt = require "util.jwt"; 10 local jwt = require "util.jwt";
13 11
14 local xmlns_push = "urn:xmpp:push2:0"; 12 local xmlns_push = "urn:xmpp:push2:0";
15 13
16 -- configuration 14 -- configuration
235 envelope:text_tag("rpad", base64.encode(random.bytes(math.min(150, max_data_size/3 - string.len(envelope_bytes))))) 233 envelope:text_tag("rpad", base64.encode(random.bytes(math.min(150, max_data_size/3 - string.len(envelope_bytes)))))
236 envelope_bytes = tostring(envelope) 234 envelope_bytes = tostring(envelope)
237 end 235 end
238 236
239 local p256dh_raw = base64.decode(match.ua_public .. "==") 237 local p256dh_raw = base64.decode(match.ua_public .. "==")
240 local p256dh = pkey.new(p256dh_raw, "*", "public", "prime256v1") 238 local p256dh = crypto.import_public_ec_raw(p256dh_raw, "prime256v1")
241 local one_time_key = pkey.new({ type = "EC", curve = "prime256v1" }) 239 local one_time_key = crypto.generate_p256_keypair()
242 local one_time_key_public = one_time_key:getParameters().pub_key:toBinary() 240 local one_time_key_public = one_time_key:public_raw()
243 local info = "WebPush: info\0" .. p256dh_raw .. one_time_key_public 241 local info = "WebPush: info\0" .. p256dh_raw .. one_time_key_public
244 local auth_secret = base64.decode(match.auth_secret .. "==") 242 local auth_secret = base64.decode(match.auth_secret .. "==")
245 local salt = random.bytes(16) 243 local salt = random.bytes(16)
246 local shared_secret = one_time_key:derive(p256dh) 244 local shared_secret = one_time_key:derive(p256dh)
247 local ikm = kdf.derive({ 245 local ikm = hashes.hkdf_hmac_sha256(32, shared_secret, auth_secret, info)
248 type = "HKDF", 246 local key = hashes.hkdf_hmac_sha256(16, ikm, salt, "Content-Encoding: aes128gcm\0")
249 outlen = 32, 247 local nonce = hashes.hkdf_hmac_sha256(12, ikm, salt, "Content-Encoding: nonce\0")
250 salt = auth_secret,
251 key = shared_secret,
252 info = info,
253 md = "sha256"
254 })
255 local key = kdf.derive({
256 type = "HKDF",
257 outlen = 16,
258 salt = salt,
259 key = ikm,
260 info = "Content-Encoding: aes128gcm\0",
261 md = "sha256"
262 })
263 local nonce = kdf.derive({
264 type = "HKDF",
265 outlen = 12,
266 salt = salt,
267 key = ikm,
268 info = "Content-Encoding: nonce\0",
269 md = "sha256"
270 })
271 local header = salt .. "\0\0\16\0" .. string.char(string.len(one_time_key_public)) .. one_time_key_public 248 local header = salt .. "\0\0\16\0" .. string.char(string.len(one_time_key_public)) .. one_time_key_public
272 local encryptor = ciphers.new("AES-128-GCM"):encrypt(key, nonce) 249 local encrypted = crypto.aes_128_gcm_encrypt(key, nonce, envelope_bytes .. "\2")
273 250
274 push_notification_payload 251 push_notification_payload
275 :tag("encrypted", { xmlns = "urn:xmpp:sce:rfc8291:0" }) 252 :tag("encrypted", { xmlns = "urn:xmpp:sce:rfc8291:0" })
276 :text_tag("payload", base64.encode(header .. encryptor:final(envelope_bytes .. "\2") .. encryptor:getTag(16))) 253 :text_tag("payload", base64.encode(header .. encrypted))
277 :up() 254 :up()
278 end 255 end
279 256
280 local function add_rfc8292(match, stanza, push_notification_payload) 257 local function add_rfc8292(match, stanza, push_notification_payload)
281 if not match.jwt_alg then return; end 258 if not match.jwt_alg then return; end
283 if match.jwt_alg ~= "HS256" then 260 if match.jwt_alg ~= "HS256" then
284 -- keypairs are in PKCS#8 PEM format without header/footer 261 -- keypairs are in PKCS#8 PEM format without header/footer
285 key = "-----BEGIN PRIVATE KEY-----\n"..key.."\n-----END PRIVATE KEY-----" 262 key = "-----BEGIN PRIVATE KEY-----\n"..key.."\n-----END PRIVATE KEY-----"
286 end 263 end
287 264
288 local public_key = pkey.new(key):getParameters().pub_key:toBinary() 265 local public_key = crypto.import_private_pem(key):public_raw()
289 local signer = jwt.new_signer(match.jwt_alg, key) 266 local signer = jwt.new_signer(match.jwt_alg, key)
290 local payload = {} 267 local payload = {}
291 for k, v in pairs(match.jwt_claims or {}) do 268 for k, v in pairs(match.jwt_claims or {}) do
292 payload[k] = v 269 payload[k] = v
293 end 270 end