Software / code / prosody-modules
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 |