Cryptographic operations sample

This full sample code demonstrates how to monitor reader events, populate a list from the certificates found in smart cards, verify a PIN, and perform signature, verification, encryption and decryption operations. Note that, for the operations made on the public key (verification and encryption), the public key is extracted from the certificate data and the cryptographic operation is computed in pure JavaScript, using the BSD-licensed Forge library.

<!doctype html>
<html>

	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>Titre de la page</title>
		<script src="libs/forge.min.js"></script>
		<script src="libs/promise-polyfill.js"></script>
		<script src="../src/scwsapi.js"></script>
		<script>

var privateKeys = {};

window.webappcert = "3WKVAuegUKJv}6.5vrlH2yJKIDd@n{fvTh{3B8#hpvR^OCB8LVjBz>@azy^qVx>Ir{zEWZjAc9TxCYkY0fF$QugbyTod}ryfwO#PYwi8y}xMOuniXJcvfFkare?]7kf/7NCf!$KwenfcEA5]T9f!+jnh7*Qre?]mwiX-xCg+rrZBz%n]fekjve?![ie?]ywgby:rxMOuniXJcviwJiwhAirzhzu:rf/IcFgby=8zl.77]a3uEmc@vMWs#=I-EbPF*EX14Y?t3CHGEgPU>q$!DZ*37zk-VBWplV.EQkEqWNo=%UyaK)6DHS2BM:6Ahf^Fp[Qj0W^a/1P]pG5#4=:P8lt@W&5L:itH<kVH5NKs*i&qbr@lBo[pPj0fvW0*]}NEm^NI?QxI.&!XJ)AKCE6E&$vfabiIlIn5am4t$r?GOIl[JoAU#.{1kF89-vG4}O=9J]egOW7Jw:>oq@fVKpmJaExQ2uU:Ah:)C=*9iC)5}.MyC?V<0KBec::^n?q%nnwb9i-XijWRH?sS:D>QIkWLJUDLYpT&5(VfJ6tc&*+H*U4hhuFHUQX4PS5<2YND^tFT9#R(=eA]>OM^9b-wPJ(YAg}-av%&ir*K/.h|MIIE5jCCAs6gAwIBAgIBADANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQGEwJGUjEdMBsGA1UEAwwUSWRvcHRlIFdlYkFwcENlcnQgQ0ExDzANBgNVBAoMBklkb3B0ZTAgFw0yNDA3MTUwOTU4MjFaGA8yMDUyMTIzMTIyNTkwMFowMTESMBAGA1UEAxMJTWF4aW1lRGV2MQ8wDQYDVQQKEwZJZG9wdGUxCjAIBgNVBAsTATAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDbbHFzPMOgflE7NLWtYXK0MV8xCLbSZ7qvUug0YdYSwiw9XDXe5uODG2ok9C1YrlSVuQ0O73CC07RqSys2XFsx6hW82JuwN+gEqJ+v+BKW3YQgT7NOzIRrvhucSo4UWrAZV6YXhd/1GZyYyyI1x3K1e1y/1p3Zw8nKAGeIP8vSQvSA7da124DOx860AXvF3eRUyonMEZagnPyueVVy0wodO1u1WRMjVN+f91FUhtbRf+u5am0vU+IZCE5Lv/ALghr0r3QqLAvHMlhe4uw9BmPCWQH7d/fdIbcZf7eDxWizei2dfl/dMh95f2RTGzE/Hnt56IVYvOT4kR5AU95gwCHAgMBAAGjgfowgfcwCQYDVR0TBAIwADAXBgNVHSUEEDAOBgwrBgEEAYHYJAECAgEwXgYDVR0gBFcwVTAPBg0rBgEEAYHYJAECAQEBMA8GDSsGAQQBgdgkAQIBAQMwDwYNKwYBBAGB2CQBAgEBBDAPBg0rBgEEAYHYJAECAQEGMA8GDSsGAQQBgdgkAQIBAQcwcQYDVR0RBGowaIYYaHR0cDovLzEwLjI1LjExLjEzMjoxMjM0hhhodHRwOi8vMTAuMjUuMTEuMTY1OjEyMzSGFWh0dHA6Ly8xMjcuMC4wLjE6MTIzNIYbaHR0cDovLzE5Mi4xNjguMTYwLjExNzoxMjM0MA0GCSqGSIb3DQEBCwUAA4ICAQA5hyRPrhPV8OhYfOxa5+mQoBi0n/m42nWotehg5QJmzUzDTDnZLgEV7t/9dVsNX8uh1t88Kgkbb98vAmgWHpslH++5P1jp9WQfNG9gzASpSglcTXF2BHblKH7oDJ5LMhXtGikUR13TuoK4iPvZxSweIeK5JZ7kMydOgFbj5xlk+rLSqqP+tebS6bOMSzUWKGwgaBQbS3sZ8B6IOhROGxbXxVQZ2vJ94meqmTG/qSoJa3vhf9kOxJLSdxCNdeuLlkIDHEqnHMMQHfnZztJ3dVt/rybr99Qx0IvW248jgRMoD39EeFYVya1sNB2LkAAeqnoVeUlotCW9F8JA3gVo/BFzoy46/vUDrrFUMvGQXWkdHga7PYwf8NHFjLO+o9R2ehATCHNykfmgbE6u+RuKJx3vqoM3MGaVa/OI1P9Jrha8/wGt5hkIMuEW0/n5w5UBs2NuUbMia+9abUy2EQxWJ2Nd4fJfmpvcsf/I1I9J0RuuBKNRcElnidBlK8tkGCw+gMv8T4H0njRoSSmo6dku8PEl71sLiorGdJddA9VRKorj2md3SW6IbeszPZM2/b/EVM4p0HPR6OV/PJruLcSqte8KaBwfsu9/s0e6FrNfhpkqnk+8asXPWSteCi3w3lo0578XQsHuIDHG8P6Dqhv4AtC+GUrhXdaFGWSZcmO9CyqU0w==";
//window.webappcert = "4gM?:G)lz^:r^BM:=BP.0{6YMM2.Vg{fOpeIjyU4cFud+E@>=ZFNFL]oK$eUW]/F?^z1gFmHj(KdQ15QEa(Vo/j*t3+b3Qnz/744vSt6UNj(Wt^R/ba5m#I/{U@)]HzXNcH:Nf}nR=)ansje.px01U1I8zGTx>O7zT}QieR7gwYPjITMoxtu799.8!LEGF?MhB$o&Ygz{<5dHkifW(9FJ6icJvxKbm<+xG1Qa%p>-J@6Q%czJ-/h@.b(XWkFA/1&u(7&=LvUB%tliH/kd3<5rcfryG]]+WZ&<^&[I[{l<xucJUM8fQHb]:cEeB*xbMzn+";
// http://127.0.0.1:1234,http://10.25.11.150:1234
window.password = "yyoussef";

  window.p12 = "30820A5E02010330820A2406092A864886F70D010701A0820A1504820A1130820A0D3082049F06092A864886F70D010706A08204903082048C0201003082048506092A864886F70D010701301C060A2A864886F70D010C0106300E0408EB8314818F8957E202020800808204584FD52765C18CF4EB7EE6F030C0D07EFECF901115D923DA104E80457E39AB58ED6D075F59EB02165DF36D6E674B80F313777F4675DA0F7E767F441D0B327AE13D347C54019BF3EEDFEDF574D2FFCDBFF09ABF66C70834E67053C57722DBEB9D37CC4E1A0624197BA8453BC7269AF210F27DFB290B16FD375DDDD36140506811412BFBAD8D3C70D1A8D3CC56BE973870B0E5D8A656E05777155A424E2E6147C66DD56EC2B844ACC8C1CBDAAEFF49FB991EBB4114422893D181ED52A1BE59B499AF0E7A2F8DE49C3C1DC4F96B4C93E342F8232D9A51949D6E2FB4B1F63D0D19196771E43B8CB0B3D849CF32DEEB62521D71318C3E35275FE00B269FE0F61768C7100D7C42DFC5E2E3CF64E56CA223CC2979EB3F9AA6B18216778F30368F06601790C7E162C8888C5FE0E29DB0DBCBE647487515A578462360DCC084C005B482EE6AF26A0B16AE61E293626D9000B370B682C3DB3514A8060600FD5AB3BE9A46C507CF69F972BA55CFF3AF6B11AFB120B7B1D917A8FB724AB3A15E799BCAF3A8DE493C141D20E7598645C3F8DA624F71C1EFC9CBE38C25666F469DA55DE4E397E76328EA2A1EA66F7C04877688C740CB68FEA034BE852300B40528E3161B7059FA2B2744846E95FED4D11474D769276FBAF61798D5B9468C48E21B5908076A80687ACB2A794F5180A2C4EE3B08E7A4C68BC58E2CC4A701B8FF0686385552A568B727998E0DFCD656DD8D5DA147A88AF0F72A3C92A08E3D03AEE504BCFA514D047A496C3E23211DFB54C2802C060202E9D10B06A929280061728D89612CE88563129669630B188D28193CE351B2544EC6155BD9EBA706804325C37972DEAFD99716E16AEA8EFE8B37DAA419E38C09515EF01C773B0BCD890CA3646FAF7B208B16033ADFBE91DCB7903EDA3C4A91D2DD210EBA5D434091F7189176A83730892CC70D35D3DF14EF0C6E7D8C45D0FFC6A409D9BD5A37A3F6EC8EAC0E56C30EAA2D276FBBB3382430908F8AEE21C9BC190DA25A7B5CDA3877C0FD7E14DCF2EF52991F87A3C805AE989EFAD89EFB76C17ED76E8416CC0089887794EDC2757D93EE81C70F7A79F705128CB487598F0C59CA1017A4F38F1270A2BB219BC26DB91DBE566720BF81D591FEC6F8166FAFBD6C8A3EF85D70AAE768908EE00A3C3053AD9C5FF57F09E70D14D33B934C946399FEBBB35096208B396B1D5526C038E704F670F804B095BC41D6EE6AB189A2C559170ED016E9FFA4BA2E153FA8635B17CE079342672CBDD7960B47527C2D3AB01916A82F86DF0CDBE8B0F123A5FE85812037450F9A5180D102B147EE6FD3A814D1872E060AA7D197FB0E07E874F92D34EE21416C0EA759C366FBBDE9E32209F72AEEBD7630C4FBA02C5F5DC7D908085C1C9B71DF34F072C95BAF2052808C7ADCC55162DE757AD53DE29EDE16EF009C3B836FC60251A5D49A075D86F86A2164F38CFE983FE571B6541B7B8B6A5C4CC09E64F4B19A829F3D67B9838779D1DF813A248ED21011610137C89272881E0D2F048B98DADF823F33DCB5EDBC5994EFBDB628341EFB1B2B699D8CEB77FDEE94773082056606092A864886F70D010701A0820557048205533082054F3082054B060B2A864886F70D010C0A0102A08204EE308204EA301C060A2A864886F70D010C0103300E0408FF988A81108A8C1602020800048204C88549F8E681336AF34A8822F0921A55FA2A718DBCB5D2B5A0733EEC24A757218DA1DA64BC73810C0217F58C6AEB8A2D5C5FB75BB0629153155A60C339734E00665D88229F96DD084D28F98BCA63E9B9353FA8F48751D164A12296DFCB38435A914EF90D1AC95E482636320FC71E8FAFD60227E8C07BB2B56D0444CF1548A87E80E315D644BE7462781E1E909C5D08D9730B4F26D2AAE68B7F8F0BFEB0CEAC08A0894B751AD52F0BCAE13FCAF2E3EF38F1C0931BADF3502D0BB0B8D803F8BC11134724B3A7320ED43BBEEF2800DFE699B677A188E12CFDD020FFFBA5751C16E779D03F99847CB3635AE9BF55BB50BBC81608D5B3E55E5C3F8686335604B24B861CCED7E02723052692A864897AB07342D6699A3938535F46833276B441B20B03BA546D6682C70A000DBE9AC208B23462BC91956BEBA7BB8A6A8F7737445B77E9D797237D9AFF31445ABD7F7A7DDE013E1EF23200137A826C3328341AFB362EBE18E0F2A2CB5DA294AD75A671E410D46BB3863501038A93CD4C254ADE0EC911D9E0EEFFFD16072BC4E1D2F881A7E1B449C18AEDC339BE1054EEC874F47B21CB2D0E27A6B9D00517468DAF209CD85A2A15F1E020FE3464D133CECF173F8075A3407BF3CCB5C5BAE26756338893A406A3EA4F09993D62C1A8495F74FAEF373B1CBEF5341324C7098E28F9FDF9824A357AEF67367C9676F228342D1DC9EC63AB9B73246BD0A770D4A64590043D055C41B718EE443E612AF2DCE5B0223AF5E9B6D9AD2BD1DCA2DBC6FE63BD6BAD2EBCC9E6F6605C8EFAF92CD92D08F1D0CD960EA517618C00B90E72879CB950BB0739091DB180308C66BA360899D457558877776A8CA375615CEAFB7DB8A7FDAC94AB52544FC87535129D42015F8E379B24F44D3D1C8629C0FDBED8A5F06EAFBDF386F60D0DA566EABE8B7F4B39C1A8E54ED285452EDA410E7719548A45A6024A221C698B306A55047F6837B0D2E35669F4A8705256757276F7BBFF8DC5CEFFDEB8E05BF019581D18FC788C0D1BB1418A978C654D7950E8ADB9D394F0360A54824862D809E3ADC5EAF7C7602F65A40758EAFCDFC6EF7824E8DC6DE40BBB4269F8E3578FF7157FA5F1BD19B0205BB50ADA7CCCF2D3AE631F5EF25F5E86B4BDB25F9A068613A1CAA76B3788F2A35BC5CD8D072105D7168EC533ABA1859CEA2904CAAA02C2719B7F1832E0AA52819492E3464BCA2260DB34650E1B2421F0D1C885CA9981A6D1BA5BE87E85CF02F6102485B7D672019931A7A7E58B33C81E0E8D139ACF0957765BCC90B147A77E3AF3E680A7DF6006FF3DD5EBCBE1C6F762A661594DDD8F012C1F8B907DF6511E41A98AABE1D93437B2C1DF09387C09B97840D1B6FCCE60096D942485BEBB2D525AD96108636AA18732B24DA59C6271690ABAD068305B8DA33974171B70F359199ACE68C140273DD7C5B98D54258D7232DC18DAE6389564A1C9E8515E57BDF05531697C8A5547AF868B24F67832A96EAA71395739651B727533EAAB53794AEAFE7EF0E89E4C8FF1C9DB3CBA3F68881B8F0B7857F2A226BFD8403ABD03ACF2FCFC18D545E47A84E846645B0B0F608D251A890B6ECCD6E8634FDF7F01E2C1145841D2A089C63B588DC6900E60DD359382AF53FD302579DD9733885D76BAF339565B52A28BEF147E4D2BEFA3668A6B99B7FC034FFA07BFAC6844CF1AD743F875B6CD9E47F6612A9AF7B0C051C568B82F41BD7130CD314A302306092A864886F70D01091431161E140079006F00750073007300650066005F00760033302306092A864886F70D01091531160414E7D7343D5B87A9E7F4B6D87353270FD8B3A89B0630313021300906052B0E03021A05000414EB2034DB2BE189DBF87422063FB6EBF5C46C4057040886C2012A3342832A02020800";
  window.certificate = "-----BEGIN CERTIFICATE-----\n MIIDNDCCAhwCCQDWfPjiGAVE3DANBgkqhkiG9w0BAQUFADBAMQswCQYDVQQGEwJGcjEPMA0GA1UECAwGVmllbm5lMQ8wDQYDVQQHDAZWaWVubmUxDzANBgNVBAoMBklkb3B0ZTAeFw0xODA1MzExMDIxNTNaFw0yMjA1MzExMDIxNTNaMHgxCzAJBgNVBAYTAkZyMQ8wDQYDVQQIDAZWaWVubmUxDzANBgNVBAcMBlZpZW5uZTEPMA0GA1UECgwGSWRvcHRlMQ4wDAYDVQQDDAVaSVRBTjEmMCQGCSqGSIb3DQEJARYXeW91c3NlZi56aXRhbkBpZG9wdGUuZnIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqPMenM1biCZbzAiaOt9rIoc7sHVEXGwex1yehBVfZi+P3B4bMY3h1i6k7YwfM2wdRRn/7vDbEwiT4tPc7MHnkWoFmrpIEVcSQzgNwBVY8yPNDxtVu3wtemCcnk7MT6c4F68cCnSsE9b2Jl2YzHOB3Ls+LSYRCscmCQTzLfIq3woW+PSgRBNiNDUZWiY1QyQWARqmyND0eD9hMeeEa/pvofZgEgiZPuCJT8QJSSOIp04Wok8wofZULc0GRImlV2QJiwogcJoExCpiVSBY+V0nC3JmITIXYzLZ+ojhTOCEETCnlmjPodQk0tiZM3NdgRA/zTCBCTqVu220/9Ik+LMnXAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBACqfHAhEQr988fVxksK5weg744wwYXoVZBCT9aIjEwjoTkP1EJEoUr8WHBvOJ9yXa6JSqRaaLzPE4E3Og62wIln39DIfAYf4OKo0noJ1Y4pT4b+nz3Hk+t3wIaUO53bnNxGaB8R5jWcMBv/sniPCAJ60/UO5NF6+D1yqCuR8fjL/WXpftSmL0Q1IFQJ/d0Xn+5VNEW4FB1/uIjZEXoAOxnsOOWUpoFKoePO6vvchE9cyL6T+1Ww36gOELT8k7g/WrnldPbc8sg4gW1UsW12kjLP9Pa3jzkRt31WZUISuTg1SSJO/QfshCY2luJNMNtSFkPcQ2tDoRNahA8xsXq8MKJI=\n-----END CERTIFICATE-----";

