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>

window.webappcert = "2SvJ4hegUKJv}6.5vrlH2yJKIDd@n{fvTh{3B8#hpvR^OCB8LVjBz>@azy/vzA5]:dh8l)wgCHBhv@b<<zGFDXiXS9#BAzE.fe24le&2ppf!>pngCR0Cgby:rxMOuniXJcviwJiwhAirzhzu:rf/IcFgby:rxMOuniXJcvfFkare?]7kf/y)If!$KwenfcEA5]T9f!$WufFk4if/?3AgC)0^VbK@U4UsBz)9:E)H04=YE8Ek-nUkjXoq6W/sw5}7](eJfN#N[]SftPov.1=*ARD<ml!lY3NIC8ph13}&WSGKY=[=fFB@(wCjuy+3e4]]c*{lIe*>IQ1J4uPGxZWLt6a6.)w10qGM4}vab0UxV?9N@rpZ1}6VnZ>A]7.6HOuV+4Ulw&hw&?KkX]c#&v5^>ngdrXx*a]MV-#vt=g+FpVD&e{N=}YGighbc?{FNqDVh>uH^a8GbxFK4yS5UOh[:]L%{e/eMgBLJ>Xg>gSU@3.6W:^c]9ttE/h753GjtwF5*rOh6Ly?tXVw@G@mbr:z%hty7A[Rn(WlR2=UZ?5-kR<7g2F(Opz0!m2J>4VCo9LiNjF$p#+x]k6:O5[$nz9$y|MIIE1TCCAr2gAwIBAgIBADANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQGEwJGUjEdMBsGA1UEAwwUSWRvcHRlIFdlYkFwcENlcnQgQ0ExDzANBgNVBAoMBklkb3B0ZTAgFw0yMzAxMDMxMTM1MTZaGA8yMDUyMTIzMTIyNTkwMFowMTESMBAGA1UEAxMJTWF4aW1lRGV2MQ8wDQYDVQQKEwZJZG9wdGUxCjAIBgNVBAsTATAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDbbHFzPMOgflE7NLWtYXK0MV8xCLbSZ7qvUug0YdYSwiw9XDXe5uODG2ok9C1YrlSVuQ0O73CC07RqSys2XFsx6hW82JuwN+gEqJ+v+BKW3YQgT7NOzIRrvhucSo4UWrAZV6YXhd/1GZyYyyI1x3K1e1y/1p3Zw8nKAGeIP8vSQvSA7da124DOx860AXvF3eRUyonMEZagnPyueVVy0wodO1u1WRMjVN+f91FUhtbRf+u5am0vU+IZCE5Lv/ALghr0r3QqLAvHMlhe4uw9BmPCWQH7d/fdIbcZf7eDxWizei2dfl/dMh95f2RTGzE/Hnt56IVYvOT4kR5AU95gwCHAgMBAAGjgekwgeYwCQYDVR0TBAIwADAXBgNVHSUEEDAOBgwrBgEEAYHYJAECAgEwTQYDVR0gBEYwRDAPBg0rBgEEAYHYJAECAQEBMA8GDSsGAQQBgdgkAQIBAQMwDwYNKwYBBAGB2CQBAgEBBDAPBg0rBgEEAYHYJAECAQEGMHEGA1UdEQRqMGiGGGh0dHA6Ly8xMC4yNS4xMS4xMzI6MTIzNIYbaHR0cDovLzE5Mi4xNjguMTYwLjExNzoxMjM0hhhodHRwOi8vMTAuMjUuMTEuMTY1OjEyMzSGFWh0dHA6Ly8xMjcuMC4wLjE6MTIzNDANBgkqhkiG9w0BAQsFAAOCAgEAe0LSJpq7rmnkR6H9i/TxJ7GabjxZutC22Fmb+k5kDe8bsg2h2wjHjk6GLHccmhqOKGL5kJMQlSY9zM7NdcVDPxk2JQbt29lKSfQGn5Yp1jpmruU7Wnhq1XZ/ODqIgm55TGa1pqz8jBOIkC8rHJvjtZ8sBZNqKgsVtziwRHKnt+hqZ6N0XPmEMRU0EbOVgKBOYDbSfV3H9MsN+aElQXGwFYx31h68pWuICYYhDVF3jX+8mRAljalUm8gM+kGYm/eOczwIPihRdjbxV0lbrjPypZK2IeZhkyw9Cd4MaxisSGdnuueIU1PJLnJoBQ1rCSkNm91ZyHoJCYu20HoCm5s6yYZKA4g3Q3Q7KWBG9O2sur2ImP8gfOFKlQ37BuG1e1zHWI7yFKu2P1AfSHkpW/OIHXoXMr+NjjFvatST2tewTvW/AUcU5+3Wi4ZZA76JpRWDkC9CcaItHmYLhTBEh4VGKZGDJvryx08kp4s9P4oTa60mPQ8a4VNF1W9o6kU0k+lg5Yk+QvqJnPNFC7HSrlq2Johm7oIm7n3G/go2XF/e9qfqOu4NePvBAkGMxwrib/ST1hDV2X8JzyY595oiCokOs3tpGA+KjvsSVljrL3wHlRO3Lydg0h3XQtitf51wwfIPlQPf4utPtoVME2Zc0rXdK317/cpngykC0cbai+Dxu8A=";
//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.connections = [];

