1 /*! jwsjs-2.0.0 (c) 2013 Kenji Urushima | kjur.github.com/jsjws/license
  2  */
  3 /*
  4  * jwsjs.js - JSON Web Signature JSON Serialization (JWSJS) Class
  5  *
  6  * version: 2.0.0 (2013 Jul 20)
  7  *
  8  * Copyright (c) 2010-2013 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/
 12  *
 13  * The above copyright and license notice shall be 
 14  * included in all copies or substantial portions of the Software.
 15  */
 16 
 17 /**
 18  * @fileOverview
 19  * @name jwsjs-2.0.js
 20  * @author Kenji Urushima kenji.urushima@gmail.com
 21  * @version 2.0.0 (2013 Jul 20)
 22  * @since jsjws 1.2
 23  * @license <a href="http://kjur.github.io/jsjws/license/">MIT License</a>
 24  */
 25 
 26 if (typeof KJUR == "undefined" || !KJUR) KJUR = {};
 27 if (typeof KJUR.jws == "undefined" || !KJUR.jws) KJUR.jws = {};
 28 
 29 /**
 30  * JSON Web Signature JSON Serialization (JWSJS) class.<br/>
 31  * @class JSON Web Signature JSON Serialization (JWSJS) class
 32  * @name KJUR.jws.JWSJS
 33  * @property {array of String} aHeader array of Encoded JWS Headers
 34  * @property {String} sPayload Encoded JWS payload
 35  * @property {array of String} aSignature array of Encoded JWS signature value
 36  * @author Kenji Urushima
 37  * @version 1.0 (18 May 2012)
 38  * @requires base64x.js, json-sans-eval.js, jws.js and jsrsasign library
 39  * @see <a href="http://kjur.github.com/jsjws/">'jwjws'(JWS JavaScript Library) home page http://kjur.github.com/jsjws/</a>
 40  * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
 41  * @see <a href="http://tools.ietf.org/html/draft-jones-json-web-signature-json-serialization-01">IETF I-D JSON Web Signature JSON Serialization (JWS-JS) specification</a>
 42  */
 43 KJUR.jws.JWSJS = function() {
 44     this.aHeader = [];
 45     this.sPayload = "";
 46     this.aSignature = [];
 47 
 48     // == initialize ===================================================================
 49     /**
 50      * (re-)initialize this object.<br/>
 51      * @name init
 52      * @memberOf KJUR.jws.JWSJS
 53      * @function
 54      */
 55     this.init = function() {
 56 	this.aHeader = [];
 57 	this.sPayload = "";
 58 	this.aSignature = [];
 59     };
 60 
 61     /**
 62      * (re-)initialize and set first signature with JWS.<br/>
 63      * @name initWithJWS
 64      * @memberOf KJUR.jws.JWSJS
 65      * @param {String} sJWS JWS signature to set
 66      * @function
 67      */
 68     this.initWithJWS = function(sJWS) {
 69 	this.init();
 70 
 71 	var jws = new KJUR.jws.JWS();
 72 	jws.parseJWS(sJWS);
 73 
 74 	this.aHeader.push(jws.parsedJWS.headB64U);
 75 	this.sPayload = jws.parsedJWS.payloadB64U;
 76 	this.aSignature.push(jws.parsedJWS.sigvalB64U);
 77     };
 78 
 79     // == add signature ===================================================================
 80     /**
 81      * add a signature to existing JWS-JS by Header and PKCS1 private key.<br/>
 82      * @name addSignatureByHeaderKey
 83      * @memberOf KJUR.jws.JWSJS
 84      * @function
 85      * @param {String} sHead JSON string of JWS Header for adding signature.
 86      * @param {String} sPemPrvKey string of PKCS1 private key
 87      */
 88     this.addSignatureByHeaderKey = function(sHead, sPemPrvKey) {
 89 	var sPayload = b64utoutf8(this.sPayload);
 90 
 91 	var jws = new KJUR.jws.JWS();
 92 	var sJWS = jws.generateJWSByP1PrvKey(sHead, sPayload, sPemPrvKey);
 93   
 94 	this.aHeader.push(jws.parsedJWS.headB64U);
 95 	this.aSignature.push(jws.parsedJWS.sigvalB64U);
 96     };
 97 
 98     /**
 99      * add a signature to existing JWS-JS by Header, Payload and PKCS1 private key.<br/>
100      * This is to add first signature to JWS-JS object.
101      * @name addSignatureByHeaderPayloadKey
102      * @memberOf KJUR.jws.JWSJS
103      * @function
104      * @param {String} sHead JSON string of JWS Header for adding signature.
105      * @param {String} sPayload string of JWS Payload for adding signature.
106      * @param {String} sPemPrvKey string of PKCS1 private key
107      */
108     this.addSignatureByHeaderPayloadKey = function(sHead, sPayload, sPemPrvKey) {
109 	var jws = new KJUR.jws.JWS();
110 	var sJWS = jws.generateJWSByP1PrvKey(sHead, sPayload, sPemPrvKey);
111   
112 	this.aHeader.push(jws.parsedJWS.headB64U);
113 	this.sPayload = jws.parsedJWS.payloadB64U;
114 	this.aSignature.push(jws.parsedJWS.sigvalB64U);
115     };
116 
117     // == verify signature ===================================================================
118     /**
119      * verify JWS-JS object with array of certificate string.<br/>
120      * @name verifyWithCerts
121      * @memberOf KJUR.jws.JWSJS
122      * @function
123      * @param {array of String} aCert array of string for X.509 PEM certificate.
124      * @return 1 if signature is valid.
125      * @throw if JWS-JS signature is invalid.
126      */
127     this.verifyWithCerts = function(aCert) {
128 	if (this.aHeader.length != aCert.length) 
129 	    throw "num headers does not match with num certs";
130 	if (this.aSignature.length != aCert.length) 
131 	    throw "num signatures does not match with num certs";
132 
133 	var payload = this.sPayload;
134 	var errMsg = "";
135 	for (var i = 0; i < aCert.length; i++) {
136 	    var cert = aCert[i];
137 	    var header = this.aHeader[i];
138 	    var sig = this.aSignature[i];
139 	    var sJWS = header + "." + payload + "." + sig;
140 
141 	    var jws = new KJUR.jws.JWS();
142 	    try {
143 		var result = jws.verifyJWSByPemX509Cert(sJWS, cert);
144 		if (result != 1) {
145 		    errMsg += (i + 1) + "th signature unmatch. ";
146 		}
147 	    } catch (ex) {
148 		errMsg += (i + 1) + "th signature fail(" + ex + "). ";
149 	    }
150 	}
151 
152 	if (errMsg == "") {
153 	    return 1;
154 	} else {
155 	    throw errMsg;
156 	}
157     };
158 
159     /**
160      * read JWS-JS string.<br/>
161      * @name raedJWSJS
162      * @memberOf KJUR.jws.JWSJS
163      * @function
164      * @param {String} string of JWS-JS to load.
165      * @throw if sJWSJS is malformed or not JSON string.
166      */
167     this.readJWSJS = function(sJWSJS) {
168 	var jws = new KJUR.jws.JWS();
169 	var oJWSJS = jws.readSafeJSONString(sJWSJS);
170 	if (oJWSJS == null) throw "argument is not JSON string: " + sJWSJS;
171 
172 	this.aHeader = oJWSJS.headers;
173 	this.sPayload = oJWSJS.payload;
174 	this.aSignature = oJWSJS.signatures;
175     };
176 
177     // == utility ===================================================================
178     /**
179      * get JSON object for this JWS-JS object.<br/>
180      * @name getJSON
181      * @memberOf KJUR.jws.JWSJS
182      * @function
183      */
184     this.getJSON = function() {
185 	return { "headers": this.aHeader,
186 		 "payload": this.sPayload,
187 		 "signatures": this.aSignature }; 
188     };
189 
190     /**
191      * check if this JWS-JS object is empty.<br/>
192      * @name isEmpty
193      * @memberOf KJUR.jws.JWSJS
194      * @function
195      * @return 1 if there is no signatures in this object, otherwise 0.
196      */
197     this.isEmpty = function() {
198 	if (this.aHeader.length == 0) return 1; 
199 	return 0;
200     };
201 };
202 
203