function log(msg) {
	window.infodiv.insertAdjacentHTML('beforeend', msg + '<br>');
	window.infodiv.scrollTop += 1000;
}

window.certlistObject = [];

window.onload = function() {
	window.infodiv = document.getElementById("infodiv");
	window.certlist = document.getElementById("certificatelist");
	window.scandlg = document.getElementById("scandlg");
	window.scanfield = document.getElementById("scanfield");
	window.scandlg.style.visibility = "hidden";

	var promise = new Promise(function(resolve, reject) {
		var req = new XMLHttpRequest();
		req.onreadystatechange = function () {
			if (this.readyState === 4) {
				if (this.status === 200){
					resolve(req.responseText);
				}
				else
					reject(new Error("Challenge generation failed"));
			}
		};
		req.open("GET", "generatechallenge.php", true);
		req.send();
	}).then(function(challenge) {
		/* connecting to SCWS */
		log("Connecting to SCWS...");
		SCWS.findService(window.webappcert, challenge).then(function(findServiceData) {
			log("Connection to SCWS succeeded");
			return new Promise(function(resolve, reject) {
				var req = new XMLHttpRequest();
				req.onreadystatechange = function () {
					if (this.readyState === 4) {
						if (this.status === 200)
							resolve(req.responseText);
						else
							reject(new Error("Cryptogram verification failed"));
					}
				};
				req.open("GET", "verifycryptogramsignchallenge.php?keyID=" + findServiceData.keyID + "&cryptogram=" + findServiceData.cryptogram + "&rnd=" + findServiceData.challenge, true);
				req.send();
			}).then(function(signature) {
				log("create environment...");
				return SCWS.createEnvironment(signature);
			});
		}).then(function() {
			log("SCWS environment created successfully");
			SCWS.onserviceunresponsive = function() {
				log("Service became unresponsive");
			}
		}).catch(function(err){
			log("ERROR: " + err.message);
			window.certlist.clearChildren();
		});
	}).catch(function(err) {
		log("ERROR: " + err.message);
		window.certlist.clearChildren();
	});
}

