From 358a861b2901d922b2be76e29221fdb2732fe861 Mon Sep 17 00:00:00 2001 From: Kenji Urushima Date: Sat, 4 Apr 2015 07:41:18 +0900 Subject: [PATCH] 3.1.0 release --- ChangeLog.txt | 4 + api/files.html | 4 +- api/symbols/KJUR.jws.IntDate.html | 2 +- api/symbols/KJUR.jws.JWS.html | 10 +- .../src/{jws-3.0.js.html => jws-3.1.js.html} | 1289 +++++++++-------- index.html | 12 +- index_mat.html | 50 +- jws-3.1.js | 715 +++++++++ jws-3.1.min.js | 3 + sample_generate.html | 2 +- sample_generate2.html | 2 +- sample_generate3.html | 2 +- sample_jwsjsgen1.html | 2 +- sample_jwsjsgen2.html | 2 +- sample_jwsjsveri1.html | 2 +- sample_verify.html | 2 +- sample_verify2.html | 2 +- sample_verify3.html | 2 +- tool_jwt.html | 20 +- tool_verifyanalyze.html | 2 +- 20 files changed, 1457 insertions(+), 672 deletions(-) rename api/symbols/src/{jws-3.0.js.html => jws-3.1.js.html} (79%) create mode 100755 jws-3.1.js create mode 100755 jws-3.1.min.js diff --git a/ChangeLog.txt b/ChangeLog.txt index e7d92f7..4f6560a 100755 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,6 +1,10 @@ ChangeLog for jsjws +* 3.1.0 Release (2015-Apr-03) + - remove alg=none signature validation support. + - jsjws will be merged into jsrsasign near in the future. + * 3.0.2 Release (2013-Sep-24) - add HS384 support with jsrsasign 4.1.4 or later. Please use diff --git a/api/files.html b/api/files.html index ceca735..3ac893b 100755 --- a/api/files.html +++ b/api/files.html @@ -203,7 +203,7 @@

File Index

-

jws-3.0.js

+

jws-3.1.js

@@ -213,7 +213,7 @@

jws-3.0.js

Version:
-
3.0.0 (2013-Aug-27)
+
3.1.0 (2015-Apr-03)
diff --git a/api/symbols/KJUR.jws.IntDate.html b/api/symbols/KJUR.jws.IntDate.html index eb84c52..177ed57 100755 --- a/api/symbols/KJUR.jws.IntDate.html +++ b/api/symbols/KJUR.jws.IntDate.html @@ -219,7 +219,7 @@

KJUR.jws.IntDate class -
Defined in: jws-3.0.js. +
Defined in: jws-3.1.js.

diff --git a/api/symbols/KJUR.jws.JWS.html b/api/symbols/KJUR.jws.JWS.html index 8bc0af4..c001cdf 100755 --- a/api/symbols/KJUR.jws.JWS.html +++ b/api/symbols/KJUR.jws.JWS.html @@ -219,7 +219,7 @@

JSON Web Signature(JWS) class -
Defined in: jws-3.0.js. +
Defined in: jws-3.1.js.

@@ -440,7 +440,8 @@

KJUR.jws.JWS.verify(sJWS, key)
-
verify JWS signature by specified key or certificate
+
verify JWS signature by specified key or certificate
+This method verifies a JSON Web Signature Compact Serialization string by the validation algorithm as described in the section 5 of Internet Draft draft-jones-json-web-signature-04.
@@ -493,7 +494,7 @@

JSON Web Signature(JWS) class.
-

Supported Algorithms

Here is supported algorithm names for
KJUR.jws.JWS.sign and KJUR.jws.JWS.verify methods.
alg valuespec requirementjsjws support
HS256REQUIREDSUPPORTED
HS384OPTIONAL-
HS512OPTIONALSUPPORTED
RS256RECOMMENDEDSUPPORTED
RS384OPTIONALSUPPORTED
RS512OPTIONALSUPPORTED
ES256RECOMMENDED+SUPPORTED
ES384OPTIONALSUPPORTED
ES512OPTIONAL-
PS256OPTIONALSUPPORTED
PS384OPTIONALSUPPORTED
PS512OPTIONALSUPPORTED
noneREQUIREDSUPPORTED
+

Supported Algorithms

Here is supported algorithm names for KJUR.jws.JWS.sign and KJUR.jws.JWS.verify methods.
alg valuespec requirementjsjws support
HS256REQUIREDSUPPORTED
HS384OPTIONALSUPPORTED
HS512OPTIONALSUPPORTED
RS256RECOMMENDEDSUPPORTED
RS384OPTIONALSUPPORTED
RS512OPTIONALSUPPORTED
ES256RECOMMENDED+SUPPORTED
ES384OPTIONALSUPPORTED
ES512OPTIONAL-
PS256OPTIONALSUPPORTED
PS384OPTIONALSUPPORTED
PS512OPTIONALSUPPORTED
noneREQUIREDSUPPORTED(generation only)
NOTE1: HS384 is supported since jsjws 3.0.2 with jsrsasign 4.1.4.
NOTE2: alg=none validation was removed since jsjws 3.1.0.
@@ -1184,7 +1185,7 @@

Supported Algorithms

Here is supported algorithm names for generate JWS signature by specified key
-This method supports following algorithms.
alg valuespec requirementjsjws support
HS256REQUIREDSUPPORTED
HS384OPTIONAL-
HS512OPTIONALSUPPORTED
RS256RECOMMENDEDSUPPORTED
RS384OPTIONALSUPPORTED
RS512OPTIONALSUPPORTED
ES256RECOMMENDED+SUPPORTED
ES384OPTIONALSUPPORTED
ES512OPTIONAL-
PS256OPTIONALSUPPORTED
PS384OPTIONALSUPPORTED
PS512OPTIONALSUPPORTED
noneREQUIREDSUPPORTED
NOTE1:
salt length of RSAPSS signature is the same as the hash algorithm length because of IETF JOSE ML discussion.
NOTE2:
The reason of HS384 unsupport is CryptoJS HmacSHA384 bug.
+This method supports following algorithms.
alg valuespec requirementjsjws support
HS256REQUIREDSUPPORTED
HS384OPTIONAL-
HS512OPTIONALSUPPORTED
RS256RECOMMENDEDSUPPORTED
RS384OPTIONALSUPPORTED
RS512OPTIONALSUPPORTED
ES256RECOMMENDED+SUPPORTED
ES384OPTIONALSUPPORTED
ES512OPTIONAL-
PS256OPTIONALSUPPORTED
PS384OPTIONALSUPPORTED
PS512OPTIONALSUPPORTED
noneREQUIREDSUPPORTED(generation only)
NOTE1:
salt length of RSAPSS signature is the same as the hash algorithm length because of IETF JOSE ML discussion.
NOTE2:
The reason of HS384 unsupport is CryptoJS HmacSHA384 bug.
NOTE3:
alg=none validation was removed since jsjws 3.1.0.

@@ -1267,6 +1268,7 @@

Supported Algorithms

