1 /**
  2  *  ---------
  3  * |.##> <##.|  SmartCard-HSM Support Scripts
  4  * |#       #|  
  5  * |#       #|  Copyright (c) 2011-2012 CardContact Software & System Consulting
  6  * |'##> <##'|  Andreas Schwier, 32429 Minden, Germany (www.cardcontact.de)
  7  *  --------- 
  8  *
  9  * Consult your license package for usage terms and conditions.
 10  *
 11  * @fileoverview Obtain a certificate from an online ca service
 12  */
 13 
 14 load("../lib/smartcardhsm.js");
 15 load("../lib/hsmkeystore.js");
 16  
 17 // var url = "http://localhost:8080/se/caws";
 18 var url = "http://devnet.cardcontact.de/se/caws";
 19 
 20 var userPIN = new ByteString("648219", ASCII);
 21 var initializationCode = new ByteString("57621880", ASCII);
 22 
 23 print("If you are behind a web proxy, then please edit the proxy settings in requestcert.js");
 24 // java.lang.System.setProperty("http.proxyHost", "myproxy.com");
 25 // java.lang.System.setProperty("http.proxyPort", "3128");
 26 
 27 
 28 /**
 29  * Creates a web service connector to access an online CA
 30  *
 31  * @class Class implementing a CA web service connector
 32  * @constructor
 33  * @param {String} url the web service endpoint
 34  */
 35 function CAConnection(url) {
 36 	this.url = url;
 37 	this.soapcon = new SOAPConnection();
 38 	this.verbose = true;
 39 	this.lastReturnCode = null;
 40 }
 41 
 42 
 43 
 44 /**
 45  * Get the last return code
 46  *
 47  * @returns the last return code received or null if none defined
 48  * @type String
 49  */
 50 CAConnection.prototype.getLastReturnCode = function() {
 51 	return this.lastReturnCode;
 52 }
 53 
 54 
 55 
 56 /**
 57  * Gets the last request
 58  *
 59  * @returns the last request
 60  * @type XML
 61  */
 62 CAConnection.prototype.getLastRequest = function() {
 63 	return this.request;
 64 }
 65 
 66 
 67 
 68 /**
 69  * Gets the last response
 70  *
 71  * @returns the last response
 72  * @type XML
 73  */
 74 CAConnection.prototype.getLastResponse = function() {
 75 	return this.response;
 76 }
 77 
 78 
 79 
 80 /**
 81  * Close the connector and release allocated resources
 82  */
 83 CAConnection.prototype.close = function() {
 84 	this.soapcon.close();
 85 }
 86 
 87 
 88 
 89 /**
 90  * Request a certificate from the CA using a web service
 91  *
 92  * @param {ByteString} certreq the certificate request
 93  * @param {String} messageID the messageID for asynchronous requests (optional)
 94  * @param {String} responseURL the URL to which the asynchronous response is send (optional)
 95  * @returns the new certificates
 96  * @type ByteString[]
 97  */
 98 CAConnection.prototype.requestCertificate = function(certreq, devicecert, commonName, eMailAddress, activationCode) {
 99 
100 	this.lastReturnCode = null;
101 
102 	var soapConnection = new SOAPConnection();
103 
104 	var ns = new Namespace("http://www.openscdp.org/CAService");
105 
106 	var request =
107 		<ns:RequestCertificate xmlns:ns={ns}>
108 			<CertificateSigningRequest>{certreq.toString(BASE64)}</CertificateSigningRequest>
109 			<DeviceCertificate>{devicecert.toString(BASE64)}</DeviceCertificate>
110 			<CommonName>{commonName}</CommonName>
111 			<eMailAddress>{eMailAddress}</eMailAddress>
112 		</ns:RequestCertificate>
113 
114 	if (activationCode) {
115 		request.eMailAddress += <ActivationCode>{activationCode}</ActivationCode>;
116 	}
117 
118 	if (this.verbose) {
119 		GPSystem.trace(request.toXMLString());
120 	}
121 
122 	this.request = request;
123 
124 	try	{
125 		var response = this.soapcon.call(this.url, request);
126 		if (this.verbose) {
127 			GPSystem.trace(response.toXMLString());
128 		}
129 	}
130 	catch(e) {
131 		GPSystem.trace("SOAP call to " + this.url + " failed : " + e);
132 		throw new GPError("CAConnection", GPError.DEVICE_ERROR, 0, "RequestCertificate failed with : " + e);
133 	}
134 	
135 	this.response = response;
136 
137 	var certlist = [];
138 
139 	this.lastReturnCode = response.ReturnCode.toString();
140 	
141 	if (this.lastReturnCode != "ok") {
142 		return null;
143 	}
144 	
145 	GPSystem.trace("Received certificates:");
146 	for each (var c in response.Certificates.Certificate) {
147 		var cert = new ByteString(c, BASE64);
148 		certlist.push(cert);
149 		GPSystem.trace(cert);
150 	}
151 
152 	return certlist;
153 }
154 
155 
156 
157  
158 // Use default crypto provider
159 var crypto = new Crypto();
160 
161 // Create card access object
162 var card = new Card(_scsh3.reader);
163 
164 card.reset(Card.RESET_COLD);
165 
166 // Create SmartCard-HSM card service
167 var sc = new SmartCardHSM(card);
168 
169 // Check if device is yet un-initialized
170 if (sc.queryUserPINStatus() == 0x6984) {
171 	var page = "<html><p><b>Warning:</b></p><br/>" + 
172 			   "<p>This is a new device that has never been initialized before.</p><br/>" + 
173 			   "<p>If you choose to continue, then the device initialization code will be set to " + initializationCode.toString(HEX) + "</p><br/>" + 
174 			   "<p>Please be advised, that this code can not be changed once set. The same code must be used in subsequent re-initialization of the device.</p><br/>" + 
175 			   "<p>Press OK to continue or Cancel to abort.</p>" + 
176 			   "</html>";
177 	var userAction = Dialog.prompt(page);
178 	assert(userAction != null);
179 
180 	var userPIN = Dialog.prompt("Please select user PIN for SmartCard-HSM", "648219");
181 	assert(userPIN != null);
182 
183 	sc.initDevice(new ByteString("0001", HEX), new ByteString(userPIN, ASCII), initializationCode, 3);
184 } else {
185 	var userPIN = Dialog.prompt("Please enter user PIN for SmartCard-HSM", "648219");
186 	assert(userPIN != null);
187 }
188 
189 // Verify user PIN
190 sc.verifyUserPIN(new ByteString(userPIN, ASCII));
191 
192 var url = Dialog.prompt("Please enter URL of Online CA", url);
193 assert(url != null);
194 
195 var label = url.match(/\w+:\/\/([\w.]+)/)[1];
196 print("Using label \"" + label + "\" for key");
197 
198 var commonName = "Joe Doe";
199 var commonName = Dialog.prompt("Please enter name or pseudonym for entry into the common name field of the certificate", commonName);
200 assert(commonName != null);
201 
202 var eMailAddress = " joe.doe@openscdp.org";
203 
204 do	{
205 	var eMailAddress = Dialog.prompt("Please enter a valid e-mail address for entry into the subjectAlternativeName field of the certificate", eMailAddress);
206 	assert(eMailAddress != null);
207 } while (eMailAddress.match(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+/)[0] != eMailAddress);
208 
209 if (eMailAddress.length > 0) {
210 	print("The CA will send an activation code to " + eMailAddress);
211 }
212 
213 var hsmks = new HSMKeyStore(sc);
214 
215 sc.enumerateKeys();
216 var key = sc.getKey(label);
217 
218 if (key) {
219 	assert(Dialog.prompt("A key with the label " + label + " already exists. Press OK to delete the key"));
220 	hsmks.deleteKey(label);
221 }
222 
223 print("Generating a 2048 bit RSA key pair can take up to 60 seconds. Please wait...");
224 var req = hsmks.generateRSAKeyPair(label, 2048);
225 
226 var devAutCert = sc.readBinary(SmartCardHSM.C_DevAut);
227 
228 var activationCode;
229 
230 do	{
231 	var cacon = new CAConnection(url);
232 	var certs = cacon.requestCertificate(req.getBytes(), devAutCert, commonName, eMailAddress, activationCode);
233 	cacon.close();
234 
235 	if (certs == null) {
236 		var rc = cacon.getLastReturnCode();
237 		if (rc == "activation_code_wrong") {
238 			assert(Dialog.prompt("Wrong activation code - Press OK to retry"));
239 		}
240 		if ((rc == "activation_code_required") || (rc == "activation_code_wrong")) {
241 			activationCode = Dialog.prompt("Please check your e-mail and enter activation code", "");
242 			assert(activationCode != null);
243 		} else {
244 			print("Online CA returned " + cacon.getLastReturnCode());
245 			break;
246 		}
247 	} else {
248 		var cert = new X509(certs[0]);
249 		print(cert);
250 		print("Received certificate from CA, now storing it on the device...");
251 		hsmks.storeEndEntityCertificate(label, cert);
252 	}
253 } while (!certs);
254