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