1 /* x509crl.js (c) 2012-2020 Kenji Urushima | kjur.github.io/jsrsasign/license 2 */ 3 /* 4 * x509crl.js - X509CRL class to parse X.509 CRL 5 * 6 * Copyright (c) 2010-2020 Kenji Urushima (kenji.urushima@gmail.com) 7 * 8 * This software is licensed under the terms of the MIT License. 9 * https://kjur.github.io/jsrsasign/license 10 * 11 * The above copyright and license notice shall be 12 * included in all copies or substantial portions of the Software. 13 */ 14 15 /** 16 * @fileOverview 17 * @name x509crl.js 18 * @author Kenji Urushima kenji.urushima@gmail.com 19 * @version jsrsasign 10.1.0 x509crl 1.0.2 (2020-Nov-18) 20 * @since jsrsasign 10.1.0 21 * @license <a href="https://kjur.github.io/jsrsasign/license/">MIT License</a> 22 */ 23 24 /** 25 * hexadecimal X.509 CRL ASN.1 parser class.<br/> 26 * @class hexadecimal X.509 CRL ASN.1 parser class 27 * @param {String} params X.509 CRL PEM string or hexadecimal string 28 * @property {String} hex hexadecimal string of X.509 CRL ASN.1 data 29 * @property {Integer} posSigAlg index of SignatureAlgorithm field in TBSCertList position depends on CRL version field 30 * @property {Integer} posRevCert index of revokedCertificates field in TBSCertList depends on CRL version and nextUpdate field 31 * @author Kenji Urushima 32 * @version 1.0.0 (2020-Aug-26) 33 * @see X509 34 * @see <a href="https://kjur.github.io/jsrsasigns/">jsrsasign home page https://kjur.github.io/jsrsasign/</a> 35 * 36 * @description 37 * This class parses X.509 CRL. Following methods are provided to 38 * get field value:<br/> 39 * <b>BASIC FIELD</b><br/> 40 * <ul> 41 * <li>version - {@link X509CRL#getVersion}</li> 42 * <li>signatureAlgorithm - {@link X509CRL#getSignatureAlgorithmField}</li> 43 * <li>issuer - {@link X509CRL#getIssuer}</li> 44 * <li>thisUpdate - {@link X509CRL#getThisUpdate}</li> 45 * <li>nextUpdate - {@link X509CRL#getNextUpdate}</li> 46 * <li>revokedCertificates - {@link X509CRL#getRevCertArray}</li> 47 * <li>revokedCertificate - {@link X509CRL#getRevCert}</li> 48 * <li>signature - {@link X509CRL#getSignatureValueHex}</li> 49 * </ul> 50 * <b>UTILITIES</b><br/> 51 * <ul> 52 * <li>{@link X509CRL#getParam} - get all parameters</li> 53 * </ul> 54 */ 55 var X509CRL = function(params) { 56 var _KJUR = KJUR, 57 _isHex = _KJUR.lang.String.isHex, 58 _ASN1HEX = ASN1HEX, 59 _getV = _ASN1HEX.getV, 60 _getTLV = _ASN1HEX.getTLV, 61 _getVbyList = _ASN1HEX.getVbyList, 62 _getTLVbyList = _ASN1HEX.getTLVbyList, 63 _getTLVbyListEx = _ASN1HEX.getTLVbyListEx, 64 _getIdxbyList = _ASN1HEX.getIdxbyList, 65 _getIdxbyListEx = _ASN1HEX.getIdxbyListEx, 66 _getChildIdx = _ASN1HEX.getChildIdx, 67 _x509obj = new X509(); 68 69 this.hex = null; 70 this.posSigAlg = null; 71 this.posRevCert = null; 72 73 /* 74 * set field position of SignatureAlgorithm and revokedCertificates<br/> 75 * @description 76 * This method will set "posSigAlg" and "posRevCert" properties. 77 */ 78 this._setPos = function() { 79 // for sigAlg 80 var idx = _getIdxbyList(this.hex, 0, [0, 0]); 81 var tag = this.hex.substr(idx, 2); 82 if (tag == "02") { 83 this.posSigAlg = 1; 84 } else if (tag == "30") { 85 this.posSigAlg = 0; 86 } else { 87 throw new Error("malformed 1st item of TBSCertList: " + tag); 88 } 89 90 // for revCerts 91 var idx2 = _getIdxbyList(this.hex, 0, [0, this.posSigAlg + 3]); 92 var tag2 = this.hex.substr(idx2, 2); 93 if (tag2 == "17" || tag2 == "18") { 94 var idx3, tag3; 95 idx3 = _getIdxbyList(this.hex, 0, [0, this.posSigAlg + 4]); 96 this.posRevCert = null; 97 if (idx3 != -1) { 98 tag3 = this.hex.substr(idx3, 2); 99 if (tag3 == "30") { 100 this.posRevCert = this.posSigAlg + 4; 101 } 102 } 103 } else if (tag2 == "30") { // found revCert 104 this.posRevCert = this.posSigAlg + 3; 105 } else if (tag2 == "a0") { // no nextUpdate and revCert 106 this.posRevCert = null; 107 } else { 108 throw new Error("malformed nextUpdate or revCert tag: " + tag2); 109 } 110 }; 111 112 /** 113 * get X.509 CRL format version<br/> 114 * @name getVersion 115 * @memberOf X509CRL# 116 * @function 117 * @return {Number} version field value (generally 2) or null 118 * @description 119 * This method returns a version field value TBSCertList. 120 * This returns null if there is no such field. 121 * @example 122 * crl = new X509CRL("-----BEGIN X509 CRL..."); 123 * crl.getVersion() → 2 124 */ 125 this.getVersion = function() { 126 if (this.posSigAlg == 0) return null; 127 return parseInt(_getVbyList(this.hex, 0, [0, 0], "02"), 16) + 1; 128 } 129 130 /** 131 * get signature algorithm name in basic field 132 * @name getSignatureAlgorithmField 133 * @memberOf X509CRL# 134 * @function 135 * @return {String} signature algorithm name (ex. SHA1withRSA, SHA256withECDSA, SHA512withRSAandMGF1) 136 * @see X509#getSignatureAlgorithmField 137 * @see KJUR.asn1.x509.AlgirithmIdentifier 138 * 139 * @description 140 * This method will get a name of signature algorithm in CRL. 141 * 142 * @example 143 * crl = new X509CRL("-----BEGIN X509 CRL..."); 144 * crl.getSignatureAlgorithmField() → "SHA256withRSAandMGF1" 145 */ 146 this.getSignatureAlgorithmField = function() { 147 var hTLV = _getTLVbyList(this.hex, 0, [0, this.posSigAlg], "30"); 148 return _x509obj.getAlgorithmIdentifierName(hTLV); 149 }; 150 151 /** 152 * get JSON object of issuer field<br/> 153 * @name getIssuer 154 * @memberOf X509CRL# 155 * @function 156 * @return {Array} JSON object of issuer field 157 * @see X509#getIssuer 158 * @see X509#getX500Name 159 * @see KJUR.asn1.x509.X500Name 160 * 161 * @description 162 * This method returns parsed issuer field value as 163 * JSON object. 164 * 165 * @example 166 * crl = new X509CRL("-----BEGIN X509 CRL..."); 167 * x.getIssuer() → 168 * { array: [[{type:'C',value:'JP',ds:'prn'}],...], 169 * str: "/C=JP/..." } 170 */ 171 this.getIssuer = function() { 172 var hIssuer = _getTLVbyList(this.hex, 0, [0, this.posSigAlg + 1], "30"); 173 return _x509obj.getX500Name(hIssuer); 174 }; 175 176 /** 177 * get JSON object of thisUpdate field<br/> 178 * @name getThisUpdate 179 * @memberOf X509CRL# 180 * @function 181 * @return {String} string of thisUpdate field (ex. "YYMMDDHHmmSSZ") 182 * @see X509#getNotBefore 183 * @see X509CRL#getNextUpdate 184 * @see KJUR.asn1.x509.Time 185 * 186 * @description 187 * This method returns parsed thisUpdate field value as 188 * string. 189 * 190 * @example 191 * crl = new X509CRL("-----BEGIN X509 CRL..."); 192 * x.getThisUpdate() → "200825235959Z" 193 */ 194 this.getThisUpdate = function() { 195 var hThisUpdate = _getVbyList(this.hex, 0, [0, this.posSigAlg + 2]); 196 return result = hextorstr(hThisUpdate); 197 }; 198 199 /** 200 * get JSON object of nextUpdate field<br/> 201 * @name getNextUpdate 202 * @memberOf X509CRL# 203 * @function 204 * @return {String} string of nextUpdate field or null 205 * @see X509#getNotBefore 206 * @see X509CRL#getThisUpdate 207 * @see KJUR.asn1.x509.Time 208 * 209 * @description 210 * This method returns parsed nextUpdate field value as 211 * string. "nextUpdate" is OPTIONAL field so 212 * when nextUpdate field doesn't exists, this returns null. 213 * 214 * @example 215 * crl = new X509CRL("-----BEGIN X509 CRL..."); 216 * crl.getNextUpdate() → "200825235959Z" 217 */ 218 this.getNextUpdate = function() { 219 var idx = _getIdxbyList(this.hex, 0, [0, this.posSigAlg + 3]); 220 var tag = this.hex.substr(idx, 2); 221 if (tag != "17" && tag != "18") return null; 222 return hextorstr(_getV(this.hex, idx)); 223 }; 224 225 /** 226 * get array for revokedCertificates field<br/> 227 * @name getRevCertArray 228 * @memberOf X509CRL# 229 * @function 230 * @return {Array} array of revokedCertificate parameter or null 231 * @see X509CRL#getRevCert 232 * 233 * @description 234 * This method returns parsed revokedCertificates field value as 235 * array of revokedCertificate parameter. 236 * If the field doesn't exists, it returns null. 237 * 238 * @example 239 * crl = new X509CRL("-----BEGIN X509 CRL..."); 240 * crl.getRevCertArray() → 241 * [{sn:"123a", date:"208025235959Z", ext: [{extname:"cRLReason",code:3}]}, 242 * {sn:"123b", date:"208026235959Z", ext: [{extname:"cRLReason",code:0}]}] 243 */ 244 this.getRevCertArray = function() { 245 if (this.posRevCert == null) return null; 246 var a = []; 247 var idx = _getIdxbyList(this.hex, 0, [0, this.posRevCert]); 248 var aIdx = _getChildIdx(this.hex, idx); 249 for (var i = 0; i < aIdx.length; i++) { 250 var hRevCert = _getTLV(this.hex, aIdx[i]); 251 a.push(this.getRevCert(hRevCert)); 252 } 253 return a; 254 }; 255 256 /** 257 * get revokedCertificate JSON parameter<br/> 258 * @name getRevCert 259 * @memberOf X509CRL# 260 * @function 261 * @return {Array} JSON object for revokedCertificate parameter 262 * @see X509CRL#getRevCertArray 263 * 264 * @description 265 * This method returns parsed revokedCertificate parameter 266 * as JSON object. 267 * 268 * @example 269 * crl = new X509CRL(); 270 * crl.getRevCertArray("30...") → 271 * {sn:"123a", date:"208025235959Z", ext: [{extname:"cRLReason",code:3}]} 272 */ 273 this.getRevCert = function(hRevCert) { 274 var param = {}; 275 var aIdx = _getChildIdx(hRevCert, 0); 276 277 param.sn = {hex: _getVbyList(hRevCert, 0, [0], "02")}; 278 param.date = hextorstr(_getVbyList(hRevCert, 0, [1])); 279 if (aIdx.length == 3) { 280 param.ext = 281 _x509obj.getExtParamArray(_getTLVbyList(hRevCert, 0, [2])); 282 } 283 284 return param; 285 }; 286 287 /** 288 * get signature value as hexadecimal string<br/> 289 * @name getSignatureValueHex 290 * @memberOf X509CRL# 291 * @function 292 * @return {String} signature value hexadecimal string without BitString unused bits 293 * 294 * @description 295 * This method will get signature value of CRL. 296 * 297 * @example 298 * crl = new X509CRL("-----BEGIN X509 CRL..."); 299 * crl.getSignatureValueHex() &rarr "8a4c47913..." 300 */ 301 this.getSignatureValueHex = function() { 302 return _getVbyList(this.hex, 0, [2], "03", true); 303 }; 304 305 /** 306 * verifies signature value by public key<br/> 307 * @name verifySignature 308 * @memberOf X509CRL# 309 * @function 310 * @param {Object} pubKey public key object, pubkey PEM or PEM issuer cert 311 * @return {Boolean} true if signature value is valid otherwise false 312 * @see X509#verifySignature 313 * @see KJUR.crypto.Signature 314 * 315 * @description 316 * This method verifies signature value of hexadecimal string of 317 * X.509 CRL by specified public key. 318 * The signature algorithm used to verify will refer 319 * signatureAlgorithm field. 320 * (See {@link X509CRL#getSignatureAlgorithmField}) 321 * 322 * @example 323 * crl = new X509CRL("-----BEGIN X509 CRL..."); 324 * x.verifySignature(pubKey) → true, false or raising exception 325 */ 326 this.verifySignature = function(pubKey) { 327 var algName = this.getSignatureAlgorithmField(); 328 var hSigVal = this.getSignatureValueHex(); 329 var hTbsCertList = _getTLVbyList(this.hex, 0, [0], "30"); 330 331 var sig = new KJUR.crypto.Signature({alg: algName}); 332 sig.init(pubKey); 333 sig.updateHex(hTbsCertList); 334 return sig.verify(hSigVal); 335 }; 336 337 /** 338 * get JSON object for CRL parameters<br/> 339 * @name getParam 340 * @memberOf X509CRL# 341 * @function 342 * @return {Array} JSON object for CRL parameters 343 * @see KJUR.asn1.x509.CRL 344 * 345 * @description 346 * This method returns a JSON object of the CRL 347 * parameters. 348 * Return value can be passed to 349 * {@link KJUR.asn1.x509.CRL} constructor. 350 * 351 * @example 352 * crl = new X509CRL("-----BEGIN X509 CRL..."); 353 * crl.getParam() → 354 * {version: 2, 355 * sigalg: "SHA256withRSA", 356 * issuer: {array: 357 * [[{type:"C",value:"JP",ds:"prn"}],[{type:"O",value:"T1",ds:"prn"}]]}, 358 * thisupdate: "200820212434Z", 359 * nextupdate: "200910212434Z", 360 * revcert: [ 361 * {sn:{hex:"123d..."}, 362 * date:"061110000000Z", 363 * ext:[{extname:"cRLReason",code:4}]}], 364 * ext: [ 365 * {extname:"authorityKeyIdentifier",kid:{hex: "03de..."}}, 366 * {extname:"cRLNumber",num:{hex:"0211"}}], 367 * sighex: "3c5e..."} 368 */ 369 this.getParam = function() { 370 var result = {}; 371 372 var version = this.getVersion(); 373 if (version != null) result.version = version; 374 375 result.sigalg = this.getSignatureAlgorithmField(); 376 result.issuer = this.getIssuer(); 377 result.thisupdate = this.getThisUpdate(); 378 379 var nextUpdate = this.getNextUpdate(); 380 if (nextUpdate != null) result.nextupdate = nextUpdate; 381 382 var revCerts = this.getRevCertArray(); 383 if (revCerts != null) result.revcert = revCerts; 384 385 var idxExt = _getIdxbyListEx(this.hex, 0, [0, "[0]"]); 386 if (idxExt != -1) { 387 var hExtSeq = _getTLVbyListEx(this.hex, 0, [0, "[0]", 0]); 388 result.ext = _x509obj.getExtParamArray(hExtSeq); 389 } 390 391 result.sighex = this.getSignatureValueHex(); 392 return result; 393 }; 394 395 if (typeof params == "string") { 396 if (_isHex(params)) { 397 this.hex = params; 398 } else if (params.match(/-----BEGIN X509 CRL/)) { 399 this.hex = pemtohex(params); 400 } 401 this._setPos(); 402 } 403 }; 404