Here is supported algorithm names for verify JWS signature by specified key or certificate
+This method verifies a JSON Web Signature Compact Serialization string by the validation algorithm as described in
the section 5 of Internet Draft draft-jones-json-web-signature-04.
NOTE: alg=none validation was removed since jsjws 3.1.0.
diff --git a/api/symbols/src/jws-3.0.js.html b/api/symbols/src/jws-3.1.js.html similarity index 79% rename from api/symbols/src/jws-3.0.js.html rename to api/symbols/src/jws-3.1.js.html index 435d459..e8b7002 100755 --- a/api/symbols/src/jws-3.0.js.html +++ b/api/symbols/src/jws-3.1.js.html @@ -5,14 +5,14 @@ .STRN {color: #393;} .REGX {color: #339;} .line {border-right: 1px dotted #666; color: #666; font-style: normal;} -
  1 /*! jws-3.0.0 (c) 2013 Kenji Urushima | kjur.github.com/jsjws/license
+	
  1 /*! jws-3.1.0 (c) 2013 Kenji Urushima | kjur.github.com/jsjws/license
   2  */
   3 /*
   4  * jws.js - JSON Web Signature Class
   5  *
-  6  * version: 3.0.0 (2013 Aug 27)
+  6  * version: 3.1.0 (2015 Apr 3)
   7  *
-  8  * Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com)
+  8  * Copyright (c) 2010-2014 Kenji Urushima (kenji.urushima@gmail.com)
   9  *
  10  * This software is licensed under the terms of the MIT License.
  11  * http://kjur.github.com/jsjws/license/
@@ -23,9 +23,9 @@
  16 
  17 /**
  18  * @fileOverview
- 19  * @name jws-3.0.js
+ 19  * @name jws-3.1.js
  20  * @author Kenji Urushima kenji.urushima@gmail.com
- 21  * @version 3.0.0 (2013-Aug-27)
+ 21  * @version 3.1.0 (2015-Apr-03)
  22  * @since jsjws 1.0
  23  * @license <a href="http://kjur.github.io/jsjws/license/">MIT License</a>
  24  */
@@ -60,7 +60,7 @@
  53  * <table>
  54  * <tr><th>alg value</th><th>spec requirement</th><th>jsjws support</th></tr>
  55  * <tr><td>HS256</td><td>REQUIRED</td><td>SUPPORTED</td></tr>
- 56  * <tr><td>HS384</td><td>OPTIONAL</td><td>-</td></tr>
+ 56  * <tr><td>HS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
  57  * <tr><td>HS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
  58  * <tr><td>RS256</td><td>RECOMMENDED</td><td>SUPPORTED</td></tr>
  59  * <tr><td>RS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
@@ -71,642 +71,653 @@
  64  * <tr><td>PS256</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
  65  * <tr><td>PS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
  66  * <tr><td>PS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
- 67  * <tr><td>none</td><td>REQUIRED</td><td>SUPPORTED</td></tr>
+ 67  * <tr><td>none</td><td>REQUIRED</td><td>SUPPORTED(generation only)</td></tr>
  68  * </table>
- 69  */
- 70 KJUR.jws.JWS = function() {
- 71 
- 72     // === utility =============================================================
+ 69  * NOTE1: HS384 is supported since jsjws 3.0.2 with jsrsasign 4.1.4.<br/>
+ 70  * NOTE2: alg=none validation was removed since jsjws 3.1.0.<br/>
+ 71  */
+ 72 KJUR.jws.JWS = function() {
  73 
- 74     /**
- 75      * parse JWS string and set public property 'parsedJWS' dictionary.<br/>
- 76      * @name parseJWS
- 77      * @memberOf KJUR.jws.JWS
- 78      * @function
- 79      * @param {String} sJWS JWS signature string to be parsed.
- 80      * @throws if sJWS is not comma separated string such like "Header.Payload.Signature".
- 81      * @throws if JWS Header is a malformed JSON string.
- 82      * @since jws 1.1
- 83      */
- 84     this.parseJWS = function(sJWS, sigValNotNeeded) {
- 85 	if ((this.parsedJWS !== undefined) &&
- 86 	    (sigValNotNeeded || (this.parsedJWS.sigvalH !== undefined))) {
- 87 	    return;
- 88 	}
- 89 	if (sJWS.match(/^([^.]+)\.([^.]+)\.([^.]+)$/) == null) {
- 90 	    throw "JWS signature is not a form of 'Head.Payload.SigValue'.";
- 91 	}
- 92 	var b6Head = RegExp.$1;
- 93 	var b6Payload = RegExp.$2;
- 94 	var b6SigVal = RegExp.$3;
- 95 	var sSI = b6Head + "." + b6Payload;
- 96 	this.parsedJWS = {};
- 97 	this.parsedJWS.headB64U = b6Head;
- 98 	this.parsedJWS.payloadB64U = b6Payload;
- 99 	this.parsedJWS.sigvalB64U = b6SigVal;
-100 	this.parsedJWS.si = sSI;
-101 
-102 	if (!sigValNotNeeded) {
-103 	    var hSigVal = b64utohex(b6SigVal);
-104 	    var biSigVal = parseBigInt(hSigVal, 16);
-105 	    this.parsedJWS.sigvalH = hSigVal;
-106 	    this.parsedJWS.sigvalBI = biSigVal;
-107 	}
-108 
-109 	var sHead = b64utoutf8(b6Head);
-110 	var sPayload = b64utoutf8(b6Payload);
-111 	this.parsedJWS.headS = sHead;
-112 	this.parsedJWS.payloadS = sPayload;
-113 
-114 	if (! this.isSafeJSONString(sHead, this.parsedJWS, 'headP'))
-115 	    throw "malformed JSON string for JWS Head: " + sHead;
-116     };
-117 
-118     // ==== JWS Validation =========================================================
-119     function _getSignatureInputByString(sHead, sPayload) {
-120 	return utf8tob64u(sHead) + "." + utf8tob64u(sPayload);
-121     };
-122 
-123     function _getHashBySignatureInput(sSignatureInput, sHashAlg) {
-124 	var hashfunc = function(s) { return KJUR.crypto.Util.hashString(s, sHashAlg); };
-125 	if (hashfunc == null) throw "hash function not defined in jsrsasign: " + sHashAlg;
-126 	return hashfunc(sSignatureInput);
-127     };
-128 
-129     function _jws_verifySignature(sHead, sPayload, hSig, hN, hE) {
-130 	var sSignatureInput = _getSignatureInputByString(sHead, sPayload);
-131 	var biSig = parseBigInt(hSig, 16);
-132 	return _rsasign_verifySignatureWithArgs(sSignatureInput, biSig, hN, hE);
-133     };
-134 
-135     /**
-136      * verify JWS signature with naked RSA public key.<br/>
-137      * This only supports "RS256" and "RS512" algorithm.
-138      * @name verifyJWSByNE
-139      * @memberOf KJUR.jws.JWS
-140      * @function
-141      * @param {String} sJWS JWS signature string to be verified
-142      * @param {String} hN hexadecimal string for modulus of RSA public key
-143      * @param {String} hE hexadecimal string for public exponent of RSA public key
-144      * @return {String} returns 1 when JWS signature is valid, otherwise returns 0
-145      * @throws if sJWS is not comma separated string such like "Header.Payload.Signature".
-146      * @throws if JWS Header is a malformed JSON string.
-147      * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify}
-148      */
-149     this.verifyJWSByNE = function(sJWS, hN, hE) {
-150 	this.parseJWS(sJWS);
-151 	return _rsasign_verifySignatureWithArgs(this.parsedJWS.si, this.parsedJWS.sigvalBI, hN, hE);    
-152     };
-153 
-154     /**
-155      * verify JWS signature with RSA public key.<br/>
-156      * This only supports "RS256", "RS512", "PS256" and "PS512" algorithms.
-157      * @name verifyJWSByKey
-158      * @memberOf KJUR.jws.JWS
-159      * @function
-160      * @param {String} sJWS JWS signature string to be verified
-161      * @param {RSAKey} key RSA public key
-162      * @return {Boolean} returns true when JWS signature is valid, otherwise returns false
-163      * @throws if sJWS is not comma separated string such like "Header.Payload.Signature".
-164      * @throws if JWS Header is a malformed JSON string.
-165      * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify}
-166      */
-167     this.verifyJWSByKey = function(sJWS, key) {
-168 	this.parseJWS(sJWS);
-169 	var hashAlg = _jws_getHashAlgFromParsedHead(this.parsedJWS.headP);
-170         var isPSS = this.parsedJWS.headP['alg'].substr(0, 2) == "PS";
-171 
-172 	if (key.hashAndVerify) {
-173 	    return key.hashAndVerify(hashAlg,
-174 				     new Buffer(this.parsedJWS.si, 'utf8').toString('base64'),
-175 				     b64utob64(this.parsedJWS.sigvalB64U),
-176 				     'base64',
-177 				     isPSS);
-178 	} else if (isPSS) {
-179 	    return key.verifyStringPSS(this.parsedJWS.si,
-180 				       this.parsedJWS.sigvalH, hashAlg);
-181 	} else {
-182 	    return key.verifyString(this.parsedJWS.si,
-183 				    this.parsedJWS.sigvalH);
-184 	}
-185     };
-186 
-187     /**
-188      * verify JWS signature by PEM formatted X.509 certificate.<br/>
-189      * This only supports "RS256" and "RS512" algorithm.
-190      * @name verifyJWSByPemX509Cert
-191      * @memberOf KJUR.jws.JWS
-192      * @function
-193      * @param {String} sJWS JWS signature string to be verified
-194      * @param {String} sPemX509Cert string of PEM formatted X.509 certificate
-195      * @return {String} returns 1 when JWS signature is valid, otherwise returns 0
-196      * @throws if sJWS is not comma separated string such like "Header.Payload.Signature".
-197      * @throws if JWS Header is a malformed JSON string.
-198      * @since 1.1
-199      * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify}
-200      */
-201     this.verifyJWSByPemX509Cert = function(sJWS, sPemX509Cert) {
-202 	this.parseJWS(sJWS);
-203 	var x509 = new X509();
-204 	x509.readCertPEM(sPemX509Cert);
-205 	return x509.subjectPublicKeyRSA.verifyString(this.parsedJWS.si, this.parsedJWS.sigvalH);
-206     };
-207 
-208     // ==== JWS Generation =========================================================
-209     function _jws_getHashAlgFromParsedHead(head) {
-210 	var sigAlg = head["alg"];
-211 	var hashAlg = "";
-212 
-213 	if (sigAlg != "RS256" && sigAlg != "RS512" &&
-214 	    sigAlg != "PS256" && sigAlg != "PS512")
-215 	    throw "JWS signature algorithm not supported: " + sigAlg;
-216 	if (sigAlg.substr(2) == "256") hashAlg = "sha256";
-217 	if (sigAlg.substr(2) == "512") hashAlg = "sha512";
-218 	return hashAlg;
-219     };
-220 
-221     function _jws_getHashAlgFromHead(sHead) {
-222 	return _jws_getHashAlgFromParsedHead(jsonParse(sHead));
-223     };
-224 
-225     function _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD) {
-226 	var rsa = new RSAKey();
-227 	rsa.setPrivate(hN, hE, hD);
-228 
-229 	var hashAlg = _jws_getHashAlgFromHead(sHead);
-230 	var sigValue = rsa.signString(sSI, hashAlg);
-231 	return sigValue;
-232     };
-233 
-234     function _jws_generateSignatureValueBySI_Key(sHead, sPayload, sSI, key, head) {
-235 	var hashAlg = null;
-236 	if (typeof head == "undefined") {
-237 	    hashAlg = _jws_getHashAlgFromHead(sHead);
-238 	} else {
-239 	    hashAlg = _jws_getHashAlgFromParsedHead(head);
-240 	}
-241 
-242 	var isPSS = head['alg'].substr(0, 2) == "PS";
+ 74     // === utility =============================================================
+ 75 
+ 76     /**
+ 77      * parse JWS string and set public property 'parsedJWS' dictionary.<br/>
+ 78      * @name parseJWS
+ 79      * @memberOf KJUR.jws.JWS
+ 80      * @function
+ 81      * @param {String} sJWS JWS signature string to be parsed.
+ 82      * @throws if sJWS is not comma separated string such like "Header.Payload.Signature".
+ 83      * @throws if JWS Header is a malformed JSON string.
+ 84      * @since jws 1.1
+ 85      */
+ 86     this.parseJWS = function(sJWS, sigValNotNeeded) {
+ 87 	if ((this.parsedJWS !== undefined) &&
+ 88 	    (sigValNotNeeded || (this.parsedJWS.sigvalH !== undefined))) {
+ 89 	    return;
+ 90 	}
+ 91 	if (sJWS.match(/^([^.]+)\.([^.]+)\.([^.]+)$/) == null) {
+ 92 	    throw "JWS signature is not a form of 'Head.Payload.SigValue'.";
+ 93 	}
+ 94 	var b6Head = RegExp.$1;
+ 95 	var b6Payload = RegExp.$2;
+ 96 	var b6SigVal = RegExp.$3;
+ 97 	var sSI = b6Head + "." + b6Payload;
+ 98 	this.parsedJWS = {};
+ 99 	this.parsedJWS.headB64U = b6Head;
+100 	this.parsedJWS.payloadB64U = b6Payload;
+101 	this.parsedJWS.sigvalB64U = b6SigVal;
+102 	this.parsedJWS.si = sSI;
+103 
+104 	if (!sigValNotNeeded) {
+105 	    var hSigVal = b64utohex(b6SigVal);
+106 	    var biSigVal = parseBigInt(hSigVal, 16);
+107 	    this.parsedJWS.sigvalH = hSigVal;
+108 	    this.parsedJWS.sigvalBI = biSigVal;
+109 	}
+110 
+111 	var sHead = b64utoutf8(b6Head);
+112 	var sPayload = b64utoutf8(b6Payload);
+113 	this.parsedJWS.headS = sHead;
+114 	this.parsedJWS.payloadS = sPayload;
+115 
+116 	if (! this.isSafeJSONString(sHead, this.parsedJWS, 'headP'))
+117 	    throw "malformed JSON string for JWS Head: " + sHead;
+118     };
+119 
+120     // ==== JWS Validation =========================================================
+121     function _getSignatureInputByString(sHead, sPayload) {
+122 	return utf8tob64u(sHead) + "." + utf8tob64u(sPayload);
+123     };
+124 
+125     function _getHashBySignatureInput(sSignatureInput, sHashAlg) {
+126 	var hashfunc = function(s) { return KJUR.crypto.Util.hashString(s, sHashAlg); };
+127 	if (hashfunc == null) throw "hash function not defined in jsrsasign: " + sHashAlg;
+128 	return hashfunc(sSignatureInput);
+129     };
+130 
+131     function _jws_verifySignature(sHead, sPayload, hSig, hN, hE) {
+132 	var sSignatureInput = _getSignatureInputByString(sHead, sPayload);
+133 	var biSig = parseBigInt(hSig, 16);
+134 	return _rsasign_verifySignatureWithArgs(sSignatureInput, biSig, hN, hE);
+135     };
+136 
+137     /**
+138      * verify JWS signature with naked RSA public key.<br/>
+139      * This only supports "RS256" and "RS512" algorithm.
+140      * @name verifyJWSByNE
+141      * @memberOf KJUR.jws.JWS
+142      * @function
+143      * @param {String} sJWS JWS signature string to be verified
+144      * @param {String} hN hexadecimal string for modulus of RSA public key
+145      * @param {String} hE hexadecimal string for public exponent of RSA public key
+146      * @return {String} returns 1 when JWS signature is valid, otherwise returns 0
+147      * @throws if sJWS is not comma separated string such like "Header.Payload.Signature".
+148      * @throws if JWS Header is a malformed JSON string.
+149      * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify}
+150      */
+151     this.verifyJWSByNE = function(sJWS, hN, hE) {
+152 	this.parseJWS(sJWS);
+153 	return _rsasign_verifySignatureWithArgs(this.parsedJWS.si, this.parsedJWS.sigvalBI, hN, hE);    
+154     };
+155 
+156     /**
+157      * verify JWS signature with RSA public key.<br/>
+158      * This only supports "RS256", "RS512", "PS256" and "PS512" algorithms.
+159      * @name verifyJWSByKey
+160      * @memberOf KJUR.jws.JWS
+161      * @function
+162      * @param {String} sJWS JWS signature string to be verified
+163      * @param {RSAKey} key RSA public key
+164      * @return {Boolean} returns true when JWS signature is valid, otherwise returns false
+165      * @throws if sJWS is not comma separated string such like "Header.Payload.Signature".
+166      * @throws if JWS Header is a malformed JSON string.
+167      * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify}
+168      */
+169     this.verifyJWSByKey = function(sJWS, key) {
+170 	this.parseJWS(sJWS);
+171 	var hashAlg = _jws_getHashAlgFromParsedHead(this.parsedJWS.headP);
+172         var isPSS = this.parsedJWS.headP['alg'].substr(0, 2) == "PS";
+173 
+174 	if (key.hashAndVerify) {
+175 	    return key.hashAndVerify(hashAlg,
+176 				     new Buffer(this.parsedJWS.si, 'utf8').toString('base64'),
+177 				     b64utob64(this.parsedJWS.sigvalB64U),
+178 				     'base64',
+179 				     isPSS);
+180 	} else if (isPSS) {
+181 	    return key.verifyStringPSS(this.parsedJWS.si,
+182 				       this.parsedJWS.sigvalH, hashAlg);
+183 	} else {
+184 	    return key.verifyString(this.parsedJWS.si,
+185 				    this.parsedJWS.sigvalH);
+186 	}
+187     };
+188 
+189     /**
+190      * verify JWS signature by PEM formatted X.509 certificate.<br/>
+191      * This only supports "RS256" and "RS512" algorithm.
+192      * @name verifyJWSByPemX509Cert
+193      * @memberOf KJUR.jws.JWS
+194      * @function
+195      * @param {String} sJWS JWS signature string to be verified
+196      * @param {String} sPemX509Cert string of PEM formatted X.509 certificate
+197      * @return {String} returns 1 when JWS signature is valid, otherwise returns 0
+198      * @throws if sJWS is not comma separated string such like "Header.Payload.Signature".
+199      * @throws if JWS Header is a malformed JSON string.
+200      * @since 1.1
+201      * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify}
+202      */
+203     this.verifyJWSByPemX509Cert = function(sJWS, sPemX509Cert) {
+204 	this.parseJWS(sJWS);
+205 	var x509 = new X509();
+206 	x509.readCertPEM(sPemX509Cert);
+207 	return x509.subjectPublicKeyRSA.verifyString(this.parsedJWS.si, this.parsedJWS.sigvalH);
+208     };
+209 
+210     // ==== JWS Generation =========================================================
+211     function _jws_getHashAlgFromParsedHead(head) {
+212 	var sigAlg = head["alg"];
+213 	var hashAlg = "";
+214 
+215 	if (sigAlg != "RS256" && sigAlg != "RS512" &&
+216 	    sigAlg != "PS256" && sigAlg != "PS512")
+217 	    throw "JWS signature algorithm not supported: " + sigAlg;
+218 	if (sigAlg.substr(2) == "256") hashAlg = "sha256";
+219 	if (sigAlg.substr(2) == "512") hashAlg = "sha512";
+220 	return hashAlg;
+221     };
+222 
+223     function _jws_getHashAlgFromHead(sHead) {
+224 	return _jws_getHashAlgFromParsedHead(jsonParse(sHead));
+225     };
+226 
+227     function _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD) {
+228 	var rsa = new RSAKey();
+229 	rsa.setPrivate(hN, hE, hD);
+230 
+231 	var hashAlg = _jws_getHashAlgFromHead(sHead);
+232 	var sigValue = rsa.signString(sSI, hashAlg);
+233 	return sigValue;
+234     };
+235 
+236     function _jws_generateSignatureValueBySI_Key(sHead, sPayload, sSI, key, head) {
+237 	var hashAlg = null;
+238 	if (typeof head == "undefined") {
+239 	    hashAlg = _jws_getHashAlgFromHead(sHead);
+240 	} else {
+241 	    hashAlg = _jws_getHashAlgFromParsedHead(head);
+242 	}
 243 
-244 	if (key.hashAndSign) {
-245 	    return b64tob64u(key.hashAndSign(hashAlg, sSI, 'binary', 'base64', isPSS));
-246 	} else if (isPSS) {
-247 	    return hextob64u(key.signStringPSS(sSI, hashAlg));
-248 	} else {
-249 	    return hextob64u(key.signString(sSI, hashAlg));
-250 	}
-251     };
-252 
-253     function _jws_generateSignatureValueByNED(sHead, sPayload, hN, hE, hD) {
-254 	var sSI = _getSignatureInputByString(sHead, sPayload);
-255 	return _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD);
-256     };
-257 
-258     /**
-259      * generate JWS signature by Header, Payload and a naked RSA private key.<br/>
-260      * This only supports "RS256" and "RS512" algorithm.
-261      * @name generateJWSByNED
-262      * @memberOf KJUR.jws.JWS
-263      * @function
-264      * @param {String} sHead string of JWS Header
-265      * @param {String} sPayload string of JWS Payload
-266      * @param {String} hN hexadecimal string for modulus of RSA public key
-267      * @param {String} hE hexadecimal string for public exponent of RSA public key
-268      * @param {String} hD hexadecimal string for private exponent of RSA private key
-269      * @return {String} JWS signature string
-270      * @throws if sHead is a malformed JSON string.
-271      * @throws if supported signature algorithm was not specified in JSON Header.
-272      * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign}
-273      */
-274     this.generateJWSByNED = function(sHead, sPayload, hN, hE, hD) {
-275 	if (! this.isSafeJSONString(sHead)) throw "JWS Head is not safe JSON string: " + sHead;
-276 	var sSI = _getSignatureInputByString(sHead, sPayload);
-277 	var hSigValue = _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD);
-278 	var b64SigValue = hextob64u(hSigValue);
-279 	
-280 	this.parsedJWS = {};
-281 	this.parsedJWS.headB64U = sSI.split(".")[0];
-282 	this.parsedJWS.payloadB64U = sSI.split(".")[1];
-283 	this.parsedJWS.sigvalB64U = b64SigValue;
-284 
-285 	return sSI + "." + b64SigValue;
-286     };
-287 
-288     /**
-289      * generate JWS signature by Header, Payload and a RSA private key.<br/>
-290      * This only supports "RS256", "RS512", "PS256" and "PS512" algorithms.
-291      * @name generateJWSByKey
-292      * @memberOf KJUR.jws.JWS
-293      * @function
-294      * @param {String} sHead string of JWS Header
-295      * @param {String} sPayload string of JWS Payload
-296      * @param {RSAKey} RSA private key
-297      * @return {String} JWS signature string
-298      * @throws if sHead is a malformed JSON string.
-299      * @throws if supported signature algorithm was not specified in JSON Header.
-300      * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign}
-301      */
-302     this.generateJWSByKey = function(sHead, sPayload, key) {
-303 	var obj = {};
-304 	if (!this.isSafeJSONString(sHead, obj, 'headP'))
-305 	    throw "JWS Head is not safe JSON string: " + sHead;
-306 	var sSI = _getSignatureInputByString(sHead, sPayload);
-307 	var b64SigValue = _jws_generateSignatureValueBySI_Key(sHead, sPayload, sSI, key, obj.headP);
-308 
-309 	this.parsedJWS = {};
-310 	this.parsedJWS.headB64U = sSI.split(".")[0];
-311 	this.parsedJWS.payloadB64U = sSI.split(".")[1];
-312 	this.parsedJWS.sigvalB64U = b64SigValue;
-313 
-314 	return sSI + "." + b64SigValue;
-315     };
-316 
-317     // === sign with PKCS#1 RSA private key =====================================================
-318     function _jws_generateSignatureValueBySI_PemPrvKey(sHead, sPayload, sSI, sPemPrvKey) {
-319 	var rsa = new RSAKey();
-320 	rsa.readPrivateKeyFromPEMString(sPemPrvKey);
-321 	var hashAlg = _jws_getHashAlgFromHead(sHead);
-322 	var sigValue = rsa.signString(sSI, hashAlg);
-323 	return sigValue;
-324     };
-325 
-326     /**
-327      * generate JWS signature by Header, Payload and a PEM formatted PKCS#1 RSA private key.<br/>
-328      * This only supports "RS256" and "RS512" algorithm.
-329      * @name generateJWSByP1PrvKey
-330      * @memberOf KJUR.jws.JWS
-331      * @function
-332      * @param {String} sHead string of JWS Header
-333      * @param {String} sPayload string of JWS Payload
-334      * @param {String} string for sPemPrvKey PEM formatted PKCS#1 RSA private key<br/>
-335      *                 Heading and trailing space characters in PEM key will be ignored.
-336      * @return {String} JWS signature string
-337      * @throws if sHead is a malformed JSON string.
-338      * @throws if supported signature algorithm was not specified in JSON Header.
-339      * @since 1.1
-340      * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign}
-341      */
-342     this.generateJWSByP1PrvKey = function(sHead, sPayload, sPemPrvKey) {
-343 	if (! this.isSafeJSONString(sHead)) throw "JWS Head is not safe JSON string: " + sHead;
-344 	var sSI = _getSignatureInputByString(sHead, sPayload);
-345 	var hSigValue = _jws_generateSignatureValueBySI_PemPrvKey(sHead, sPayload, sSI, sPemPrvKey);
-346 	var b64SigValue = hextob64u(hSigValue);
-347 
-348 	this.parsedJWS = {};
-349 	this.parsedJWS.headB64U = sSI.split(".")[0];
-350 	this.parsedJWS.payloadB64U = sSI.split(".")[1];
-351 	this.parsedJWS.sigvalB64U = b64SigValue;
-352 
-353 	return sSI + "." + b64SigValue;
-354     };
-355 };
-356 
-357 // === major static method ========================================================
+244 	var isPSS = head['alg'].substr(0, 2) == "PS";
+245 
+246 	if (key.hashAndSign) {
+247 	    return b64tob64u(key.hashAndSign(hashAlg, sSI, 'binary', 'base64', isPSS));
+248 	} else if (isPSS) {
+249 	    return hextob64u(key.signStringPSS(sSI, hashAlg));
+250 	} else {
+251 	    return hextob64u(key.signString(sSI, hashAlg));
+252 	}
+253     };
+254 
+255     function _jws_generateSignatureValueByNED(sHead, sPayload, hN, hE, hD) {
+256 	var sSI = _getSignatureInputByString(sHead, sPayload);
+257 	return _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD);
+258     };
+259 
+260     /**
+261      * generate JWS signature by Header, Payload and a naked RSA private key.<br/>
+262      * This only supports "RS256" and "RS512" algorithm.
+263      * @name generateJWSByNED
+264      * @memberOf KJUR.jws.JWS
+265      * @function
+266      * @param {String} sHead string of JWS Header
+267      * @param {String} sPayload string of JWS Payload
+268      * @param {String} hN hexadecimal string for modulus of RSA public key
+269      * @param {String} hE hexadecimal string for public exponent of RSA public key
+270      * @param {String} hD hexadecimal string for private exponent of RSA private key
+271      * @return {String} JWS signature string
+272      * @throws if sHead is a malformed JSON string.
+273      * @throws if supported signature algorithm was not specified in JSON Header.
+274      * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign}
+275      */
+276     this.generateJWSByNED = function(sHead, sPayload, hN, hE, hD) {
+277 	if (! this.isSafeJSONString(sHead)) throw "JWS Head is not safe JSON string: " + sHead;
+278 	var sSI = _getSignatureInputByString(sHead, sPayload);
+279 	var hSigValue = _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD);
+280 	var b64SigValue = hextob64u(hSigValue);
+281 	
+282 	this.parsedJWS = {};
+283 	this.parsedJWS.headB64U = sSI.split(".")[0];
+284 	this.parsedJWS.payloadB64U = sSI.split(".")[1];
+285 	this.parsedJWS.sigvalB64U = b64SigValue;
+286 
+287 	return sSI + "." + b64SigValue;
+288     };
+289 
+290     /**
+291      * generate JWS signature by Header, Payload and a RSA private key.<br/>
+292      * This only supports "RS256", "RS512", "PS256" and "PS512" algorithms.
+293      * @name generateJWSByKey
+294      * @memberOf KJUR.jws.JWS
+295      * @function
+296      * @param {String} sHead string of JWS Header
+297      * @param {String} sPayload string of JWS Payload
+298      * @param {RSAKey} RSA private key
+299      * @return {String} JWS signature string
+300      * @throws if sHead is a malformed JSON string.
+301      * @throws if supported signature algorithm was not specified in JSON Header.
+302      * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign}
+303      */
+304     this.generateJWSByKey = function(sHead, sPayload, key) {
+305 	var obj = {};
+306 	if (!this.isSafeJSONString(sHead, obj, 'headP'))
+307 	    throw "JWS Head is not safe JSON string: " + sHead;
+308 	var sSI = _getSignatureInputByString(sHead, sPayload);
+309 	var b64SigValue = _jws_generateSignatureValueBySI_Key(sHead, sPayload, sSI, key, obj.headP);
+310 
+311 	this.parsedJWS = {};
+312 	this.parsedJWS.headB64U = sSI.split(".")[0];
+313 	this.parsedJWS.payloadB64U = sSI.split(".")[1];
+314 	this.parsedJWS.sigvalB64U = b64SigValue;
+315 
+316 	return sSI + "." + b64SigValue;
+317     };
+318 
+319     // === sign with PKCS#1 RSA private key =====================================================
+320     function _jws_generateSignatureValueBySI_PemPrvKey(sHead, sPayload, sSI, sPemPrvKey) {
+321 	var rsa = new RSAKey();
+322 	rsa.readPrivateKeyFromPEMString(sPemPrvKey);
+323 	var hashAlg = _jws_getHashAlgFromHead(sHead);
+324 	var sigValue = rsa.signString(sSI, hashAlg);
+325 	return sigValue;
+326     };
+327 
+328     /**
+329      * generate JWS signature by Header, Payload and a PEM formatted PKCS#1 RSA private key.<br/>
+330      * This only supports "RS256" and "RS512" algorithm.
+331      * @name generateJWSByP1PrvKey
+332      * @memberOf KJUR.jws.JWS
+333      * @function
+334      * @param {String} sHead string of JWS Header
+335      * @param {String} sPayload string of JWS Payload
+336      * @param {String} string for sPemPrvKey PEM formatted PKCS#1 RSA private key<br/>
+337      *                 Heading and trailing space characters in PEM key will be ignored.
+338      * @return {String} JWS signature string
+339      * @throws if sHead is a malformed JSON string.
+340      * @throws if supported signature algorithm was not specified in JSON Header.
+341      * @since 1.1
+342      * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign}
+343      */
+344     this.generateJWSByP1PrvKey = function(sHead, sPayload, sPemPrvKey) {
+345 	if (! this.isSafeJSONString(sHead)) throw "JWS Head is not safe JSON string: " + sHead;
+346 	var sSI = _getSignatureInputByString(sHead, sPayload);
+347 	var hSigValue = _jws_generateSignatureValueBySI_PemPrvKey(sHead, sPayload, sSI, sPemPrvKey);
+348 	var b64SigValue = hextob64u(hSigValue);
+349 
+350 	this.parsedJWS = {};
+351 	this.parsedJWS.headB64U = sSI.split(".")[0];
+352 	this.parsedJWS.payloadB64U = sSI.split(".")[1];
+353 	this.parsedJWS.sigvalB64U = b64SigValue;
+354 
+355 	return sSI + "." + b64SigValue;
+356     };
+357 };
 358 
