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 	var signingTAAlgorithmIdentifier = req.getPublicKeyOID();
469 
470 	if (car == null) {				// No CA certificate found
471 		if (this.isRootCA()) {
472 			car = req.getCHR();		// Generate a self-signed root certificate
473 		} else {
474 			throw new GPError("CVCCA", GPError.INVALID_DATA, 0, "No current certificate found");
475 		}
476 	} else {
477 		var cacvc = this.certstore.getCertificate(this.path, car);
478 		var signingTAAlgorithmIdentifier = cacvc.getPublicKeyOID();
479 		if (policy.shellModelForExpirationDate) {
480 			maxExpDate = cacvc.getCXD();
481 		}
482 	}
483 
484 	var generator = new EAC2CVCertificateGenerator(this.getCrypto());
485 	generator.setCAR(car);
486 	generator.setCHR(req.getCHR());
487 	var effDate = new Date();
488 	if (policy.ced) {
489 		effDate = policy.ced;
490 	}
491 	effDate.setHours(12, 0, 0, 0);
492 	var expDate = new Date((policy.certificateValidityDays - 1) * (1000 * 60 * 60 * 24) + effDate.getTime());
493 	expDate.setHours(12, 0, 0, 0);
494 
495 	if (maxExpDate != null) {
496 		if (effDate.getTime() > maxExpDate.getTime()) {
497 			throw new GPError("CVCCA", GPError.INVALID_DATA, 0, "CA certificate is expired");
498 		}
499 		// Expiration date of issued certificate must not exceed expiration date of issuing CA
500 		if (expDate.getTime() > maxExpDate.getTime()) {
501 			expDate = maxExpDate;
502 		}
503 	}
504 
505 	generator.setEffectiveDate(effDate);
506 	generator.setExpiryDate(expDate);
507 	generator.setChatOID(policy.chatRoleOID);
508 	generator.setChatAuthorizationLevel(policy.chatRights);
509 	generator.setPublicKey(req.getPublicKey());
510 	generator.setProfileIdentifier(0x00);
511 	generator.setTAAlgorithmIdentifier(req.getPublicKeyOID());
512 	generator.setIncludeDomainParameters(policy.includeDomainParameter);
513 	generator.setExtensions(policy.extensions);
514 	var prk = this.getPrivateKey(this.path, car);
515 	var cvc = generator.generateCVCertificate(prk, signingTAAlgorithmIdentifier);
516 
517 	return cvc;
518 }
519 
520 
521 
522 /**
523  * Store issued certificate
524  *
525  * @param {CVC} cert a newly issued certificate
526  */
527 CVCCA.prototype.storeCertificate = function(cert) {
528 	GPSystem.log(GPSystem.DEBUG, module.id, "storeCertificate('" + cert + "')");
529 
530 	var chrHolder = cert.getCHR().getHolder();
531 	this.certstore.storeCertificate(this.path + "/" + chrHolder, cert, false);
532 }
533 
534 
535 
536 /**
537  * Remove previous key
538  *
539  * @param {PublicKeyReference} previous the previously used CHR
540  */
541 CVCCA.prototype.removePreviouslyUsedKey = function(previous) {
542 	GPSystem.log(GPSystem.DEBUG, module.id, "removePreviouslyUsedKey('" + previous + "')");
543 
544 	if (previous.equals(this.certstore.getCurrentCHR(this.path))) {
545 		GPSystem.log(GPSystem.INFO, module.id, "CHR " + previous + " is still the active key. Not deleting it");
546 		return;
547 	}
548 
549 	if (this.eaccpf) {
550 		var eaccp = this.eaccpf.getEACCryptoProvider(this.eaccpid, true);
551 		eaccp.deletePrivateKey(this.path, previous);
552 	} else {
553 		this.certstore.deletePrivateKey(this.path, previous);
554 	}
555 }
556 
557 
558 
559 /**
560  * Import a certificate into the certificate store and make it the current certificate
561  *
562  * @param {CVC} cert the certificate
563  */
564 CVCCA.prototype.importCertificate = function(cert) {
565 	GPSystem.log(GPSystem.DEBUG, module.id, "importCertificate('" + cert + "')");
566 
567 	var chr = cert.getCHR();
568 	var prk = this.getPrivateKey(this.path, chr);
569 	if (prk == null) {
570 		throw new GPError("CVCCA", GPError.INVALID_DATA, 0, "Invalid certificate, no matching private key");
571 	}
572 	var c = this.certstore.getCertificate(this.path, cert.getCHR());
573 	if (c != null) {
574 		GPSystem.log(GPSystem.INFO, module.id, "Certificate " + c + " already existing");
575 	}
576 
577 	// Save currentchr
578 	var currentchr = this.certstore.getCurrentCHR(this.path);
579 
580 	if (this.isRootCA() && !this.isOperational()) {
581 		this.certstore.storeCertificate(this.path, cert, (c == null));
582 	} else {
583 		if (!this.certstore.insertCertificate(this.getCrypto(), cert, this.path)) {
584 			throw new GPError("CVCCA", GPError.CRYPTO_FAILED, 0, "Could not validate certificate");
585 		}
586 	}
587 	if (this.removePreviousKey && currentchr) {
588 		this.removePreviouslyUsedKey(currentchr);
589 	}
590 }
591 
592 
593 
594 /**
595  * Import a list of certificates into the certificate store
596  *
597  * @param {CVC[]} certs the list of certificates
598  */
599 CVCCA.prototype.importCertificates = function(certs) {
600 	GPSystem.log(GPSystem.DEBUG, module.id, "importCertificates('" + certs + "')");
601 
602 	// Save currentchr
603 	var currentchr = this.certstore.getCurrentCHR(this.path);
604 
605 	var list = this.certstore.insertCertificates(this.getCrypto(), certs, true, this.path);
606 
607 	if (this.removePreviousKey && currentchr) {
608 		this.removePreviouslyUsedKey(currentchr);
609 	}
610 
611 	return list;
612 }
613 
614 
615 
616 /**
617  * Returns a list of relevant certificates.
618  *
619  * <p>If the CA is the root CA, then all self-signed and link certificates are returned.</p>
620  * <p>If the CA is a DVCA, then all certificates of the associated root and the current
621  *    DVCA certificate is returned.</p>
622  *
623  * @param {PublicKeyReference} fromCAR the optional starting point for the list if not a root CA
624  */
625 CVCCA.prototype.getCertificateList = function(fromCAR) {
626 	GPSystem.log(GPSystem.DEBUG, module.id, "getCertificateList(" + fromCAR + ")");
627 
628 	var list;
629 
630 	if (this.isRootCA()) {
631 		list = this.certstore.listCertificates(this.path);
632 	} else {
633 		var path = this.path;
634 
635 		while(true) {
636 			var chr = this.certstore.getCurrentCHR(path);
637 			if (chr == null) {
638 				var ofs = path.lastIndexOf("/");
639 				if (ofs == 0) {
640 					list = [];
641 				} else {
642 					path = path.substr(0, ofs);
643 					continue;
644 				}
645 			} else {
646 				list = this.certstore.getCertificateChain(path, chr, fromCAR);
647 			}
648 			break;
649 		}
650 	}
651 
652 	return list;
653 }
654 
655 
656 
657 /**
658  * Return certificate issued by this CA
659  *
660  * @param {PublicKeyReference} chr the certificate holder reference
661  * @returns the certificate or null if not found
662  * @type CVC
663  */
664 CVCCA.prototype.getIssuedCertificate = function(chr) {
665 	GPSystem.log(GPSystem.DEBUG, module.id, "getIssuedCertificate(" + chr + ")");
666 
667 	var path = this.path + "/" + chr.getHolder();
668 
669 	var cvc = this.certstore.getCertificate(path, chr);
670 	if (cvc == null) {
671 		GPSystem.trace("No certificate found for " + chr);
672 		return null;
673 	}
674 
675 	return cvc;
676 }
677 
678 
679 
680 /**
681  * Return authentic public key with domain parameter for a given CHR subordinate to the CA
682  *
683  * @param {PublicKeyReference} chr the certificate holder reference
684  * @returns the public key or null
685  * @type Key
686  */
687 CVCCA.prototype.getAuthenticPublicKey = function(chr) {
688 	GPSystem.log(GPSystem.DEBUG, module.id, "getAuthenticPublicKey(" + chr + ")");
689 
690 	var cvc = this.getIssuedCertificate(chr);
691 
692 	if (cvc == null) {
693 		return null;
694 	}
695 
696 	if (this.isRootCA()) {
697 		var dp = this.certstore.getDomainParameter(cvc.getCAR());
698 	} else {
699 		var dvcacvc = this.certstore.getCertificate(this.path, cvc.getCAR());
700 		if (dvcacvc == null) {
701 			GPSystem.trace("No certificate found for " + cvc.getCAR());
702 			return null;
703 		}
704 		var dp = this.certstore.getDomainParameter(dvcacvc.getCAR());
705 	}
706 
707 	return(cvc.getPublicKey(dp));
708 }
709 
710 
711 
712 CVCCA.test = function(daofcvca, daofdvca, daofterm) {
713 
714 	var crypto = new Crypto();
715 
716 	var ss = new CVCertificateStore(daofcvca);
717 	ss.setContextMarker(0);
718 	var cvca = new CVCCA(crypto, ss, null, null, "/UTCVCA");
719 
720 	// Create a new request
721 	var req = cvca.generateRequest(null, false);
722 	GPSystem.trace("Request: " + req);
723 	GPSystem.trace(req.getASN1());
724 
725 	assert(req.verifyWith(crypto, req.getPublicKey()));
726 
727 	// Create self-signed or link certificate based on request
728 	var policy = { certificateValidityDays: 2,
729 				   chatRoleOID: new ByteString("id-IS", OID),
730 				   chatRights: new ByteString("E3", HEX),
731 				   includeDomainParameter: true,
732 				   extensions: []
733 				 };
734 	var cert = cvca.generateCertificate(req, policy);
735 	GPSystem.trace("Certificate: " + cert);
736 	GPSystem.trace(cert.getASN1());
737 
738 	// Import certificate into store, making it the most current certificate
739 	cvca.importCertificate(cert);
740 
741 	// Generate additional self-signed root certificate
742 	// This must be done after the link certificate has been imported
743 	var policy = { certificateValidityDays: 2,
744 				   chatRoleOID: new ByteString("id-IS", OID),
745 				   chatRights: new ByteString("E3", HEX),
746 				   includeDomainParameter: true,
747 				   extensions: []
748 				 };
749 	var cert = cvca.generateCertificate(req, policy);
750 	GPSystem.trace("Certificate: " + cert);
751 	GPSystem.trace(cert.getASN1());
752 
753 	// Import certificate into store, making it the most current certificate
754 	cvca.importCertificate(cert);
755 
756 	var ss = new CVCertificateStore(daofdvca);
757 	ss.setContextMarker(1);
758 	var dvca = new CVCCA(crypto, ss, null, null, "/UTCVCA/UTDVCA");
759 
760 	var certlist = cvca.getCertificateList();
761 	var list = dvca.importCertificates(certlist);
762 
763 	if (list.length > 0) {
764 		GPSystem.trace("Warning: Could not import the following certificates");
765 		for (var i = 0; i < list.length; i++) {
766 			GPSystem.trace(list[i]);
767 		}
768 	}
769 
770 	// Create a new request
771 	var req = dvca.generateRequest(null, false);
772 	GPSystem.trace("Request: " + req);
773 	GPSystem.trace(req.getASN1());
774 
775 	// Sign this request with root CA
776 	// This must be done after the link certificate has been imported
777 	var policy = { certificateValidityDays: 2,
778 				   chatRoleOID: new ByteString("id-IS", OID),
779 				   chatRights: new ByteString("A3", HEX),
780 				   includeDomainParameter: false,
781 				   extensions: []
782 				 };
783 	var cert = cvca.generateCertificate(req, policy);
784 	GPSystem.trace("Certificate: " + cert);
785 	GPSystem.trace(cert.getASN1());
786 
787 	cvca.storeCertificate(cert);
788 	dvca.importCertificate(cert);
789 
790 
791 	var ss = new CVCertificateStore(daofterm);
792 	ss.setContextMarker(2);
793 	var term = new CVCCA(crypto, ss, null, null, "/UTCVCA/UTDVCA/UTTERM");
794 
795 	term.setRemovePreviousKey(true);
796 
797 	var certlist = dvca.getCertificateList();
798 	GPSystem.trace("Certificate list: ");
799 	GPSystem.trace(certlist);
800 	var list = term.importCertificates(certlist);
801 
802 	if (list.length > 0) {
803 		GPSystem.trace("Warning: Could not import the following certificates");
804 		for (var i = 0; i < list.length; i++) {
805 			GPSystem.trace(list[i]);
806 		}
807 	}
808 
809 	// Create a new request
810 	var req = term.generateRequest(null, false);
811 	GPSystem.trace("Request: " + req);
812 	GPSystem.trace(req.getASN1());
813 
814 	// Sign this request with DVCA
815 	// This must be done after the link certificate has been imported
816 	var policy = { certificateValidityDays: 2,
817 				   chatRoleOID: new ByteString("id-IS", OID),
818 				   chatRights: new ByteString("23", HEX),
819 				   includeDomainParameter: false,
820 				   extensions: []
821 				 };
822 	var cert = dvca.generateCertificate(req, policy);
823 	GPSystem.trace("Certificate: " + cert);
824 	GPSystem.trace(cert.getASN1());
825 
826 	dvca.storeCertificate(cert);
827 	term.importCertificate(cert);
828 }
829