1 /* jws-3.3.12 (c) 2013-2022 Kenji Urushima | kjur.github.io/jsrsasign/license 2 */ 3 /* 4 * jws.js - JSON Web Signature(JWS) and JSON Web Token(JWT) Class 5 * 6 * Copyright (c) 2010-2022 Kenji Urushima (kenji.urushima@gmail.com) 7 * 8 * This software is licensed under the terms of the MIT License. 9 * https://kjur.github.io/jsrsasign/license/ 10 * 11 * The above copyright and license notice shall be 12 * included in all copies or substantial portions of the Software. 13 */ 14 15 /** 16 * @fileOverview 17 * @name jws-3.3.js 18 * @author Kenji Urushima kenji.urushima@gmail.com 19 * @version jsrsasign 10.5.25 jws 3.3.12 (2022-Jun-23) 20 * @since jsjws 1.0, jsrsasign 4.8.0 21 * @license <a href="https://kjur.github.io/jsrsasign/license/">MIT License</a> 22 */ 23 24 if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; 25 26 /** 27 * kjur's JSON Web Signature/Token(JWS/JWT) library name space 28 * <p> 29 * This namespace privides following JWS/JWS related classes. 30 * <ul> 31 * <li>{@link KJUR.jws.JWS} - JSON Web Signature/Token(JWS/JWT) class</li> 32 * <li>{@link KJUR.jws.JWSJS} - JWS JSON Serialization(JWSJS) class</li> 33 * <li>{@link KJUR.jws.IntDate} - UNIX origin time utility class</li> 34 * </ul> 35 * NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2. 36 * </p> 37 * @name KJUR.jws 38 * @namespace 39 */ 40 if (typeof KJUR.jws == "undefined" || !KJUR.jws) KJUR.jws = {}; 41 42 /** 43 * JSON Web Signature(JWS) class.<br/> 44 * @name KJUR.jws.JWS 45 * @class JSON Web Signature(JWS) class 46 * @see <a href="https://kjur.github.io/jsjws/">'jwjws'(JWS JavaScript Library) home page https://kjur.github.io/jsjws/</a> 47 * @see <a href="https://kjur.github.io/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page https://kjur.github.io/jsrsasign/</a> 48 * @see <a href="http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-14">IETF I-D JSON Web Algorithms (JWA)</a> 49 * @since jsjws 1.0 50 * @description 51 * This class provides JSON Web Signature(JWS)/JSON Web Token(JWT) signing and validation. 52 * 53 * <h4>METHOD SUMMARY</h4> 54 * Here is major methods of {@link KJUR.jws.JWS} class. 55 * <ul> 56 * <li><b>SIGN</b><br/> 57 * <li>{@link KJUR.jws.JWS.sign} - sign JWS</li> 58 * </li> 59 * <li><b>VERIFY</b><br/> 60 * <li>{@link KJUR.jws.JWS.verify} - verify JWS signature</li> 61 * <li>{@link KJUR.jws.JWS.verifyJWT} - verify properties of JWT token at specified time</li> 62 * </li> 63 * <li><b>UTILITY</b><br/> 64 * <li>{@link KJUR.jws.JWS.getJWKthumbprint} - get RFC 7638 JWK thumbprint</li> 65 * <li>{@link KJUR.jws.JWS.isSafeJSONString} - check whether safe JSON string or not</li> 66 * <li>{@link KJUR.jws.JWS.readSafeJSONString} - read safe JSON string only</li> 67 * </li> 68 * </ul> 69 * 70 * <h4>SUPPORTED SIGNATURE ALGORITHMS</h4> 71 * Here is supported algorithm names for {@link KJUR.jws.JWS.sign} and 72 * {@link KJUR.jws.JWS.verify} methods. 73 * <table> 74 * <tr><th>alg value</th><th>spec requirement</th><th>jsjws support</th></tr> 75 * <tr><td>HS256</td><td>REQUIRED</td><td>SUPPORTED</td></tr> 76 * <tr><td>HS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 77 * <tr><td>HS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 78 * <tr><td>RS256</td><td>RECOMMENDED</td><td>SUPPORTED</td></tr> 79 * <tr><td>RS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 80 * <tr><td>RS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 81 * <tr><td>ES256</td><td>RECOMMENDED+</td><td>SUPPORTED</td></tr> 82 * <tr><td>ES384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 83 * <tr><td>ES512</td><td>OPTIONAL</td><td>-</td></tr> 84 * <tr><td>PS256</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 85 * <tr><td>PS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 86 * <tr><td>PS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 87 * <tr><td>none</td><td>REQUIRED</td><td>SUPPORTED(signature generation only)</td></tr> 88 * </table> 89 * <dl> 90 * <dt><b>NOTE1</b> 91 * <dd>HS384 is supported since jsjws 3.0.2 with jsrsasign 4.1.4. 92 * <dt><b>NOTE2</b> 93 * <dd>Some deprecated methods have been removed since jws 3.3 of jsrsasign 4.10.0. 94 * Removed methods are following: 95 * <ul> 96 * <li>JWS.verifyJWSByNE</li> 97 * <li>JWS.verifyJWSByKey</li> 98 * <li>JWS.generateJWSByNED</li> 99 * <li>JWS.generateJWSByKey</li> 100 * <li>JWS.generateJWSByP1PrvKey</li> 101 * </ul> 102 * </dl> 103 * <b>EXAMPLE</b><br/> 104 * @example 105 * // JWS signing 106 * sJWS = KJUR.jws.JWS.sign(null, '{"alg":"HS256", "cty":"JWT"}', '{"age": 21}', {"utf8": "password"}); 107 * // JWS validation 108 * isValid = KJUR.jws.JWS.verify('eyJjdHkiOiJKV1QiLCJhbGc...', {"utf8": "password"}); 109 * // JWT validation 110 * isValid = KJUR.jws.JWS.verifyJWT('eyJh...', {"utf8": "password"}, { 111 * alg: ['HS256', 'HS384'], 112 * iss: ['http://foo.com'] 113 * }); 114 */ 115 KJUR.jws.JWS = function() { 116 var _KJUR = KJUR, 117 _KJUR_jws_JWS = _KJUR.jws.JWS, 118 _isSafeJSONString = _KJUR_jws_JWS.isSafeJSONString; 119 120 // === utility ============================================================= 121 122 /** 123 * parse JWS string and set public property 'parsedJWS' dictionary.<br/> 124 * @name parseJWS 125 * @memberOf KJUR.jws.JWS 126 * @function 127 * @param {String} sJWS JWS signature string to be parsed. 128 * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". 129 * @throws if JWS Header is a malformed JSON string. 130 * @since jws 1.1 131 */ 132 this.parseJWS = function(sJWS, sigValNotNeeded) { 133 if ((this.parsedJWS !== undefined) && 134 (sigValNotNeeded || (this.parsedJWS.sigvalH !== undefined))) { 135 return; 136 } 137 var matchResult = sJWS.match(/^([^.]+)\.([^.]+)\.([^.]+)$/); 138 if (matchResult == null) { 139 throw "JWS signature is not a form of 'Head.Payload.SigValue'."; 140 } 141 var b6Head = matchResult[1]; 142 var b6Payload = matchResult[2]; 143 var b6SigVal = matchResult[3]; 144 var sSI = b6Head + "." + b6Payload; 145 this.parsedJWS = {}; 146 this.parsedJWS.headB64U = b6Head; 147 this.parsedJWS.payloadB64U = b6Payload; 148 this.parsedJWS.sigvalB64U = b6SigVal; 149 this.parsedJWS.si = sSI; 150 151 if (!sigValNotNeeded) { 152 var hSigVal = b64utohex(b6SigVal); 153 var biSigVal = parseBigInt(hSigVal, 16); 154 this.parsedJWS.sigvalH = hSigVal; 155 this.parsedJWS.sigvalBI = biSigVal; 156 } 157 158 var sHead = b64utoutf8(b6Head); 159 var sPayload = b64utoutf8(b6Payload); 160 this.parsedJWS.headS = sHead; 161 this.parsedJWS.payloadS = sPayload; 162 163 if (! _isSafeJSONString(sHead, this.parsedJWS, 'headP')) 164 throw "malformed JSON string for JWS Head: " + sHead; 165 }; 166 }; 167 168 // === major static method ======================================================== 169 170 /** 171 * generate JWS signature by specified key<br/> 172 * @name sign 173 * @memberOf KJUR.jws.JWS 174 * @function 175 * @static 176 * @param {String} alg JWS algorithm name to sign and force set to sHead or null 177 * @param {String} spHead string or object of JWS Header 178 * @param {String} spPayload string or object of JWS Payload 179 * @param {String} key string of private key or mac key object to sign 180 * @param {String} pass (OPTION)passcode to use encrypted asymmetric private key 181 * @return {String} JWS signature string 182 * @since jws 3.0.0 183 * @see <a href="https://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Signature.html">jsrsasign KJUR.crypto.Signature method</a> 184 * @see <a href="https://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Mac.html">jsrsasign KJUR.crypto.Mac method</a> 185 * @description 186 * This method supports following algorithms. 187 * <table> 188 * <tr><th>alg value</th><th>spec requirement</th><th>jsjws support</th></tr> 189 * <tr><td>HS256</td><td>REQUIRED</td><td>SUPPORTED</td></tr> 190 * <tr><td>HS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 191 * <tr><td>HS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 192 * <tr><td>RS256</td><td>RECOMMENDED</td><td>SUPPORTED</td></tr> 193 * <tr><td>RS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 194 * <tr><td>RS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 195 * <tr><td>ES256</td><td>RECOMMENDED+</td><td>SUPPORTED</td></tr> 196 * <tr><td>ES384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 197 * <tr><td>ES512</td><td>OPTIONAL</td><td>-</td></tr> 198 * <tr><td>PS256</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 199 * <tr><td>PS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 200 * <tr><td>PS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr> 201 * <tr><td>none</td><td>REQUIRED</td><td>SUPPORTED(signature generation only)</td></tr> 202 * </table> 203 * <dl> 204 * <dt>NOTE1: 205 * <dd>salt length of RSAPSS signature is the same as the hash algorithm length 206 * because of <a href="http://www.ietf.org/mail-archive/web/jose/current/msg02901.html">IETF JOSE ML discussion</a>. 207 * <dt>NOTE2: 208 * <dd>To support HS384, patched version of CryptoJS is used. 209 * <a href="https://code.google.com/p/crypto-js/issues/detail?id=84">See here for detail</a>. 210 * <dt>NOTE3: 211 * From jsrsasign 4.10.0 jws 3.3.0, Way to provide password 212 * for HS* algorithm is changed. The 'key' attribute value is 213 * passed to {@link KJUR.crypto.Mac.setPassword} so please see 214 * {@link KJUR.crypto.Mac.setPassword} for detail. 215 * As for backword compatibility, if key is a string, has even length and 216 * 0..9, A-F or a-f characters, key string is treated as a hexadecimal 217 * otherwise it is treated as a raw string. 218 * <dd> 219 * </dl> 220 * <b>EXAMPLE</b><br/> 221 * @example 222 * // sign HS256 signature with password "aaa" implicitly handled as string 223 * sJWS = KJUR.jws.JWS.sign(null, {alg: "HS256", cty: "JWT"}, {age: 21}, "aaa"); 224 * // sign HS256 signature with password "6161" implicitly handled as hex 225 * sJWS = KJUR.jws.JWS.sign(null, {alg: "HS256", cty: "JWT"}, {age: 21}, "6161"); 226 * // sign HS256 signature with base64 password 227 * sJWS = KJUR.jws.JWS.sign(null, {alg: "HS256"}, {age: 21}, {b64: "Mi/8..a="}); 228 * // sign RS256 signature with PKCS#8 PEM RSA private key 229 * sJWS = KJUR.jws.JWS.sign(null, {alg: "RS256"}, {age: 21}, "-----BEGIN PRIVATE KEY..."); 230 * // sign RS256 signature with PKCS#8 PEM ECC private key with passcode 231 * sJWS = KJUR.jws.JWS.sign(null, {alg: "ES256"}, {age: 21}, 232 * "-----BEGIN PRIVATE KEY...", "keypass"); 233 * // header and payload can be passed by both string and object 234 * sJWS = KJUR.jws.JWS.sign(null, '{alg:"HS256",cty:"JWT"}', '{age:21}', "aaa"); 235 */ 236 KJUR.jws.JWS.sign = function(alg, spHeader, spPayload, key, pass) { 237 var _KJUR = KJUR, 238 _KJUR_jws = _KJUR.jws, 239 _KJUR_jws_JWS = _KJUR_jws.JWS, 240 _readSafeJSONString = _KJUR_jws_JWS.readSafeJSONString, 241 _isSafeJSONString = _KJUR_jws_JWS.isSafeJSONString, 242 _KJUR_crypto = _KJUR.crypto, 243 _ECDSA = _KJUR_crypto.ECDSA, 244 _Mac = _KJUR_crypto.Mac, 245 _Signature = _KJUR_crypto.Signature, 246 _JSON = JSON; 247 248 var sHeader, pHeader, sPayload; 249 250 // 1. check signatureInput(Header, Payload) is string or object 251 if (typeof spHeader != 'string' && typeof spHeader != 'object') 252 throw "spHeader must be JSON string or object: " + spHeader; 253 254 if (typeof spHeader == 'object') { 255 pHeader = spHeader; 256 sHeader = _JSON.stringify(pHeader); 257 } 258 259 if (typeof spHeader == 'string') { 260 sHeader = spHeader; 261 if (! _isSafeJSONString(sHeader)) 262 throw "JWS Head is not safe JSON string: " + sHeader; 263 pHeader = _readSafeJSONString(sHeader); 264 265 } 266 267 sPayload = spPayload; 268 if (typeof spPayload == 'object') sPayload = _JSON.stringify(spPayload); 269 270 // 2. use alg if defined in sHeader 271 if ((alg == '' || alg == null) && 272 pHeader['alg'] !== undefined) { 273 alg = pHeader['alg']; 274 } 275 276 // 3. update sHeader to add alg if alg undefined 277 if ((alg != '' && alg != null) && 278 pHeader['alg'] === undefined) { 279 pHeader['alg'] = alg; 280 sHeader = _JSON.stringify(pHeader); 281 } 282 283 // 4. check explicit algorithm doesn't match with JWS header. 284 if (alg !== pHeader.alg) 285 throw "alg and sHeader.alg doesn't match: " + alg + "!=" + pHeader.alg; 286 287 // 5. set signature algorithm like SHA1withRSA 288 var sigAlg = null; 289 if (_KJUR_jws_JWS.jwsalg2sigalg[alg] === undefined) { 290 throw "unsupported alg name: " + alg; 291 } else { 292 sigAlg = _KJUR_jws_JWS.jwsalg2sigalg[alg]; 293 } 294 295 var uHeader = utf8tob64u(sHeader); 296 var uPayload = utf8tob64u(sPayload); 297 var uSignatureInput = uHeader + "." + uPayload 298 // 6. sign 299 var hSig = ""; 300 if (sigAlg.substr(0, 4) == "Hmac") { 301 if (key === undefined) 302 throw "mac key shall be specified for HS* alg"; 303 //alert("sigAlg=" + sigAlg); 304 var mac = new _Mac({'alg': sigAlg, 'prov': 'cryptojs', 'pass': key}); 305 mac.updateString(uSignatureInput); 306 hSig = mac.doFinal(); 307 } else if (sigAlg.indexOf("withECDSA") != -1) { 308 var sig = new _Signature({'alg': sigAlg}); 309 sig.init(key, pass); 310 sig.updateString(uSignatureInput); 311 var hASN1Sig = sig.sign(); 312 hSig = KJUR.crypto.ECDSA.asn1SigToConcatSig(hASN1Sig); 313 } else if (sigAlg != "none") { 314 var sig = new _Signature({'alg': sigAlg}); 315 sig.init(key, pass); 316 sig.updateString(uSignatureInput); 317 hSig = sig.sign(); 318 } 319 320 var uSig = hextob64u(hSig); 321 return uSignatureInput + "." + uSig; 322 }; 323 324 /** 325 * verify JWS signature by specified key or certificate<br/> 326 * @name verify 327 * @memberOf KJUR.jws.JWS 328 * @function 329 * @static 330 * @param {String} sJWS string of JWS signature to verify 331 * @param {Object} key string of public key, certificate or key object to verify 332 * @param {String} acceptAlgs array of algorithm name strings (OPTION) 333 * @return {Boolean} true if the signature is valid otherwise false including no signature case or without head and payload 334 * @since jws 3.0.0 335 * @see <a href="https://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Signature.html">jsrsasign KJUR.crypto.Signature method</a> 336 * @see <a href="https://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Mac.html">jsrsasign KJUR.crypto.Mac method</a> 337 * @description 338 * <p> 339 * This method verifies a JSON Web Signature Compact Serialization string by the validation 340 * algorithm as described in 341 * <a href="http://self-issued.info/docs/draft-jones-json-web-signature-04.html#anchor5"> 342 * the section 5 of Internet Draft draft-jones-json-web-signature-04.</a> 343 * </p> 344 * <p> 345 * Since 3.2.0 strict key checking has been provided against a JWS algorithm 346 * in a JWS header. 347 * <ul> 348 * <li>In case 'alg' is 'HS*' in the JWS header, 349 * 'key' shall be hexadecimal string for Hmac{256,384,512} shared secret key. 350 * Otherwise it raise an error.</li> 351 * <li>In case 'alg' is 'RS*' or 'PS*' in the JWS header, 352 * 'key' shall be a RSAKey object or a PEM string of 353 * X.509 RSA public key certificate or PKCS#8 RSA public key. 354 * Otherwise it raise an error.</li> 355 * <li>In case 'alg' is 'ES*' in the JWS header, 356 * 'key' shall be a KJUR.crypto.ECDSA object or a PEM string of 357 * X.509 ECC public key certificate or PKCS#8 ECC public key. 358 * Otherwise it raise an error.</li> 359 * <li>In case 'alg' is 'none' in the JWS header, 360 * validation not supported after jsjws 3.1.0.</li> 361 * </ul> 362 * </p> 363 * <p> 364 * NOTE1: The argument 'acceptAlgs' is supported since 3.2.0. 365 * Strongly recommended to provide acceptAlgs to mitigate 366 * signature replacement attacks.<br/> 367 * </p> 368 * <p> 369 * NOTE2: From jsrsasign 4.9.0 jws 3.2.5, Way to provide password 370 * for HS* algorithm is changed. The 'key' attribute value is 371 * passed to {@link KJUR.crypto.Mac.setPassword} so please see 372 * {@link KJUR.crypto.Mac.setPassword} for detail. 373 * As for backword compatibility, if key is a string, has even length and 374 * 0..9, A-F or a-f characters, key string is treated as a hexadecimal 375 * otherwise it is treated as a raw string. 376 * </p> 377 * NOTE3: From jsrsasign 11.1.2, "crit" header parameter 378 * existance check processing is supported as defined in RFC 7515 section 4.1.11. 379 * However, you must implement the validation of the header parameter values 380 * specified as “crit” yourself. 381 * 382 * @example 383 * // 1) verify a RS256 JWS signature by a certificate string. 384 * isValid = KJUR.jws.JWS.verify('eyJh...', '-----BEGIN...', ['RS256']); 385 * 386 * // 2) verify a HS256 JWS signature by a certificate string. 387 * isValid = KJUR.jws.JWS.verify('eyJh...', {hex: '6f62ad...'}, ['HS256']); 388 * isValid = KJUR.jws.JWS.verify('eyJh...', {b64: 'Mi/ab8...a=='}, ['HS256']); 389 * isValid = KJUR.jws.JWS.verify('eyJh...', {utf8: 'Secret秘密'}, ['HS256']); 390 * isValid = KJUR.jws.JWS.verify('eyJh...', '6f62ad', ['HS256']); // implicit hex 391 * isValid = KJUR.jws.JWS.verify('eyJh...', '6f62ada', ['HS256']); // implicit raw string 392 * 393 * // 3) verify a ES256 JWS signature by a KJUR.crypto.ECDSA key object. 394 * var pubkey = KEYUTIL.getKey('-----BEGIN CERT...'); 395 * var isValid = KJUR.jws.JWS.verify('eyJh...', pubkey); 396 */ 397 KJUR.jws.JWS.verify = function(sJWS, key, acceptAlgs) { 398 var _KJUR = KJUR, 399 _KJUR_jws = _KJUR.jws, 400 _KJUR_jws_JWS = _KJUR_jws.JWS, 401 _readSafeJSONString = _KJUR_jws_JWS.readSafeJSONString, 402 _KJUR_crypto = _KJUR.crypto, 403 _ECDSA = _KJUR_crypto.ECDSA, 404 _Mac = _KJUR_crypto.Mac, 405 _Signature = _KJUR_crypto.Signature, 406 _RSAKey; 407 408 if (typeof RSAKey !== undefined) _RSAKey = RSAKey; 409 410 // 0. checking dot concatinatd Base64URL encoded string 411 if (! isBase64URLDot(sJWS)) return false; 412 413 var a = sJWS.split("."); 414 if (a.length !== 3) return false; 415 416 var uHeader = a[0]; 417 var uPayload = a[1]; 418 var uSignatureInput = uHeader + "." + uPayload; 419 var hSig = b64utohex(a[2]); 420 421 // 1. parse JWS header 422 var pHeader = _readSafeJSONString(b64utoutf8(a[0])); 423 var alg = null; 424 var algType = null; // HS|RS|PS|ES|no 425 if (pHeader.alg === undefined) { 426 throw "algorithm not specified in header"; 427 } else { 428 alg = pHeader.alg; 429 algType = alg.substr(0, 2); 430 } 431 432 // 2. check whether alg is acceptable algorithms 433 if (acceptAlgs != null && 434 Object.prototype.toString.call(acceptAlgs) === '[object Array]' && 435 acceptAlgs.length > 0) { 436 var acceptAlgStr = ":" + acceptAlgs.join(":") + ":"; 437 if (acceptAlgStr.indexOf(":" + alg + ":") == -1) { 438 throw "algorithm '" + alg + "' not accepted in the list"; 439 } 440 } 441 442 // 3. check whether key is a proper key for alg. 443 if (alg != "none" && key === null) { 444 throw "key shall be specified to verify."; 445 } 446 447 // 3.1. There is no key check for HS* because Mac will check it. 448 // since jsrsasign 5.0.0. 449 450 // 3.2. convert key object if key is a public key or cert PEM string 451 if (typeof key == "string" && 452 key.indexOf("-----BEGIN ") != -1) { 453 key = KEYUTIL.getKey(key); 454 } 455 456 // 3.3. check whether key is RSAKey obj if alg is RS* or PS*. 457 if (algType == "RS" || algType == "PS") { 458 if (!(key instanceof _RSAKey)) { 459 throw "key shall be a RSAKey obj for RS* and PS* algs"; 460 } 461 } 462 463 // 3.4. check whether key is ECDSA obj if alg is ES*. 464 if (algType == "ES") { 465 if (!(key instanceof _ECDSA)) { 466 throw "key shall be a ECDSA obj for ES* algs"; 467 } 468 } 469 470 // 3.5. check when alg is 'none' 471 if (alg == "none") { 472 } 473 474 // 4. check whether alg is supported alg in jsjws. 475 var sigAlg = null; 476 if (_KJUR_jws_JWS.jwsalg2sigalg[pHeader.alg] === undefined) { 477 throw new Error("unsupported alg name: " + alg); 478 } else { 479 sigAlg = _KJUR_jws_JWS.jwsalg2sigalg[alg]; 480 } 481 482 // 5. check critical header 483 if (pHeader.crit !== undefined) { 484 if (! Array.isArray(pHeader.crit) || pHeader.crit.length === 0) 485 throw new Error("wrong critical header"); 486 for (var i = 0; i < pHeader.crit.length; i++) { 487 var p = pHeader.crit[i]; 488 if (typeof p !== "string" || p.length === 0) 489 throw new Error("wrong critical header"); 490 if (pHeader[p] === undefined) 491 throw new Error("critical header '" + p + "' missing"); 492 } 493 } 494 495 // 6. verify signature 496 if (sigAlg == "none") { 497 throw new Error("not supported"); 498 } else if (sigAlg.substr(0, 4) == "Hmac") { 499 var hSig2 = null; 500 if (key === undefined) 501 throw new Error("hexadecimal key shall be specified for HMAC"); 502 var mac = new _Mac({'alg': sigAlg, 'pass': key}); 503 mac.updateString(uSignatureInput); 504 hSig2 = mac.doFinal(); 505 return timingSafeEqual(hSig, hSig2); 506 } else if (sigAlg.indexOf("withECDSA") != -1) { 507 var hASN1Sig = null; 508 try { 509 hASN1Sig = _ECDSA.concatSigToASN1Sig(hSig); 510 } catch (ex) { 511 return false; 512 } 513 var sig = new _Signature({'alg': sigAlg}); 514 sig.init(key) 515 sig.updateString(uSignatureInput); 516 return sig.verify(hASN1Sig); 517 } else { 518 var sig = new _Signature({'alg': sigAlg}); 519 sig.init(key) 520 sig.updateString(uSignatureInput); 521 return sig.verify(hSig); 522 } 523 }; 524 525 /** 526 * parse header and payload of JWS signature<br/> 527 * @name parse 528 * @memberOf KJUR.jws.JWS 529 * @function 530 * @static 531 * @param {String} sJWS string of JWS signature to parse 532 * @return {Array} associative array of parsed header and payload. See below. 533 * @throws if sJWS is malformed JWS signature 534 * @since jws 3.3.3 535 * @description 536 * This method parses JWS signature string. 537 * Resulted associative array has following properties: 538 * <ul> 539 * <li>headerObj - JSON object of header</li> 540 * <li>payloadObj - JSON object of payload if payload is JSON string otherwise undefined</li> 541 * <li>headerPP - pretty printed JSON header by stringify</li> 542 * <li>payloadPP - pretty printed JSON payload by stringify if payload is JSON otherwise Base64URL decoded raw string of payload</li> 543 * <li>sigHex - hexadecimal string of signature</li> 544 * </ul> 545 * @example 546 * KJUR.jws.JWS.parse(sJWS) -> 547 * { 548 * headerObj: {"alg": "RS256", "typ": "JWS"}, 549 * payloadObj: {"product": "orange", "quantity": 100}, 550 * headerPP: 551 * '{ 552 * "alg": "RS256", 553 * "typ": "JWS" 554 * }', 555 * payloadPP: 556 * '{ 557 * "product": "orange", 558 * "quantity": 100 559 * }', 560 * sigHex: "91f3cd..." 561 * } 562 */ 563 KJUR.jws.JWS.parse = function(sJWS) { 564 var a = sJWS.split("."); 565 var result = {}; 566 var uHeader, uPayload, uSig; 567 if (a.length != 2 && a.length != 3) 568 throw "malformed sJWS: wrong number of '.' splitted elements"; 569 570 uHeader = a[0]; 571 uPayload = a[1]; 572 if (a.length == 3) uSig = a[2]; 573 574 result.headerObj = KJUR.jws.JWS.readSafeJSONString(b64utoutf8(uHeader)); 575 result.payloadObj = KJUR.jws.JWS.readSafeJSONString(b64utoutf8(uPayload)); 576 577 result.headerPP = JSON.stringify(result.headerObj, null, " "); 578 if (result.payloadObj == null) { 579 result.payloadPP = b64utoutf8(uPayload); 580 } else { 581 result.payloadPP = JSON.stringify(result.payloadObj, null, " "); 582 } 583 584 if (uSig !== undefined) { 585 result.sigHex = b64utohex(uSig); 586 } 587 588 return result; 589 }; 590 591 /** 592 * @name verifyJWT 593 * @memberOf KJUR.jws.JWS 594 * @function 595 * @static 596 * @param {String} sJWT string of JSON Web Token(JWT) to verify 597 * @param {Object} key string of public key, certificate or key object to verify 598 * @param {Array} acceptField associative array of acceptable fields (OPTION) 599 * @return {Boolean} true if the JWT token is valid otherwise false 600 * @since jws 3.2.3 jsrsasign 4.8.0 601 * 602 * @description 603 * This method verifies a 604 * <a href="https://tools.ietf.org/html/rfc7519">RFC 7519</a> 605 * JSON Web Token(JWT). 606 * It will verify following: 607 * <ul> 608 * <li>Header.alg 609 * <ul> 610 * <li>alg is specified in JWT header.</li> 611 * <li>alg is included in acceptField.alg array. (MANDATORY)</li> 612 * <li>alg is proper for key.</li> 613 * </ul> 614 * </li> 615 * <li>Payload.iss (issuer) - Payload.iss is included in acceptField.iss array if specified. (OPTION)</li> 616 * <li>Payload.sub (subject) - Payload.sub is included in acceptField.sub array if specified. (OPTION)</li> 617 * <li>Payload.aud (audience) - Payload.aud is included in acceptField.aud array or 618 * the same as value if specified. (OPTION)</li> 619 * <li>Time validity 620 * <ul> 621 * <li> 622 * If acceptField.verifyAt as number of UNIX origin time is specifed for validation time, 623 * this method will verify at the time for it, otherwise current time will be used to verify. 624 * </li> 625 * <li> 626 * Clock of JWT generator or verifier can be fast or slow. If these clocks are 627 * very different, JWT validation may fail. To avoid such case, 'jsrsasign' supports 628 * 'acceptField.gracePeriod' parameter which specifies acceptable time difference 629 * of those clocks in seconds. So if you want to accept slow or fast in 2 hours, 630 * you can specify <code>acceptField.gracePeriod = 2 * 60 * 60;</code>. 631 * "gracePeriod" is zero by default. 632 * "gracePeriod" is supported since jsrsasign 5.0.12. 633 * </li> 634 * <li>Payload.exp (expire) - Validation time is smaller than Payload.exp + gracePeriod.</li> 635 * <li>Payload.nbf (not before) - Validation time is greater than Payload.nbf - gracePeriod.</li> 636 * <li>Payload.iat (issued at) - Validation time is greater than Payload.iat - gracePeriod.</li> 637 * </ul> 638 * </li> 639 * <li>Payload.jti (JWT id) - Payload.jti is included in acceptField.jti if specified. (OPTION)</li> 640 * <li>JWS signature of JWS is valid for specified key.</li> 641 * </ul> 642 * 643 * <h4>acceptField parameters</h4> 644 * Here is available acceptField argument parameters: 645 * <ul> 646 * <li>alg - array of acceptable signature algorithm names (ex. ["HS256", "HS384"])</li> 647 * <li>iss - array of acceptable issuer names (ex. ['http://foo.com'])</li> 648 * <li>sub - array of acceptable subject names (ex. ['mailto:john@foo.com'])</li> 649 * <li>aud - array of acceptable audience name (ex. ['http://foo.com'])</li> 650 * <li>jti - string of acceptable JWT ID (OPTION) (ex. 'id1234')</li> 651 * <li> 652 * verifyAt - time to verify 'nbf', 'iat' and 'exp' in UNIX seconds 653 * (OPTION) (ex. 1377663900). 654 * If this is not specified, current time of verifier will be used. 655 * {@link KJUR.jws.IntDate} may be useful to specify it. 656 * </li> 657 * <li>gracePeriod - acceptable time difference between signer and verifier 658 * in seconds (ex. 3600). If this is not specified, zero will be used.</li> 659 * </ul> 660 * 661 * @example 662 * // simple validation for HS256 663 * isValid = KJUR.jws.JWS.verifyJWT("eyJhbG...", "616161", {alg: ["HS256"]}), 664 * 665 * // full validation for RS or PS 666 * pubkey = KEYUTIL.getKey('-----BEGIN CERT...'); 667 * isValid = KJUR.jws.JWS.verifyJWT('eyJh...', pubkey, { 668 * alg: ['RS256', 'RS512', 'PS256', 'PS512'], 669 * iss: ['http://foo.com'], 670 * sub: ['mailto:john@foo.com', 'mailto:alice@foo.com'], 671 * verifyAt: KJUR.jws.IntDate.get('20150520235959Z'), 672 * aud: ['http://foo.com'], // aud: 'http://foo.com' is fine too. 673 * jti: 'id123456', 674 * gracePeriod: 1 * 60 * 60 // accept 1 hour slow or fast 675 * }); 676 */ 677 KJUR.jws.JWS.verifyJWT = function(sJWT, key, acceptField) { 678 var _KJUR = KJUR, 679 _KJUR_jws = _KJUR.jws, 680 _KJUR_jws_JWS = _KJUR_jws.JWS, 681 _readSafeJSONString = _KJUR_jws_JWS.readSafeJSONString, 682 _inArray = _KJUR_jws_JWS.inArray, 683 _includedArray = _KJUR_jws_JWS.includedArray; 684 685 // 0. checking dot concatinatd Base64URL encoded string 686 if (! isBase64URLDot(sJWT)) return false; 687 688 // 1. parse JWT 689 var a = sJWT.split("."); 690 if (a.length != 3) return false; 691 var uHeader = a[0]; 692 var uPayload = a[1]; 693 var uSignatureInput = uHeader + "." + uPayload; 694 var hSig = b64utohex(a[2]); 695 696 // 2. parse JWS header 697 var pHeader = _readSafeJSONString(b64utoutf8(uHeader)); 698 699 // 3. parse JWS payload 700 var pPayload = _readSafeJSONString(b64utoutf8(uPayload)); 701 702 // 4. algorithm ('alg' in header) check 703 if (pHeader.alg === undefined) return false; 704 if (acceptField.alg === undefined) 705 throw "acceptField.alg shall be specified"; 706 if (! _inArray(pHeader.alg, acceptField.alg)) return false; 707 708 // 5. issuer ('iss' in payload) check 709 if (pPayload.iss !== undefined && typeof acceptField.iss === "object") { 710 if (! _inArray(pPayload.iss, acceptField.iss)) return false; 711 } 712 713 // 6. subject ('sub' in payload) check 714 if (pPayload.sub !== undefined && typeof acceptField.sub === "object") { 715 if (! _inArray(pPayload.sub, acceptField.sub)) return false; 716 } 717 718 // 7. audience ('aud' in payload) check 719 if (pPayload.aud !== undefined && typeof acceptField.aud === "object") { 720 if (typeof pPayload.aud == "string") { 721 if (! _inArray(pPayload.aud, acceptField.aud)) 722 return false; 723 } else if (typeof pPayload.aud == "object") { 724 if (! _includedArray(pPayload.aud, acceptField.aud)) 725 return false; 726 } 727 } 728 729 // 8. time validity 730 // (nbf - gracePeriod < now < exp + gracePeriod) && (iat - gracePeriod < now) 731 var now = _KJUR_jws.IntDate.getNow(); 732 if (acceptField.verifyAt !== undefined && typeof acceptField.verifyAt === "number") { 733 now = acceptField.verifyAt; 734 } 735 if (acceptField.gracePeriod === undefined || 736 typeof acceptField.gracePeriod !== "number") { 737 acceptField.gracePeriod = 0; 738 } 739 740 // 8.1 expired time 'exp' check 741 if (pPayload.exp !== undefined && typeof pPayload.exp == "number") { 742 if (pPayload.exp + acceptField.gracePeriod < now) return false; 743 } 744 745 // 8.2 not before time 'nbf' check 746 if (pPayload.nbf !== undefined && typeof pPayload.nbf == "number") { 747 if (now < pPayload.nbf - acceptField.gracePeriod) return false; 748 } 749 750 // 8.3 issued at time 'iat' check 751 if (pPayload.iat !== undefined && typeof pPayload.iat == "number") { 752 if (now < pPayload.iat - acceptField.gracePeriod) return false; 753 } 754 755 // 9 JWT id 'jti' check 756 if (pPayload.jti !== undefined && acceptField.jti !== undefined) { 757 if (pPayload.jti !== acceptField.jti) return false; 758 } 759 760 // 10 JWS signature check 761 if (! _KJUR_jws_JWS.verify(sJWT, key, acceptField.alg)) return false; 762 763 // 11 passed all check 764 return true; 765 }; 766 767 /** 768 * check whether array is included by another array 769 * @name includedArray 770 * @memberOf KJUR.jws.JWS 771 * @function 772 * @static 773 * @param {Array} a1 check whether set a1 is included by a2 774 * @param {Array} a2 check whether set a1 is included by a2 775 * @return {Boolean} check whether set a1 is included by a2 776 * @since jws 3.2.3 777 * This method verifies whether an array is included by another array. 778 * It doesn't care about item ordering in a array. 779 * @example 780 * KJUR.jws.JWS.includedArray(['b'], ['b', 'c', 'a']) => true 781 * KJUR.jws.JWS.includedArray(['a', 'b'], ['b', 'c', 'a']) => true 782 * KJUR.jws.JWS.includedArray(['a', 'b'], ['b', 'c']) => false 783 */ 784 KJUR.jws.JWS.includedArray = function(a1, a2) { 785 var _inArray = KJUR.jws.JWS.inArray; 786 if (a1 === null) return false; 787 if (typeof a1 !== "object") return false; 788 if (typeof a1.length !== "number") return false; 789 790 for (var i = 0; i < a1.length; i++) { 791 if (! _inArray(a1[i], a2)) return false; 792 } 793 return true; 794 }; 795 796 /** 797 * check whether item is included by array 798 * @name inArray 799 * @memberOf KJUR.jws.JWS 800 * @function 801 * @static 802 * @param {String} item check whether item is included by array 803 * @param {Array} a check whether item is included by array 804 * @return {Boolean} check whether item is included by array 805 * @since jws 3.2.3 806 * This method verifies whether an item is included by an array. 807 * It doesn't care about item ordering in an array. 808 * @example 809 * KJUR.jws.JWS.inArray('b', ['b', 'c', 'a']) => true 810 * KJUR.jws.JWS.inArray('a', ['b', 'c', 'a']) => true 811 * KJUR.jws.JWS.inArray('a', ['b', 'c']) => false 812 */ 813 KJUR.jws.JWS.inArray = function(item, a) { 814 if (a === null) return false; 815 if (typeof a !== "object") return false; 816 if (typeof a.length !== "number") return false; 817 for (var i = 0; i < a.length; i++) { 818 if (a[i] == item) return true; 819 } 820 return false; 821 }; 822 823 /** 824 * static associative array of general signature algorithm name from JWS algorithm name 825 * @since jws 3.0.0 826 */ 827 KJUR.jws.JWS.jwsalg2sigalg = { 828 "HS256": "HmacSHA256", 829 "HS384": "HmacSHA384", 830 "HS512": "HmacSHA512", 831 "RS256": "SHA256withRSA", 832 "RS384": "SHA384withRSA", 833 "RS512": "SHA512withRSA", 834 "ES256": "SHA256withECDSA", 835 "ES384": "SHA384withECDSA", 836 "ES512": "SHA512withECDSA", 837 "PS256": "SHA256withRSAandMGF1", 838 "PS384": "SHA384withRSAandMGF1", 839 "PS512": "SHA512withRSAandMGF1", 840 "none": "none", 841 }; 842 843 // === utility static method ================================================== 844 845 /** 846 * check whether a String "s" is a safe JSON string or not.<br/> 847 * If a String "s" is a malformed JSON string or an other object type 848 * this returns 0, otherwise this returns 1. 849 * @name isSafeJSONString 850 * @memberOf KJUR.jws.JWS 851 * @function 852 * @static 853 * @param {String} s JSON string 854 * @return {Number} 1 or 0 855 */ 856 KJUR.jws.JWS.isSafeJSONString = function(s, h, p) { 857 var o = null; 858 try { 859 o = jsonParse(s); 860 if (typeof o != "object") return 0; 861 if (o.constructor === Array) return 0; 862 if (h) h[p] = o; 863 return 1; 864 } catch (ex) { 865 return 0; 866 } 867 }; 868 869 /** 870 * read a String "s" as JSON object if it is safe.<br/> 871 * If a String "s" is a malformed JSON string or not JSON string, 872 * this returns null, otherwise returns JSON object. 873 * @name readSafeJSONString 874 * @memberOf KJUR.jws.JWS 875 * @function 876 * @static 877 * @param {String} s JSON string 878 * @return {Object} JSON object or null 879 * @since 1.1.1 880 */ 881 KJUR.jws.JWS.readSafeJSONString = function(s) { 882 var o = null; 883 try { 884 o = jsonParse(s); 885 if (typeof o != "object") return null; 886 if (o.constructor === Array) return null; 887 return o; 888 } catch (ex) { 889 return null; 890 } 891 }; 892 893 /** 894 * get Encoed Signature Value from JWS string.<br/> 895 * @name getEncodedSignatureValueFromJWS 896 * @memberOf KJUR.jws.JWS 897 * @function 898 * @static 899 * @param {String} sJWS JWS signature string to be verified 900 * @return {String} string of Encoded Signature Value 901 * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". 902 */ 903 KJUR.jws.JWS.getEncodedSignatureValueFromJWS = function(sJWS) { 904 var matchResult = sJWS.match(/^[^.]+\.[^.]+\.([^.]+)$/); 905 if (matchResult == null) { 906 throw "JWS signature is not a form of 'Head.Payload.SigValue'."; 907 } 908 return matchResult[1]; 909 }; 910 911 /** 912 * get RFC 7638 JWK thumbprint from JWK object 913 * @name getJWKthumbprint 914 * @memberOf KJUR.jws.JWS 915 * @function 916 * @static 917 * @param {Object} o JWK object to be calculated thumbprint 918 * @return {String} Base64 URL encoded JWK thumbprint value 919 * @since jsrsasign 5.0.2 jws 3.3.2 920 * @description 921 * This method calculates JWK thmubprint for specified JWK object 922 * as described in 923 * <a href="https://tools.ietf.org/html/rfc7638">RFC 7638</a>. 924 * It supports all type of "kty". (i.e. "RSA", "EC" and "oct" 925 * (for symmetric key)) 926 * Working sample is 927 * <a href="https://kjur.github.io/jsrsasign/sample/tool_jwktp.html">here</a>. 928 * @example 929 * jwk = {"kty":"RSA", "n":"0vx...", "e":"AQAB", ...}; 930 * thumbprint = KJUR.jws.JWS.getJWKthumbprint(jwk); 931 */ 932 KJUR.jws.JWS.getJWKthumbprint = function(o) { 933 if (o.kty !== "RSA" && 934 o.kty !== "EC" && 935 o.kty !== "oct") 936 throw new Error("unsupported algorithm for JWK Thumprint"); 937 938 // 1. get canonically ordered json string 939 var s = '{'; 940 if (o.kty === "RSA") { 941 if (typeof o.n != "string" || typeof o.e != "string") 942 throw new Error("wrong n and e value for RSA key"); 943 s += '"' + 'e' + '":"' + o.e + '",'; 944 s += '"' + 'kty' + '":"' + o.kty + '",'; 945 s += '"' + 'n' + '":"' + o.n + '"}'; 946 } else if (o.kty === "EC") { 947 if (typeof o.crv != "string" || 948 typeof o.x != "string" || 949 typeof o.y != "string") 950 throw new Error("wrong crv, x and y value for EC key"); 951 s += '"' + 'crv' + '":"' + o.crv + '",'; 952 s += '"' + 'kty' + '":"' + o.kty + '",'; 953 s += '"' + 'x' + '":"' + o.x + '",'; 954 s += '"' + 'y' + '":"' + o.y + '"}'; 955 } else if (o.kty === "oct") { 956 if (typeof o.k != "string") 957 throw new Error("wrong k value for oct(symmetric) key"); 958 s += '"' + 'k' + '":"' + o.k + '",'; 959 s += '"' + 'kty' + '":"' + o.kty + '"}'; 960 } 961 962 // 2. get thumb print 963 var hJWK = rstrtohex(s); 964 var hash = KJUR.crypto.Util.hashHex(hJWK, "sha256"); 965 var hashB64U = hextob64u(hash); 966 967 return hashB64U; 968 }; 969 970 /** 971 * IntDate class for time representation for JSON Web Token(JWT) 972 * @class KJUR.jws.IntDate class 973 * @name KJUR.jws.IntDate 974 * @since jws 3.0.1 975 * @description 976 * Utility class for IntDate which is integer representation of UNIX origin time 977 * used in JSON Web Token(JWT). 978 */ 979 KJUR.jws.IntDate = {}; 980 981 /** 982 * get UNIX origin time from by string 983 * @name get 984 * @memberOf KJUR.jws.IntDate 985 * @function 986 * @static 987 * @param {String} s string of time representation 988 * @return {Integer} UNIX origin time in seconds for argument 's' 989 * @since jws 3.0.1 990 * @throws "unsupported format: s" when malformed format 991 * @description 992 * This method will accept following representation of time. 993 * <ul> 994 * <li>now - current time</li> 995 * <li>now + 1hour - after 1 hour from now</li> 996 * <li>now + 1day - after 1 day from now</li> 997 * <li>now + 1month - after 30 days from now</li> 998 * <li>now + 1year - after 365 days from now</li> 999 * <li>YYYYmmDDHHMMSSZ - UTC time (ex. 20130828235959Z)</li> 1000 * <li>number - UNIX origin time (seconds from 1970-01-01 00:00:00) (ex. 1377714748)</li> 1001 * </ul> 1002 */ 1003 KJUR.jws.IntDate.get = function(s) { 1004 var _KJUR_jws_IntDate = KJUR.jws.IntDate, 1005 _getNow = _KJUR_jws_IntDate.getNow, 1006 _getZulu = _KJUR_jws_IntDate.getZulu; 1007 1008 if (s == "now") { 1009 return _getNow(); 1010 } else if (s == "now + 1hour") { 1011 return _getNow() + 60 * 60; 1012 } else if (s == "now + 1day") { 1013 return _getNow() + 60 * 60 * 24; 1014 } else if (s == "now + 1month") { 1015 return _getNow() + 60 * 60 * 24 * 30; 1016 } else if (s == "now + 1year") { 1017 return _getNow() + 60 * 60 * 24 * 365; 1018 } else if (s.match(/Z$/)) { 1019 return _getZulu(s); 1020 } else if (s.match(/^[0-9]+$/)) { 1021 return parseInt(s); 1022 } 1023 throw "unsupported format: " + s; 1024 }; 1025 1026 /** 1027 * get UNIX origin time from Zulu time representation string 1028 * @name getZulu 1029 * @memberOf KJUR.jws.IntDate 1030 * @function 1031 * @static 1032 * @param {String} s string of Zulu time representation (ex. 20151012125959Z) 1033 * @return {Integer} UNIX origin time in seconds for argument 's' 1034 * @since jws 3.0.1 1035 * @throws "unsupported format: s" when malformed format 1036 * @description 1037 * This method provides UNIX origin time from Zulu time. 1038 * Following representations are supported: 1039 * <ul> 1040 * <li>YYYYMMDDHHmmSSZ - GeneralizedTime format</li> 1041 * <li>YYMMDDHHmmSSZ - UTCTime format. If YY is greater or equal to 1042 * 50 then it represents 19YY otherwise 20YY.</li> 1043 * </ul> 1044 * @example 1045 * KJUR.jws.IntDate.getZulu("20151012125959Z") => 1478... 1046 * KJUR.jws.IntDate.getZulu("151012125959Z") => 1478... 1047 */ 1048 KJUR.jws.IntDate.getZulu = function(s) { 1049 return zulutosec(s); 1050 }; 1051 1052 /** 1053 * get UNIX origin time of current time 1054 * @name getNow 1055 * @memberOf KJUR.jws.IntDate 1056 * @function 1057 * @static 1058 * @return {Integer} UNIX origin time for current time 1059 * @since jws 3.0.1 1060 * @description 1061 * This method provides UNIX origin time for current time 1062 * @example 1063 * KJUR.jws.IntDate.getNow() => 1478... 1064 */ 1065 KJUR.jws.IntDate.getNow = function() { 1066 var d = ~~(new Date() / 1000); 1067 return d; 1068 }; 1069 1070 /** 1071 * get UTC time string from UNIX origin time value 1072 * @name intDate2UTCString 1073 * @memberOf KJUR.jws.IntDate 1074 * @function 1075 * @static 1076 * @param {Integer} intDate UNIX origin time value (ex. 1478...) 1077 * @return {String} UTC time string 1078 * @since jws 3.0.1 1079 * @description 1080 * This method provides UTC time string for UNIX origin time value. 1081 * @example 1082 * KJUR.jws.IntDate.intDate2UTCString(1478...) => "2015 Oct ..." 1083 */ 1084 KJUR.jws.IntDate.intDate2UTCString = function(intDate) { 1085 var d = new Date(intDate * 1000); 1086 return d.toUTCString(); 1087 }; 1088 1089 /** 1090 * get UTC time string from UNIX origin time value 1091 * @name intDate2Zulu 1092 * @memberOf KJUR.jws.IntDate 1093 * @function 1094 * @static 1095 * @param {Integer} intDate UNIX origin time value (ex. 1478...) 1096 * @return {String} Zulu time string 1097 * @since jws 3.0.1 1098 * @description 1099 * This method provides Zulu time string for UNIX origin time value. 1100 * @example 1101 * KJUR.jws.IntDate.intDate2UTCString(1478...) => "20151012...Z" 1102 */ 1103 KJUR.jws.IntDate.intDate2Zulu = function(intDate) { 1104 var d = new Date(intDate * 1000), 1105 year = ("0000" + d.getUTCFullYear()).slice(-4), 1106 mon = ("00" + (d.getUTCMonth() + 1)).slice(-2), 1107 day = ("00" + d.getUTCDate()).slice(-2), 1108 hour = ("00" + d.getUTCHours()).slice(-2), 1109 min = ("00" + d.getUTCMinutes()).slice(-2), 1110 sec = ("00" + d.getUTCSeconds()).slice(-2); 1111 return year + mon + day + hour + min + sec + "Z"; 1112 }; 1113 1114