Created
May 16, 2018 18:24
-
-
Save tateisu/18e9807dfb8779c247d6297bcf445686 to your computer and use it in GitHub Desktop.
verifing WebPush JWT on node.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict" | |
const util=require('util') | |
const jwt=require('jsonwebtoken') | |
const asn = require('asn1.js'); | |
// const fs = require('fs') | |
// ECDSA public key ASN.1 format | |
const ECPublicKey = asn.define("PublicKey", function() { | |
this.seq().obj( | |
this.key("algorithm").seq().obj( | |
this.key("id").objid(), | |
this.key("curve").objid() | |
), | |
this.key("pub").bitstr() | |
); | |
}); | |
// convert public key from p256ecdsa to PEM | |
function getPemFromPublicKey(public_key){ | |
return ECPublicKey.encode({ | |
algorithm: { | |
id: [1, 2, 840, 10045, 2, 1], // :id-ecPublicKey | |
curve: [1,2,840,10045,3,1,7] // prime256v1 | |
}, | |
pub: { | |
// このunused により bitstringの先頭に 00 が置かれる。 | |
// 先頭の00 04 が uncompressed を示す | |
// https://tools.ietf.org/html/rfc5480#section-2.3.2 | |
// http://www.secg.org/sec1-v2.pdf section 2.3.3 | |
unused: 0, | |
data: public_key, | |
}, | |
}, "pem", {label: "PUBLIC KEY"}) | |
} | |
function decodeBase64(src){ | |
return new Buffer(src,'base64') | |
} | |
// test data | |
const auth_header = "WebPush eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJodHRwczovL21hc3RvZG9uLW1zZy5qdWdnbGVyLmpwIiwiZXhwIjoxNTI2NTU5OTg2LCJzdWIiOiJtYWlsdG86dGF0ZWlzdUBnbWFpbC5jb20ifQ.h8p58F3MmbXUSQKyxoQSWG8Qu8EJoJqykbnPXuOcyeImlfe4uHKhpUYrK-mPH5lx_Adoz_t522UHYSqadgPHRA" | |
const crypto_key = "dh=BBjDnasYpkCkA1EmvOGO0AhH_CDlMrv1Os0SLH9ynjuPxeZ6XVbC-RZSyEv_T14FA2zs3YnWqKFnX8XpbyLQRPg;p256ecdsa=BLzIgsz-VRhTxuVgNoQljTwAFzxbanfGxNk8tldaruBztvsK9elES_2lE_8c91-RNOInEBEFUrCzDw-60bzUCr8" | |
const reAuthorizationWebPush = new RegExp("^WebPush\\s+(\\S+)") | |
const reCryptoKeySignPublicKey = new RegExp("p256ecdsa=([^;\\s]+)") | |
let m = reAuthorizationWebPush.exec( auth_header ) | |
if( !m ){ | |
console.log("header not match: Authorization") | |
}else{ | |
const token = m[1] | |
m = reCryptoKeySignPublicKey.exec(crypto_key) | |
if( !m ){ | |
console.log("header not match: Crypto-Key") | |
}else{ | |
const public_key = decodeBase64(m[1]) | |
const pem = getPemFromPublicKey(public_key) | |
// fs.writeFileSync("./public2.pem", pem + "\n"); | |
const decoded = jwt.verify(token, Buffer.from(pem), { algorithms: ['ES256'] }) | |
console.log(decoded) | |
// { aud: 'https://mastodon-msg.juggler.jp',exp: 1526559986,sub: 'mailto:tateisu@gmail.com' } | |
// error case | |
try{ | |
const decoded2 = jwt.verify(token+"xxx", Buffer.from(pem), { algorithms: ['ES256'] }) | |
}catch(err){ | |
console.log(`verify failed: ${err}`) | |
// verify failed: JsonWebTokenError: invalid token | |
} | |
} | |
} | |
/* | |
JWTトークンの署名の検証 | |
(1) openSSLで作成したPEMファイルで署名の作成と検証 | |
(2) 公開鍵をp256ecdsaバイトデータからPEMフォーマットに変換 | |
// jsonwebtoken はPEMファイルがあればjwtのエンコードとデコード(署名検証)ができる | |
// openssl ecparam -genkey -name prime256v1 -noout -out private.pem | |
// openssl ec -in private.pem -pubout -out public.pem | |
var priv = fs.readFileSync('./private.pem') | |
var token = jwt.sign("{ foo: 'bar' }", priv, { algorithm: 'ES256' }) | |
console.log(token) | |
var pub = fs.readFileSync('./public.pem') | |
var decoded = jwt.verify(token, pub, { algorithms: ['ES256'] }) | |
console.log(decoded) | |
dump of pem file | |
$ openssl asn1parse -in public.pem -dump | |
0:d=0 hl=2 l= 89 cons: SEQUENCE | |
2:d=1 hl=2 l= 19 cons: SEQUENCE | |
4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey | |
13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 | |
23:d=1 hl=2 l= 66 prim: BIT STRING | |
0000 - 00 04 e0 a5 f8 06 b7 0a-05 cc fa 97 06 cb f8 04 ................ | |
0010 - 0c 1b e3 52 13 3d bb a9-de 74 7d 25 ac 7b 39 d0 ...R.=...t}%.{9. | |
0020 - e1 e6 ee 3a 96 47 9f be-41 ae c2 ff d0 36 53 43 ...:.G..A....6SC | |
0030 - 88 e6 5d f7 a4 09 32 13-d6 57 e5 91 3f 5d d6 70 ..]...2..W..?].p | |
0040 - 07 c2 | |
d:depth | |
hl:header length (tag and length octets) of the current type. | |
l: length of the contents octets. | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment