      1 /**
      2  *  ---------
      3  * |.##> <##.|  Open Smart Card Development Platform (www.openscdp.org)
      4  * |#       #|
      5  * |#       #|  Copyright (c) 1999-2010 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 Simple CVC-CA
     25  */
     26
     27
     28 // Imports
     29 var CVC = require('scsh/eac/CVC').CVC;
     30 var CVCertificateStore = require('scsh/eac/CVCertificateStore').CVCertificateStore;
     31 var PublicKeyReference = require('scsh/eac/PublicKeyReference').PublicKeyReference;
     32 var EAC2CVRequestGenerator = require('scsh/eac/EAC2CVRequestGenerator').EAC2CVRequestGenerator;
     33 var EAC2CVCertificateGenerator = require('scsh/eac/EAC2CVCertificateGenerator').EAC2CVCertificateGenerator;
     34
     35
     36
     37 /**
     38  * Creates a new CVC-CA instance
     39  *
     40  * @class Class supporting a certification authority that can issue CVC certificates
     41  * for the EAC protocol.
     42  *
     43  * @constructor
     44  * @param {Crypto} crypto the crypto provider to use
     45  * @param {CVCertificateStore} certstore the certificate store to use
     46  * @param {String} path the path of holderIDs (eg. "/UTCVCA/UTDVCA/UTTERM")
     47  */
     48 function CVCCA(crypto, certstore, holderId, parentId, path) {
     49 	GPSystem.log(GPSystem.DEBUG, module.id, "new(" + crypto + "," + certstore + "," + holderId + "," + parentId + "," + path + ")");
     50
     51 	this.crypto = crypto;
     52 	this.certstore = certstore;
     53
     54 	if (typeof(path) == "undefined") {	// ToDo: Remove after migration
     55 		this.holderId = holderId;
     56 		this.parentId = parentId;
     57
     58 		if (this.isRootCA()) {		// CVCA
     59 			this.path = "/" + holderId;
     60 		} else {					// DVCA
     61 			this.path = "/" + parentId + "/" + holderId;
     62 		}
     63 	} else {
     64 		this.path = path;
     65 		var pe = path.substr(1).split("/");
     66 		var l = pe.length;
     67 		assert(l >= 1);
     68 		this.holderId = pe[l - 1];
     69 		if (l > 1) {
     70 			this.parentId = pe[l - 2];
     71 		} else {
     72 			this.parentId = this.holderId;
     73 		}
     74 	}
     75 	this.keyspec = new Key();
     76 	this.keyspec.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID));
     77 	this.taAlgorithmIdentifier = new ByteString("id-TA-ECDSA-SHA-256", OID);
     78 	this.countryseq = null;
     79 }
     80
     81 exports.CVCCA = CVCCA;
     82
     83
     84
     85 /**
     86  * Set factory generating EACCryptoProvider for private key operations (create, use, delete)
     87  *
     88  * @param {EACCryptoProvider} eaccp the EAC Crypto Provider for this instance
     89  * @param {String} eaccpid the instance id
     90  */
     91 CVCCA.prototype.setEACCryptoProviderFactory = function(eaccpf, eaccpid) {
     92 	this.eaccpf = eaccpf;
     93 	this.eaccpid = eaccpid;
     94 }
     95
     96
     97
     98 /**
     99  * Return a suitable crypto instance
    100  *
    101  */
    102 CVCCA.prototype.getCrypto = function() {
    103 	GPSystem.log(GPSystem.DEBUG, module.id, "getCrypto()");
    104
    105 	if (this.crypto) {
    106 		return this.crypto;
    107 	}
    108
    109 	if (this.eaccpf) {
    110 		var eaccp = this.eaccpf.getEACCryptoProvider(this.eaccpid, true);
    111 		return eaccp.getCrypto();
    112 	}
    113
    114 	return this.certstore.getCrypto()
    115 }
    116
    117
    118
    119 /**
    120  * Returns true if this is a root CA
    121  *
    122  * @returns true if this is a root CA
    123  * @type boolean
    124  */
    125 CVCCA.prototype.isRootCA = function() {
    126 	GPSystem.log(GPSystem.DEBUG, module.id, "isRootCA()");
    127
    128 	return this.holderId == this.parentId;
    129 }
    130
    131
    132
    133 /**
    134  * Returns true if this CA has a certificate.
    135  *
    136  * @returns true if this CA is operational
    137  * @type boolean
    138  */
    139 CVCCA.prototype.hasCertificate = function() {
    140 	GPSystem.log(GPSystem.DEBUG, module.id, "hasCertificate()");
    141
    142 	var currentchr = this.certstore.getCurrentCHR(this.path);
    143 	return currentchr != null;
    144 }
    145
    146
    147
    148 /**
    149  * Returns true if this CA is operational.
    150  *
    151  * @returns true if this CA is operational
    152  * @type boolean
    153  */
    154 CVCCA.prototype.isOperational = function() {
    155 	GPSystem.log(GPSystem.DEBUG, module.id, "isOperational()");
    156
    157 	var currentchr = this.certstore.getCurrentCHR(this.path);
    158 	if (currentchr == null) {
    159 		return false;
    160 	}
    161 	var cvc = this.certstore.getCertificate(this.path, currentchr);
    162 	return !cvc.isExpired();
    163 }
    164
    165
    166
    167 /**
    168  * Sets the key specification for generating requests
    169  *
    170  * @param {Key} keyparam a key object containing key parameters (e.g. EC Curve)
    171  * @param {ByteString} algorithm the terminal authentication algorithm object identifier
    172  */
    173 CVCCA.prototype.setKeySpec = function(keyparam, algorithm) {
    174 	GPSystem.log(GPSystem.DEBUG, module.id, "setKeySpec(" + keyparam + "," + algorithm + ")");
    175
    176 	this.keyspec = keyparam;
    177 	this.taAlgorithmIdentifier = algorithm;
    178 }
    179
    180
    181
    182 /**
    183  * Set flags that controls the removal of the previous key if the certificate for the new key is imported
    184  *
    185  * @param {boolean} removePreviousKey true to remove, false to keep
    186  */
    187 CVCCA.prototype.setRemovePreviousKey = function(removePreviousKey) {
    188 	GPSystem.log(GPSystem.DEBUG, module.id, "setRemovePreviousKey(" + removePreviousKey + ")");
    189
    190 	this.removePreviousKey = removePreviousKey;
    191 }
    192
    193
    194
    195 /**
    196  * Set country code to be included in sequence number of public key reference
    197  *
    198  * @param {String} countryseq the two character country code
    199  */
    200 CVCCA.prototype.setCountryCodeForSequence = function(countryseq) {
    201 	GPSystem.log(GPSystem.DEBUG, module.id, "setCountryCodeForSequence(" + countryseq + ")");
    202
    203 	this.countryseq = countryseq;
    204 }
    205
    206
    207
    208 /**
    209  * Return private key handle, either from EACCryptoProvider or Certificate Store
    210  *
    211  */
    212 CVCCA.prototype.getPrivateKey = function(path, chr) {
    213 	GPSystem.log(GPSystem.DEBUG, module.id, "getPrivateKey(" + path + "," + chr + ")");
    214
    215 	if (this.eaccpf) {
    216 		var eaccp = this.eaccpf.getEACCryptoProvider(this.eaccpid, true);
    217
    218 		var blob = this.certstore.getSigner(path, chr);
    219 		var prkey = eaccp.getPrivateKey(path, chr, blob);
    220
    221 		if (prkey && !blob) {		// Have a key but no matching signer
    222 			GPSystem.log(GPSystem.DEBUG, module.id, "Signer " + chr + " not found in database, but on crypto device. Creating signer now.");
    223
    224 			// Calculate current signer number
    225 			var seq = chr.getSequenceNo();
    226 			var cnt = parseInt(seq.substr(-5), 10);			// Full 5 digit sequence
    227 			if (isNaN(cnt)) {
    228 				var cnt = parseInt(seq.substr(-3), 10);		// 3 Digit sequence number
    229 			}
    230
    231 			GPSystem.log(GPSystem.DEBUG, module.id, "Setting signer number to " + cnt);
    232 			this.certstore.setSignerNo(path, cnt);
    233 			this.certstore.newSigner(path, chr);
    234 		}
    235 		return prkey;
    236 	} else {
    237 		return this.certstore.getPrivateKey(path, chr);
    238 	}
    239 }
    240
    241
    242
    243 /**
    244  * Generate a certificate request
    245  *
    246  * @param {PublicKeyReference} car the CA at which this request is addressed
    247  * @param {boolean} forceInitial force an initial request, even if a current certificate is available
    248  * @param {boolean} signinitial sign with initial key (sequence = 00000)
    249  * @return the certificate request
    250  * @type CVC
    251  */
    252 CVCCA.prototype.generateRequest = function(car, forceinitial, signinitial) {
    253 	GPSystem.log(GPSystem.DEBUG, module.id, "generateRequest(" + car + "," + forceinitial + "," + signinitial + ")");
    254
    255 	if (typeof(this.certstore.sc) != "undefined") {
    256 		return this.generateRequestHSM(car, forceinitial, signinitial);
    257 	}
    258
    259 	if (this.eaccpf) {
    260 		var eaccp = this.eaccpf.getEACCryptoProvider(this.eaccpid, true);
    261 		if (typeof(eaccp.generateRequest) == "function") {
    262 			return this.generateRequestHSMCP(eaccp, car, forceinitial, signinitial);
    263 		}
    264 	}
    265
    266 	// Obtain key parameter
    267
    268 	if (typeof(this.keyspec.getComponent(Key.ECC_P)) != "undefined") {
    269 		var prk = new Key(this.keyspec);
    270 		prk.setType(Key.PRIVATE);
    271 		var keyalg = Crypto.EC;
    272 	} else {
    273 		var prk = new Key();
    274 		prk.setType(Key.PRIVATE);
    275 		var keyalg = Crypto.RSA;
    276 	}
    277 	var puk = new Key(this.keyspec);
    278 	puk.setType(Key.PUBLIC);
    279
    280 	// Determine CHR
    281 	var currentchr = this.certstore.getCurrentCHR(this.path);
    282 	var nextchr = this.certstore.getNextCHR(this.path, this.countryseq);
    283
    284 	// Generate key pair
    285 	if (this.eaccpf) {
    286 		var eaccp = this.eaccpf.getEACCryptoProvider(this.eaccpid, true);
    287 		eaccp.generateKeyPair(this.path, nextchr, keyalg, prk, puk);
    288 	} else {
    289 		this.certstore.generateKeyPair(this.path, nextchr, keyalg, prk, puk);
    290 	}
    291
    292 	// Generate certificate request
    293 	var reqGenerator = new EAC2CVRequestGenerator(this.getCrypto());
    294
    295 	// Set CPI
    296 	reqGenerator.setProfileIdentifier(0x00);
    297
    298 	// Set public key for request
    299 	reqGenerator.setPublicKey(puk);
    300
    301 	// Set oid of algorithm
    302 	reqGenerator.setTAAlgorithmIdentifier(this.taAlgorithmIdentifier);
    303
    304 	// Set CHR for the request
    305 	reqGenerator.setCHR(nextchr);
    306
    307 	if ((typeof(car) != "undefined") && (car != null)) {
    308 		reqGenerator.setCAR(car);
    309 	}
    310
    311 	if ((currentchr != null) && !forceinitial) {
    312 		var previousprk = this.getPrivateKey(this.path, currentchr);
    313 		var previouscvc = this.certstore.getCertificate(this.path, currentchr);
    314 		var req = reqGenerator.generateAuthenticatedCVRequest(prk, previousprk, currentchr, previouscvc.getPublicKeyOID());
    315 	} else {
    316 		// Generate the request
    317 		if (signinitial) {
    318 			var initialchr = new PublicKeyReference(nextchr.getHolder() + "00000");
    319 			var firstprk = this.getPrivateKey(this.path, initialchr);
    320 			var req = reqGenerator.generateAuthenticatedCVRequest(prk, firstprk, initialchr);
    321 		} else {
    322 			var req = reqGenerator.generateCVRequest(prk);
    323 		}
    324 	}
    325
    326 	req = new CVC(req);
    327
    328 	this.certstore.storeRequest(this.path, req);
    329
    330 	return req;
    331 }
    332
    333
    334
    335 /**
    336  * Generate a certificate request using a SmartCard-HSM based private key
    337  *
    338  * @param {PublicKeyReference} car the CA at which this request is addressed
    339  * @param {boolean} forceInitial force an initial request, even if a current certificate is available
    340  * @param {boolean} signinitial sign with initial key (sequence = 00000)
    341  * @return the certificate request
    342  * @type CVC
    343  */
    344 CVCCA.prototype.generateRequestHSM = function(car, forceinitial, signinitial) {
    345 	GPSystem.log(GPSystem.DEBUG, module.id, "generateRequestHSM(" + car + "," + forceinitial + "," + signinitial + ")");
    346
    347 	var req = this.certstore.generateRequest(this.path, car, forceinitial, signinitial, this.keyspec, this.taAlgorithmIdentifier, this.countryseq);
    348 	this.certstore.storeRequest(this.path, req);
    349
    350 	return req;
    351 }
    352
    353
    354
    355 /**
    356  * Generate a certificate request using a SmartCard-HSM based private key via EACCryptoProvider
    357  *
    358  * @param {EACCryptoProvider} prov the EACCryptoProvider
    359  * @param {PublicKeyReference} car the CA at which this request is addressed
    360  * @param {boolean} forceInitial force an initial request, even if a current certificate is available
    361  * @param {boolean} signinitial sign with initial key (sequence = 00000)
    362  * @return the certificate request
    363  * @type CVC
    364  */
    365 CVCCA.prototype.generateRequestHSMCP = function(prov, car, forceinitial, signinitial) {
    366 	GPSystem.log(GPSystem.DEBUG, module.id, "generateRequestHSM(" + car + "," + forceinitial + "," + signinitial + ")");
    367
    368 	// Determine CHR
    369 	var currentchr = this.certstore.getCurrentCHR(this.path);
    370 	do	{
    371 		var nextchr = this.certstore.getNextCHR(this.path, this.countryseq);
    372 		var prk = this.getPrivateKey(this.path, nextchr);
    373 		if (!prk) {
    374 			break;
    375 		}
    376 		GPSystem.log(GPSystem.INFO, module.id, "CHR " + nextchr + " already in use, skipping to next CHR");
    377 	} while (true);
    378
    379 	var req = prov.generateRequest(this.path, currentchr, nextchr, car, forceinitial, signinitial, this.keyspec, this.taAlgorithmIdentifier);
    380 	this.certstore.storeRequest(this.path, req);
    381 	this.certstore.newSigner(this.path, nextchr);
    382
    383 	return req;
    384 }
    385
    386
    387
    388 /**
    389  * Counter-sign a request
    390  *
    391  * @param {CVC} req the initial request
    392  * @return the certificate request
    393  * @type CVC
    394  */
    395 CVCCA.prototype.counterSignRequest = function(request) {
    396 	GPSystem.log(GPSystem.DEBUG, module.id, "counterSignRequest('" + request + "')");
    397
    398 	assert(!request.isAuthenticatedRequest());
    399
    400 	var car = this.certstore.getCurrentCHR(this.path);
    401 	assert(car != null);
    402
    403 	var cacvc = this.certstore.getCertificate(this.path, car);
    404 	assert(cacvc != null);
    405
    406 	var signingTAAlgorithmIdentifier = cacvc.getPublicKeyOID();
    407 	var prk = this.getPrivateKey(this.path, car);
    408
    409 	var req = EAC2CVRequestGenerator.signAuthenticatedCVRequest(this.getCrypto(), request.getASN1(), prk, car, signingTAAlgorithmIdentifier);
    410 	return new CVC(req);
    411 }
    412
    413
    414
    415 /**
    416  * Generate an initial certificate request
    417  *
    418  * @param {PublicKeyReference} car the CA at which this request is addressed
    419  * @return the certificate request
    420  * @type CVC
    421  */
    422 CVCCA.prototype.generateInitialRequest = function(car) {
    423 	GPSystem.log(GPSystem.DEBUG, module.id, "generateInitialRequest(" + car + ")");
    424
    425 	return this.generateRequest(car, true, false);
    426 }
    427
    428
    429
    430 /**
    431  * Generate a signed initial certificate request
    432  *
    433  * @param {PublicKeyReference} car the CA at which this request is addressed
    434  * @return the certificate request
    435  * @type CVC
    436  */
    437 CVCCA.prototype.generateSignedInitialRequest = function(car) {
    438 	GPSystem.log(GPSystem.DEBUG, module.id, "generateSignedInitialRequest(" + car + ")");
    439
    440 	return this.generateRequest(car, true, true);
    441 }
    442
    443
    444
    445 /**
    446  * Generate certificate for certificate request
    447  *
    448  * <p>Certificate contents is defined through the policy object:</p>
    449  * <pre>
    450  *  	var policy = { certificateValidityDays: 2,
    451  * 				   chatRoleOID: new ByteString("id-IS", OID),
    452  * 				   chatRights: new ByteString("E3", HEX),
    453  * 				   includeDomainParameter: true,
    454  * 				   extensions: []
    455  * 				 };
    456  * </pre>
    457  *
    458  * @param {CVC} req the certificate request
    459  * @param {Object} policy the object with policy settings
    460  * @returns the certificate
    461  * @type CVC
    462  */
    463 CVCCA.prototype.generateCertificate = function(req, policy) {
    464 	GPSystem.log(GPSystem.DEBUG, module.id, "generateCertificate('" + req + "'" + policy + ")");
    465
    466 	var car = this.certstore.getCurrentCHR(this.path);
    467 	var maxExpDate = null;
    468
    469 	if (car == null) {				// No CA certificate found
    470 		if (this.isRootCA()) {
    471 			car = req.getCHR();		// Generate a self-signed root certificate
    472 		} else {
    473 			throw new GPError("CVCCA", GPError.INVALID_DATA, 0, "No current certificate found");
    474 		}
    475 		if (policy.publicKeyOID) {
    476 			var signingTAAlgorithmIdentifier = policy.publicKeyOID;
    477 		} else {
    478 			var signingTAAlgorithmIdentifier = req.getPublicKeyOID();
    479 		}
    480 	} else {
    481 		var cacvc = this.certstore.getCertificate(this.path, car);
    482 		var signingTAAlgorithmIdentifier = cacvc.getPublicKeyOID();
    483 		if (policy.shellModelForExpirationDate) {
    484 			maxExpDate = cacvc.getCXD();
    485 		}
    486 	}
    487
    488 	var generator = new EAC2CVCertificateGenerator(this.getCrypto());
    489 	generator.setCAR(car);
    490 	generator.setCHR(req.getCHR());
    491 	var effDate = new Date();
    492 	if (policy.ced) {
    493 		effDate = policy.ced;
    494 	}
    495 	effDate.setHours(12, 0, 0, 0);
    496 	var expDate = new Date((policy.certificateValidityDays - 1) * (1000 * 60 * 60 * 24) + effDate.getTime());
    497 	expDate.setHours(12, 0, 0, 0);
    498
    499 	if (maxExpDate != null) {
    500 		if (effDate.getTime() > maxExpDate.getTime()) {
    501 			throw new GPError("CVCCA", GPError.INVALID_DATA, 0, "CA certificate is expired");
    502 		}
    503 		// Expiration date of issued certificate must not exceed expiration date of issuing CA
    504 		if (expDate.getTime() > maxExpDate.getTime()) {
    505 			expDate = maxExpDate;
    506 		}
    507 	}
    508
    509 	generator.setEffectiveDate(effDate);
    510 	generator.setExpiryDate(expDate);
    511 	generator.setChatOID(policy.chatRoleOID);
    512 	generator.setChatAuthorizationLevel(policy.chatRights);
    513 	generator.setPublicKey(req.getPublicKey());
    514 	generator.setProfileIdentifier(0x00);
    515 	if (policy.publicKeyOID) {
    516 		generator.setTAAlgorithmIdentifier(policy.publicKeyOID);
    517 	} else {
    518 		generator.setTAAlgorithmIdentifier(req.getPublicKeyOID());
    519 	}
    520
    521 	generator.setIncludeDomainParameters(policy.includeDomainParameter);
    522 	generator.setExtensions(policy.extensions);
    523 	var prk = this.getPrivateKey(this.path, car);
    524 	var cvc = generator.generateCVCertificate(prk, signingTAAlgorithmIdentifier);
    525
    526 	return cvc;
    527 }
    528
    529
    530
    531 /**
    532  * Store issued certificate
    533  *
    534  * @param {CVC} cert a newly issued certificate
    535  */
    536 CVCCA.prototype.storeCertificate = function(cert) {
    537 	GPSystem.log(GPSystem.DEBUG, module.id, "storeCertificate('" + cert + "')");
    538
    539 	var chrHolder = cert.getCHR().getHolder();
    540 	this.certstore.storeCertificate(this.path + "/" + chrHolder, cert, false);
    541 }
    542
    543
    544
    545 /**
    546  * Remove previous key
    547  *
    548  * @param {PublicKeyReference} previous the previously used CHR
    549  */
    550 CVCCA.prototype.removePreviouslyUsedKey = function(previous) {
    551 	GPSystem.log(GPSystem.DEBUG, module.id, "removePreviouslyUsedKey('" + previous + "')");
    552
    553 	if (previous.equals(this.certstore.getCurrentCHR(this.path))) {
    554 		GPSystem.log(GPSystem.INFO, module.id, "CHR " + previous + " is still the active key. Not deleting it");
    555 		return;
    556 	}
    557
    558 	if (this.eaccpf) {
    559 		var eaccp = this.eaccpf.getEACCryptoProvider(this.eaccpid, true);
    560 		eaccp.deletePrivateKey(this.path, previous);
    561 	} else {
    562 		this.certstore.deletePrivateKey(this.path, previous);
    563 	}
    564 }
    565
    566
    567
    568 /**
    569  * Import a certificate into the certificate store and make it the current certificate
    570  *
    571  * @param {CVC} cert the certificate
    572  */
    573 CVCCA.prototype.importCertificate = function(cert) {
    574 	GPSystem.log(GPSystem.DEBUG, module.id, "importCertificate('" + cert + "')");
    575
    576 	var chr = cert.getCHR();
    577 	var prk = this.getPrivateKey(this.path, chr);
    578 	if (prk == null) {
    579 		throw new GPError("CVCCA", GPError.INVALID_DATA, 0, "Invalid certificate, no matching private key");
    580 	}
    581 	var c = this.certstore.getCertificate(this.path, cert.getCHR());
    582 	if (c != null) {
    583 		GPSystem.log(GPSystem.INFO, module.id, "Certificate " + c + " already existing");
    584 	}
    585
    586 	// Save currentchr
    587 	var currentchr = this.certstore.getCurrentCHR(this.path);
    588
    589 	if (this.isRootCA() && !this.isOperational()) {
    590 		this.certstore.storeCertificate(this.path, cert, (c == null));
    591 	} else {
    592 		if (!this.certstore.insertCertificate(this.getCrypto(), cert, this.path)) {
    593 			throw new GPError("CVCCA", GPError.CRYPTO_FAILED, 0, "Could not validate certificate");
    594 		}
    595 	}
    596 	if (this.removePreviousKey && currentchr) {
    597 		this.removePreviouslyUsedKey(currentchr);
    598 	}
    599 }
    600
    601
    602
    603 /**
    604  * Import a list of certificates into the certificate store
    605  *
    606  * @param {CVC[]} certs the list of certificates
    607  */
    608 CVCCA.prototype.importCertificates = function(certs) {
    609 	GPSystem.log(GPSystem.DEBUG, module.id, "importCertificates('" + certs + "')");
    610
    611 	// Save currentchr
    612 	var currentchr = this.certstore.getCurrentCHR(this.path);
    613
    614 	var list = this.certstore.insertCertificates(this.getCrypto(), certs, true, this.path);
    615
    616 	if (this.removePreviousKey && currentchr) {
    617 		this.removePreviouslyUsedKey(currentchr);
    618 	}
    619
    620 	return list;
    621 }
    622
    623
    624
    625 /**
    626  * Returns a list of relevant certificates.
    627  *
    628  * <p>If the CA is the root CA, then all self-signed and link certificates are returned.</p>
    629  * <p>If the CA is a DVCA, then all certificates of the associated root and the current
    630  *    DVCA certificate is returned.</p>
    631  *
    632  * @param {PublicKeyReference} fromCAR the optional starting point for the list if not a root CA
    633  */
    634 CVCCA.prototype.getCertificateList = function(fromCAR) {
    635 	GPSystem.log(GPSystem.DEBUG, module.id, "getCertificateList(" + fromCAR + ")");
    636
    637 	var list;
    638
    639 	if (this.isRootCA()) {
    640 		list = this.certstore.listCertificates(this.path);
    641 	} else {
    642 		var path = this.path;
    643
    644 		while(true) {
    645 			var chr = this.certstore.getCurrentCHR(path);
    646 			if (chr == null) {
    647 				var ofs = path.lastIndexOf("/");
    648 				if (ofs == 0) {
    649 					list = [];
    650 				} else {
    651 					path = path.substr(0, ofs);
    652 					continue;
    653 				}
    654 			} else {
    655 				list = this.certstore.getCertificateChain(path, chr, fromCAR);
    656 			}
    657 			break;
    658 		}
    659 	}
    660
    661 	return list;
    662 }
    663
    664
    665
    666 /**
    667  * Return certificate issued by this CA
    668  *
    669  * @param {PublicKeyReference} chr the certificate holder reference
    670  * @returns the certificate or null if not found
    671  * @type CVC
    672  */
    673 CVCCA.prototype.getIssuedCertificate = function(chr) {
    674 	GPSystem.log(GPSystem.DEBUG, module.id, "getIssuedCertificate(" + chr + ")");
    675
    676 	var path = this.path + "/" + chr.getHolder();
    677
    678 	var cvc = this.certstore.getCertificate(path, chr);
    679 	if (cvc == null) {
    680 		GPSystem.trace("No certificate found for " + chr);
    681 		return null;
    682 	}
    683
    684 	return cvc;
    685 }
    686
    687
    688
    689 /**
    690  * Return authentic public key with domain parameter for a given CHR subordinate to the CA
    691  *
    692  * @param {PublicKeyReference} chr the certificate holder reference
    693  * @returns the public key or null
    694  * @type Key
    695  */
    696 CVCCA.prototype.getAuthenticPublicKey = function(chr) {
    697 	GPSystem.log(GPSystem.DEBUG, module.id, "getAuthenticPublicKey(" + chr + ")");
    698
    699 	var cvc = this.getIssuedCertificate(chr);
    700
    701 	if (cvc == null) {
    702 		return null;
    703 	}
    704
    705 	if (this.isRootCA()) {
    706 		var dp = this.certstore.getDomainParameter(cvc.getCAR());
    707 	} else {
    708 		var dvcacvc = this.certstore.getCertificate(this.path, cvc.getCAR());
    709 		if (dvcacvc == null) {
    710 			GPSystem.trace("No certificate found for " + cvc.getCAR());
    711 			return null;
    712 		}
    713 		var dp = this.certstore.getDomainParameter(dvcacvc.getCAR());
    714 	}
    715
    716 	return(cvc.getPublicKey(dp));
    717 }
    718
    719
    720
    721 CVCCA.test = function(daofcvca, daofdvca, daofterm) {
    722
    723 	var crypto = new Crypto();
    724
    725 	var ss = new CVCertificateStore(daofcvca);
    726 	ss.setContextMarker(0);
    727 	var cvca = new CVCCA(crypto, ss, null, null, "/UTCVCA");
    728
    729 	// Create a new request
    730 	var req = cvca.generateRequest(null, false);
    731 	GPSystem.trace("Request: " + req);
    732 	GPSystem.trace(req.getASN1());
    733
    734 	assert(req.verifyWith(crypto, req.getPublicKey()));
    735
    736 	// Create self-signed or link certificate based on request
    737 	var policy = { certificateValidityDays: 2,
    738 				   chatRoleOID: new ByteString("id-IS", OID),
    739 				   chatRights: new ByteString("E3", HEX),
    740 				   includeDomainParameter: true,
    741 				   extensions: []
    742 				 };
    743 	var cert = cvca.generateCertificate(req, policy);
    744 	GPSystem.trace("Certificate: " + cert);
    745 	GPSystem.trace(cert.getASN1());
    746
    747 	// Import certificate into store, making it the most current certificate
    748 	cvca.importCertificate(cert);
    749
    750 	// Generate additional self-signed root certificate
    751 	// This must be done after the link certificate has been imported
    752 	var policy = { certificateValidityDays: 2,
    753 				   chatRoleOID: new ByteString("id-IS", OID),
    754 				   chatRights: new ByteString("E3", HEX),
    755 				   includeDomainParameter: true,
    756 				   extensions: []
    757 				 };
    758 	var cert = cvca.generateCertificate(req, policy);
    759 	GPSystem.trace("Certificate: " + cert);
    760 	GPSystem.trace(cert.getASN1());
    761
    762 	// Import certificate into store, making it the most current certificate
    763 	cvca.importCertificate(cert);
    764
    765 	var ss = new CVCertificateStore(daofdvca);
    766 	ss.setContextMarker(1);
    767 	var dvca = new CVCCA(crypto, ss, null, null, "/UTCVCA/UTDVCA");
    768
    769 	var certlist = cvca.getCertificateList();
    770 	var list = dvca.importCertificates(certlist);
    771
    772 	if (list.length > 0) {
    773 		GPSystem.trace("Warning: Could not import the following certificates");
    774 		for (var i = 0; i < list.length; i++) {
    775 			GPSystem.trace(list[i]);
    776 		}
    777 	}
    778
    779 	// Create a new request
    780 	var req = dvca.generateRequest(null, false);
    781 	GPSystem.trace("Request: " + req);
    782 	GPSystem.trace(req.getASN1());
    783
    784 	// Sign this request with root CA
    785 	// This must be done after the link certificate has been imported
    786 	var policy = { certificateValidityDays: 2,
    787 				   chatRoleOID: new ByteString("id-IS", OID),
    788 				   chatRights: new ByteString("A3", HEX),
    789 				   includeDomainParameter: false,
    790 				   extensions: []
    791 				 };
    792 	var cert = cvca.generateCertificate(req, policy);
    793 	GPSystem.trace("Certificate: " + cert);
    794 	GPSystem.trace(cert.getASN1());
    795
    796 	cvca.storeCertificate(cert);
    797 	dvca.importCertificate(cert);
    798
    799
    800 	var ss = new CVCertificateStore(daofterm);
    801 	ss.setContextMarker(2);
    802 	var term = new CVCCA(crypto, ss, null, null, "/UTCVCA/UTDVCA/UTTERM");
    803
    804 	term.setRemovePreviousKey(true);
    805
    806 	var certlist = dvca.getCertificateList();
    807 	GPSystem.trace("Certificate list: ");
    808 	GPSystem.trace(certlist);
    809 	var list = term.importCertificates(certlist);
    810
    811 	if (list.length > 0) {
    812 		GPSystem.trace("Warning: Could not import the following certificates");
    813 		for (var i = 0; i < list.length; i++) {
    814 			GPSystem.trace(list[i]);
    815 		}
    816 	}
    817
    818 	// Create a new request
    819 	var req = term.generateRequest(null, false);
    820 	GPSystem.trace("Request: " + req);
    821 	GPSystem.trace(req.getASN1());
    822
    823 	// Sign this request with DVCA
    824 	// This must be done after the link certificate has been imported
    825 	var policy = { certificateValidityDays: 2,
    826 				   chatRoleOID: new ByteString("id-IS", OID),
    827 				   chatRights: new ByteString("23", HEX),
    828 				   includeDomainParameter: false,
    829 				   extensions: []
    830 				 };
    831 	var cert = dvca.generateCertificate(req, policy);
    832 	GPSystem.trace("Certificate: " + cert);
    833 	GPSystem.trace(cert.getASN1());
    834
    835 	dvca.storeCertificate(cert);
    836 	term.importCertificate(cert);
    837 }
    838