window.onload = function() {
	window.infodiv = document.getElementById("infodiv");
	window.certlist = document.getElementById("certificatelist");
	/* connecting to SCWS */
	log("Connecting to SCWS...");
	SCWS.findService(window.webappcert).then(function(challenge) {
		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("Challenge signature failed"));
				}
			};
			req.open("GET", "signchallenge.php?rnd=" + challenge, true);
			req.send();
		}).then(function(signature) {
			return SCWS.createEnvironment(signature);
		});
	}).then(function() {
		log("SCWS environment created successfully");
		SCWS.onserviceunresponsive = function() {
			log("Service became unresponsive");
		}
		/* check all readers already connected */
		SCWS.getSoftToken().then(function(token){
			var connection = { reader: null };
			window.connections.push(connection);
			connection.token = token;
			connection.items = [];
			log("Getting objects from reader '" + "SoftReader" + "'...");
			token.getObjects().then(function(items) {
				var numcert = 0;
				for (var i = 0; i < items.length; i++) {
					if (items[i].type == "certificate") {
						var cert = items[i];
						var elt = document.createElement("option");
						elt.textContent = cert.subject + " (" + cert.issuer + ") - " + connection.token.label;
						connection.items.push({ cert: cert, elt: elt });
						window.certlist.appendChild(elt);
						numcert++;
					}
				}
				log("Found " + numcert + " certificates (out of " + items.length + " token objects)");
			}).catch(function(err) {
				log("ERROR: " + err.message);
			});
		});
		var readers = SCWS.readers;
		if (readers.length == 0) {
			log("No readers found");
		}
		else {
			for (var i = 0; i < readers.length; i++)
				checkReader(readers[i]);
		}
		/* register event callbacks for checking readers changes */
		SCWS.onreaderadded = function(reader) {
			log("Reader inserted: '" + reader.name + "'");
			checkReader(reader);
		}
		SCWS.onreaderremoved = function(reader) {
			log("Reader removed: '" + reader.name + "'");
			checkReader(reader);
		}
		SCWS.onreaderstatechanged = function(reader) {
			log("Reader state changed: '" + reader.name + "'");
			checkReader(reader);
		}
	}).catch(function(err) {
		log("ERROR: " + err.message);
	});
}

/**
 * Connects or disconnects from a reader (depending on its state and on previously established connections).
 */
function checkReader(reader) {
	/* trying to find reader from existing connections */
	for (var connidx = 0; connidx < window.connections.length; connidx++) {
		if (window.connections[connidx].reader == reader)
			break;
	}
	if (connidx == window.connections.length) {
		if (reader.status == "ok" && reader.cardPresent) {
			/* reader not found in existing connections, and reader contains card: connecting */
			log("Connecting to reader '" + reader.name + "'...");
			var connection = { reader: reader };
			window.connections.push(connection);
			reader.connect().then(function(token) {
				connection.token = token;
				connection.items = [];
				log("Getting objects from reader '" + reader.name + "'...");
				return token.getObjects();
			}).then(function(items) {
				var numcert = 0;
				for (var i = 0; i < items.length; i++) {
					if (items[i].type == "certificate") {
						var cert = items[i];
						var elt = document.createElement("option");
						elt.textContent = cert.subject + " (" + cert.issuer + ") - " + connection.token.label;
						connection.items.push({ cert: cert, elt: elt });
						window.certlist.appendChild(elt);
						numcert++;
					}
				}
				log("Found " + numcert + " certificates (out of " + items.length + " token objects)");
			}).catch(function(err) {
				log("ERROR: " + err.message);
			});
		}
	}
	else {
		var conn = connections[connidx];
		if (reader.status != "ok" || !reader.cardPresent) {
			/* reader found in existing connections, but contains no card: removing */
			if (conn.token) {
				for (var i = 0; i < conn.items.length; i++)
					window.certlist.removeChild(conn.items[i].elt);
				log("Disconnecting from reader '" + reader.name + "'.");
				conn.token.disconnect();
			}
			window.connections.splice(connidx, 1);
		}
	}
}