if( typeof Element.prototype.clearChildren === 'undefined' ) {
	Object.defineProperty(Element.prototype, 'clearChildren', {
		configurable: true,
		enumerable: false,
		value: function() {
			while(this.firstChild) this.removeChild(this.lastChild);
		}
	});
}

function requestCertificates() {
	log("request certificates...");
	var options = {
	};
	var enableSoftToken = getEnableSoftToken();
	if (enableSoftToken != "default") 
		options["enableSoftToken"] = enableSoftToken;
	var scanDialogMode = getScanDialogMode();
	if (scanDialogMode == "synchronous") {
		options["showScanDlg"] = showScanDlg;
		options["closeScanDlg"] = closeScanDlg;
		options["setScanDlgMsg"] = setScanDlgMsg;
	}
	else if (scanDialogMode == "asynchronous") {
		options["showScanDlg"] = showScanDlgAsynchronous;
		options["closeScanDlg"] = closeScanDlgAsynchronous;
		options["setScanDlgMsg"] = setScanDlgMsgAsynchronous;
	}
	if (getScanMessageMode() == "customized") {
		options["waitingMsg"] = "Veuillez insérer une carte.";
		options["connectingMsg"] = "Connexion à la carte.";
		options["readingMsg"] = "Lecture de la carte";
	}

	return SCWS.requestCertificates(function(certificates) {
		log("update list of certificates...");
		window.certlist.clearChildren();
		for (var i = 0; i < certificates.length; i++) {
			var certificate = certificates[i];
			var elt = document.createElement("option");
			elt.id = window.certlistObject.length;
			window.certlistObject.push(certificate);
			var readerName = "soft token";
			if (certificate.parent.reader)
				readerName = certificate.parent.reader.name;
			elt.textContent = certificate.subject + " (" + certificate.issuer + ") - " + readerName ;
			window.certlist.appendChild(elt);
		}
		log("Found " + certificates.length + " certificates");
		return certificates;
	}, options).then(function(certificates){
		log("requestCertificates finished");
		log("Found " + certificates.length + " certificates");
		log("");
	}).catch(function(err) {
		log("ERROR on request certificates: " + err.message);
		window.certlist.clearChildren();
		log("");
	});
}

function getEnableSoftToken()
{
	var elt = document.querySelector('input[name="softToken"]:checked');
	if (!elt || !elt.value)
		return "default";
	return elt.value;
}

function getScanDialogMode()
{
	var elt = document.querySelector('input[name="scandlg"]:checked');
	if (!elt || !elt.value)
		return "asynchronous";
	return elt.value;
}

function getScanMessageMode()
{
	var elt = document.querySelector('input[name="scanMessage"]:checked');
	if (!elt || !elt.value)
		return "asynchronous";
	return elt.value;
}

function showScanDlg() {
	window.scandlg.style.visibility = "visible";
}

function closeScanDlg(message) {
	window.scanfield.value = getCloseScanMessage(message);
	window.scandlg.style.visibility = "hidden";
}

function getCloseScanMessage(message) {
	if (message)
		return message;
	else if (getScanMessageMode() == "nominal")
		return "The operation is finished with success.";
	else
		return "L'opération s'est terminée avec succés.";
}

function setScanDlgMsg(message) {
	window.scanfield.value = message;
}

function showScanDlgAsynchronous() {
	return new Promise(function(resolve, reject) {
		window.scandlg.style.visibility = "visible";
		resolve();
	});
}

function closeScanDlgAsynchronous(message) {
	return new Promise(function(resolve, reject) {
		window.scanfield.value = getCloseScanMessage(message);
		return setTimeout(function() {
			window.scandlg.style.visibility = "hidden";
			resolve();
		}, 2000);
	});
}

function setScanDlgMsgAsynchronous(message) {
	return new Promise(function(resolve, reject) {
		window.scanfield.value = message;
		resolve();
	});
}

function reconnectCertificate(certificate)
{
	return new Promise(function(resolve, reject){
		var reader = SCWS.getReader(certificate.parent.reader.name);
		if(!reader)
			reject("reader not found");
		reader.connect().then(function(token) {
			token.getObjects().then(function(objects){
				for (var i = 0; i < objects.length; ++i) {
					var object = objects[i];
					if(object.type === "certificate" && object.ckId === certificate.ckId)
						resolve([certificate,token]);
				}
			}).catch(reject)
		}).catch(reject)
	});
}

function chooseCert()
{
	/* get selected certificate element */
	var elt = window.certlist.options[window.certlist.selectedIndex];
	/* enumerate through connections and certificate items to retrieved corresponding certificate object */
	var conn = null;
	var certificate = window.certlistObject[elt.id];
	
	/* remember selected elements */
	window.choosenCertificate = certificate;
	if (certificate) {
		/* updating pin name label */
		document.getElementById("pinname").textContent = certificate.parent.pins[certificate.pinNumber].label || "(Default PIN)";
		/* updating certificate value */
		certificate.getValue().then(function(value) {
			document.getElementById("certificatevalue").textContent = value;
		/* build software certificate and public key using forge library */
			window.forgeCert = forge.pki.certificateFromPem(value);
			window.forgePubKey = window.forgeCert.publicKey;
		})
	}
}

function getGlobalPin()
{
	return new Promise(function (resolve, reject) {
		if (!window.choosenCertificate)
			throw "no certificate selected";
		reconnectCertificate(window.choosenCertificate).then(function(res) {
			window.connection = res[1];
			resolve(res[1].pins[res[0].pinNumber]);
		});
	});
}

function getGlobalToken()
{
	return new Promise(function (resolve, reject) {
		if (!window.choosenCertificate)
			throw "no certificate selected";
		reconnectCertificate(window.choosenCertificate).then(function(res) {
			window.connection = res[1];
			resolve(window.connection);
		});
	});
}

function disconnectAll()
{
	if(window.connection)
		return window.connection.disconnect();
	else
		return Promise.resolve();
}

function startAutoLogin()
{
	getGlobalPin().then(function(pin) {
		log("startAutoLogin ...");
		pin.startAutoLogin(document.getElementById("auto-login-counter").value).then(function() {
			disconnectAll().then(function() {
				log("startAutoLogin successful");
			});
		}, function(err) {
			disconnectAll().then(function() {
				log("ERROR: " + err.message);
			});
		});
	});
}

