1 /*! asn1ocsp-1.0.1.js (c) 2016 Kenji Urushima | kjur.github.com/jsrsasign/license
  2  */
  3 /*
  4  * asn1ocsp.js - ASN.1 DER encoder classes for OCSP protocol
  5  *
  6  * Copyright (c) 2016 Kenji Urushima (kenji.urushima@gmail.com)
  7  *
  8  * This software is licensed under the terms of the MIT License.
  9  * http://kjur.github.com/jsrsasign/license
 10  *
 11  * The above copyright and license notice shall be 
 12  * included in all copies or substantial portions of the Software.
 13  */
 14 
 15 /**
 16  * @fileOverview
 17  * @name asn1ocsp-1.0.js
 18  * @author Kenji Urushima kenji.urushima@gmail.com
 19  * @version 1.0.1 (2016-Oct-02)
 20  * @since jsrsasign 6.1.0
 21  * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
 22  */
 23 
 24 if (typeof KJUR == "undefined" || !KJUR) KJUR = {};
 25 if (typeof KJUR.asn1 == "undefined" || !KJUR.asn1) KJUR.asn1 = {};
 26 
 27 /**
 28  * ASN.1 classes for OCSP protocol<br/>
 29  * <p>
 30  * This name space provides 
 31  * <a href="https://tools.ietf.org/html/rfc6960">RFC 6960
 32  * Online Certificate Status Protocol (OCSP)</a> ASN.1 request and response generator.
 33  *
 34  * <h4>FEATURES</h4>
 35  * <ul>
 36  * <li>easily generate OCSP data</li>
 37  * </ul>
 38  * 
 39  * <h4>PROVIDED CLASSES</h4>
 40  * <ul>
 41  * <li>{@link KJUR.asn1.ocsp.CertID} for ASN.1 class as defined in 
 42  * <a href="https://tools.ietf.org/html/rfc6960#section-4.1.1">RFC 6960 4.1.1</a>. </li>
 43  * <li>{@link KJUR.asn1.ocsp.Request} for ASN.1 class as defined in
 44  * <a href="https://tools.ietf.org/html/rfc6960#section-4.1.1">RFC 6960 4.1.1</a>. </li>
 45  * <li>{@link KJUR.asn1.ocsp.TBSRequest} for ASN.1 class as defined in
 46  * <a href="https://tools.ietf.org/html/rfc6960#section-4.1.1">RFC 6960 4.1.1</a>. </li>
 47  * <li>{@link KJUR.asn1.ocsp.OCSPRequest} for ASN.1 class as defined in
 48  * <a href="https://tools.ietf.org/html/rfc6960#section-4.1.1">RFC 6960 4.1.1</a>. </li>
 49  * <li>{@link KJUR.asn1.ocsp.OCSPUtil} for static utility methods.</li>
 50  * </ul>
 51  * </p>
 52  * @name KJUR.asn1.ocsp
 53  * @namespace
 54  */
 55 if (typeof KJUR.asn1.ocsp == "undefined" || !KJUR.asn1.ocsp) KJUR.asn1.ocsp = {};
 56 
 57 KJUR.asn1.ocsp.DEFAULT_HASH = "sha1";
 58 
 59 /**
 60  * ASN.1 CertID class for OCSP<br/>
 61  * @name KJUR.asn1.ocsp.CertID
 62  * @class ASN.1 CertID class for OCSP
 63  * @param {Array} params associative array of parameters
 64  * @extends KJUR.asn1.ASN1Object
 65  * @since jsrsasign 6.1.0 asn1ocsp 1.0.0
 66  * @description
 67  * CertID ASN.1 class is defined in 
 68  * <a href="https://tools.ietf.org/html/rfc6960#section-4.1.1">RFC 6960 4.1.1</a>. 
 69  * <pre>
 70  * CertID ::= SEQUENCE {
 71  *   hashAlgorithm   AlgorithmIdentifier,
 72  *   issuerNameHash  OCTET STRING, -- Hash of issuer's DN
 73  *   issuerKeyHash   OCTET STRING, -- Hash of issuer's public key
 74  *   serialNumber    CertificateSerialNumber }
 75  * </pre>
 76  * @example
 77  * // default constructor
 78  * o = new KJUR.asn1.ocsp.CertID();
 79  * // constructor with certs (sha1 is used by default)
 80  * o = new KJUR.asn1.ocsp.CertID({issuerCert: "-----BEGIN...", subjectCert: "-----BEGIN..."});
 81  * // constructor with certs and sha256
 82  * o = new KJUR.asn1.ocsp.CertID({issuerCert: "-----BEGIN...", subjectCert: "-----BEGIN...", alg: "sha256"});
 83  * // constructor with values
 84  * o = new KJUR.asn1.ocsp.CertID({namehash: "1a...", keyhash: "ad...", serial: "1234", alg: "sha256"});
 85  */
 86 KJUR.asn1.ocsp.CertID = function(params) {
 87     KJUR.asn1.ocsp.CertID.superclass.constructor.call(this);
 88     var nA = KJUR.asn1;
 89     var nX = KJUR.asn1.x509;
 90     this.dHashAlg = null;
 91     this.dIssuerNameHash = null;
 92     this.dIssuerKeyHash = null;
 93     this.dSerialNumber = null;
 94 
 95     /**
 96      * set CertID ASN.1 object by values.<br/>
 97      * @name setByValue
 98      * @memberOf KJUR.asn1.ocsp.CertID#
 99      * @function
100      * @param {String} issuerNameHashHex hexadecimal string of hash value of issuer name
101      * @param {String} issuerKeyHashHex hexadecimal string of hash value of issuer public key
102      * @param {String} serialNumberHex hexadecimal string of certificate serial number to be verified
103      * @param {String} algName hash algorithm name used for above arguments (ex. "sha1") DEFAULT: sha1
104      * @since jsrsasign 6.1.0 asn1ocsp 1.0.0
105      * @example
106      * o = new KJUR.asn1.ocsp.CertID();
107      * o.setByValue("1fac...", "fd3a...", "1234"); // sha1 is used by default
108      * o.setByValue("1fac...", "fd3a...", "1234", "sha256");
109      */
110     this.setByValue = function(issuerNameHashHex, issuerKeyHashHex,
111 			       serialNumberHex, algName) {
112 	if (algName === undefined)
113 	    algName = KJUR.asn1.ocsp.DEFAULT_HASH;
114 	this.dHashAlg =        new nX.AlgorithmIdentifier({name: algName});
115 	this.dIssuerNameHash = new nA.DEROctetString({hex: issuerNameHashHex});
116 	this.dIssuerKeyHash =  new nA.DEROctetString({hex: issuerKeyHashHex});
117 	this.dSerialNumber =   new nA.DERInteger({hex: serialNumberHex});
118     };
119 
120     /**
121      * set CertID ASN.1 object by PEM certificates.<br/>
122      * @name setByCert
123      * @memberOf KJUR.asn1.ocsp.CertID#
124      * @function
125      * @param {String} issuerCert string of PEM issuer certificate
126      * @param {String} subjectCert string of PEM subject certificate to be verified by OCSP
127      * @param {String} algName hash algorithm name used for above arguments (ex. "sha1") DEFAULT: sha1
128      * @since jsrsasign 6.1.0 asn1ocsp 1.0.0
129      * @example
130      * o = new KJUR.asn1.ocsp.CertID();
131      * o.setByCert("-----BEGIN...", "-----BEGIN..."); // sha1 is used by default
132      * o.setByCert("-----BEGIN...", "-----BEGIN...", "sha256");
133      */
134     this.setByCert = function(issuerCert, subjectCert, algName) {
135 	if (algName === undefined)
136 	    algName = KJUR.asn1.ocsp.DEFAULT_HASH;
137 
138 	var xSbj = new X509();
139 	xSbj.readCertPEM(subjectCert);
140 	var xIss = new X509();
141 	xIss.readCertPEM(issuerCert);
142 	var kiPropIss = X509.getPublicKeyInfoPropOfCertPEM(issuerCert);
143         var issuerKeyHex = kiPropIss.keyhex;
144 
145 	var serialNumberHex = xSbj.getSerialNumberHex();
146 	var issuerNameHashHex = KJUR.crypto.Util.hashHex(xIss.getSubjectHex(), algName);
147 	var issuerKeyHashHex = KJUR.crypto.Util.hashHex(issuerKeyHex, algName);
148 	this.setByValue(issuerNameHashHex, issuerKeyHashHex,
149 			serialNumberHex, algName);
150 	this.hoge = xSbj.getSerialNumberHex();
151     };
152 
153     this.getEncodedHex = function() {
154 	if (this.dHashAlg === null && 
155 	    this.dIssuerNameHash === null &&
156 	    this.dIssuerKeyHash === null &&
157 	    this.dSerialNumber === null)
158 	    throw "not yet set values";
159 
160 	var a = [this.dHashAlg, this.dIssuerNameHash,
161 		 this.dIssuerKeyHash, this.dSerialNumber];
162 	var seq = new nA.DERSequence({array: a});
163         this.hTLV = seq.getEncodedHex();
164         return this.hTLV;
165     };
166 
167     if (typeof params !== "undefined") {
168 	var p = params;
169 	if (typeof p.issuerCert !== "undefined" &&
170 	    typeof p.subjectCert !== "undefined") {
171 	    var alg = KJUR.asn1.ocsp.DEFAULT_HASH;
172 	    if (typeof p.alg === "undefined") alg = undefined;
173 	    this.setByCert(p.issuerCert, p.subjectCert, alg);
174 	} else if (typeof p.namehash !== "undefined" &&
175 		   typeof p.keyhash !== "undefined" &&
176 		   typeof p.serial !== "undefined") {
177 	    var alg = KJUR.asn1.ocsp.DEFAULT_HASH;
178 	    if (typeof p.alg === "undefined") alg = undefined;
179 	    this.setByValue(p.namehash, p.keyhash, p.serial, alg);
180 	} else {
181 	    throw "invalid constructor arguments";
182 	}
183     }
184 };
185 YAHOO.lang.extend(KJUR.asn1.ocsp.CertID, KJUR.asn1.ASN1Object);
186 
187 /**
188  * ASN.1 Request class for OCSP<br/>
189  * @name KJUR.asn1.ocsp.Request
190  * @class ASN.1 Request class for OCSP
191  * @param {Array} params associative array of parameters
192  * @extends KJUR.asn1.ASN1Object
193  * @since jsrsasign 6.1.0 asn1ocsp 1.0.0
194  * @description
195  * Request ASN.1 class is defined in 
196  * <a href="https://tools.ietf.org/html/rfc6960#section-4.1.1">RFC 6960 4.1.1</a>. 
197  * singleRequestExtensions is not supported yet in this version such as nonce.
198  * <pre>
199  * Request ::= SEQUENCE {
200  *   reqCert                  CertID,
201  *   singleRequestExtensions  [0] EXPLICIT Extensions OPTIONAL }
202  * </pre>
203  * @example
204  * // default constructor
205  * o = new KJUR.asn1.ocsp.Request();
206  * // constructor with certs (sha1 is used by default)
207  * o = new KJUR.asn1.ocsp.Request({issuerCert: "-----BEGIN...", subjectCert: "-----BEGIN..."});
208  * // constructor with certs and sha256
209  * o = new KJUR.asn1.ocsp.Request({issuerCert: "-----BEGIN...", subjectCert: "-----BEGIN...", alg: "sha256"});
210  * // constructor with values
211  * o = new KJUR.asn1.ocsp.Request({namehash: "1a...", keyhash: "ad...", serial: "1234", alg: "sha256"});
212  */
213 KJUR.asn1.ocsp.Request = function(params) {
214     KJUR.asn1.ocsp.Request.superclass.constructor.call(this);
215     this.dReqCert = null;
216     this.dExt = null;
217     
218     this.getEncodedHex = function() {
219 	var a = [];
220 
221 	// 1. reqCert
222 	if (this.dReqCert === null)
223 	    throw "reqCert not set";
224 	a.push(this.dReqCert);
225 
226 	// 2. singleRequestExtensions (not supported yet)
227 
228 	// 3. construct SEQUENCE
229 	var seq = new KJUR.asn1.DERSequence({array: a});
230         this.hTLV = seq.getEncodedHex();
231         return this.hTLV;
232     };
233 
234     if (typeof params !== "undefined") {
235 	var o = new KJUR.asn1.ocsp.CertID(params);
236 	this.dReqCert = o;
237     }
238 };
239 YAHOO.lang.extend(KJUR.asn1.ocsp.Request, KJUR.asn1.ASN1Object);
240 
241 /**
242  * ASN.1 TBSRequest class for OCSP<br/>
243  * @name KJUR.asn1.ocsp.TBSRequest
244  * @class ASN.1 TBSRequest class for OCSP
245  * @param {Array} params associative array of parameters
246  * @extends KJUR.asn1.ASN1Object
247  * @since jsrsasign 6.1.0 asn1ocsp 1.0.0
248  * @description
249  * TBSRequest ASN.1 class is defined in 
250  * <a href="https://tools.ietf.org/html/rfc6960#section-4.1.1">RFC 6960 4.1.1</a>. 
251  * <pre>
252  * TBSRequest ::= SEQUENCE {
253  *   version            [0] EXPLICIT Version DEFAULT v1,
254  *   requestorName      [1] EXPLICIT GeneralName OPTIONAL,
255  *   requestList            SEQUENCE OF Request,
256  *   requestExtensions  [2] EXPLICIT Extensions OPTIONAL }
257  * </pre>
258  * @example
259  * // default constructor
260  * o = new KJUR.asn1.ocsp.TBSRequest();
261  * // constructor with requestList parameter
262  * o = new KJUR.asn1.ocsp.TBSRequest({reqList:[
263  *   {issuerCert: "-----BEGIN...", subjectCert: "-----BEGIN...", alg:},
264  *   {issuerCert: "-----BEGIN...", subjectCert: "-----BEGIN...", alg: "sha256"}
265  * ]});
266  */
267 KJUR.asn1.ocsp.TBSRequest = function(params) {
268     KJUR.asn1.ocsp.TBSRequest.superclass.constructor.call(this);
269     this.version = 0;
270     this.dRequestorName = null;
271     this.dRequestList = [];
272     this.dRequestExt = null;
273 
274     /**
275      * set TBSRequest ASN.1 object by array of parameters.<br/>
276      * @name setRequestListByParam
277      * @memberOf KJUR.asn1.ocsp.TBSRequest#
278      * @function
279      * @param {Array} aParams array of parameters for Request class
280      * @since jsrsasign 6.1.0 asn1ocsp 1.0.0
281      * @example
282      * o = new KJUR.asn1.ocsp.TBSRequest();
283      * o.setRequestListByParam([
284      *   {issuerCert: "-----BEGIN...", subjectCert: "-----BEGIN...", alg:},
285      *   {issuerCert: "-----BEGIN...", subjectCert: "-----BEGIN...", alg: "sha256"}
286      * ]);
287      */
288     this.setRequestListByParam = function(aParams) {
289 	var a = [];
290 	for (var i = 0; i < aParams.length; i++) {
291 	    var dReq = new KJUR.asn1.ocsp.Request(aParams[0]);
292 	    a.push(dReq);
293 	}
294 	this.dRequestList = a;
295     };
296 
297     this.getEncodedHex = function() {
298 	var a = [];
299 
300 	// 1. version
301 	if (this.version !== 0)
302 	    throw "not supported version: " + this.version;
303 
304 	// 2. requestorName
305 	if (this.dRequestorName !== null)
306 	    throw "requestorName not supported";
307 
308 	// 3. requestList
309 	var seqRequestList = 
310 	    new KJUR.asn1.DERSequence({array: this.dRequestList});
311 	a.push(seqRequestList);
312 
313 	// 4. requestExtensions
314 	if (this.dRequestExt !== null)
315 	    throw "requestExtensions not supported";
316 
317 	// 5. construct SEQUENCE
318 	var seq = new KJUR.asn1.DERSequence({array: a});
319         this.hTLV = seq.getEncodedHex();
320         return this.hTLV;
321     };
322 
323     if (typeof params !== "undefined") {
324 	if (typeof params.reqList !== "undefined")
325 	    this.setRequestListByParam(params.reqList);
326     }
327 };
328 YAHOO.lang.extend(KJUR.asn1.ocsp.TBSRequest, KJUR.asn1.ASN1Object);
329 
330 
331 /**
332  * ASN.1 OCSPRequest class for OCSP<br/>
333  * @name KJUR.asn1.ocsp.OCSPRequest
334  * @class ASN.1 OCSPRequest class for OCSP
335  * @param {Array} params associative array of parameters
336  * @extends KJUR.asn1.ASN1Object
337  * @since jsrsasign 6.1.0 asn1ocsp 1.0.0
338  * @description
339  * OCSPRequest ASN.1 class is defined in 
340  * <a href="https://tools.ietf.org/html/rfc6960#section-4.1.1">RFC 6960 4.1.1</a>. 
341  * A signed request is not supported yet in this version.
342  * <pre>
343  * OCSPRequest ::= SEQUENCE {
344  *   tbsRequest             TBSRequest,
345  *   optionalSignature  [0] EXPLICIT Signature OPTIONAL }
346  * </pre>
347  * @example
348  * // default constructor
349  * o = new KJUR.asn1.ocsp.OCSPRequest();
350  * // constructor with requestList parameter
351  * o = new KJUR.asn1.ocsp.OCSPRequest({reqList:[
352  *   {issuerCert: "-----BEGIN...", subjectCert: "-----BEGIN...", alg:},
353  *   {issuerCert: "-----BEGIN...", subjectCert: "-----BEGIN...", alg: "sha256"}
354  * ]});
355  */
356 KJUR.asn1.ocsp.OCSPRequest = function(params) {
357     KJUR.asn1.ocsp.OCSPRequest.superclass.constructor.call(this);
358     this.dTbsRequest = null;
359     this.dOptionalSignature = null;
360 
361     this.getEncodedHex = function() {
362 	var a = [];
363 
364 	// 1. tbsRequest
365 	if (this.dTbsRequest !== null) {
366 	    a.push(this.dTbsRequest);
367 	} else {
368 	    throw "tbsRequest not set";
369 	}
370 
371 	// 2. optionalSignature
372 	if (this.dOptionalSignature !== null)
373 	    throw "optionalSignature not supported";
374 
375 	// 3. construct SEQUENCE
376 	var seq = new KJUR.asn1.DERSequence({array: a});
377         this.hTLV = seq.getEncodedHex();
378         return this.hTLV;
379     };
380 
381     if (typeof params !== "undefined") {
382 	if (typeof params.reqList !== "undefined") {
383 	    var o = new KJUR.asn1.ocsp.TBSRequest(params);
384 	    this.dTbsRequest = o;
385 	}
386     }
387 };
388 YAHOO.lang.extend(KJUR.asn1.ocsp.OCSPRequest, KJUR.asn1.ASN1Object);
389 
390 /**
391  * Utility class for OCSP<br/>
392  * @name KJUR.asn1.ocsp.OCSPUtil
393  * @class Utility class for OCSP
394  * @since jsrsasign 6.1.0 asn1ocsp 1.0.0
395  * @description
396  * This class provides utility static methods for OCSP.
397  * <ul>
398  * <li>{@link KJUR.asn1.ocsp.OCSPUtil.getRequestHex} - generates hexadecimal string of OCSP request</li>
399  * </ul>
400  */
401 KJUR.asn1.ocsp.OCSPUtil = {};
402 
403 /**
404  * generates hexadecimal string of OCSP request<br/>
405  * @name getRequestHex
406  * @memberOf KJUR.asn1.ocsp.OCSPUtil
407  * @function
408  * @param {String} issuerCert string of PEM issuer certificate
409  * @param {String} subjectCert string of PEM subject certificate to be verified by OCSP
410  * @param {String} algName hash algorithm name used for above arguments (ex. "sha1") DEFAULT: sha1
411  * @return {String} hexadecimal string of generated OCSP request
412  * @since jsrsasign 6.1.0 asn1ocsp 1.0.0
413  * @description
414  * This static method generates hexadecimal string of OCSP request.
415  * @example
416  * // generate OCSP request using sha1 algorithnm by default.
417  * hReq = KJUR.asn1.ocsp.OCSPUtil.getRequestHex("-----BEGIN...", "-----BEGIN...");
418  */
419 KJUR.asn1.ocsp.OCSPUtil.getRequestHex = function(issuerCert, subjectCert, alg) {
420     if (alg === undefined) alg = KJUR.asn1.ocsp.DEFAULT_HASH;
421     var param = {alg: alg, issuerCert: issuerCert, subjectCert: subjectCert};
422     var o = new KJUR.asn1.ocsp.OCSPRequest({reqList: [param]});
423     return o.getEncodedHex();
424 };
425 
426 /**
427  * parse OCSPResponse<br/>
428  * @name getOCSPResponseInfo
429  * @memberOf KJUR.asn1.ocsp.OCSPUtil
430  * @function
431  * @param {String} h hexadecimal string of DER OCSPResponse
432  * @return {Object} JSON object of parsed OCSPResponse
433  * @since jsrsasign 6.1.0 asn1ocsp 1.0.1
434  * @description
435  * This static method parse a hexadecimal string of DER OCSPResponse and
436  * returns JSON object of its parsed result.
437  * Its result has following properties:
438  * <ul>
439  * <li>responseStatus - integer of responseStatus</li>
440  * <li>certStatus - string of certStatus (ex. good, revoked or unknown)</li>
441  * <li>thisUpdate - string of thisUpdate in Zulu(ex. 20151231235959Z)</li>
442  * <li>nextUpdate - string of nextUpdate in Zulu(ex. 20151231235959Z)</li>
443  * </ul>
444  * @example
445  * info = KJUR.asn1.ocsp.OCSPUtil.getOCSPResponseInfo("3082...");
446  */
447 KJUR.asn1.ocsp.OCSPUtil.getOCSPResponseInfo = function(h) {
448     var result = {};
449     try {
450 	var v = ASN1HEX.getVbyList(h, 0, [0], "0a");
451 	result.responseStatus = parseInt(v, 16);
452     } catch(ex) {};
453     if (result.responseStatus !== 0) return result;
454 
455     try {
456 	// certStatus
457 	var idxCertStatus = ASN1HEX.getDecendantIndexByNthList(h, 0, [1,0,1,0,0,2,0,1]);
458 	if (h.substr(idxCertStatus, 2) === "80") {
459 	    result.certStatus = "good";
460 	} else if (h.substr(idxCertStatus, 2) === "a1") {
461 	    result.certStatus = "revoked";
462 	    result.revocationTime = 
463 		hextoutf8(ASN1HEX.getDecendantHexVByNthList(h, idxCertStatus, [0]));
464 	} else if (h.substr(idxCertStatus, 2) === "82") {
465 	    result.certStatus = "unknown";
466 	}
467     } catch (ex) {};
468 
469     // thisUpdate
470     try {
471 	var idxThisUpdate = ASN1HEX.getDecendantIndexByNthList(h, 0, [1,0,1,0,0,2,0,2]);
472 	result.thisUpdate = hextoutf8(ASN1HEX.getHexOfV_AtObj(h, idxThisUpdate));
473     } catch (ex) {};
474 
475     // nextUpdate
476     try {
477 	var idxEncapNextUpdate = ASN1HEX.getDecendantIndexByNthList(h, 0, [1,0,1,0,0,2,0,3]);
478 	if (h.substr(idxEncapNextUpdate, 2) === "a0") {
479 	    result.nextUpdate = 
480 		hextoutf8(ASN1HEX.getDecendantHexVByNthList(h, idxEncapNextUpdate, [0]));
481 	}
482     } catch (ex) {};
483 
484     return result;
485 };
486 
487