1 /** 2 * --------- 3 * |.##> <##.| Open Smart Card Development Platform (www.openscdp.org) 4 * |# #| 5 * |# #| Copyright (c) 1999-2009 CardContact Software & System Consulting 6 * |'##> <##'| Andreas Schwier, 32429 Minden, Germany (www.cardcontact.de) 7 * --------- 8 * 9 * This file is part of OpenSCDP. 10 * 11 * OpenSCDP is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License version 2 as 13 * published by the Free Software Foundation. 14 * 15 * OpenSCDP is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with OpenSCDP; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 * 24 * @fileoverview Support for card verifiable certificates and certificate requests according to EAC 1.1/2.0 25 */ 26 27 28 29 load("tools/eccutils.js"); 30 31 if (typeof(__ScriptingServer) == "undefined") { 32 load("publickeyreference.js"); 33 } 34 35 36 37 /** 38 * Create a CVC object from a DER encoded ByteString. 39 * 40 * @class Class implementing a decoder for card verifiable certificates or requests according to 41 * Extended Access Control (EAC) as defined in BSI TR-03110 1.11 and 2.02. 42 * @constructor 43 * @param {ByteString} param the DER encoded certificate 44 * @return 45 */ 46 function CVC() { 47 if (arguments.length > 0) { 48 var arg = arguments[0]; 49 if (arg instanceof ASN1) { 50 this.asn = arg; 51 this.bin = this.asn.getBytes(); 52 } else if (arg instanceof ByteString) { 53 this.bin = arg; 54 this.asn = new ASN1(this.bin); 55 } else { 56 throw new GPError("CVC", GPError.INVALID_DATA, 0, "Argument must be of type ByteString or ASN1"); 57 } 58 if (this.asn.tag == CVC.TAG_AT) { 59 this.body = this.asn.get(0).get(0); 60 } else if (this.asn.tag == CVC.TAG_CVC) { 61 this.body = this.asn.get(0); 62 } else { 63 throw new GPError("CVC", GPError.INVALID_DATA, 0, "Argument is neither a CVC or CVC request"); 64 } 65 } 66 } 67 68 69 70 /** Authentication Template */ 71 CVC.TAG_AT = 0x67; 72 /** CV Certificate */ 73 CVC.TAG_CVC = 0x7F21; 74 /** Certificate Body */ 75 CVC.TAG_BODY = 0x7F4E; 76 /** Certificate Profile Identifier */ 77 CVC.TAG_CPI = 0x5F29; 78 /** Certification Authority Reference */ 79 CVC.TAG_CAR = 0x42; 80 /** Public Key */ 81 CVC.TAG_PUK = 0x7F49; 82 /** Prime Modulus */ 83 CVC.TAG_ECC_P = 0x81; 84 /** First coefficient a */ 85 CVC.TAG_ECC_A = 0x82; 86 /** Second coefficient b */ 87 CVC.TAG_ECC_B = 0x83; 88 /** Base Point G */ 89 CVC.TAG_ECC_G = 0x84; 90 /** Order of the base point */ 91 CVC.TAG_ECC_N = 0x85; 92 /** Public Point y */ 93 CVC.TAG_ECC_Q = 0x86; 94 /** Cofactor f */ 95 CVC.TAG_ECC_H = 0x87; 96 /** Certificate Holder Reference */ 97 CVC.TAG_CHR = 0x5F20; 98 /** Certificate Holder Authorisation Template */ 99 CVC.TAG_CHAT = 0x7F4C; 100 /** Certificate Extension */ 101 CVC.TAG_EXTN = 0x65; 102 /** Certificate Effective Date */ 103 CVC.TAG_CED = 0x5F25; 104 /** Certificate Expiration Date */ 105 CVC.TAG_CXD = 0x5F24; 106 /** Signature */ 107 CVC.TAG_SIG = 0x5F37; 108 109 110 /** Table of tag names */ 111 CVC.OBJECTNAMES = [] 112 CVC.OBJECTNAMES[CVC.TAG_AT] = "Authentication Template"; 113 CVC.OBJECTNAMES[CVC.TAG_CVC] = "CV Certificate"; 114 CVC.OBJECTNAMES[CVC.TAG_BODY] = "Certificate Body"; 115 CVC.OBJECTNAMES[CVC.TAG_CPI] = "Certificate Profile Indicator"; 116 CVC.OBJECTNAMES[CVC.TAG_CAR] = "Certification Authority Reference"; 117 CVC.OBJECTNAMES[CVC.TAG_PUK] = "Public Key"; 118 CVC.OBJECTNAMES[CVC.TAG_ECC_P] = "Prime/Modulus"; 119 CVC.OBJECTNAMES[CVC.TAG_ECC_A] = "First coefficient a/Exponent"; 120 CVC.OBJECTNAMES[CVC.TAG_ECC_B] = "Second coefficient b"; 121 CVC.OBJECTNAMES[CVC.TAG_ECC_G] = "Base Point G"; 122 CVC.OBJECTNAMES[CVC.TAG_ECC_N] = "Order of the base point"; 123 CVC.OBJECTNAMES[CVC.TAG_ECC_Q] = "Public Point y"; 124 CVC.OBJECTNAMES[CVC.TAG_ECC_H] = "Cofactor f"; 125 CVC.OBJECTNAMES[CVC.TAG_CHR] = "Certificate Holder Reference"; 126 CVC.OBJECTNAMES[CVC.TAG_CHAT] = "Certificate Holder Authentication Template"; 127 CVC.OBJECTNAMES[CVC.TAG_EXTN] = "Extension"; 128 CVC.OBJECTNAMES[CVC.TAG_CED] = "Certificate Effective Date"; 129 CVC.OBJECTNAMES[CVC.TAG_CXD] = "Certificate Expiration Date"; 130 CVC.OBJECTNAMES[CVC.TAG_SIG] = "Signature"; 131 132 133 /** Table of rights description for id-IS */ 134 CVC.ISRIGHTS = [ 135 "Read access to ePassport application: DG 3 (Fingerprint)", 136 "Read access to ePassport application: DG 4 (Iris)", 137 "RFU (Bit 3)", 138 "RFU (Bit 4)", 139 "RFU (Bit 5)", 140 "Read access to eID application" 141 ]; 142 CVC.idIS = new ByteString("id-IS", OID); 143 144 145 /** Table of rights description for id-AT */ 146 CVC.ATRIGHTS = [ 147 "Age Verification", 148 "Community ID Verification", 149 "Restricted Identification", 150 "Privileged Terminal", 151 "CAN allowed", 152 "PIN Management", 153 "Install Certificate", 154 "Install Qualified Certificate", 155 156 "Read Access DG 1 (Document Type)", 157 "Read Access DG 2 (Issuing State)", 158 "Read Access DG 3 (Date of Expiration)", 159 "Read Access DG 4 (Given Name)", 160 "Read Access DG 5 (Surname)", 161 "Read Access DG 6 (Pseudonym)", 162 "Read Access DG 7 (Academic Grade)", 163 "Read Access DG 8 (Date of Birth)", 164 165 "Read Access DG 9 (Place of Birth)", 166 "Read Access DG 10", 167 "Read Access DG 11", 168 "Read Access DG 12", 169 "Read Access DG 13", 170 "Read Access DG 14", 171 "Read Access DG 15", 172 "Read Access DG 16", 173 174 "Read Access DG 17 (Place of Residence)", 175 "Read Access DG 18 (Community ID)", 176 "Read Access DG 19 (Conditions I-eAT)", 177 "Read Access DG 20 (Conditions II-eAT)", 178 "Read Access DG 21", 179 "RFU (Bit 29)", 180 "RFU (Bit 30)", 181 "RFU (Bit 31)", 182 183 "RFU (Bit 32)", 184 "Write Access DG 21", 185 "Write Access DG 20 (Conditions II-eAT)", 186 "Write Access DG 19 (Conditions I-eAT)", 187 "Write Access DG 18 (Community ID)", 188 "Write Access DG 17 (Place of Residence)" 189 ]; 190 CVC.idAT = new ByteString("id-AT", OID); 191 192 193 194 /** Table of rights description for id-ST */ 195 CVC.STRIGHTS = [ 196 "Generate electronic signature", 197 "Generate qualified electronic signature", 198 "RFU (Bit 2)", 199 "RFU (Bit 3)", 200 "RFU (Bit 4)", 201 "RFU (Bit 5)" 202 ]; 203 CVC.idST = new ByteString("id-ST", OID); 204 205 CVC.idSC_HSM = new ByteString("2B0601040181C31F030101", HEX); 206 207 208 209 /** TA constants */ 210 CVC.id_TA_ECDSA = new ByteString("id-TA-ECDSA", OID); 211 CVC.id_TA_ECDSA_SHA_1 = new ByteString("id-TA-ECDSA-SHA-1", OID); 212 CVC.id_TA_ECDSA_SHA_224 = new ByteString("id-TA-ECDSA-SHA-224", OID); 213 CVC.id_TA_ECDSA_SHA_256 = new ByteString("id-TA-ECDSA-SHA-256", OID); 214 CVC.id_TA_ECDSA_SHA_384 = new ByteString("id-TA-ECDSA-SHA-384", OID); 215 CVC.id_TA_ECDSA_SHA_512 = new ByteString("id-TA-ECDSA-SHA-512", OID); 216 CVC.id_TA_RSA_v1_5_SHA_1 = new ByteString("id-TA-RSA-v1-5-SHA-1", OID); 217 CVC.id_TA_RSA_v1_5_SHA_256 = new ByteString("id-TA-RSA-v1-5-SHA-256", OID); 218 CVC.id_TA_RSA_v1_5_SHA_512 = new ByteString("id-TA-RSA-v1-5-SHA-512", OID); 219 CVC.id_TA_RSA_PSS_SHA_1 = new ByteString("id-TA-RSA-PSS-SHA-1", OID); 220 CVC.id_TA_RSA_PSS_SHA_256 = new ByteString("id-TA-RSA-PSS-SHA-256", OID); 221 CVC.id_TA_RSA_PSS_SHA_512 = new ByteString("id-TA-RSA-PSS-SHA-512", OID); 222 223 224 225 /** 226 * Return signature mechanism for object identifier 227 * 228 * @param {ByteString} oid the object identifer from the public key object 229 * @returns the signature mechanism as Crypto. constant or -1 if not defined 230 * @type Number 231 */ 232 CVC.getSignatureMech = function(oid) { 233 if (oid.equals(CVC.id_TA_ECDSA_SHA_1)) 234 return Crypto.ECDSA_SHA1; 235 if (oid.equals(CVC.id_TA_ECDSA_SHA_224)) 236 return Crypto.ECDSA_SHA224; 237 if (oid.equals(CVC.id_TA_ECDSA_SHA_256)) 238 return Crypto.ECDSA_SHA256; 239 if (oid.equals(CVC.id_TA_ECDSA_SHA_384)) 240 return Crypto.ECDSA_SHA384; 241 if (oid.equals(CVC.id_TA_ECDSA_SHA_512)) 242 return Crypto.ECDSA_SHA512; 243 if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_1)) 244 return Crypto.RSA_SHA1; 245 if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_256)) 246 return Crypto.RSA_SHA256; 247 if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_512)) 248 return Crypto.RSA_SHA512; 249 if (oid.equals(CVC.id_TA_RSA_PSS_SHA_1)) 250 return Crypto.RSA_PSS_SHA1; 251 if (oid.equals(CVC.id_TA_RSA_PSS_SHA_256)) 252 return Crypto.RSA_PSS_SHA256; 253 if (oid.equals(CVC.id_TA_RSA_PSS_SHA_512)) 254 return Crypto.RSA_PSS_SHA512; 255 return -1; 256 } 257 258 259 260 /** 261 * Return hash mechanism for object identifier 262 * 263 * @param {ByteString} oid the object identifer from the public key object 264 * @returns the hash mechanism as Crypto. constant or -1 if not defined 265 * @type Number 266 */ 267 CVC.getHashMech = function(oid) { 268 if (oid.equals(CVC.id_TA_ECDSA_SHA_1)) 269 return Crypto.SHA_1; 270 if (oid.equals(CVC.id_TA_ECDSA_SHA_224)) 271 return Crypto.SHA_224; 272 if (oid.equals(CVC.id_TA_ECDSA_SHA_256)) 273 return Crypto.SHA_256; 274 if (oid.equals(CVC.id_TA_ECDSA_SHA_384)) 275 return Crypto.SHA_384; 276 if (oid.equals(CVC.id_TA_ECDSA_SHA_512)) 277 return Crypto.SHA_512; 278 if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_1)) 279 return Crypto.SHA1; 280 if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_256)) 281 return Crypto.SHA_256; 282 if (oid.equals(CVC.id_TA_RSA_v1_5_SHA_512)) 283 return Crypto.SHA_512; 284 if (oid.equals(CVC.id_TA_RSA_PSS_SHA_1)) 285 return Crypto.SHA_1; 286 if (oid.equals(CVC.id_TA_RSA_PSS_SHA_256)) 287 return Crypto.SHA_256; 288 if (oid.equals(CVC.id_TA_RSA_PSS_SHA_512)) 289 return Crypto.SHA_512; 290 return -1; 291 } 292 293 294 295 /** 296 * Return true of the object identifier starts with id-TA-ECDSA 297 * 298 * @type boolean 299 * @return true, if ECDSA based OID 300 */ 301 CVC.isECDSA = function(oid) { 302 return oid.startsWith(CVC.id_TA_ECDSA) == CVC.id_TA_ECDSA.length; 303 } 304 305 306 307 /** 308 * Return true of the certificate contains domain parameter 309 * 310 * @type boolean 311 * @return true, if certificate contains domain parameter 312 */ 313 CVC.prototype.containsDomainParameter = function() { 314 var pdo = this.body.find(CVC.TAG_PUK); 315 if (pdo == null) { 316 return false; 317 } 318 319 var d = pdo.find(0x84); // Generator 320 return (d != null); 321 } 322 323 324 325 /** 326 * Returns the certification authority reference (CAR). 327 * 328 * @return the CAR or null 329 * @type PublicKeyReference 330 */ 331 CVC.prototype.getCAR = function() { 332 var cardo = this.body.find(CVC.TAG_CAR); 333 334 if (!cardo) { 335 return null; 336 } 337 338 return new PublicKeyReference(cardo.value); 339 } 340 341 342 343 /** 344 * Returns the certificate holder reference (CHR). 345 * 346 * @return the CHR 347 * @type PublicKeyReference 348 */ 349 CVC.prototype.getCHR = function() { 350 var chrdo = this.body.find(CVC.TAG_CHR); 351 352 if (!chrdo) { 353 throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a CHR"); 354 } 355 356 return new PublicKeyReference(chrdo.value); 357 } 358 359 360 361 /** 362 * Returns the certificate effective date (CED). 363 * 364 * @return the CED or null 365 * @type Date 366 */ 367 CVC.prototype.getCED = function() { 368 var ceddo = this.body.find(CVC.TAG_CED); 369 370 if (!ceddo) { 371 return null 372 } 373 374 var b = ceddo.value; 375 376 var d = new Date(); 377 d.setFullYear(b.byteAt(0) * 10 + b.byteAt(1) + 2000, 378 b.byteAt(2) * 10 + b.byteAt(3) - 1, 379 b.byteAt(4) * 10 + b.byteAt(5)); 380 d.setHours(12, 0, 0, 0); 381 return d; 382 } 383 384 385 386 /** 387 * Returns the certificate expiration date (CXD). 388 * 389 * @return the CXD or null 390 * @type Date 391 */ 392 CVC.prototype.getCXD = function() { 393 var cxddo = this.body.find(CVC.TAG_CXD); 394 395 if (!cxddo) { 396 return null 397 } 398 399 var b = cxddo.value; 400 401 var d = new Date(); 402 d.setFullYear(b.byteAt(0) * 10 + b.byteAt(1) + 2000, 403 b.byteAt(2) * 10 + b.byteAt(3) - 1, 404 b.byteAt(4) * 10 + b.byteAt(5)); 405 d.setHours(12, 0, 0, 0); 406 return d; 407 } 408 409 410 411 /** 412 * Returns the outer certification authority reference (CAR). 413 * 414 * @return the outer CAR or null 415 * @type PublicKeyReference 416 */ 417 CVC.prototype.getOuterCAR = function() { 418 if (!this.isAuthenticatedRequest()) { 419 return null; 420 } 421 var cardo = this.asn.get(1); 422 423 if (!cardo) { 424 return null 425 } 426 427 return new PublicKeyReference(cardo.value); 428 } 429 430 431 432 /** 433 * Returns the extension identified by the object identifier. 434 * 435 * @return the extension including the OID or null if not defined 436 * @type ASN1 437 */ 438 CVC.prototype.getExtension = function(extoid) { 439 var extdo = this.body.find(CVC.TAG_EXTN); 440 441 if (!extdo) { 442 return null; 443 } 444 445 // print(extdo); 446 447 for (var i = 0; i < extdo.length; i++) { 448 var ext = extdo.get(i); 449 var oid = ext.get(0); 450 assert(oid.tag == ASN1.OBJECT_IDENTIFIER); 451 if (oid.value.equals(extoid)) { 452 return ext; 453 } 454 } 455 return null; 456 } 457 458 459 460 /** 461 * Returns the extension identified by the object identifier. 462 * 463 * @return the extension including the OID or null if not defined 464 * @type ASN1 465 */ 466 CVC.prototype.getCHAT = function() { 467 var chat = this.body.find(CVC.TAG_CHAT); 468 469 return chat; 470 } 471 472 473 474 /** 475 * Returns the public key object identifier 476 * 477 * @returns the object identifier assigned to the public key 478 * @type ByteString 479 */ 480 CVC.prototype.getPublicKeyOID = function() { 481 var pdo = this.body.find(CVC.TAG_PUK); 482 if (pdo == null) { 483 throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key"); 484 } 485 486 var d = pdo.find(ASN1.OBJECT_IDENTIFIER); 487 if (d == null) { 488 throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Public key does not contain an object identifier"); 489 } 490 return d.value; 491 } 492 493 494 495 /** 496 * Decode a public key from the TR-03110 format 497 * 498 * @param {ASN1} pdo the public key data object 499 * @param {Key} key the key object to fill 500 */ 501 CVC.decodeECPublicKey = function(pdo, key) { 502 503 var d = pdo.find(0x86); // Public point 504 if (d == null) { 505 throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key value"); 506 } 507 508 var b = d.value.bytes(1); 509 key.setComponent(Key.ECC_QX, b.left(b.length >> 1)); 510 key.setComponent(Key.ECC_QY, b.right(b.length >> 1)); 511 512 var d = pdo.find(0x81); // Prime modulus 513 if (d != null) { 514 key.setComponent(Key.ECC_P, d.value); 515 } 516 517 var d = pdo.find(0x82); // First coefficient a 518 if (d != null) { 519 key.setComponent(Key.ECC_A, d.value); 520 } 521 522 var d = pdo.find(0x83); // First coefficient b 523 if (d != null) { 524 key.setComponent(Key.ECC_B, d.value); 525 } 526 527 var d = pdo.find(0x84); // Base Point G 528 if (d != null) { 529 var b = d.value.bytes(1); 530 key.setComponent(Key.ECC_GX, b.left(b.length >> 1)); 531 key.setComponent(Key.ECC_GY, b.right(b.length >> 1)); 532 } 533 534 var d = pdo.find(0x85); // Order of the base point 535 if (d != null) { 536 key.setComponent(Key.ECC_N, d.value); 537 } 538 539 var d = pdo.find(0x87); // Cofactor f 540 if (d != null) { 541 key.setComponent(Key.ECC_H, d.value); 542 } 543 } 544 545 546 547 /** 548 * Returns the EC public key contained in the certificate. 549 * 550 * @param {Key} domParam optional domain parameter if they are not contained in certificate 551 * @return the public key object 552 * @type Key 553 */ 554 CVC.prototype.getECPublicKey = function(domParam) { 555 if (typeof(domParam) != "undefined") { 556 var key = new Key(domParam); 557 } else { 558 var key = new Key(); 559 } 560 561 key.setType(Key.PUBLIC); 562 563 var pdo = this.body.find(CVC.TAG_PUK); 564 if (pdo == null) { 565 throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key"); 566 } 567 568 CVC.decodeECPublicKey(pdo, key); 569 570 return key; 571 } 572 573 574 575 /** 576 * Returns the RSA public key contained in the certificate. 577 * 578 * @return the public key object 579 * @type Key 580 */ 581 CVC.prototype.getRSAPublicKey = function() { 582 var key = new Key(); 583 584 key.setType(Key.PUBLIC); 585 586 var pdo = this.body.find(CVC.TAG_PUK); 587 if (pdo == null) { 588 throw new GPError("CVC", GPError.OBJECT_NOT_FOUND, 0, "Certificate does not contain a public key"); 589 } 590 591 var d = pdo.find(0x81); // modulus 592 if (d != null) { 593 key.setComponent(Key.MODULUS, d.value); 594 } 595 596 var d = pdo.find(0x82); // public exponent 597 if (d != null) { 598 key.setComponent(Key.EXPONENT, d.value); 599 } 600 601 return key; 602 } 603 604 605 606 /** 607 * Returns the public key contained in the certificate. 608 * 609 * @param {Key} domParam optional domain parameter if they are not contained in certificate 610 * @return the public key object 611 * @type Key 612 */ 613 CVC.prototype.getPublicKey = function(domParam) { 614 var pkoid = this.getPublicKeyOID(); 615 616 if (CVC.isECDSA(pkoid)) { 617 return this.getECPublicKey(domParam); 618 } 619 return this.getRSAPublicKey(); 620 } 621 622 623 624 /** 625 * Determine if this is an authenticated request 626 * 627 * @returns true, if authenticated request 628 * @type Boolean 629 */ 630 CVC.prototype.isAuthenticatedRequest = function() { 631 return (this.asn.tag == CVC.TAG_AT); 632 } 633 634 635 636 /** 637 * Determine if this is a certificate request 638 * 639 * @returns true, if certificate request 640 * @type Boolean 641 */ 642 CVC.prototype.isCertificateRequest = function() { 643 if (isAuthenticatedRequest()) { 644 return true; 645 } 646 647 var ced = this.getCED(); 648 return ced == null; 649 } 650 651 652 653 /** 654 * Determine if this is a countersigned authenticated request 655 * 656 * @returns true, if countersigned authenticated request 657 * @type Boolean 658 */ 659 CVC.prototype.isCountersignedRequest = function() { 660 if (!this.isAuthenticatedRequest()) { 661 return false; 662 } 663 return (this.getCHR().getHolder() != this.getOuterCAR().getHolder()); 664 } 665 666 667 668 /** 669 * Determine if this certificate is expired 670 * 671 * @returns true, if certificate is expired 672 * @type Boolean 673 */ 674 CVC.prototype.isExpired = function() { 675 var now = new Date(); 676 now.setHours(12, 0, 0, 0); 677 return (now.valueOf() > this.getCXD().valueOf()); 678 } 679 680 681 682 /** 683 * Verify certificate signature with public key 684 * 685 * @param {Key} puk the public key 686 * @param {ByteString} oid the signature algorithm 687 * @returns true if the signature is valid 688 * @type Boolean 689 */ 690 CVC.prototype.verifyWith = function(crypto, puk, oid) { 691 if (this.asn.tag == CVC.TAG_AT) { 692 var signature = this.asn.get(0).get(1); 693 } else { 694 var signature = this.asn.get(1); 695 } 696 697 if (typeof(oid) == "undefined") { 698 var oid = this.getPublicKeyOID(); 699 } 700 var mech = CVC.getSignatureMech(oid); 701 702 if (CVC.isECDSA(oid)) { 703 var signatureValue = ECCUtils.wrapSignature(signature.value); 704 } else { 705 var signatureValue = signature.value; 706 } 707 708 return crypto.verify(puk, mech, this.body.getBytes(), signatureValue); 709 } 710 711 712 713 /** 714 * Verify certificate signature with public key from card verifiable certificate 715 * 716 * @param {CVC} cvc the card verifiable certificate used to obtain the public key 717 * @returns true if the signature is valid 718 * @type Boolean 719 */ 720 CVC.prototype.verifyWithCVC = function(crypto, cvc) { 721 return this.verifyWith(crypto, cvc.getPublicKey(), cvc.getPublicKeyOID()); 722 } 723 724 725 726 /** 727 * Verify outer signature of an authenticated request with public key 728 * 729 * @param {Key} puk the public key 730 * @param {ByteString} oid the signature algorithm 731 * @returns true if the signature is valid 732 * @type Boolean 733 */ 734 CVC.prototype.verifyATWith = function(crypto, puk, oid) { 735 if (!this.isAuthenticatedRequest()) { 736 throw new GPError("CVC", GPError.INVALID_DATA, 0, "Not an authenticated request"); 737 } 738 739 var signature = this.asn.get(2); 740 var signatureInput = this.asn.get(0).getBytes().concat(this.asn.get(1).getBytes()); 741 742 if (typeof(oid) == "undefined") { 743 var oid = this.getPublicKeyOID(); 744 } 745 var mech = CVC.getSignatureMech(oid); 746 747 if (CVC.isECDSA(oid)) { 748 var signatureValue = ECCUtils.wrapSignature(signature.value); 749 } else { 750 var signatureValue = signature.value; 751 } 752 return crypto.verify(puk, mech, signatureInput, signatureValue); 753 } 754 755 756 757 /** 758 * Verify outer signature of an authenticated request with public key from card verifiable certificate 759 * 760 * @param {CVC} cvc the card verifiable certificate used to obtain the public key 761 * @returns true if the signature is valid 762 * @type Boolean 763 */ 764 CVC.prototype.verifyATWithCVC = function(crypto, cvc) { 765 return this.verifyATWith(crypto, cvc.getPublicKey(), cvc.getPublicKeyOID()); 766 } 767 768 769 770 /** 771 * Returns the encoded certificate 772 * 773 * @return the DER encoded certificate 774 * @type ByteString 775 */ 776 CVC.prototype.getBytes = function() { 777 return this.bin; 778 } 779 780 781 782 /** 783 * Returns the certificate as ASN1 structure 784 * 785 * @return the certificate as ASN1 structure 786 * @type ASN1 787 */ 788 CVC.prototype.getASN1 = function() { 789 return this.asn; 790 } 791 792 793 794 /** 795 * Function to recursively walk the ASN.1 tree 796 */ 797 CVC.decorateTree = function(node) { 798 var name = CVC.OBJECTNAMES[node.tag]; 799 800 if (name) { 801 node.setName(name); 802 } 803 804 if (node.isconstructed) { 805 for (var i = 0; i < node.elements; i++) { 806 CVC.decorateTree(node.get(i)); 807 } 808 } 809 } 810 811 812 813 /** 814 * Decorate the ASN.1 object with the correct name 815 */ 816 CVC.prototype.decorate = function() { 817 CVC.decorateTree(this.asn); 818 var cxddo = this.body.find(CVC.TAG_CXD); 819 if (cxddo == null) { 820 if (this.asn.tag == CVC.TAG_AT) { 821 this.asn.setName("Authenticated CVC Request"); 822 } else { 823 this.asn.setName("CVC Request"); 824 } 825 } 826 } 827 828 829 830 /** 831 * Return list of rights granted by the certificate 832 * 833 * @returns the list of rights 834 * @type String[] 835 */ 836 CVC.prototype.getRightsAsList = function() { 837 var list = []; 838 839 var rtab; 840 var chat = this.getCHAT(); 841 if (chat == null) { 842 return list; 843 } 844 845 var oid = chat.get(0).value; 846 847 if (oid.equals(CVC.idIS)) { 848 rtab = CVC.ISRIGHTS; 849 } else if (oid.equals(CVC.idAT)) { 850 rtab = CVC.ATRIGHTS; 851 } else if (oid.equals(CVC.idST)) { 852 rtab = CVC.STRIGHTS; 853 } else { 854 return null; 855 } 856 857 var mask = chat.get(1).value; 858 var c = 0; 859 for (var i = mask.length - 1; i >= 0; i--) { 860 var akku = mask.byteAt(i); 861 for (var j = 0; j < (i == 0 ? 6 : 8); j++) { 862 if (akku & 1) { 863 list.push(rtab[c]); 864 } 865 c++; 866 akku >>= 1; 867 } 868 } 869 return list; 870 } 871 872 873 874 /** 875 * Return a string describing the certificate type 876 * 877 * @returns a describing string 878 * @type String 879 */ 880 CVC.prototype.getType = function() { 881 var ced = this.getCED(); 882 var chat = this.getCHAT(); 883 884 // Decode certificate / request type 885 var str = "CVC "; 886 if (ced == null) { 887 if (this.asn.tag == CVC.TAG_AT) { 888 str = "AT-CVREQ "; 889 } else { 890 str = "CVREQ "; 891 } 892 } 893 894 // Decode CA type 895 if (chat != null) { 896 var oid = chat.get(0).value; 897 898 var trustedDV = ""; 899 var untrustedDV = ""; 900 901 if (oid.equals(CVC.idIS)) { 902 str += "id-IS "; 903 trustedDV = "(official domestic) "; 904 untrustedDV = "(official foreign) "; 905 } else if (oid.equals(CVC.idAT)) { 906 str += "id-AT "; 907 trustedDV = "(official domestic) "; 908 untrustedDV = "(non-official / foreign) "; 909 } else if (oid.equals(CVC.idST)) { 910 str += "id-ST "; 911 trustedDV = "(accreditation body) "; 912 untrustedDV = "(certification service provider) "; 913 } else if (oid.equals(CVC.idSC_HSM)) { 914 str += "id-SC-HSM "; 915 trustedDV = ""; 916 } else { 917 str += oid.toString(OID) + " "; 918 } 919 920 switch(chat.get(1).value.byteAt(0) & 0xC0) { 921 case 0xC0: str += "CVCA "; break; 922 case 0x80: str += "DV " + trustedDV; break; 923 case 0x40: str += "DV " + untrustedDV; break; 924 case 0x00: str += "Terminal "; break; 925 } 926 } 927 928 return str; 929 } 930 931 932 933 /** 934 * Return a textual description of the certificate 935 * 936 * @returns a string containing information about the certificate 937 * @type String 938 */ 939 CVC.prototype.toString = function() { 940 var car = this.getCAR(); 941 var ced = this.getCED(); 942 943 var str = this.getType(); 944 945 if (car) { 946 str += "CAR=" + car.toString() + " "; 947 } 948 949 str += "CHR=" + this.getCHR().toString() + " "; 950 951 if (ced) { 952 str += "CED=" + ced.toLocaleDateString() + " "; 953 } 954 955 var cxd = this.getCXD(); 956 if (cxd) { 957 str += "CXD=" + cxd.toLocaleDateString() + " "; 958 } 959 960 if (this.isAuthenticatedRequest()) { 961 str += "oCAR=" + this.getOuterCAR().toString() + " "; 962 } 963 964 return str; 965 } 966 967