function stopAutoLogin()
{
	getGlobalPin().then(function(pin) {
		log("stopAutoLogin ...");
		pin.stopAutoLogin().then(function() {
			disconnectAll().then(function() {
				log("stopAutoLogin successful");
			});
		}, function(err) {
			disconnectAll().then(function() {
				log("ERROR: " + err.message);
			});
		});
	});
}

function login()
{
	getGlobalPin().then(function(pin) {
		log("Login...");
		pin.login(document.getElementById("pin").value).then(function() {
			disconnectAll().then(function() {
				log("Login successful");
			});
		}, function(err) {
			disconnectAll().then(function() {
				log("ERROR: " + err.message);
			});
		});
	});
}

function loginWithPinDialog()
{
	getGlobalPin().then(function(pin) {
		log("Login...");
		pin.login(false).then(function() {
			disconnectAll().then(function() {
				log("Login successful");
			});
		}, function(err) {
			disconnectAll().then(function() {
				log("ERROR: " + err.message);
			});
		});
	});
}

function loginWithPinPad()
{
	getGlobalPin().then(function(pin) {
		log("Login...");
		pin.login().then(function() {
			disconnectAll().then(function() {
				log("Login successful");
			});
		}, function(err) {
			disconnectAll().then(function() {
				log("ERROR: " + err.message);
			});
		});	
	});
}

function GetCredential()
{
	getGlobalPin().then(function(pin) {
		var state = pin.initSubmissionsState;
		log("Login...");
		pin.requestCredential(
			pin.credentialProperties,
			state,
			pin.token.reader.name,
			pin.token.label).then(function(credential) {
				if (credential) {
					pin.login(credential).then(function() {
						disconnectAll().then(function() {
							log("Login successful");
						});
					}, function(err) {
						disconnectAll().then(function() {
							log("ERROR: " + err.message);
						});
					});
				}
				else {
					disconnectAll().then(function() {
						log("Canceled by the user.");
					});
				}
			}, function(err) {
				disconnectAll().then(function() {
					log("ERROR requestCredential: " + err.message);
				});
			}
		);
	});
}

function initPin()
{
	getGlobalPin().then(function(pin) {
		log("Login...");
		pin.login("000000000000000000000000000000000000000000000000", true).then(function() {
			log("login so successful");
			pin.init("0000").then(function() {
				disconnectAll().then(function() {
					log("initPin successful");
				});
			}, function(err) {
				disconnectAll().then(function() {
					log("ERROR initPin: " + err.message);
				});
			});	
		}, function(err) {
			disconnectAll().then(function() {
				log("ERROR loginso: " + err.message);
			});
		});	
	});
}

function bioEnroll() {
	getGlobalPin().then(function(pin) {
		log("Bio enroll...");
		pin.bioEnroll().then(
			function() {
				log("bio enroll successful");
			},
			function(err) {
				log("ERROR bio enroll: " + err.message);
			}
		);
	});
}

function getHashAlg()
{
	var elt = document.querySelector('input[name="hashalg"]:checked');
	if (!elt || !elt.value)
		return null;
	return elt.value;
}

function sign()
{
	/* sign the input data using the selected hash algorithm */
	log("request private key...")
	var options = {
	};
	var enableSoftToken = getEnableSoftToken();
	if (enableSoftToken != "default") 
		options["enableSoftToken"] = enableSoftToken;
	var scanDialogMode = getScanDialogMode();
	if (scanDialogMode == "synchronous") {
		options["showScanDlg"] = showScanDlg;
		options["closeScanDlg"] = closeScanDlg;
		options["setScanDlgMsg"] = setScanDlgMsg;
	}
	else if (scanDialogMode == "asynchronous") {
		options["showScanDlg"] = showScanDlgAsynchronous;
		options["closeScanDlg"] = closeScanDlgAsynchronous;
		options["setScanDlgMsg"] = setScanDlgMsgAsynchronous;
	}
	if (getScanMessageMode() == "customized") {
		options["waitingMsg"] = "Veuillez insérer une carte.";
		options["connectingMsg"] = "Connexion à la carte.";
		options["readingMsg"] = "Lecture de la carte";
	}

	SCWS.requestPrivateKey(window.choosenCertificate, false, function(pkey){
		log("Signature...");
		try {
			var data = document.getElementById("datafield").value;
			var hashAlg = getHashAlg();
			if (hashAlg) {
				return pkey.hashAndSign(data, hashAlg).then(function(data) {
					data = SCWS.toHexString(data);
					log("Signature done:<br>&nbsp;&nbsp;" + data);
					window.lastRet = forge.util.hexToBytes(data);
				});
			}
			else {
				return pkey.sign(SCWS.fromHexString(data)).then(function(data) {
					data = SCWS.toHexString(data);
					disconnectAll().then(function() {
						log("Signature done:<br>&nbsp;&nbsp;" + data);
						window.lastRet = forge.util.hexToBytes(data);
					});
				});
			}
		}
		catch(err)	{
			log("ERROR: " + err.message);
			throw err;
		}
	}, options).then(function() {
		log("request private key succeeded.");
		log("");
	}).catch(function(error) {
		log("request private key failed: " + error.message);
		log("");
	});
}

function verify()
{
	/* verify the previously generated signature, using the input data and hash algorithm */
	var r;
	try {
		var hash, scheme;
		var data = document.getElementById("datafield").value;
		var hashAlg = getHashAlg();
		if (hashAlg) {
			hash = forge.md[hashAlg].create();
			hash.update(data);
			hash = hash.digest().bytes();
			scheme = "RSASSA-PKCS1-V1_5";
		}
		else {
			hash = forge.util.hexToBytes(data);
			scheme = null;
		}
		log("Recovered data:<br>&nbsp;&nbsp;" + forge.util.bytesToHex(forge.rsa.decrypt(window.lastRet, window.forgePubKey, true, true)));
		r = window.forgePubKey.verify(hash, window.lastRet, scheme) ? "OK" : "failed";
	}
	catch (ex) {
		r = "failed (" + ex + ")";
	}
	log("Verification " + r);
}

function encrypt()
{
	/* encrypt the input data */
	var data = document.getElementById("datafield").value;
	var r = window.forgePubKey.encrypt(forge.util.hexToBytes(data));
	window.lastRet = r;
	r = forge.util.bytesToHex(r);
	log("Encryption done:<br>&nbsp;&nbsp;" + r);
}

function decrypt()
{
	/* decrypt the result of the last encryption */
	getGlobalToken().then(function(token) {
		SCWS.requestPrivateKey(window.choosenCertificate, false, function(pkey){
			try {
				//var a = forge.util.binary.raw.decode(window.lastRet);  Ligne utile pour essayer décrypt en IE
				//log("Decryption... :<br>&nbsp;&nbsp" + a );
				log("Decryption...");
				return pkey.decrypt(forge.util.binary.raw.decode(window.lastRet)).then(function(data) {
					data = SCWS.toHexString(data);
					log("Decryption done:<br>&nbsp;&nbsp;" + data);
				});
			}
			catch(err) {
				log("ERROR: " + err.message);
			}
		});
	});
}

function loadFile(file, callback)
{
	var xobj = new XMLHttpRequest();
	xobj.open('GET', file, true);
	xobj.onreadystatechange = function () {
		if (xobj.readyState == 4 && xobj.status == "200") {
			callback(xobj.responseText);
		}
	};
	xobj.send(null);
}

loadFile('rootCA.crt', function(file) {
	window.caCert = forge.pki.certificateFromPem(file);
});

loadFile('rootCA.key', function(file) {
	window.caKey = forge.pki.privateKeyFromPem(file);
});

function changePage()
{
	localStorage.setItem("arr", JSON.stringify(SCWS.saveEnvironment()));
	window.location.href = "restore_environment.html";
}

function signCSR(csrPath)
{
	return new Promise(function(resolve, reject) {
		var req = new XMLHttpRequest();
		req.onreadystatechange = function () {
			if (this.readyState === 4) {
				if (this.status === 200)
					resolve(req.responseText);
				else
					reject(new Error("read file failed"));
			}
		};
		req.open("GET", csrPath, true);
		req.send();
	}).then(function(csrPem) {
		var csr = forge.pki.certificationRequestFromPem(csrPem);
		var certificate = forge.pki.createCertificate();
		certificate.serialNumber = '01';
		certificate.validity.notBefore = new Date();
		certificate.validity.notAfter = new Date();
		certificate.validity.notAfter.setFullYear(certificate.validity.notBefore.getFullYear() + 1);
		certificate.setSubject(csr.subject.attributes);
		certificate.setIssuer(window.caCert.subject.attributes);
		certificate.setExtensions([{
			name: 'keyUsage',
			keyCertSign: true,
			digitalSignature: true,
			nonRepudiation: true,
			keyEncipherment: true,
			dataEncipherment: true
		}]);
		certificate.publicKey = csr.publicKey;
		// sign certificate with CA key
		certificate.sign(window.caKey);
		return certificate;
	});
}