-359 /**
-360  * generate JWS signature by specified key<br/>
-361  * @name sign
-362  * @memberOf KJUR.jws.JWS
-363  * @function
-364  * @static
-365  * @param {String} alg JWS algorithm name to sign and force set to sHead or null 
-366  * @param {String} sHead string of JWS Header
-367  * @param {String} sPayload string of JWS Payload
-368  * @param {String} key string of private key or key object to sign
-369  * @param {String} pass (OPTION)passcode to use encrypted private key 
-370  * @return {String} JWS signature string
-371  * @since jws 3.0.0
-372  * @see <a href="http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Signature.html">jsrsasign KJUR.crypto.Signature method</a>
-373  * @see <a href="http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Mac.html">jsrsasign KJUR.crypto.Mac method</a>
-374  * @description
-375  * This method supports following algorithms.
-376  * <table>
-377  * <tr><th>alg value</th><th>spec requirement</th><th>jsjws support</th></tr>
-378  * <tr><td>HS256</td><td>REQUIRED</td><td>SUPPORTED</td></tr>
-379  * <tr><td>HS384</td><td>OPTIONAL</td><td>-</td></tr>
-380  * <tr><td>HS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
-381  * <tr><td>RS256</td><td>RECOMMENDED</td><td>SUPPORTED</td></tr>
-382  * <tr><td>RS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
-383  * <tr><td>RS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
-384  * <tr><td>ES256</td><td>RECOMMENDED+</td><td>SUPPORTED</td></tr>
-385  * <tr><td>ES384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
-386  * <tr><td>ES512</td><td>OPTIONAL</td><td>-</td></tr>
-387  * <tr><td>PS256</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
-388  * <tr><td>PS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
-389  * <tr><td>PS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
-390  * <tr><td>none</td><td>REQUIRED</td><td>SUPPORTED</td></tr>
-391  * </table>
-392  * <dl>
-393  * <dt>NOTE1:
-394  * <dd>salt length of RSAPSS signature is the same as the hash algorithm length
-395  * because of <a href="http://www.ietf.org/mail-archive/web/jose/current/msg02901.html">IETF JOSE ML discussion</a>.
-396  * <dt>NOTE2:
-397  * <dd>The reason of HS384 unsupport is  
-398  * <a href="https://code.google.com/p/crypto-js/issues/detail?id=84">CryptoJS HmacSHA384 bug</a>.
-399  * </dl>
-400  */
-401 KJUR.jws.JWS.sign = function(alg, sHeader, sPayload, key, pass) {
-402     var ns1 = KJUR.jws.JWS;
-403 
-404     if (! ns1.isSafeJSONString(sHeader))
-405 	throw "JWS Head is not safe JSON string: " + sHead;
-406 
-407     var pHeader = ns1.readSafeJSONString(sHeader);
-408 
-409     // 1. use alg if defined in sHeader
-410     if ((alg == '' || alg == null) &&
-411 	pHeader['alg'] !== undefined) {
-412 	alg = pHeader['alg'];
-413     }
-414 
-415     // 2. set alg in sHeader if undefined
-416     if ((alg != '' && alg != null) &&
-417 	pHeader['alg'] === undefined) {
-418 	pHeader['alg'] = alg;
-419 	sHeader = JSON.stringify(pHeader);
-420     }
-421 
-422     // 3. set signature algorithm like SHA1withRSA
-423     var sigAlg = null;
-424     if (ns1.jwsalg2sigalg[alg] === undefined) {
-425 	throw "unsupported alg name: " + alg;
-426     } else {
-427 	sigAlg = ns1.jwsalg2sigalg[alg];
-428     }
-429     
-430     var uHeader = utf8tob64u(sHeader);
-431     var uPayload = utf8tob64u(sPayload);
-432     var uSignatureInput = uHeader + "." + uPayload
+359 // === major static method ========================================================
+360 
+361 /**
+362  * generate JWS signature by specified key<br/>
+363  * @name sign
+364  * @memberOf KJUR.jws.JWS
+365  * @function
+366  * @static
+367  * @param {String} alg JWS algorithm name to sign and force set to sHead or null 
+368  * @param {String} sHead string of JWS Header
+369  * @param {String} sPayload string of JWS Payload
+370  * @param {String} key string of private key or key object to sign
+371  * @param {String} pass (OPTION)passcode to use encrypted private key 
+372  * @return {String} JWS signature string
+373  * @since jws 3.0.0
+374  * @see <a href="http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Signature.html">jsrsasign KJUR.crypto.Signature method</a>
+375  * @see <a href="http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Mac.html">jsrsasign KJUR.crypto.Mac method</a>
+376  * @description
+377  * This method supports following algorithms.
+378  * <table>
+379  * <tr><th>alg value</th><th>spec requirement</th><th>jsjws support</th></tr>
+380  * <tr><td>HS256</td><td>REQUIRED</td><td>SUPPORTED</td></tr>
+381  * <tr><td>HS384</td><td>OPTIONAL</td><td>-</td></tr>
+382  * <tr><td>HS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
+383  * <tr><td>RS256</td><td>RECOMMENDED</td><td>SUPPORTED</td></tr>
+384  * <tr><td>RS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
+385  * <tr><td>RS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
+386  * <tr><td>ES256</td><td>RECOMMENDED+</td><td>SUPPORTED</td></tr>
+387  * <tr><td>ES384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
+388  * <tr><td>ES512</td><td>OPTIONAL</td><td>-</td></tr>
+389  * <tr><td>PS256</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
+390  * <tr><td>PS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
+391  * <tr><td>PS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
+392  * <tr><td>none</td><td>REQUIRED</td><td>SUPPORTED(generation only)</td></tr>
+393  * </table>
+394  * <dl>
+395  * <dt>NOTE1:
+396  * <dd>salt length of RSAPSS signature is the same as the hash algorithm length
+397  * because of <a href="http://www.ietf.org/mail-archive/web/jose/current/msg02901.html">IETF JOSE ML discussion</a>.
+398  * <dt>NOTE2:
+399  * <dd>The reason of HS384 unsupport is  
+400  * <a href="https://code.google.com/p/crypto-js/issues/detail?id=84">CryptoJS HmacSHA384 bug</a>.
+401  * <dt>NOTE3:
+402  * <dd>alg=none validation was removed since jsjws 3.1.0.<br/>
+403  * </dl>
+404  */
+405 KJUR.jws.JWS.sign = function(alg, sHeader, sPayload, key, pass) {
+406     var ns1 = KJUR.jws.JWS;
+407 
+408     if (! ns1.isSafeJSONString(sHeader))
+409 	throw "JWS Head is not safe JSON string: " + sHead;
+410 
+411     var pHeader = ns1.readSafeJSONString(sHeader);
+412 
+413     // 1. use alg if defined in sHeader
+414     if ((alg == '' || alg == null) &&
+415 	pHeader['alg'] !== undefined) {
+416 	alg = pHeader['alg'];
+417     }
+418 
+419     // 2. set alg in sHeader if undefined
+420     if ((alg != '' && alg != null) &&
+421 	pHeader['alg'] === undefined) {
+422 	pHeader['alg'] = alg;
+423 	sHeader = JSON.stringify(pHeader);
+424     }
+425 
+426     // 3. set signature algorithm like SHA1withRSA
+427     var sigAlg = null;
+428     if (ns1.jwsalg2sigalg[alg] === undefined) {
+429 	throw "unsupported alg name: " + alg;
+430     } else {
+431 	sigAlg = ns1.jwsalg2sigalg[alg];
+432     }
 433     
-434     // 4. sign
-435     var hSig = "";
-436     if (sigAlg.substr(0, 4) == "Hmac") {
-437 	if (key === undefined)
-438 	    throw "hexadecimal key shall be specified for HMAC";
-439 	var mac = new KJUR.crypto.Mac({'alg': sigAlg, 'pass': hextorstr(key)});
-440 	mac.updateString(uSignatureInput);
-441 	hSig = mac.doFinal();
-442     } else if (sigAlg.indexOf("withECDSA") != -1) {
-443 	var sig = new KJUR.crypto.Signature({'alg': sigAlg});
-444 	sig.init(key, pass);
-445 	sig.updateString(uSignatureInput);
-446 	hASN1Sig = sig.sign();
-447 	hSig = KJUR.crypto.ECDSA.asn1SigToConcatSig(hASN1Sig);
-448     } else if (sigAlg != "none") {
-449 	var sig = new KJUR.crypto.Signature({'alg': sigAlg});
-450 	sig.init(key, pass);
-451 	sig.updateString(uSignatureInput);
-452 	hSig = sig.sign();
-453     }
-454 
-455     var uSig = hextob64u(hSig);
-456     return uSignatureInput + "." + uSig;
-457 };
+434     var uHeader = utf8tob64u(sHeader);
+435     var uPayload = utf8tob64u(sPayload);
+436     var uSignatureInput = uHeader + "." + uPayload
+437     
+438     // 4. sign
+439     var hSig = "";
+440     if (sigAlg.substr(0, 4) == "Hmac") {
+441 	if (key === undefined)
+442 	    throw "hexadecimal key shall be specified for HMAC";
+443 	var mac = new KJUR.crypto.Mac({'alg': sigAlg, 'pass': hextorstr(key)});
+444 	mac.updateString(uSignatureInput);
+445 	hSig = mac.doFinal();
+446     } else if (sigAlg.indexOf("withECDSA") != -1) {
+447 	var sig = new KJUR.crypto.Signature({'alg': sigAlg});
+448 	sig.init(key, pass);
+449 	sig.updateString(uSignatureInput);
+450 	hASN1Sig = sig.sign();
+451 	hSig = KJUR.crypto.ECDSA.asn1SigToConcatSig(hASN1Sig);
+452     } else if (sigAlg != "none") {
+453 	var sig = new KJUR.crypto.Signature({'alg': sigAlg});
+454 	sig.init(key, pass);
+455 	sig.updateString(uSignatureInput);
+456 	hSig = sig.sign();
+457     }
 458 
-459 /**
-460  * verify JWS signature by specified key or certificate<br/>
-461  * @name verify
-462  * @memberOf KJUR.jws.JWS
-463  * @function
-464  * @static
-465  * @param {String} sJWS string of JWS signature to verify
-466  * @param {String} key string of public key, certificate or key object to verify
-467  * @return {Boolean} true if the signature is valid otherwise false
-468  * @since jws 3.0.0
-469  * @see <a href="http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Signature.html">jsrsasign KJUR.crypto.Signature method</a>
-470  * @see <a href="http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Mac.html">jsrsasign KJUR.crypto.Mac method</a>
-471  */
-472 KJUR.jws.JWS.verify = function(sJWS, key) {
-473     var jws = KJUR.jws.JWS;
-474     var a = sJWS.split(".");
-475     var uHeader = a[0];
-476     var uPayload = a[1];
-477     var uSignatureInput = uHeader + "." + uPayload;
-478     var hSig = b64utohex(a[2]);
-479 
-480     var pHeader = jws.readSafeJSONString(b64utoutf8(a[0]));
-481     var alg = null;
-482     if (pHeader.alg === undefined) {
-483 	throw "algorithm not specified in header";
-484     } else {
-485 	alg = pHeader.alg;
-486     }
-487 
-488     var sigAlg = null;
-489     if (jws.jwsalg2sigalg[pHeader.alg] === undefined) {
-490 	throw "unsupported alg name: " + alg;
-491     } else {
-492 	sigAlg = jws.jwsalg2sigalg[alg];
-493     }
-494 
-495     // x. verify
-496     if (sigAlg == "none") {
-497 	return true;
-498     } else if (sigAlg.substr(0, 4) == "Hmac") {
-499 	if (key === undefined)
-500 	    throw "hexadecimal key shall be specified for HMAC";
-501 	var mac = new KJUR.crypto.Mac({'alg': sigAlg, 'pass': hextorstr(key)});
-502 	mac.updateString(uSignatureInput);
-503 	hSig2 = mac.doFinal();
-504 	return hSig == hSig2;
-505     } else if (sigAlg.indexOf("withECDSA") != -1) {
-506 	var hASN1Sig = null;
-507         try {
-508 	    hASN1Sig = KJUR.crypto.ECDSA.concatSigToASN1Sig(hSig);
-509 	} catch (ex) {
-510 	    return false;
-511 	}
-512 	var sig = new KJUR.crypto.Signature({'alg': sigAlg});
-513 	sig.init(key)
-514 	sig.updateString(uSignatureInput);
-515 	return sig.verify(hASN1Sig);
-516     } else {
-517 	var sig = new KJUR.crypto.Signature({'alg': sigAlg});
-518 	sig.init(key)
-519 	sig.updateString(uSignatureInput);
-520 	return sig.verify(hSig);
-521     }
-522 };
-523 
-524 /*
-525  * @since jws 3.0.0
-526  */
-527 KJUR.jws.JWS.jwsalg2sigalg = {
-528     "HS256":	"HmacSHA256",
-529     //"HS384":	"HmacSHA384", // unsupported because of CryptoJS bug
-530     "HS512":	"HmacSHA512",
-531     "RS256":	"SHA256withRSA",
-532     "RS384":	"SHA384withRSA",
-533     "RS512":	"SHA512withRSA",
-534     "ES256":	"SHA256withECDSA",
-535     "ES384":	"SHA384withECDSA",
-536     //"ES512":	"SHA512withECDSA", // unsupported because of jsrsasign's bug
-537     "PS256":	"SHA256withRSAandMGF1",
-538     "PS384":	"SHA384withRSAandMGF1",
-539     "PS512":	"SHA512withRSAandMGF1",
-540     "none":	"none",
-541 };
-542 
-543 // === utility static method ======================================================
-544 
-545 /**
-546  * check whether a String "s" is a safe JSON string or not.<br/>
-547  * If a String "s" is a malformed JSON string or an other object type
-548  * this returns 0, otherwise this returns 1.
-549  * @name isSafeJSONString
-550  * @memberOf KJUR.jws.JWS
-551  * @function
-552  * @static
-553  * @param {String} s JSON string
-554  * @return {Number} 1 or 0
-555  */
-556 KJUR.jws.JWS.isSafeJSONString = function(s, h, p) {
-557     var o = null;
-558     try {
-559 	o = jsonParse(s);
-560 	if (typeof o != "object") return 0;
-561 	if (o.constructor === Array) return 0;
-562 	if (h) h[p] = o;
-563 	return 1;
-564     } catch (ex) {
-565 	return 0;
-566     }
-567 };
-568 
-569 /**
-570  * read a String "s" as JSON object if it is safe.<br/>
-571  * If a String "s" is a malformed JSON string or not JSON string,
-572  * this returns null, otherwise returns JSON object.
-573  * @name readSafeJSONString
-574  * @memberOf KJUR.jws.JWS
-575  * @function
-576  * @static
-577  * @param {String} s JSON string
-578  * @return {Object} JSON object or null
-579  * @since 1.1.1
-580  */
-581 KJUR.jws.JWS.readSafeJSONString = function(s) {
-582     var o = null;
-583     try {
-584 	o = jsonParse(s);
-585 	if (typeof o != "object") return null;
-586 	if (o.constructor === Array) return null;
-587 	return o;
-588     } catch (ex) {
-589 	return null;
-590     }
-591 };
-592 
-593 /**
-594  * get Encoed Signature Value from JWS string.<br/>
-595  * @name getEncodedSignatureValueFromJWS
-596  * @memberOf KJUR.jws.JWS
-597  * @function
-598  * @static
-599  * @param {String} sJWS JWS signature string to be verified
-600  * @return {String} string of Encoded Signature Value 
-601  * @throws if sJWS is not comma separated string such like "Header.Payload.Signature".
-602  */
-603 KJUR.jws.JWS.getEncodedSignatureValueFromJWS = function(sJWS) {
-604     if (sJWS.match(/^[^.]+\.[^.]+\.([^.]+)$/) == null) {
-605 	throw "JWS signature is not a form of 'Head.Payload.SigValue'.";
-606     }
-607     return RegExp.$1;
-608 };
-609 
-610 /**
-611  * IntDate class for time representation for JSON Web Token(JWT)
-612  * @class KJUR.jws.IntDate class
-613  * @name KJUR.jws.IntDate
-614  * @since jws 3.0.1
-615  * @description
-616  * Utility class for IntDate which is integer representation of UNIX origin time
-617  * used in JSON Web Token(JWT).
-618  */
-619 KJUR.jws.IntDate = function() {
-620 };
-621 
-622 /**
-623  * @name get
-624  * @memberOf KJUR.jws.IntDate
-625  * @function
-626  * @static
-627  * @param {String} s string of time representation
-628  * @return {Integer} UNIX origin time in seconds for argument 's'
-629  * @since jws 3.0.1
-630  * @throws "unsupported format: s" when malformed format
-631  * @description
-632  * This method will accept following representation of time.
-633  * <ul>
-634  * <li>now - current time</li>
-635  * <li>now + 1hour - after 1 hour from now</li>
-636  * <li>now + 1day - after 1 day from now</li>
-637  * <li>now + 1month - after 30 days from now</li>
-638  * <li>now + 1year - after 365 days from now</li>
-639  * <li>YYYYmmDDHHMMSSZ - UTC time (ex. 20130828235959Z)</li>
-640  * <li>number - UNIX origin time (seconds from 1970-01-01 00:00:00) (ex. 1377714748)</li>
-641  * </ul>
-642  */
-643 KJUR.jws.IntDate.get = function(s) {
-644     if (s == "now") {
-645 	return KJUR.jws.IntDate.getNow();
-646     } else if (s == "now + 1hour") {
-647 	return KJUR.jws.IntDate.getNow() + 60 * 60;
-648     } else if (s == "now + 1day") {
-649 	return KJUR.jws.IntDate.getNow() + 60 * 60 * 24;
-650     } else if (s == "now + 1month") {
-651 	return KJUR.jws.IntDate.getNow() + 60 * 60 * 24 * 30;
-652     } else if (s == "now + 1year") {
-653 	return KJUR.jws.IntDate.getNow() + 60 * 60 * 24 * 365;
-654     } else if (s.match(/Z$/)) {
-655 	return KJUR.jws.IntDate.getZulu(s);
-656     } else if (s.match(/^[0-9]+$/)) {
-657 	return parseInt(s);
-658     }
-659     throw "unsupported format: " + s;
-660 };
-661 
-662 KJUR.jws.IntDate.getZulu = function(s) {
-663     if (a = s.match(/(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)Z/)) {
-664 	var year = parseInt(RegExp.$1);
-665 	var month = parseInt(RegExp.$2) - 1;
-666 	var day = parseInt(RegExp.$3);
-667 	var hour = parseInt(RegExp.$4);
-668 	var min = parseInt(RegExp.$5);
-669 	var sec = parseInt(RegExp.$6);
-670 	var d = new Date(Date.UTC(year, month, day, hour, min, sec));
-671 	return ~~(d / 1000);
-672     }
-673     throw "unsupported format: " + s;
-674 };
-675 
-676 /*
-677  * @since jws 3.0.1
-678  */
-679 KJUR.jws.IntDate.getNow = function() {
-680     var d = ~~(new Date() / 1000);
-681     return d;
-682 };
-683 
-684 /*
-685  * @since jws 3.0.1
-686  */
-687 KJUR.jws.IntDate.intDate2UTCString = function(intDate) {
-688     var d = new Date(intDate * 1000);
-689     return d.toUTCString();
-690 };
-691 
-692 /*
-693  * @since jws 3.0.1
-694  */
-695 KJUR.jws.IntDate.intDate2Zulu = function(intDate) {
-696     var d = new Date(intDate * 1000);
-697     var year = ("0000" + d.getUTCFullYear()).slice(-4);    
-698     var mon =  ("00" + (d.getUTCMonth() + 1)).slice(-2);    
-699     var day =  ("00" + d.getUTCDate()).slice(-2);    
-700     var hour = ("00" + d.getUTCHours()).slice(-2);    
-701     var min =  ("00" + d.getUTCMinutes()).slice(-2);    
-702     var sec =  ("00" + d.getUTCSeconds()).slice(-2);    
-703     return year + mon + day + hour + min + sec + "Z";
-704 };
-705 
\ No newline at end of file +459
var uSig = hextob64u(hSig); +460 return uSignatureInput + "." + uSig; +461 }; +462 +463 /** +464 * verify JWS signature by specified key or certificate<br/> +465 * @name verify +466 * @memberOf KJUR.jws.JWS +467 * @function +468 * @static +469 * @param {String} sJWS string of JWS signature to verify +470 * @param {String} key string of public key, certificate or key object to verify +471 * @return {Boolean} true if the signature is valid otherwise false +472 * @since jws 3.0.0 +473 * @see <a href="http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Signature.html">jsrsasign KJUR.crypto.Signature method</a> +474 * @see <a href="http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Mac.html">jsrsasign KJUR.crypto.Mac method</a> +475 * @description +476 * This method verifies a JSON Web Signature Compact Serialization string by the validation +477 * algorithm as described in +478 * <a href="http://self-issued.info/docs/draft-jones-json-web-signature-04.html#anchor5"> +479 * the section 5 of Internet Draft draft-jones-json-web-signature-04.</a> +480 * <br/> +481 * NOTE: alg=none validation was removed since jsjws 3.1.0.<br/> +482 */ +483 KJUR.jws.JWS.verify = function(sJWS, key) { +484 var jws = KJUR.jws.JWS; +485 var a = sJWS.split("."); +486 var uHeader = a[0]; +487 var uPayload = a[1]; +488 var uSignatureInput = uHeader + "." + uPayload; +489 var hSig = b64utohex(a[2]); +490 +491 var pHeader = jws.readSafeJSONString(b64utoutf8(a[0])); +492 var alg = null; +493 if (pHeader.alg === undefined) { +494 throw "algorithm not specified in header"; +495 } else { +496 alg = pHeader.alg; +497 } +498 +499 var sigAlg = null; +500 if (jws.jwsalg2sigalg[pHeader.alg] === undefined) { +501 throw "unsupported alg name: " + alg; +502 } else { +503 sigAlg = jws.jwsalg2sigalg[alg]; +504 } +505 +506 // x. verify +507 if (sigAlg == "none") { +508 throw "not supported"; +509 } else if (sigAlg.substr(0, 4) == "Hmac") { +510 if (key === undefined) +511 throw "hexadecimal key shall be specified for HMAC"; +512 var mac = new KJUR.crypto.Mac({'alg': sigAlg, 'pass': hextorstr(key)}); +513 mac.updateString(uSignatureInput); +514 hSig2 = mac.doFinal(); +515 return hSig == hSig2; +516 } else if (sigAlg.indexOf("withECDSA") != -1) { +517 var hASN1Sig = null; +518 try { +519 hASN1Sig = KJUR.crypto.ECDSA.concatSigToASN1Sig(hSig); +520 } catch (ex) { +521 return false; +522 } +523 var sig = new KJUR.crypto.Signature({'alg': sigAlg}); +524 sig.init(key) +525 sig.updateString(uSignatureInput); +526 return sig.verify(hASN1Sig); +527 } else { +528 var sig = new KJUR.crypto.Signature({'alg': sigAlg}); +529 sig.init(key) +530 sig.updateString(uSignatureInput); +531 return sig.verify(hSig); +532 } +533 }; +534 +535 /* +536 * @since jws 3.0.0 +537 */ +538 KJUR.jws.JWS.jwsalg2sigalg = { +539 "HS256": "HmacSHA256", +540 //"HS384": "HmacSHA384", // unsupported because of CryptoJS bug +541 "HS512": "HmacSHA512", +542 "RS256": "SHA256withRSA", +543 "RS384": "SHA384withRSA", +544 "RS512": "SHA512withRSA", +545 "ES256": "SHA256withECDSA", +546 "ES384": "SHA384withECDSA", +547 //"ES512": "SHA512withECDSA", // unsupported because of jsrsasign's bug +548 "PS256": "SHA256withRSAandMGF1", +549 "PS384": "SHA384withRSAandMGF1", +550 "PS512": "SHA512withRSAandMGF1", +551 "none": "none", +552 }; +553 +554 // === utility static method ====================================================== +555 +556 /** +557 * check whether a String "s" is a safe JSON string or not.<br/> +558 * If a String "s" is a malformed JSON string or an other object type +559 * this returns 0, otherwise this returns 1. +560 * @name isSafeJSONString +561 * @memberOf KJUR.jws.JWS +562 * @function +563 * @static +564 * @param {String} s JSON string +565 * @return {Number} 1 or 0 +566 */ +567 KJUR.jws.JWS.isSafeJSONString = function(s, h, p) { +568 var o = null; +569 try { +570 o = jsonParse(s); +571 if (typeof o != "object") return 0; +572 if (o.constructor === Array) return 0; +573 if (h) h[p] = o; +574 return 1; +575 } catch (ex) { +576 return 0; +577 } +578 }; +579 +580 /** +581 * read a String "s" as JSON object if it is safe.<br/> +582 * If a String "s" is a malformed JSON string or not JSON string, +583 * this returns null, otherwise returns JSON object. +584 * @name readSafeJSONString +585 * @memberOf KJUR.jws.JWS +586 * @function +587 * @static +588 * @param {String} s JSON string +589 * @return {Object} JSON object or null +590 * @since 1.1.1 +591 */ +592 KJUR.jws.JWS.readSafeJSONString = function(s) { +593 var o = null; +594 try { +595 o = jsonParse(s); +596 if (typeof o != "object") return null; +597 if (o.constructor === Array) return null; +598 return o; +599 } catch (ex) { +600 return null; +601 } +602 }; +603 +604 /** +605 * get Encoed Signature Value from JWS string.<br/> +606 * @name getEncodedSignatureValueFromJWS +607 * @memberOf KJUR.jws.JWS +608 * @function +609 * @static +610 * @param {String} sJWS JWS signature string to be verified +611 * @return {String} string of Encoded Signature Value +612 * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". +613 */ +614 KJUR.jws.JWS.getEncodedSignatureValueFromJWS = function(sJWS) { +615 if (sJWS.match(/^[^.]+\.[^.]+\.([^.]+)$/) == null) { +616 throw "JWS signature is not a form of 'Head.Payload.SigValue'."; +617 } +618 return RegExp.$1; +619 }; +620 +621 /** +622 * IntDate class for time representation for JSON Web Token(JWT) +623 * @class KJUR.jws.IntDate class +624 * @name KJUR.jws.IntDate +625 * @since jws 3.0.1 +626 * @description +627 * Utility class for IntDate which is integer representation of UNIX origin time +628 * used in JSON Web Token(JWT). +629 */ +630 KJUR.jws.IntDate = function() { +631 }; +632 +633 /** +634 * @name get +635 * @memberOf KJUR.jws.IntDate +636 * @function +637 * @static +638 * @param {String} s string of time representation +639 * @return {Integer} UNIX origin time in seconds for argument 's' +640 * @since jws 3.0.1 +641 * @throws "unsupported format: s" when malformed format +642 * @description +643 * This method will accept following representation of time. +644 * <ul> +645 * <li>now - current time</li> +646 * <li>now + 1hour - after 1 hour from now</li> +647 * <li>now + 1day - after 1 day from now</li> +648 * <li>now + 1month - after 30 days from now</li> +649 * <li>now + 1year - after 365 days from now</li> +650 * <li>YYYYmmDDHHMMSSZ - UTC time (ex. 20130828235959Z)</li> +651 * <li>number - UNIX origin time (seconds from 1970-01-01 00:00:00) (ex. 1377714748)</li> +652 * </ul> +653 */ +654 KJUR.jws.IntDate.get = function(s) { +655 if (s == "now") { +656 return KJUR.jws.IntDate.getNow(); +657 } else if (s == "now + 1hour") { +658 return KJUR.jws.IntDate.getNow() + 60 * 60; +659 } else if (s == "now + 1day") { +660 return KJUR.jws.IntDate.getNow() + 60 * 60 * 24; +661 } else if (s == "now + 1month") { +662 return KJUR.jws.IntDate.getNow() + 60 * 60 * 24 * 30; +663 } else if (s == "now + 1year") { +664 return KJUR.jws.IntDate.getNow() + 60 * 60 * 24 * 365; +665 } else if (s.match(/Z$/)) { +666 return KJUR.jws.IntDate.getZulu(s); +667 } else if (s.match(/^[0-9]+$/)) { +668 return parseInt(s); +669 } +670 throw "unsupported format: " + s; +671 }; +672 +673 KJUR.jws.IntDate.getZulu = function(s) { +674 if (a = s.match(/(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)Z/)) { +675 var year = parseInt(RegExp.$1); +676 var month = parseInt(RegExp.$2) - 1; +677 var day = parseInt(RegExp.$3); +678 var hour = parseInt(RegExp.$4); +679 var min = parseInt(RegExp.$5); +680 var sec = parseInt(RegExp.$6); +681 var d = new Date(Date.UTC(year, month, day, hour, min, sec)); +682 return ~~(d / 1000); +683 } +684 throw "unsupported format: " + s; +685 }; +686 +687 /* +688 * @since jws 3.0.1 +689 */ +690 KJUR.jws.IntDate.getNow = function() { +691 var d = ~~(new Date() / 1000); +692 return d; +693 }; +694 +695 /* +696 * @since jws 3.0.1 +697 */ +698 KJUR.jws.IntDate.intDate2UTCString = function(intDate) { +699 var d = new Date(intDate * 1000); +700 return d.toUTCString(); +701 }; +702 +703 /* +704 * @since jws 3.0.1 +705 */ +706 KJUR.jws.IntDate.intDate2Zulu = function(intDate) { +707 var d = new Date(intDate * 1000); +708 var year = ("0000" + d.getUTCFullYear()).slice(-4); +709 var mon = ("00" + (d.getUTCMonth() + 1)).slice(-2); +710 var day = ("00" + d.getUTCDate()).slice(-2); +711 var hour = ("00" + d.getUTCHours()).slice(-2); +712 var min = ("00" + d.getUTCMinutes()).slice(-2); +713 var sec = ("00" + d.getUTCSeconds()).slice(-2); +714 return year + mon + day + hour + min + sec + "Z"; +715 }; +716
\ No newline at end of file diff --git a/index.html b/index.html index a35a60a..d44573a 100755 --- a/index.html +++ b/index.html @@ -28,6 +28,7 @@

jsjws : pure JavaScript implementation of JWT ( JSON We API REFERENCE | DEMOS | MOBILE | + NPM | @@ -54,8 +55,8 @@

FEATURES

  • sign and verify a JSON Web Token(JWT) and Signature(JWS) with RSA/RSAPSS/ECDSA algorithm
  • implemented by pure JavaScript
  • work on any modern browsers including smart phones
  • -
  • supports all algorithms except HS384 and ES512 (i.e. jsjws now supports - HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, PS256, PS384, PS512, none.)
  • +
  • supports all algorithms except ES512 (i.e. jsjws now supports + HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, PS256, PS384, PS512)
  • powerful and easy 'sign' and 'verify' method.
  • used with naked key, X.509 certificate and PKCS#5/PKCS#8 encrypted/plain private/public key
  • supports UTF-8 characters including CJK, Latin and non-ASCII in JWS Header and Payload
  • @@ -65,6 +66,13 @@

    FEATURES

    NEWS

    +
    2015-Apr-04: +
    +3.1.0 released. alg=none support have been removed. + +
    2013-Oct-07: +
    Node.js npm module of jsrsasign is now registered in the repository. It also includes this 'jsjws'. +
    2013-Sep-24
    3.0.2 released. Now supports HS384 (HmacSHA384) signature diff --git a/index_mat.html b/index_mat.html index 4668dcf..c796745 100755 --- a/index_mat.html +++ b/index_mat.html @@ -46,7 +46,7 @@

    Algorithm Support Matrix of JWT/JWS Implementations

    -
    LAST UPDATE: 2013-Sep-24
    +
    LAST UPDATE: 2014-Jun-06

    There are many implementations of JWT/JWS and below shows which algorithms are supported. @@ -89,7 +89,7 @@

    Algorithm Support Matrix of JWT/JWS Implementations

    ✔ ✔ ✔ -✔ +— Tom Wu's RSA, jsrsasign, @@ -210,6 +210,27 @@

    Algorithm Support Matrix of JWT/JWS Implementations

    + +jose.4.j +Java +✔ +✔ +✔ +✔ +✔ +✔ +✔ +✔ +✔ +✔ +✔ +✔ +✔ + +Default JCE + + + Nimbus JWT Java @@ -266,7 +287,7 @@

    Algorithm Support Matrix of JWT/JWS Implementations

    — — — -? +hashlib, ecdsa, Crypto.PublicKey.RSA module @@ -325,7 +346,7 @@

    Algorithm Support Matrix of JWT/JWS Implementations

    — — — -? +Digest::SHA, Crypt::OpenSSL::RSA module @@ -347,6 +368,25 @@

    Algorithm Support Matrix of JWT/JWS Implementations

    CNG,CAPI + +mod_auth_openidc +C +✔ +✔ +✔ +✔ +✔ +✔ +✔ +✔ +✔ +✔ +✔ +✔ +— +OpenSSL + + Back to TOP. @@ -362,7 +402,7 @@

    Algorithm Support Matrix of JWT/JWS Implementations

    Published with GitHub Pages

    -Copyright © 2013 Kenji Urushima. All rights reserved. +Copyright © 2013-2014 Kenji Urushima. All rights reserved.
    diff --git a/jws-3.1.js b/jws-3.1.js new file mode 100755 index 0000000..97c6afd --- /dev/null +++ b/jws-3.1.js @@ -0,0 +1,715 @@ +/*! jws-3.1.0 (c) 2013 Kenji Urushima | kjur.github.com/jsjws/license + */ +/* + * jws.js - JSON Web Signature Class + * + * version: 3.1.0 (2015 Apr 3) + * + * Copyright (c) 2010-2014 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * http://kjur.github.com/jsjws/license/ + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + */ + +/** + * @fileOverview + * @name jws-3.1.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version 3.1.0 (2015-Apr-03) + * @since jsjws 1.0 + * @license MIT License + */ + +if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; +if (typeof KJUR.jws == "undefined" || !KJUR.jws) KJUR.jws = {}; + +/** + * JSON Web Signature(JWS) class.
    + * @name KJUR.jws.JWS + * @class JSON Web Signature(JWS) class + * @property {Dictionary} parsedJWS This property is set after JWS signature verification.
    + * Following "parsedJWS_*" properties can be accessed as "parsedJWS.*" because of + * JsDoc restriction. + * @property {String} parsedJWS_headB64U string of Encrypted JWS Header + * @property {String} parsedJWS_payloadB64U string of Encrypted JWS Payload + * @property {String} parsedJWS_sigvalB64U string of Encrypted JWS signature value + * @property {String} parsedJWS_si string of Signature Input + * @property {String} parsedJWS_sigvalH hexadecimal string of JWS signature value + * @property {String} parsedJWS_sigvalBI BigInteger(defined in jsbn.js) object of JWS signature value + * @property {String} parsedJWS_headS string of decoded JWS Header + * @property {String} parsedJWS_headS string of decoded JWS Payload + * @requires base64x.js, json-sans-eval.js and jsrsasign library + * @see 'jwjws'(JWS JavaScript Library) home page http://kjur.github.com/jsjws/ + * @see 'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/ + * @see IETF I-D JSON Web Algorithms (JWA) + * @since jsjws 1.0 + * @description + *

    Supported Algorithms

    + * Here is supported algorithm names for {@link KJUR.jws.JWS.sign} and {@link KJUR.jws.JWS.verify} + * methods. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    alg valuespec requirementjsjws support
    HS256REQUIREDSUPPORTED
    HS384OPTIONALSUPPORTED
    HS512OPTIONALSUPPORTED
    RS256RECOMMENDEDSUPPORTED
    RS384OPTIONALSUPPORTED
    RS512OPTIONALSUPPORTED
    ES256RECOMMENDED+SUPPORTED
    ES384OPTIONALSUPPORTED
    ES512OPTIONAL-
    PS256OPTIONALSUPPORTED
    PS384OPTIONALSUPPORTED
    PS512OPTIONALSUPPORTED
    noneREQUIREDSUPPORTED(generation only)
    + * NOTE1: HS384 is supported since jsjws 3.0.2 with jsrsasign 4.1.4.
    + * NOTE2: alg=none validation was removed since jsjws 3.1.0.
    + */ +KJUR.jws.JWS = function() { + + // === utility ============================================================= + + /** + * parse JWS string and set public property 'parsedJWS' dictionary.
    + * @name parseJWS + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sJWS JWS signature string to be parsed. + * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". + * @throws if JWS Header is a malformed JSON string. + * @since jws 1.1 + */ + this.parseJWS = function(sJWS, sigValNotNeeded) { + if ((this.parsedJWS !== undefined) && + (sigValNotNeeded || (this.parsedJWS.sigvalH !== undefined))) { + return; + } + if (sJWS.match(/^([^.]+)\.([^.]+)\.([^.]+)$/) == null) { + throw "JWS signature is not a form of 'Head.Payload.SigValue'."; + } + var b6Head = RegExp.$1; + var b6Payload = RegExp.$2; + var b6SigVal = RegExp.$3; + var sSI = b6Head + "." + b6Payload; + this.parsedJWS = {}; + this.parsedJWS.headB64U = b6Head; + this.parsedJWS.payloadB64U = b6Payload; + this.parsedJWS.sigvalB64U = b6SigVal; + this.parsedJWS.si = sSI; + + if (!sigValNotNeeded) { + var hSigVal = b64utohex(b6SigVal); + var biSigVal = parseBigInt(hSigVal, 16); + this.parsedJWS.sigvalH = hSigVal; + this.parsedJWS.sigvalBI = biSigVal; + } + + var sHead = b64utoutf8(b6Head); + var sPayload = b64utoutf8(b6Payload); + this.parsedJWS.headS = sHead; + this.parsedJWS.payloadS = sPayload; + + if (! this.isSafeJSONString(sHead, this.parsedJWS, 'headP')) + throw "malformed JSON string for JWS Head: " + sHead; + }; + + // ==== JWS Validation ========================================================= + function _getSignatureInputByString(sHead, sPayload) { + return utf8tob64u(sHead) + "." + utf8tob64u(sPayload); + }; + + function _getHashBySignatureInput(sSignatureInput, sHashAlg) { + var hashfunc = function(s) { return KJUR.crypto.Util.hashString(s, sHashAlg); }; + if (hashfunc == null) throw "hash function not defined in jsrsasign: " + sHashAlg; + return hashfunc(sSignatureInput); + }; + + function _jws_verifySignature(sHead, sPayload, hSig, hN, hE) { + var sSignatureInput = _getSignatureInputByString(sHead, sPayload); + var biSig = parseBigInt(hSig, 16); + return _rsasign_verifySignatureWithArgs(sSignatureInput, biSig, hN, hE); + }; + + /** + * verify JWS signature with naked RSA public key.
    + * This only supports "RS256" and "RS512" algorithm. + * @name verifyJWSByNE + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sJWS JWS signature string to be verified + * @param {String} hN hexadecimal string for modulus of RSA public key + * @param {String} hE hexadecimal string for public exponent of RSA public key + * @return {String} returns 1 when JWS signature is valid, otherwise returns 0 + * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". + * @throws if JWS Header is a malformed JSON string. + * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify} + */ + this.verifyJWSByNE = function(sJWS, hN, hE) { + this.parseJWS(sJWS); + return _rsasign_verifySignatureWithArgs(this.parsedJWS.si, this.parsedJWS.sigvalBI, hN, hE); + }; + + /** + * verify JWS signature with RSA public key.
    + * This only supports "RS256", "RS512", "PS256" and "PS512" algorithms. + * @name verifyJWSByKey + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sJWS JWS signature string to be verified + * @param {RSAKey} key RSA public key + * @return {Boolean} returns true when JWS signature is valid, otherwise returns false + * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". + * @throws if JWS Header is a malformed JSON string. + * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify} + */ + this.verifyJWSByKey = function(sJWS, key) { + this.parseJWS(sJWS); + var hashAlg = _jws_getHashAlgFromParsedHead(this.parsedJWS.headP); + var isPSS = this.parsedJWS.headP['alg'].substr(0, 2) == "PS"; + + if (key.hashAndVerify) { + return key.hashAndVerify(hashAlg, + new Buffer(this.parsedJWS.si, 'utf8').toString('base64'), + b64utob64(this.parsedJWS.sigvalB64U), + 'base64', + isPSS); + } else if (isPSS) { + return key.verifyStringPSS(this.parsedJWS.si, + this.parsedJWS.sigvalH, hashAlg); + } else { + return key.verifyString(this.parsedJWS.si, + this.parsedJWS.sigvalH); + } + }; + + /** + * verify JWS signature by PEM formatted X.509 certificate.
    + * This only supports "RS256" and "RS512" algorithm. + * @name verifyJWSByPemX509Cert + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sJWS JWS signature string to be verified + * @param {String} sPemX509Cert string of PEM formatted X.509 certificate + * @return {String} returns 1 when JWS signature is valid, otherwise returns 0 + * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". + * @throws if JWS Header is a malformed JSON string. + * @since 1.1 + * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify} + */ + this.verifyJWSByPemX509Cert = function(sJWS, sPemX509Cert) { + this.parseJWS(sJWS); + var x509 = new X509(); + x509.readCertPEM(sPemX509Cert); + return x509.subjectPublicKeyRSA.verifyString(this.parsedJWS.si, this.parsedJWS.sigvalH); + }; + + // ==== JWS Generation ========================================================= + function _jws_getHashAlgFromParsedHead(head) { + var sigAlg = head["alg"]; + var hashAlg = ""; + + if (sigAlg != "RS256" && sigAlg != "RS512" && + sigAlg != "PS256" && sigAlg != "PS512") + throw "JWS signature algorithm not supported: " + sigAlg; + if (sigAlg.substr(2) == "256") hashAlg = "sha256"; + if (sigAlg.substr(2) == "512") hashAlg = "sha512"; + return hashAlg; + }; + + function _jws_getHashAlgFromHead(sHead) { + return _jws_getHashAlgFromParsedHead(jsonParse(sHead)); + }; + + function _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD) { + var rsa = new RSAKey(); + rsa.setPrivate(hN, hE, hD); + + var hashAlg = _jws_getHashAlgFromHead(sHead); + var sigValue = rsa.signString(sSI, hashAlg); + return sigValue; + }; + + function _jws_generateSignatureValueBySI_Key(sHead, sPayload, sSI, key, head) { + var hashAlg = null; + if (typeof head == "undefined") { + hashAlg = _jws_getHashAlgFromHead(sHead); + } else { + hashAlg = _jws_getHashAlgFromParsedHead(head); + } + + var isPSS = head['alg'].substr(0, 2) == "PS"; + + if (key.hashAndSign) { + return b64tob64u(key.hashAndSign(hashAlg, sSI, 'binary', 'base64', isPSS)); + } else if (isPSS) { + return hextob64u(key.signStringPSS(sSI, hashAlg)); + } else { + return hextob64u(key.signString(sSI, hashAlg)); + } + }; + + function _jws_generateSignatureValueByNED(sHead, sPayload, hN, hE, hD) { + var sSI = _getSignatureInputByString(sHead, sPayload); + return _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD); + }; + + /** + * generate JWS signature by Header, Payload and a naked RSA private key.
    + * This only supports "RS256" and "RS512" algorithm. + * @name generateJWSByNED + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sHead string of JWS Header + * @param {String} sPayload string of JWS Payload + * @param {String} hN hexadecimal string for modulus of RSA public key + * @param {String} hE hexadecimal string for public exponent of RSA public key + * @param {String} hD hexadecimal string for private exponent of RSA private key + * @return {String} JWS signature string + * @throws if sHead is a malformed JSON string. + * @throws if supported signature algorithm was not specified in JSON Header. + * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign} + */ + this.generateJWSByNED = function(sHead, sPayload, hN, hE, hD) { + if (! this.isSafeJSONString(sHead)) throw "JWS Head is not safe JSON string: " + sHead; + var sSI = _getSignatureInputByString(sHead, sPayload); + var hSigValue = _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD); + var b64SigValue = hextob64u(hSigValue); + + this.parsedJWS = {}; + this.parsedJWS.headB64U = sSI.split(".")[0]; + this.parsedJWS.payloadB64U = sSI.split(".")[1]; + this.parsedJWS.sigvalB64U = b64SigValue; + + return sSI + "." + b64SigValue; + }; + + /** + * generate JWS signature by Header, Payload and a RSA private key.
    + * This only supports "RS256", "RS512", "PS256" and "PS512" algorithms. + * @name generateJWSByKey + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sHead string of JWS Header + * @param {String} sPayload string of JWS Payload + * @param {RSAKey} RSA private key + * @return {String} JWS signature string + * @throws if sHead is a malformed JSON string. + * @throws if supported signature algorithm was not specified in JSON Header. + * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign} + */ + this.generateJWSByKey = function(sHead, sPayload, key) { + var obj = {}; + if (!this.isSafeJSONString(sHead, obj, 'headP')) + throw "JWS Head is not safe JSON string: " + sHead; + var sSI = _getSignatureInputByString(sHead, sPayload); + var b64SigValue = _jws_generateSignatureValueBySI_Key(sHead, sPayload, sSI, key, obj.headP); + + this.parsedJWS = {}; + this.parsedJWS.headB64U = sSI.split(".")[0]; + this.parsedJWS.payloadB64U = sSI.split(".")[1]; + this.parsedJWS.sigvalB64U = b64SigValue; + + return sSI + "." + b64SigValue; + }; + + // === sign with PKCS#1 RSA private key ===================================================== + function _jws_generateSignatureValueBySI_PemPrvKey(sHead, sPayload, sSI, sPemPrvKey) { + var rsa = new RSAKey(); + rsa.readPrivateKeyFromPEMString(sPemPrvKey); + var hashAlg = _jws_getHashAlgFromHead(sHead); + var sigValue = rsa.signString(sSI, hashAlg); + return sigValue; + }; + + /** + * generate JWS signature by Header, Payload and a PEM formatted PKCS#1 RSA private key.
    + * This only supports "RS256" and "RS512" algorithm. + * @name generateJWSByP1PrvKey + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sHead string of JWS Header + * @param {String} sPayload string of JWS Payload + * @param {String} string for sPemPrvKey PEM formatted PKCS#1 RSA private key
    + * Heading and trailing space characters in PEM key will be ignored. + * @return {String} JWS signature string + * @throws if sHead is a malformed JSON string. + * @throws if supported signature algorithm was not specified in JSON Header. + * @since 1.1 + * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign} + */ + this.generateJWSByP1PrvKey = function(sHead, sPayload, sPemPrvKey) { + if (! this.isSafeJSONString(sHead)) throw "JWS Head is not safe JSON string: " + sHead; + var sSI = _getSignatureInputByString(sHead, sPayload); + var hSigValue = _jws_generateSignatureValueBySI_PemPrvKey(sHead, sPayload, sSI, sPemPrvKey); + var b64SigValue = hextob64u(hSigValue); + + this.parsedJWS = {}; + this.parsedJWS.headB64U = sSI.split(".")[0]; + this.parsedJWS.payloadB64U = sSI.split(".")[1]; + this.parsedJWS.sigvalB64U = b64SigValue; + + return sSI + "." + b64SigValue; + }; +}; + +// === major static method ======================================================== + +/** + * generate JWS signature by specified key
    + * @name sign + * @memberOf KJUR.jws.JWS + * @function + * @static + * @param {String} alg JWS algorithm name to sign and force set to sHead or null + * @param {String} sHead string of JWS Header + * @param {String} sPayload string of JWS Payload + * @param {String} key string of private key or key object to sign + * @param {String} pass (OPTION)passcode to use encrypted private key + * @return {String} JWS signature string + * @since jws 3.0.0 + * @see jsrsasign KJUR.crypto.Signature method + * @see jsrsasign KJUR.crypto.Mac method + * @description + * This method supports following algorithms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    alg valuespec requirementjsjws support
    HS256REQUIREDSUPPORTED
    HS384OPTIONAL-
    HS512OPTIONALSUPPORTED
    RS256RECOMMENDEDSUPPORTED
    RS384OPTIONALSUPPORTED
    RS512OPTIONALSUPPORTED
    ES256RECOMMENDED+SUPPORTED
    ES384OPTIONALSUPPORTED
    ES512OPTIONAL-
    PS256OPTIONALSUPPORTED
    PS384OPTIONALSUPPORTED
    PS512OPTIONALSUPPORTED
    noneREQUIREDSUPPORTED(generation only)
    + *
    + *
    NOTE1: + *
    salt length of RSAPSS signature is the same as the hash algorithm length + * because of IETF JOSE ML discussion. + *
    NOTE2: + *
    The reason of HS384 unsupport is + * CryptoJS HmacSHA384 bug. + *
    NOTE3: + *
    alg=none validation was removed since jsjws 3.1.0.
    + *
    + */ +KJUR.jws.JWS.sign = function(alg, sHeader, sPayload, key, pass) { + var ns1 = KJUR.jws.JWS; + + if (! ns1.isSafeJSONString(sHeader)) + throw "JWS Head is not safe JSON string: " + sHead; + + var pHeader = ns1.readSafeJSONString(sHeader); + + // 1. use alg if defined in sHeader + if ((alg == '' || alg == null) && + pHeader['alg'] !== undefined) { + alg = pHeader['alg']; + } + + // 2. set alg in sHeader if undefined + if ((alg != '' && alg != null) && + pHeader['alg'] === undefined) { + pHeader['alg'] = alg; + sHeader = JSON.stringify(pHeader); + } + + // 3. set signature algorithm like SHA1withRSA + var sigAlg = null; + if (ns1.jwsalg2sigalg[alg] === undefined) { + throw "unsupported alg name: " + alg; + } else { + sigAlg = ns1.jwsalg2sigalg[alg]; + } + + var uHeader = utf8tob64u(sHeader); + var uPayload = utf8tob64u(sPayload); + var uSignatureInput = uHeader + "." + uPayload + + // 4. sign + var hSig = ""; + if (sigAlg.substr(0, 4) == "Hmac") { + if (key === undefined) + throw "hexadecimal key shall be specified for HMAC"; + var mac = new KJUR.crypto.Mac({'alg': sigAlg, 'pass': hextorstr(key)}); + mac.updateString(uSignatureInput); + hSig = mac.doFinal(); + } else if (sigAlg.indexOf("withECDSA") != -1) { + var sig = new KJUR.crypto.Signature({'alg': sigAlg}); + sig.init(key, pass); + sig.updateString(uSignatureInput); + hASN1Sig = sig.sign(); + hSig = KJUR.crypto.ECDSA.asn1SigToConcatSig(hASN1Sig); + } else if (sigAlg != "none") { + var sig = new KJUR.crypto.Signature({'alg': sigAlg}); + sig.init(key, pass); + sig.updateString(uSignatureInput); + hSig = sig.sign(); + } + + var uSig = hextob64u(hSig); + return uSignatureInput + "." + uSig; +}; + +/** + * verify JWS signature by specified key or certificate
    + * @name verify + * @memberOf KJUR.jws.JWS + * @function + * @static + * @param {String} sJWS string of JWS signature to verify + * @param {String} key string of public key, certificate or key object to verify + * @return {Boolean} true if the signature is valid otherwise false + * @since jws 3.0.0 + * @see jsrsasign KJUR.crypto.Signature method + * @see jsrsasign KJUR.crypto.Mac method + * @description + * This method verifies a JSON Web Signature Compact Serialization string by the validation + * algorithm as described in + * + * the section 5 of Internet Draft draft-jones-json-web-signature-04. + *
    + * NOTE: alg=none validation was removed since jsjws 3.1.0.
    + */ +KJUR.jws.JWS.verify = function(sJWS, key) { + var jws = KJUR.jws.JWS; + var a = sJWS.split("."); + var uHeader = a[0]; + var uPayload = a[1]; + var uSignatureInput = uHeader + "." + uPayload; + var hSig = b64utohex(a[2]); + + var pHeader = jws.readSafeJSONString(b64utoutf8(a[0])); + var alg = null; + if (pHeader.alg === undefined) { + throw "algorithm not specified in header"; + } else { + alg = pHeader.alg; + } + + var sigAlg = null; + if (jws.jwsalg2sigalg[pHeader.alg] === undefined) { + throw "unsupported alg name: " + alg; + } else { + sigAlg = jws.jwsalg2sigalg[alg]; + } + + // x. verify + if (sigAlg == "none") { + throw "not supported"; + } else if (sigAlg.substr(0, 4) == "Hmac") { + if (key === undefined) + throw "hexadecimal key shall be specified for HMAC"; + var mac = new KJUR.crypto.Mac({'alg': sigAlg, 'pass': hextorstr(key)}); + mac.updateString(uSignatureInput); + hSig2 = mac.doFinal(); + return hSig == hSig2; + } else if (sigAlg.indexOf("withECDSA") != -1) { + var hASN1Sig = null; + try { + hASN1Sig = KJUR.crypto.ECDSA.concatSigToASN1Sig(hSig); + } catch (ex) { + return false; + } + var sig = new KJUR.crypto.Signature({'alg': sigAlg}); + sig.init(key) + sig.updateString(uSignatureInput); + return sig.verify(hASN1Sig); + } else { + var sig = new KJUR.crypto.Signature({'alg': sigAlg}); + sig.init(key) + sig.updateString(uSignatureInput); + return sig.verify(hSig); + } +}; + +/* + * @since jws 3.0.0 + */ +KJUR.jws.JWS.jwsalg2sigalg = { + "HS256": "HmacSHA256", + //"HS384": "HmacSHA384", // unsupported because of CryptoJS bug + "HS512": "HmacSHA512", + "RS256": "SHA256withRSA", + "RS384": "SHA384withRSA", + "RS512": "SHA512withRSA", + "ES256": "SHA256withECDSA", + "ES384": "SHA384withECDSA", + //"ES512": "SHA512withECDSA", // unsupported because of jsrsasign's bug + "PS256": "SHA256withRSAandMGF1", + "PS384": "SHA384withRSAandMGF1", + "PS512": "SHA512withRSAandMGF1", + "none": "none", +}; + +// === utility static method ====================================================== + +/** + * check whether a String "s" is a safe JSON string or not.
    + * If a String "s" is a malformed JSON string or an other object type + * this returns 0, otherwise this returns 1. + * @name isSafeJSONString + * @memberOf KJUR.jws.JWS + * @function + * @static + * @param {String} s JSON string + * @return {Number} 1 or 0 + */ +KJUR.jws.JWS.isSafeJSONString = function(s, h, p) { + var o = null; + try { + o = jsonParse(s); + if (typeof o != "object") return 0; + if (o.constructor === Array) return 0; + if (h) h[p] = o; + return 1; + } catch (ex) { + return 0; + } +}; + +/** + * read a String "s" as JSON object if it is safe.
    + * If a String "s" is a malformed JSON string or not JSON string, + * this returns null, otherwise returns JSON object. + * @name readSafeJSONString + * @memberOf KJUR.jws.JWS + * @function + * @static + * @param {String} s JSON string + * @return {Object} JSON object or null + * @since 1.1.1 + */ +KJUR.jws.JWS.readSafeJSONString = function(s) { + var o = null; + try { + o = jsonParse(s); + if (typeof o != "object") return null; + if (o.constructor === Array) return null; + return o; + } catch (ex) { + return null; + } +}; + +/** + * get Encoed Signature Value from JWS string.
    + * @name getEncodedSignatureValueFromJWS + * @memberOf KJUR.jws.JWS + * @function + * @static + * @param {String} sJWS JWS signature string to be verified + * @return {String} string of Encoded Signature Value + * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". + */ +KJUR.jws.JWS.getEncodedSignatureValueFromJWS = function(sJWS) { + if (sJWS.match(/^[^.]+\.[^.]+\.([^.]+)$/) == null) { + throw "JWS signature is not a form of 'Head.Payload.SigValue'."; + } + return RegExp.$1; +}; + +/** + * IntDate class for time representation for JSON Web Token(JWT) + * @class KJUR.jws.IntDate class + * @name KJUR.jws.IntDate + * @since jws 3.0.1 + * @description + * Utility class for IntDate which is integer representation of UNIX origin time + * used in JSON Web Token(JWT). + */ +KJUR.jws.IntDate = function() { +}; + +/** + * @name get + * @memberOf KJUR.jws.IntDate + * @function + * @static + * @param {String} s string of time representation + * @return {Integer} UNIX origin time in seconds for argument 's' + * @since jws 3.0.1 + * @throws "unsupported format: s" when malformed format + * @description + * This method will accept following representation of time. + *
      + *
    • now - current time
    • + *
    • now + 1hour - after 1 hour from now
    • + *
    • now + 1day - after 1 day from now
    • + *
    • now + 1month - after 30 days from now
    • + *
    • now + 1year - after 365 days from now
    • + *
    • YYYYmmDDHHMMSSZ - UTC time (ex. 20130828235959Z)
    • + *
    • number - UNIX origin time (seconds from 1970-01-01 00:00:00) (ex. 1377714748)
    • + *
    + */ +KJUR.jws.IntDate.get = function(s) { + if (s == "now") { + return KJUR.jws.IntDate.getNow(); + } else if (s == "now + 1hour") { + return KJUR.jws.IntDate.getNow() + 60 * 60; + } else if (s == "now + 1day") { + return KJUR.jws.IntDate.getNow() + 60 * 60 * 24; + } else if (s == "now + 1month") { + return KJUR.jws.IntDate.getNow() + 60 * 60 * 24 * 30; + } else if (s == "now + 1year") { + return KJUR.jws.IntDate.getNow() + 60 * 60 * 24 * 365; + } else if (s.match(/Z$/)) { + return KJUR.jws.IntDate.getZulu(s); + } else if (s.match(/^[0-9]+$/)) { + return parseInt(s); + } + throw "unsupported format: " + s; +}; + +KJUR.jws.IntDate.getZulu = function(s) { + if (a = s.match(/(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)Z/)) { + var year = parseInt(RegExp.$1); + var month = parseInt(RegExp.$2) - 1; + var day = parseInt(RegExp.$3); + var hour = parseInt(RegExp.$4); + var min = parseInt(RegExp.$5); + var sec = parseInt(RegExp.$6); + var d = new Date(Date.UTC(year, month, day, hour, min, sec)); + return ~~(d / 1000); + } + throw "unsupported format: " + s; +}; + +/* + * @since jws 3.0.1 + */ +KJUR.jws.IntDate.getNow = function() { + var d = ~~(new Date() / 1000); + return d; +}; + +/* + * @since jws 3.0.1 + */ +KJUR.jws.IntDate.intDate2UTCString = function(intDate) { + var d = new Date(intDate * 1000); + return d.toUTCString(); +}; + +/* + * @since jws 3.0.1 + */ +KJUR.jws.IntDate.intDate2Zulu = function(intDate) { + var d = new Date(intDate * 1000); + var year = ("0000" + d.getUTCFullYear()).slice(-4); + var mon = ("00" + (d.getUTCMonth() + 1)).slice(-2); + var day = ("00" + d.getUTCDate()).slice(-2); + var hour = ("00" + d.getUTCHours()).slice(-2); + var min = ("00" + d.getUTCMinutes()).slice(-2); + var sec = ("00" + d.getUTCSeconds()).slice(-2); + return year + mon + day + hour + min + sec + "Z"; +}; diff --git a/jws-3.1.min.js b/jws-3.1.min.js new file mode 100755 index 0000000..b2ef9bf --- /dev/null +++ b/jws-3.1.min.js @@ -0,0 +1,3 @@ +/*! jws-3.1.0 (c) 2013 Kenji Urushima | kjur.github.com/jsjws/license + */ +if(typeof KJUR=="undefined"||!KJUR){KJUR={}}if(typeof KJUR.jws=="undefined"||!KJUR.jws){KJUR.jws={}}KJUR.jws.JWS=function(){this.parseJWS=function(n,p){if((this.parsedJWS!==undefined)&&(p||(this.parsedJWS.sigvalH!==undefined))){return}if(n.match(/^([^.]+)\.([^.]+)\.([^.]+)$/)==null){throw"JWS signature is not a form of 'Head.Payload.SigValue'."}var q=RegExp.$1;var l=RegExp.$2;var r=RegExp.$3;var t=q+"."+l;this.parsedJWS={};this.parsedJWS.headB64U=q;this.parsedJWS.payloadB64U=l;this.parsedJWS.sigvalB64U=r;this.parsedJWS.si=t;if(!p){var o=b64utohex(r);var m=parseBigInt(o,16);this.parsedJWS.sigvalH=o;this.parsedJWS.sigvalBI=m}var k=b64utoutf8(q);var s=b64utoutf8(l);this.parsedJWS.headS=k;this.parsedJWS.payloadS=s;if(!this.isSafeJSONString(k,this.parsedJWS,"headP")){throw"malformed JSON string for JWS Head: "+k}};function b(l,k){return utf8tob64u(l)+"."+utf8tob64u(k)}function f(m,l){var k=function(n){return KJUR.crypto.Util.hashString(n,l)};if(k==null){throw"hash function not defined in jsrsasign: "+l}return k(m)}function h(q,n,k,o,m){var p=b(q,n);var l=parseBigInt(k,16);return _rsasign_verifySignatureWithArgs(p,l,o,m)}this.verifyJWSByNE=function(m,l,k){this.parseJWS(m);return _rsasign_verifySignatureWithArgs(this.parsedJWS.si,this.parsedJWS.sigvalBI,l,k)};this.verifyJWSByKey=function(n,m){this.parseJWS(n);var k=c(this.parsedJWS.headP);var l=this.parsedJWS.headP.alg.substr(0,2)=="PS";if(m.hashAndVerify){return m.hashAndVerify(k,new Buffer(this.parsedJWS.si,"utf8").toString("base64"),b64utob64(this.parsedJWS.sigvalB64U),"base64",l)}else{if(l){return m.verifyStringPSS(this.parsedJWS.si,this.parsedJWS.sigvalH,k)}else{return m.verifyString(this.parsedJWS.si,this.parsedJWS.sigvalH)}}};this.verifyJWSByPemX509Cert=function(m,k){this.parseJWS(m);var l=new X509();l.readCertPEM(k);return l.subjectPublicKeyRSA.verifyString(this.parsedJWS.si,this.parsedJWS.sigvalH)};function c(l){var m=l.alg;var k="";if(m!="RS256"&&m!="RS512"&&m!="PS256"&&m!="PS512"){throw"JWS signature algorithm not supported: "+m}if(m.substr(2)=="256"){k="sha256"}if(m.substr(2)=="512"){k="sha512"}return k}function e(k){return c(jsonParse(k))}function j(k,p,s,m,q,r){var n=new RSAKey();n.setPrivate(m,q,r);var l=e(k);var o=n.signString(s,l);return o}function i(q,p,o,n,m){var k=null;if(typeof m=="undefined"){k=e(q)}else{k=c(m)}var l=m.alg.substr(0,2)=="PS";if(n.hashAndSign){return b64tob64u(n.hashAndSign(k,o,"binary","base64",l))}else{if(l){return hextob64u(n.signStringPSS(o,k))}else{return hextob64u(n.signString(o,k))}}}function g(p,m,o,l,n){var k=b(p,m);return j(p,m,k,o,l,n)}this.generateJWSByNED=function(r,n,q,m,p){if(!this.isSafeJSONString(r)){throw"JWS Head is not safe JSON string: "+r}var l=b(r,n);var o=j(r,n,l,q,m,p);var k=hextob64u(o);this.parsedJWS={};this.parsedJWS.headB64U=l.split(".")[0];this.parsedJWS.payloadB64U=l.split(".")[1];this.parsedJWS.sigvalB64U=k;return l+"."+k};this.generateJWSByKey=function(p,n,k){var o={};if(!this.isSafeJSONString(p,o,"headP")){throw"JWS Head is not safe JSON string: "+p}var m=b(p,n);var l=i(p,n,m,k,o.headP);this.parsedJWS={};this.parsedJWS.headB64U=m.split(".")[0];this.parsedJWS.payloadB64U=m.split(".")[1];this.parsedJWS.sigvalB64U=l;return m+"."+l};function d(q,p,o,l){var n=new RSAKey();n.readPrivateKeyFromPEMString(l);var k=e(q);var m=n.signString(o,k);return m}this.generateJWSByP1PrvKey=function(p,n,k){if(!this.isSafeJSONString(p)){throw"JWS Head is not safe JSON string: "+p}var m=b(p,n);var o=d(p,n,m,k);var l=hextob64u(o);this.parsedJWS={};this.parsedJWS.headB64U=m.split(".")[0];this.parsedJWS.payloadB64U=m.split(".")[1];this.parsedJWS.sigvalB64U=l;return m+"."+l}};KJUR.jws.JWS.sign=function(b,p,i,l,k){var j=KJUR.jws.JWS;if(!j.isSafeJSONString(p)){throw"JWS Head is not safe JSON string: "+sHead}var e=j.readSafeJSONString(p);if((b==""||b==null)&&e.alg!==undefined){b=e.alg}if((b!=""&&b!=null)&&e.alg===undefined){e.alg=b;p=JSON.stringify(e)}var d=null;if(j.jwsalg2sigalg[b]===undefined){throw"unsupported alg name: "+b}else{d=j.jwsalg2sigalg[b]}var c=utf8tob64u(p);var g=utf8tob64u(i);var n=c+"."+g;var m="";if(d.substr(0,4)=="Hmac"){if(l===undefined){throw"hexadecimal key shall be specified for HMAC"}var h=new KJUR.crypto.Mac({alg:d,pass:hextorstr(l)});h.updateString(n);m=h.doFinal()}else{if(d.indexOf("withECDSA")!=-1){var o=new KJUR.crypto.Signature({alg:d});o.init(l,k);o.updateString(n);hASN1Sig=o.sign();m=KJUR.crypto.ECDSA.asn1SigToConcatSig(hASN1Sig)}else{if(d!="none"){var o=new KJUR.crypto.Signature({alg:d});o.init(l,k);o.updateString(n);m=o.sign()}}}var f=hextob64u(m);return n+"."+f};KJUR.jws.JWS.verify=function(d,m){var k=KJUR.jws.JWS;var l=d.split(".");var c=l[0];var h=l[1];var o=c+"."+h;var n=b64utohex(l[2]);var f=k.readSafeJSONString(b64utoutf8(l[0]));var b=null;if(f.alg===undefined){throw"algorithm not specified in header"}else{b=f.alg}var e=null;if(k.jwsalg2sigalg[f.alg]===undefined){throw"unsupported alg name: "+b}else{e=k.jwsalg2sigalg[b]}if(e=="none"){throw"not supported"}else{if(e.substr(0,4)=="Hmac"){if(m===undefined){throw"hexadecimal key shall be specified for HMAC"}var j=new KJUR.crypto.Mac({alg:e,pass:hextorstr(m)});j.updateString(o);hSig2=j.doFinal();return n==hSig2}else{if(e.indexOf("withECDSA")!=-1){var g=null;try{g=KJUR.crypto.ECDSA.concatSigToASN1Sig(n)}catch(i){return false}var p=new KJUR.crypto.Signature({alg:e});p.init(m);p.updateString(o);return p.verify(g)}else{var p=new KJUR.crypto.Signature({alg:e});p.init(m);p.updateString(o);return p.verify(n)}}}};KJUR.jws.JWS.jwsalg2sigalg={HS256:"HmacSHA256",HS512:"HmacSHA512",RS256:"SHA256withRSA",RS384:"SHA384withRSA",RS512:"SHA512withRSA",ES256:"SHA256withECDSA",ES384:"SHA384withECDSA",PS256:"SHA256withRSAandMGF1",PS384:"SHA384withRSAandMGF1",PS512:"SHA512withRSAandMGF1",none:"none",};KJUR.jws.JWS.isSafeJSONString=function(d,c,e){var f=null;try{f=jsonParse(d);if(typeof f!="object"){return 0}if(f.constructor===Array){return 0}if(c){c[e]=f}return 1}catch(b){return 0}};KJUR.jws.JWS.readSafeJSONString=function(c){var d=null;try{d=jsonParse(c);if(typeof d!="object"){return null}if(d.constructor===Array){return null}return d}catch(b){return null}};KJUR.jws.JWS.getEncodedSignatureValueFromJWS=function(b){if(b.match(/^[^.]+\.[^.]+\.([^.]+)$/)==null){throw"JWS signature is not a form of 'Head.Payload.SigValue'."}return RegExp.$1};KJUR.jws.IntDate=function(){};KJUR.jws.IntDate.get=function(b){if(b=="now"){return KJUR.jws.IntDate.getNow()}else{if(b=="now + 1hour"){return KJUR.jws.IntDate.getNow()+60*60}else{if(b=="now + 1day"){return KJUR.jws.IntDate.getNow()+60*60*24}else{if(b=="now + 1month"){return KJUR.jws.IntDate.getNow()+60*60*24*30}else{if(b=="now + 1year"){return KJUR.jws.IntDate.getNow()+60*60*24*365}else{if(b.match(/Z$/)){return KJUR.jws.IntDate.getZulu(b)}else{if(b.match(/^[0-9]+$/)){return parseInt(b)}}}}}}}throw"unsupported format: "+b};KJUR.jws.IntDate.getZulu=function(h){if(a=h.match(/(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)Z/)){var g=parseInt(RegExp.$1);var i=parseInt(RegExp.$2)-1;var c=parseInt(RegExp.$3);var b=parseInt(RegExp.$4);var e=parseInt(RegExp.$5);var f=parseInt(RegExp.$6);var j=new Date(Date.UTC(g,i,c,b,e,f));return ~~(j/1000)}throw"unsupported format: "+h};KJUR.jws.IntDate.getNow=function(){var b=~~(new Date()/1000);return b};KJUR.jws.IntDate.intDate2UTCString=function(b){var c=new Date(b*1000);return c.toUTCString()};KJUR.jws.IntDate.intDate2Zulu=function(f){var j=new Date(f*1000);var i=("0000"+j.getUTCFullYear()).slice(-4);var h=("00"+(j.getUTCMonth()+1)).slice(-2);var c=("00"+j.getUTCDate()).slice(-2);var b=("00"+j.getUTCHours()).slice(-2);var e=("00"+j.getUTCMinutes()).slice(-2);var g=("00"+j.getUTCSeconds()).slice(-2);return i+h+c+b+e+g+"Z"}; \ No newline at end of file diff --git a/sample_generate.html b/sample_generate.html index 4cc31ec..e0deb5c 100644 --- a/sample_generate.html +++ b/sample_generate.html @@ -20,7 +20,7 @@ - +