function chooseCert()
{
	/* get selected certificate element */
	var elt = window.certlist.options[window.certlist.selectedIndex];
	/* enumerate through connections and certificate items to retrieved corresponding cert object */
	var conn = null;
	var cert = null;
	for (var connidx = 0; connidx < window.connections.length; connidx++) {
		conn = connections[connidx];
		if (conn.items) {
			for (var itemidx = 0; itemidx < conn.items.length; itemidx++) {
				if (conn.items[itemidx].elt == elt) {
					cert = conn.items[itemidx].cert;
					break;
				}
			}
			if (cert)
				break;
		}
	}
	/* remember selected elements */
	window.cert = cert;
	window.token = cert ? conn.token : null;
	window.pin = cert ? conn.token.pins[cert.pinNumber] : null;
	if (cert) {
		/* updating pin name label */
		document.getElementById("pinname").textContent = window.pin.label || "(Default PIN)";
		/* updating certificate value */
		cert.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 login()
{
	if (!window.pin)
		return;
	log("Login...");
	window.pin.login(document.getElementById("pin").value).then(function() {
		log("Login successful");
	}, function(err) {
		log("ERROR: " + err.message);
	});
}

function loginWithPinDialog()
{
	if (!window.pin)
		return;
	log("Login...");
	window.pin.login(false).then(function() {
		log("Login successful");
	}, function(err) {
		log("ERROR: " + err.message);
	});	
}

function loginWithPinPad()
{
	if (!window.pin)
		return;
	log("Login...");
	window.pin.login().then(function() {
		log("Login successful");
	}, function(err) {
		log("ERROR: " + err.message);
	});	
}

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

}

function getPrivateKey()
{
	log("Getting private key associated to certificate...");
	return window.token.getObjects().then(function(items) {
		for (var i = 0; i < items.length; i++) {
			if (items[i].type == "privateKey" && items[i].ckId == window.cert.ckId) {
				return items[i];
			}
		}
		throw new Error("Unable to find the private key associated to the certificate. Did you verify the PIN?");    
	});
}

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

function sign()
{
	var b = window.pin.validated;
	/* sign the input data using the selected hash algorithm */
	getPrivateKey().then(function(pkey) {
		log("Signature...");
		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);
				log("Signature done:<br>&nbsp;&nbsp;" + data);
				window.lastRet = forge.util.hexToBytes(data);
			});
		}
	}).catch(function(err) {
		log("ERROR: " + err.message);
	});
}

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 */
	getPrivateKey().then(function(pkey) {
		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(function(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";
}

async function signCSR(csrPath)
{
  return new Promise(async 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(async function(csrPem ) {
	var csr = forge.pki.certificationRequestFromPem(csrPem);
	var cert = forge.pki.createCertificate();
	cert.serialNumber = '01';
	cert.validity.notBefore = new Date();
	cert.validity.notAfter = new Date();
	cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);
	cert.setSubject(csr.subject.attributes);
	cert.setIssuer(window.caCert.subject.attributes);
	cert.setExtensions([{
	  name: 'keyUsage',
	  keyCertSign: true,
	  digitalSignature: true,
	  nonRepudiation: true,
	  keyEncipherment: true,
	  dataEncipherment: true
	}]);
	cert.publicKey = csr.publicKey;
	// sign certificate with CA key
	cert.sign(window.caKey);
	return cert;
  });
}

async function softtoken() 
{
	var token = await SCWS.getSoftToken();  
	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 blob = new Blob([window.certificate]);
	//formData.append("file", blob);
	//var cert = await token.import(formData, attributes);
	var formData = new FormData()
	var byteArray = new Uint8Array(window.p12.match(/.{2}/g).map(e => parseInt(e, 16)));
	var blob = new Blob([byteArray], {type: "application/octet-stream"});
	formData.append("file", blob);
	formData.append("password", window.password);
	var objects = await token.import(formData, attributes);
	await SCWS.destroyObjects(objects.privateKey);
	await SCWS.destroyObjects(objects.publicKey);
	await SCWS.destroyObjects(objects.certificate);

	/*var keypair = await token.generateKeyPair(2048, attributes);
	var csrPath = await keypair.privateKey.generateCSR(data);
	const cert = await signCSR(csrPath);
	var formData = new FormData();
	const pem = forge.pki.certificateToPem(cert);
	var blob = new Blob([pem]);
	formData.append("file", blob);
	var certAttributes = {"label": "test"};
	var certificate = await token.import(formData, certAttributes);
	await SCWS.destroyObjects(keypair.privateKey);
	await SCWS.destroyObjects(keypair.publicKey);
	await SCWS.destroyObjects(certificate.certificate);*/

}

function callbackChipAuth(pubKey) {
	return pubKey;
}
		</script>   
	</head>

	<body>
		
		<p><form id="dataform">
			Input data:<br>
			<textarea id="datafield" name="data" cols="40" rows="8"></textarea><br>
		</form></p>

		<p><form id="certificateform">
			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>
		<p><form id="loginform">
			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"/>
		</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"/>
				<input type="button" onclick="softtoken()" value="SoftToken"/>
				<input type="button" onclick="initPin()" value="initPin"/>
				<input type="button" onclick="changePage()" value="ChangePage"/>
			</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>

		<div id="infodiv" style="display:inline-block;vertical-align:top;width:100%;height:10rem;overflow:auto;border:1px solid gray;"></div>

	</body>
</html>