// bout de code pour détruire un objet dans la carte via SCWS
// A mettre dans la console
/*
SCWS.readers[0].connect().then(function(token) {
    pin = new SCWS.Pin(token, 0);
    pin.login(false, false).then(function(value){
        token.getObjects().then(function(objects){
            console.log(objects);
            SCWS.destroyObjects(objects[1]).then(function(){
                console.log("object destroyed");
            });
        });
    }, function(err) {console.log(err);});
});
*/

// A mettre dans la console
//Genere une paire de clés
/*
SCWS.readers[0].connect().then(function(token) {
    pin = new SCWS.Pin(token, 0);
    pin.login(false, false).then(function(value){
        token.generateKeyPair(2048, {container: "auth", label: "test"}).then(function(){
           console.log("key pair generated."); 
        });
    }, function(err) {console.log(err);});
});
*/

// A mettre dans la console
//importe le certficat Voldemort (Pour l'utiliser sur IE il faut le passer par Babel)
/*
var formData = new FormData();
var p12_1 = "30820ED102010330820E9706092A864886F70D010701A0820E8804820E8430820E80308204B706092A864886F70D010706A08204A8308204A40201003082049D06092A864886F70D010701301C060A2A864886F70D010C0106300E0408494179C1A0857B4C0202080080820470BDD9C74C9A0CF83D84140769D944CE1363AEC607A61E1C8D029B81EFE2A18155FE3ED188F0AF9C961ABF4504B84DAD799CA43F48568C6703759DEDD1E4F1B34197FDC1E977B98FE8001A6BD88E6264F6C759B2AE0D3848F82B8D4B040CC8B9587747393B03E21C1649C7EA9A9EA2F88BEA45932A021FE5508386452A1F7257FB725145431333DA98547F36A576CDDE12FEB9E1BC1A637495248B6BF173B4C4D537B353D5BA43A91F08D547BB06E2CDD5CD34ECBEF825633C12476FD14B8AB8C3C8B386478B87F6F8DA17BE21090BD4D7B4D82D82587FB15DB6918A1225C6AE1F31AB51B32F9C2EC4A049267BE76E66DB37639EE83CDE59320652BA65D0815E6E6A6BEF2E81C06ECD4AFBFAEDFE1FDF60CC90FE0615D92EF2F8BD23254A4AE606C1AD43E1CC928F2A625FFAC09DCF66CA7A0A8CADC11EB0B4A0DB1B59F85BE0F0AC3514A2A920CF9346910EC14E7A6E16160CBD44ECEA65F3D1A859170DA8E9303DDB219D8F10439C503684DFEAD035E98786AF802371DD5E671017F6E611035E4650F8528886129B3124885121BE6F4B17E29B6D44F848E596496FF1EF0296B800AE35927E6B55B150780CE40303BDEF2B0FBE5E49D70ABE15511100DDC09C0ACDED17480FE64A299CD4B7FE5A6E32ECDA35B9272AE247D4BB6B37625BB49353A6271B9B87B86F145C4557381861CFE575C984CB35A01CF82C2C6370E8174F56340613F2D8D76D4C409D06461DE43EBB64A7C67113EF6285225F934B8048102DE55E49F9E3390F2C0EBCC33D6110E7F8F9A1DD4722CE1D7AEFE72E41B91FB0FF0F03D1F35AB65EDAE19DC3A9915728B5B16F1072025EDAA8D49D3D5C62AE3E74D010DEF568B33EFDD2DE3F5593E7EBCF52D78A5054A06234B9C31AF7FE8374402EF8EF1B75315F9561843F3ADE56E9235CB93B2147FFFC3DA890EAA49DA0D46AA7B11C8B55DEBE605072C8D5E7EDFB5C5AE59DDDEFE1BC3F72A78777CD77E258B332D0B3F4CAEE17D2B6666EF07548315A992F1044FE9776860F3049EA266529CAD3AB635689B2145072162BE179F5DC4406C3D0E749A9101B88D9B77673509013B48811A8762D504301349B5A4B6CA7803D2A238BE26A6B865A869FE4509EFD7313389F740EA4D44B40E68EE5B3139279D1B75AB74EAD6B41308FF3F78861477C9B016383343F37D3D5018C5E8C90A96BE0AAF1658DE5377AF39B58AE881D41B711D09030257E446CB737A20CE8D8DDDD1C1F38BB1B43C629522C22C670AEA42DC27AF05AB936A76D457E08BFBAF90A140E861A74D1630C0EEC44215ECCC5559E9C53B140A3963F039DA7800F1F4CFEDA2D2953ABDE245C87CBACA452F1EF44B356BC4F59C474EB03D9658CA662F529F124D471D8863A4FA6EFBBA2EE37373762693258F8728B95BA4FEEF6F4529B8ACB629C5B77EE713461365671AB9D744C32338FF59C898A38C22ADBF850CD179A25ADA62740AD2E7D25EB757B864F4070D5C2E338CFB3377CB203E6E71BBA6ED9546A76C80E83DE9D5A2194352BD1C456EE2B8564282A5EF3E4152C94BB2275A99FD13C872E2F47AB39E9BAEBA582700A9D6968E8DB3B50F538EDCBB7E0CEA08A308209C106092A864886F70D010701A08209B2048209AE308209AA308209A6060B2A864886F70D010C0A0102A082096E3082096A301C060A2A864886F70D010C0103300E0408E2B529BCA62C2E6102020800048209481F406C1306D006BDFB5D389E2B48DA151519E67F0AE5DD6CF0383809BC63349FEA998C604A3DA577368A43CBDB714ACDE42AAAF56D8EE4342246CEFC92E71ACB778527FB543F01EC9639F4B54CA57D758ACD71D3E8354C50088E010FB939A58BEB0DD065FF04AFDAFB60134DA8B45889BEE8A16DF092FD2C49863C666460F02F96EE12E8345EC5778B3EDBA083381C8035F5D4DB97C08267CDADD9DF3A7F13ADB3063F285A5A53FD9DD6BDC8E49E2A9B490000E08EC1A4BC6088D578351E8A407F86C781CB85D2722050128EF5C07789559FEEF76FF580788A2E8AE834711924A60B67888003CB8160EAD88A13D1A8C124E099891D1B70A8CAF5BC84271A4B6E23898057E3B6F170B1FC86993059159622EEC94C3248D39423F4DE262A8D815FE46627B87FAE713983BC1E1466C0BB2BCFAC7528BE72D2EC1296D9F9669945E5EFABD1A98534D9225EE1FBD3CECE92B7CDBAC12015CF2BCB0D57A6C28CA6F52BA715FBFC14A298AF421A5DD86D3FB37E47068AD0FBAC2036EC6B667851114BB50FAC0D7327203CA812C57CCDE11EA0382CA725B39EE7BB0C1BA001659B44104795F1AD5069980437EC473EB6DB45BA947E7199044CD5E2F919ED6A1BD8141950D9202C2FF4D85A3DB0C1272EBDDF851DD94B8D19DE71EB9302FDC433C3EFF618B31483D5578503D88AB1DDE47C88109453821C41E38529720ED739968C1C7C53B72E7319B0358809EA63CB124FFB808346F7B8E26DED03B622337DFDE9665FD756649D630E32FB1A9EA22F06F1EFCD4A08F571158A4CCCEE6E77EE369B410818D3910206247C2C007EC7BD719AB58989CC0928ABECCCFBE2F26E025DEED9B92E6221218C7DC35342DEA26C64C7C4CF1ACB5848B17D5B00EA64E21562DD6DF49D4BDCFCD073ADB5C8EC245DB37680BF49580ABECB8326B2BF4730988E29F38FA79BB5B16575F7AA0923557B55CCD5F599AC8D34387A47B2CD59DF76B524129AC2C16D9B227BA895CA7B4657B1B1B9363EE68B533BFAF927E7CC8E34BB665DE59339041E1402D4BBBD06005CE1944B48245BA049A51591A2CF72B6796EA8F0E8DC5653F88FF3758DC0F903151C6A2C10ADD310B9A71CAF7B31E03BBCFDD3099E09136C456422DB9F97848F307ABE4A5BECFDFDBF083B8DAE617DEC8B91B45A0700D60ECBDA89F353A220F3D453147F85EF6C0F150A892FA352709BBB7890541416CCC6A83C45F935D5364F9B2562C97F21B3D502F352F67EE5E5ADFB937C9970FB46B2DC0427BE1357F2B2C3FC9E4B82F134783A2201078BE351CB5F5895331CCFCF161A4728E74F20392640F62CADDB61B153CB51E927D2132294353C5E961A2394E85D2797DF1C62B8ECDC52CE7B8842DEEB42337D3A5A23DD81723453818F3C3D60600B3F108F4FF105C464AD4D2012B123F5D3C7304DD0C8AB0C49296E17F7C34A51E0BFBF83A889B1EDB73AEFE87AC6D21DCF6DD3E3F783A88A13197B9AEB910ECFAB88D25B47758795FE36CAED4B9DFAE379793FD4B15EEA6BB78D8C11B6AC721BB3CCB711262B431F283138C9634E9939D04BB7C5006D7AC792D7F9CC3E18618277FF398A636FFA41303BBDB96D1DDD2BC198B9914FF1C816237C878C8E62FA0567B8061006FB4F7464EB84EB9394BEB90932A2464398348BF47DEBE6D2B527EA9E93B9FBB6A4E7CBF84E5957BD07F92AB7425A920868F7DABE9852B6AB49ACC95064902F97A3621C59168F3B78D3D6B91A9A98A271E91A40642DB9A1F839D8B7E26AF5B5E86E20CB007B7748C90BCE58CA643D6DBB8753A19AABE0246DD9C64BB14B6077F7C909901F0A7B0968479340297A0D01889F87B7553AC0EE9DF9A8BE4895BDB4179E42B35D8650D1729EE2CCB37458EB777023590A75FD1591C814AFB50EB17830A9C5DC4A90D2F2515F78D1B8E34F9F1B35C29CEF63982FB78C178A1F1C52019323964BD299A8C12C0FBA7B8B66B563888A7F069D00816BEE76C4EB37A8D088F0FE846698601A41AF28465A790B87542BE2CE058A7D7BA9EE607E5F014801592401079502B2738F50651D5F683C29AF2F2461FDDAF0984F785C8CF8568138B4DFF328C26971BE81B19A679B2CD049012D5C5073A9C6A9BBA8B10C07A9CE85E23382313D1B2F2C59422638A54D1919FEA68B3996D869C97FFFAFD86EBBFFCF63090C73D57070963C43047B976714BFA73A96EAC237C4109C8512D6012237FFC73567B57A2893B3F735E4093D484530B19ECDD2E2FF410B0EA6D2FC87F1CC7FEF540DE871272A99FC1C7067C0310FDC0E339D8F20DDECF839400704D5426E5412B76951B4B49D957DB7E8E180428AA6CC7B24844DBC3C0540C73482AB3E2D2BABE8891B3D2A66A465636AF0EA2C2C9938AC9579B2707E93504590250AB389CFFAD9EC7118C7C0443E790436845346CDB5F10B17EE2D8C52C3300CC890433CDDB154811270EC161789D48B070EB5B7305F2CA764025B82DC929160F54FCE280B8E496B7ADB494B132AE0767A6E53A0B076F9EFAA3B41F1DFAB5035155DA337D8BF4F8F21A95830FF4A9D0241ADAC75CA0EA1E06FAEFBA9BEED97DD5BC73FEC8B5E9DF0F2735328E28B7F5495A11F65542C10BFE607DF7D9C209934ACD3AAFA01645CBE4D346E898F8C737FF74756C222063B7C4030A7F019945F16911771C5D515F8A7B835DD094D2FF28CC2F5291210CD6A261523EABB50F82EC42B5DEBB6527E3AF128DAA905255EADFE0B4AEEF671F53A9DCC19D3E28F58239D7917D20194FC690E3717E557877F0BB70A129AA4C0980D048D5194727DDE359B415E41AD6EFC9A09EE0B7C739E5B471D95B0AD6A0BA96948E353CBAC8B09D96C9F505CEBAD12178145480156D0E4B9E5F986DE3554358E9DCE3940A5B2402FE4CE33EAA34A5D47AE6F5C3D04296009AD28DA2B49DA9C5AB91D2317F140BBD09E7026B52BB1638B4634405204FA7AAFBDE4E917F89DA54F66F4DC266310C812879BBA5EB01DC73B0E8A73777239C7CCDA599DB03309198F2C56B6E0E319391B0C8E1B65AB529AA8785C60499D333543D4D35AC32AB7F93B2387F4DA5751FEA0389557BE5E9E839B95D0BB2525FF20CB2FF5C1D7E8C17BCA775F2299D2AABF23A46ABA565BA117F1F78E0845EEB935C41AF293D256F719CEA2C0E1968071CB88EC9FD039A8764A390718379026E00E9502D17ECB6EF3C3CD80CDCD4AE453144E61E52D15BC3536C9DCDE1B6A19DB803DC419667EA5AA18E838143D7C39A1185909773E72E8803CAC3D4D76BD938865138E02E8B27EFEE8985BA85B270080DF1F7F22CB56ADB08B0EFE809E70DBA5A4E7AE563D23B22918092EE32192815DBE6EC2C00B5670ADDDEA3125302306092A864886F70D010915311604145889DC9A6EDC33B421C06020AA0E1AA53302D20630313021300906052B0E03021A0500041438234ECC794DEA8185C68702DFCD318E0DA4A249040803240516228D99EE02020800";
var byteArray1 = new Uint8Array(p12_1.match(/.{2}/g).map(e => parseInt(e, 16)));
var blob1 = new Blob([byteArray1], {type: "application/octet-stream"});
formData.append("file", blob1);
formData.append("password", "yyoussef");

SCWS.readers[0].connect().then(function(token) {
    pin = new SCWS.Pin(token, 0);
    pin.login(false, false).then(function(value){
        token.getObjects().then(function(objects){
            token.import(formData, {label: "P12"}).then(() => {
                console.log("object imported.");
            });
        });
    }, function(err) {console.log(err);});
});
*/

function softtoken() 
{
	return new Promise(function(resolve, reject) {
		SCWS.getSoftToken().then(function(token) {
			var attributes = {"label": "test"};
			var data = {"subjectName":{"CN":"Test Sign","OU":"Dev","O":"Idopte","L":"Vienne","ST":"Isere","C":"FR", "emailAddress":"test@idopte.fr"}};

			var formData = new FormData()
			var byteArray = new Uint8Array(window.p12.match(/.{2}/g).map(function(e) { return parseInt(e, 16);}));
			var blob = new Blob([byteArray], {type: "application/octet-stream"});
			formData.append("file", blob);
			formData.append("password", window.password);
			token.import(formData, attributes).then(function(objects) {
				var promises = [];
				promises.push(SCWS.destroyObjects(objects.privateKey));
				promises.push(SCWS.destroyObjects(objects.publicKey));
				promises.push(SCWS.destroyObjects(objects.certificate));
				Promise.allSettled(promises).then(function() {
					log("Softoken success");
					resolve();
				});
			});
		});
	});
}

function callbackChipAuth(pubKey) {
	return pubKey;
}


// SignEncrypt functions

/* Download file content from a blob client side */
function downloadBlobLocal(blob, fileName) {
	var a = document.createElement("a");
	document.body.appendChild(a);
	a.style = "display: none";
	var url = window.URL.createObjectURL(blob);
	a.href = url;
	a.download = fileName;
	a.click();
	window.URL.revokeObjectURL(url);
};

function isIE(){
	var ua = window.navigator.userAgent;
	var pf = window.navigator.platform ;
	return window.document.documentMode || (!!ua.match(/MSIE/i) && !!pf.match(/win/i));
}

/* Send a Blob object to web server running locally on 127.0.0.1:1234 */
function sendBlobToServer(blob, fileName) {
	var xhr = new XMLHttpRequest();
	xhr.open("POST", 'http://127.0.0.1:1234/test/saveFile.php?fileName=' + fileName);
	xhr.send(blob);
}

/* Download file content from a blob */
function downloadBlob(blob, fileName) {
	if (isIE()) {
		log ("Downloading " + fileName + " server side (scwsapi/javascript/test/downloads)")
		sendBlobToServer(blob, fileName)
	} else
		downloadBlobLocal(blob, fileName)
};

/* Get PDF from local storage as a Blob */
function getBlobFromLocal(inputID) {
	var selectedFile = document.getElementById(inputID).files[0];
	return selectedFile;
}

function getFormatName(format) {
	if (format == "PADES") {
		return "pades";
	}
	else if (format == "PKCS7") {
		return "p7";
	}
	else if (format == "CADES_ATTACHED") {
		return "cades_att";
	}
	else if (format == "CADES_DETACHED") {
		return "cades_det";
	}
	else if (format == "XADES_DETACHED") {
		return "xades";
	}
	else {
		console.log("unsupported format: "+ format);
		return "undefined";
	}
}


function getDownloadExtension(format) {
	if (format == "PADES"){
		return ".pdf";
	}
	else if (format == "PKCS7" || format == "CADES_ATTACHED" || format == "CADES_DETACHED") {
		return ".p7s";
	}
	else if (format == "XADES_DETACHED") {
		return ".xml";
	}
	else {
		console.log("unsupported format: "+ format);
		return;
	}
}

function signDoc() {
	var blob = getBlobFromLocal("inputFile");
	var options = {format: document.querySelector('input[name="signEncryptFormat"]:checked').value, hashAlgorithm: document.querySelector('input[name="signEncryptHashAlg"]:checked').value};
	if (options.format == "XADES_DETACHED"){
		for(var key in {fileName: "filename"}){
			if({fileName: "filename"}.hasOwnProperty(key)){
				options[key] = {fileName: "filename"}[key];
			}
		}
	}
	
	SCWS.requestCertificates(function(certificates) {
		return certificates;
	}).then(function(certificates) {
		var index = 0;
		if (window.certlist != undefined && window.certlist.selectedIndex != undefined) {
			index = window.certlist.selectedIndex;
		}
		SCWS.requestPrivateKey(certificates[index], false, function(pKey, cert) {
			return SCWS.signDocument(blob, pKey, cert, options).then(function(signedBlob) {
				log("Signature has succeeded.");
				downloadBlob(
					signedBlob,
					"Test_sign_" + blob.name + "_" + getFormatName(options.format) + 
					"_" + options.hashAlgorithm + getDownloadExtension(options.format));
			}, function(err) {log(err);});
		});
	});
}


function encryptDoc() {
	var blob = getBlobFromLocal("inputFile");

	SCWS.requestCertificates(function(certificates) {
		var certsForEncryption = certificates;
		if (window.certlist != undefined && window.certlist.selectedIndex != undefined) {
			certsForEncryption = certificates[window.certlist.selectedIndex];
		}
		return SCWS.encryptDocument(blob, certsForEncryption).then(function(signedBlob) {
			log("Encryption has succeeded.");
			downloadBlob(signedBlob, "Test_encrypted_" + blob.name + ".p7");
		}, function(err) {log(err);});
		return certificates;
	});
}

function signEncryptDoc() {
	var blob = getBlobFromLocal("inputFile");
	var options = {hashAlgorithm: document.querySelector('input[name="signEncryptHashAlg"]:checked').value};

	// var x509_raw = "308206B73082059FA003020102021211212643A594608C44C30238006F117D6796300D06092A864886F70D01010B0500306D310B300906035504061302465231123010060355040A13094B45594E4543544953310C300A060355040B130349435331173015060355040B130E3030303220343738323137333138312330210603550403131A4B45594E454354495320494353205155414C4946494544204341301E170D3230303531343131343832385A170D3233303531343131343832385A3081B9310B300906035504061302465231123010060355040A0C09484153484C4F4749433118301606035504610C0F4E545246522D34323134353731383531293027060355040C0C20496E646570656E64616E74732064697665727320707265737461746169726573311730150603550405130E4F543030303852335044303030383111300F060355042A0C085068696C69707065310D300B06035504040C04445241593116301406035504030C0D5068696C69707065204452415930820122300D06092A864886F70D01010105000382010F003082010A0282010100C12BDF410EFC5CF770AEAC60380661326F0032D7BD4A49A63F9478FF3711D69056A2D19D5D0930747EAF24DF2F6CBBDB7EC21BC4350B2B2F0ABEE5F161408C6153B0D52AB93B7265FCD5E975A7F7B475EC253C5C3BA9810E7812185A7D2C27FE6EC8BC2BF6CFA4D83822F12D17D77DC95286AA0B434074B2918A3DE06F66DC710B71D480E097A09C63FC63518478EB98A4D75B7C24B707174039E8F17C51D6148415403C9A5C0B73F359BBCF2D6FA29430DFB20DCB7C74C89C2A9B5A8586108DBD6CFC138486E6511B366B2BFDCF24FFF13E5E14D4E1F26B04D6E6D421383C523BE39DB3640F44E1356B3F9F6CBD9BD105F6162EA9D4EA6C309D47EE92F16DAB0203010001A3820302308202FE300E0603551D0F0101FF0404030206C03013060A2A864886F72F0101090204053003020101302A0603551D2504233021060A2B0601040182370A030C06092A864886F72F01010506082B0601050507030230650603551D20045E305C305A060C2B0601040181AD5A0209030F304A304806082B06010505070201163C68747470733A2F2F7777772E646F63757369676E2E66722F736F63696574652F706F6C697469717565732D64652D63657274696669636174696F6E73300C0603551D130101FF0402300030600603551D1F045930573055A053A051864F687474703A2F2F747275737463656E7465722D63726C2E63657274696669636174322E636F6D2F4B65796E65637469732F4B45594E45435449535F4943535F5155414C49464945445F43412E63726C30819306082B06010505070101048186308183303C06082B060105050730018630687474703A2F2F6F6373702D69642E6473662E646F63757369676E2E6E65742F6963735F7175616C69666965645F6361304306082B060105050730028637687474703A2F2F6372742E6473662E646F63757369676E2E6E65742F6B65796E65637469736963737175616C696669656463612E70376330260603551D11041F301D811B5048494C495050452E4452415940484153484C4F4749432E434F4D3037060A2A864886F72F01010901042930270201018622687474703A2F2F7473732E6473662E646F63757369676E2E6E65742F63657274696430819C06082B0601050507010304818F30818C3008060604008E4601013008060604008E460104304A060604008E4601053040303E163868747470733A2F2F7064732E6473662E646F63757369676E2E6E65742F6B65796E65637469736963737175616C696669656463612E7064661302454E3013060604008E4601063009060704008E46010601301506082B06010505070B023009060704008BEC490102301D0603551D0E041604140F90E2B99C6875B0AB1A4384293866149603D6E5301F0603551D23041830168014549745C1EA00C545A8CDDB82F87DCBF59041A078300D06092A864886F70D01010B050003820101004BCE22A1A19B2CA0D520B41B7B78C6CBAA9E79CA60D7C9C3EE3E78750189BCCAEB6C385F3891A8D6A7323D1482634D70886F6A7C2AA7E7B263B6875F390E45F5DEA486ACEC3F429F45B3BDF63EFDE406DF6929104AAC05D4CC66D5C9D8FDE3F4C44EE796AD64A8AE3C035F8721FEA558B0A3BF73A17CF2E88D204CC92066EB815F06A51852E4C5ADAC7328E830E2B48BF1880D39A4C58461CFB6490F047044ABB8D026E7789F70A5DF07CFC70D7A57A8C249E53F73161374448B3140F8F5C30E8FA6224FF69F159AFA2DB98D83674DDDD9E467E528FBDD667995CF0E4F7B90FDD40E26BEEC8963B31E538B8FFF44DEF6ABA09AB3962AE85D322CEDBB5479C749";
	// var byteArray = new Uint8Array(x509_raw.match(/.{2}/g).map(e => parseInt(e, 16)));
	// var blobCert = new Blob([byteArray], {type: "application/octet-stream"});
	// SCWS.createCertificate(blobCert).then(function(certificate) {
	// 	console.log(certificate);
	// });

	SCWS.requestCertificates(function(certificates) {
		return certificates;
	}).then(function(certificates) {
		var index = 0;
		if (window.certlist != undefined && window.certlist.selectedIndex != undefined) {
			index = window.certlist.selectedIndex;
		}

		SCWS.requestPrivateKey(certificates[index], false, function(pKey, cert) {
			return SCWS.signEncryptDocument(blob, pKey, cert, cert, options).then(function(signEncryptedBlob) {
				log("SignEncryption has succeeded.");
				downloadBlob(signEncryptedBlob, "Test_signEncrypted.p7");
			}, function(err) {log(err);});
		});
	});
}


function verifyDoc() {
	var blob = getBlobFromLocal("inputFile");
	var originalBlob = undefined;
	var originalBlobCallback = undefined;

	var options = {format: document.querySelector('input[name="signEncryptFormat"]:checked').value};

	if (options.format == "CADES_DETACHED" || options.format == "XADES_DETACHED") {
		originalBlob = document.getElementById("originalFile").files[0];
	}

	if (options.format == "CADES_ATTACHED" || options.format == "PKCS7") {
		originalBlobCallback = downloadBlob;
	}

	SCWS.verifyDocument(blob, options, originalBlob, originalBlobCallback).then(function(verifResult){
		log("");
		log("Verification has succeeded.");
		log("globalSignatureValidity: " + verifResult.globalSignatureValidity);
		for (var i = 0; i < verifResult.signatories.length; i++) {
			log("");
			log("\nSignatory " + i + ":");
			log("Name: " + verifResult.signatories[i].certificate._subjectName);
			log("Certificate handle: " + verifResult.signatories[i].certificate._handle);
			log("signatureValidity: " + verifResult.signatories[i].signatureValidity);
			log("signerTrust: " + verifResult.signatories[i].signerTrust);
			log("cadesBESCompliance: " + verifResult.signatories[i].cadesBESCompliance);

		}
	}, function(err) {log(err);});
}

function decryptDoc() {
	var blob = document.getElementById("inputFile").files[0];

	function callbackDecrypt(recipientsList, decryptWith) {
		SCWS.requestCertificates(function(certificates) {
			return SCWS.matchIssuerAndSerialsWithCerts(recipientsList, certificates).then(function(result) {
				for (var i = 0; i < certificates.length; i++) {
					const index = result.indexOf(certificates[i]._handle);
					if (index != -1)
						return certificates[i];
				}
			});
		}).then(function(certificate) {
			return SCWS.requestPrivateKey(certificate, false, function(pKey, cert) {
				return decryptWith(pKey, cert);
			});
		});
	}

	SCWS.decryptDocument(blob, callbackDecrypt).then(function(blob){
		log("Decryption has succeeded.");
		downloadBlob(blob, "Test_decrypted");
	}, function(err) {log(err);});
}


function decryptVerifyDoc() {
	var blob = document.getElementById("inputFile").files[0];

	function callbackDecrypt(recipientsList, decryptWith) {
		SCWS.requestCertificates(function(certificates) {
			return SCWS.matchIssuerAndSerialsWithCerts(recipientsList, certificates).then(function(result) {
				for (var i = 0; i < certificates.length; i++) {
					const index = result.indexOf(certificates[i]._handle);
					if (index != -1)
						return certificates[i];
				}
			});
		}).then(function(certificate) {
			return SCWS.requestPrivateKey(certificate, false, function(pKey, cert) {
				return decryptWith(pKey, cert);
			});
		});
	}

	SCWS.decryptVerifyDocument(blob, callbackDecrypt, downloadBlob).then(function(verifResult){
		log("");
		log("DecryptVerification has succeeded.");
		log("globalSignatureValidity: " + verifResult.globalSignatureValidity);
		for (var i = 0; i < verifResult.signatories.length; i++) {
			log("");
			log("\nSignatory " + i + ":");
			log("Name: " + verifResult.signatories[i].certificate._subjectName);
			log("Certificate handle: " + verifResult.signatories[i].certificate._handle);
			log("signatureValidity: " + verifResult.signatories[i].signatureValidity);
			log("signerTrust: " + verifResult.signatories[i].signerTrust);
			log("cadesBESCompliance: " + verifResult.signatories[i].cadesBESCompliance);

		}
	}, function(err) {log(err);});
}

		</script>
	</head>

	<body>
		<table>
			<tr>
				<td>
					<form id="certificateform">
						<table>
							<tr>
								<td>
									Enable soft token:<br>
									<label><input type="radio" name="softToken" value="default" checked="checked">default</label><br>
									<label><input type="radio" name="softToken" value="true">true</label><br>
									<label><input type="radio" name="softToken" value="false">false</label><br/>
								</td>
								<td>
									Scan dialog:<br>
									<label><input type="radio" name="scandlg" value="nominal">nominal</label><br>
									<label><input type="radio" name="scandlg" value="synchronous">synchronous</label><br>
									<label><input type="radio" name="scandlg" value="asynchronous" checked="checked">asynchronous</label><br/>
								</td>
								<td>
									message:<br>
									<label><input type="radio" name="scanMessage" value="nominal" checked="checked">nominal</label><br>
									<label><input type="radio" name="scanMessage" value="customized">customized</label><br/>
								</td>
								<td id="scandlg">
									Scan dialog:<br/>
									<form id="scanform">
										<textarea id="scanfield" name="scan" cols="40" rows="4"></textarea><br>
									</form>
								</td>
							</tr>
						</table>
						<input type="button" onclick="requestCertificates()" value="request certificates"/><br/>
						Certificate to use:<br>
						<div style="display:inline-block;vertical-align:top;">
							<select style="height:8rem;" size="4" id="certificatelist" onchange="chooseCert()">
							</select>
						</div>
						<div id="certificatevalue" style="white-space:pre;display:inline-block;vertical-align:top;width:20em;height:8rem;overflow:auto;border:1px solid gray;">

						</div>
					</form>
			
					<p><form id="dataform">
						Input data:<br>
						<textarea id="datafield" name="data" cols="40" rows="8"></textarea><br>
					</form></p>
			
					<p><form id="loginform">
						Counter (0 or less equals infinity) :<input id="auto-login-counter" type="number"/>
						<input type="button" onclick="startAutoLogin()" value="startAutoLogin"/>
						<input type="button" onclick="stopAutoLogin()" value="stopAutoLogin"/><br/>
						Pin <span id="pinname"></span>:<br>
						<input id="pin" type="password" />
						<input type="button" onclick="login()" value="Login"/>
						<input type="button" onclick="loginWithPinDialog()" value="LoginWithPinDialog"/>
						<input type="button" onclick="loginWithPinPad()" value="LoginWithPinPad"/>
						<input type="button" onclick="GetCredential()" value="GetCredential"/>
					</form></p>
					
					<p>
						<div style="display:inline-block;text-align:center;margin:0.5em 2em;">
							<input type="button" onclick="sign()" value="Sign"/><br>
							<input type="button" onclick="verify()" value="Verify"/><br>
							<input type="button" onclick="encrypt()" value="Encrypt"/><br>
							<input type="button" onclick="decrypt()" value="Decrypt"/><br>
							<input type="button" onclick="softtoken()" value="SoftToken"/><br>
							<input type="button" onclick="initPin()" value="initPin"/>
							<input type="button" onclick="bioEnroll()" value="Bio Enroll"/><br>
							<input type="button" onclick="changePage()" value="ChangePage"/><br>
						</div>
						<div style="display:inline-block"><form id="hashcfgform">
							Hashing algorithm:<br>
							<label><input type="radio" name="hashalg" value="" checked="checked">None (hex block as input)</label><br>
							<label><input type="radio" name="hashalg" value="sha1">SHA-1</label><br>
							<label><input type="radio" name="hashalg" value="sha256">SHA-256</label>
						</form></div>
					</p>
				</td>
				<td>
					<p>Information logs:</p>
					<div id="infodiv" style="display:inline-block;vertical-align:top;width:100%;height:30rem;overflow:auto;border:1px solid gray;"></div>
				</td>
			</tr>
		</table>

		<h3>
			SignEncrypt high level entry points
		</h3>

		<p>
			<div style="display:inline-block">
				Input file(s) :<br>
				<label for="inputFile">Input file</label><br>
				<input type="file" id="inputFile" name="inputFile"/><br>
		
				<label for="originalFile">Original file (for detached verification)</label><br>
				<input type="file" id="originalFile" name="originalFile"/>
			</div>

			<div style="display:inline-block">
				Format:<br>
				<label><input type="radio" name="signEncryptFormat" value="PKCS7">PKCS7</label><br>
				<label><input type="radio" name="signEncryptFormat" value="CADES_ATTACHED">Attached CADES</label><br>
				<label><input type="radio" name="signEncryptFormat" value="CADES_DETACHED">Detached CADES</label><br>
				<label><input type="radio" name="signEncryptFormat" value="PADES">PADES</label><br>
				<label><input type="radio" name="signEncryptFormat" value="XADES_DETACHED">Detached XADES</label>
			</div>

			<div style="display:inline-block">
				Hashing algorithm:<br>
				<label><input type="radio" name="signEncryptHashAlg" value="sha1">SHA-1</label><br>
				<label><input type="radio" name="signEncryptHashAlg" value="sha256">SHA-256</label><br>
				<label><input type="radio" name="signEncryptHashAlg" value="sha384">SHA-384</label><br>
				<label><input type="radio" name="signEncryptHashAlg" value="sha512">SHA-512</label>
			</div>

			<div style="display:inline-block;text-align:center;margin:0.5em 2em;">
				<input type="button" onclick="signDoc()" value="SignDocument"/><br>
				<input type="button" onclick="encryptDoc()" value="EncryptDocument"/><br>
				<input type="button" onclick="signEncryptDoc()" value="SignEncryptDocument"/><br>
				<input type="button" onclick="verifyDoc()" value="VerifyDocument"/><br>
				<input type="button" onclick="decryptDoc()" value="DecryptDocument"/>
				<input type="button" onclick="decryptVerifyDoc()" value="DecryptVerifyDocument"/>
			</div>
		</p>



	</body>
</html>