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 Connector implementing a web service interface to a terminal control center as defined in TR-03129 25 */ 26 27 28 load("../cvc.js"); 29 30 31 /** 32 * Creates a web service connector to access services of a terminal control center as defined in TR-03129 33 * 34 * @class Class implementing a terminal control center web service connector 35 * @constructor 36 * @param {String} url the web service endpoint 37 */ 38 function TCCConnection(url) { 39 this.url = url; 40 this.soapcon = new SOAPConnection(); 41 this.verbose = true; 42 this.lastError = null; 43 this.version = "1.1"; 44 } 45 46 47 48 /** 49 * Get the last error return code 50 * 51 * @returns the last error return code received or null if none defined 52 * @type String 53 */ 54 TCCConnection.prototype.getLastError = function() { 55 return this.lastError; 56 } 57 58 59 60 /** 61 * Close the connector and release allocated resources 62 */ 63 TCCConnection.prototype.close = function() { 64 this.soapcon.close(); 65 } 66 67 68 69 /** 70 * Obtain a list of card verifiable certificates that can be used to provide the MRTD with a chain of certificates 71 * up to and including the terminal certificate. 72 * 73 * @param {PublicKeyReference} keyNameMRTD the certificate holder reference of the trust anchor used by the MRTD 74 * @returns a lists of card verifiable certificates from root to terminal or null in case of error 75 * @type CVC[] 76 */ 77 TCCConnection.prototype.getCertificateChain = function(keyNameMRTD) { 78 79 this.lastError = null; 80 81 var ns = new Namespace("uri:EAC-PKI-TermContr-Protocol/" + this.version); 82 var ns1 = new Namespace("uri:eacBT/" + this.version); 83 84 if (this.version == "1.0") { 85 var request = 86 <ns:GetCertificateChain xmlns:ns={ns} xmlns:ns1={ns1}> 87 <keyNameMRTD>{keyNameMRTD.getBytes().toString(BASE64)}</keyNameMRTD> 88 </ns:GetCertificateChain> 89 } else { 90 var request = 91 <ns:GetCertificateChain xmlns:ns={ns} xmlns:ns1={ns1}> 92 <keyCAR>{keyNameMRTD.getBytes().toString(BASE64)}</keyCAR> 93 </ns:GetCertificateChain> 94 } 95 96 if (this.verbose) { 97 GPSystem.trace(request.toXMLString()); 98 } 99 100 var response = this.soapcon.call(this.url, request); 101 102 if (this.verbose) { 103 GPSystem.trace(response.toXMLString()); 104 } 105 106 var certmap = []; 107 108 if (response.Result.ns1::returnCode.toString() == "ok_cert_available") { 109 if (this.verbose) { 110 GPSystem.trace("Received certificates from TCC:"); 111 } 112 for each (var c in response.Result.ns1::certificateSeq.ns1::certificate) { 113 var cvc = new CVC(new ByteString(c, BASE64)); 114 certmap[cvc.getCAR().toString()] = cvc; 115 if (this.verbose) { 116 GPSystem.trace(cvc.getCAR().toString()); 117 GPSystem.trace(cvc); 118 } 119 } 120 } else { 121 this.lastError = response.Result.ns1::returnCode.toString(); 122 return null; 123 } 124 125 var certlist = []; 126 127 var car = keyNameMRTD; 128 var cvc = certmap[car.toString()]; 129 130 while (typeof(cvc) != "undefined") { 131 certlist.push(cvc); 132 if (this.verbose) { 133 GPSystem.trace("Added: " + cvc); 134 } 135 car = cvc.getCHR() 136 cvc = certmap[car.toString()] 137 } 138 139 return certlist; 140 } 141 142 143 144 /** 145 * Obtain a signature from the TCC for a hash or a block of data 146 * 147 * @param {PublicKeyReference} keyCHR the key to be used for signing 148 * @param {ByteString} digest the message digest or null if second variant is used 149 * @returns the signature as a concatenation of coordinates on the curve or null in case of error 150 * @type ByteString 151 */ 152 TCCConnection.prototype.getTASignature = function(keyCHR, digest) { 153 154 this.lastError = null; 155 156 var ns = new Namespace("uri:EAC-PKI-TermContr-Protocol/" + this.version); 157 var ns1 = new Namespace("uri:eacBT/" + this.version); 158 159 var request = 160 <ns:GetTASignature xmlns:ns={ns} xmlns:ns1={ns1}> 161 <hashTBS> 162 </hashTBS> 163 <idPICC> 164 </idPICC> 165 <challengePICC> 166 </challengePICC> 167 <hashPK> 168 </hashPK> 169 <auxPCD> 170 </auxPCD> 171 <keyCHR>{keyCHR.getBytes().toString(BASE64)}</keyCHR> 172 </ns:GetTASignature> 173 174 request.hashTBS.ns1::binary = <ns1:binary xmlns:ns1={ns1}>{digest.toString(BASE64)}</ns1:binary>; 175 176 if (this.verbose) { 177 GPSystem.trace(request.toXMLString()); 178 } 179 180 var response = this.soapcon.call(this.url, request); 181 182 if (this.verbose) { 183 GPSystem.trace(response.toXMLString()); 184 } 185 186 var signature = null; 187 188 if (response.Result.ns1::returnCode.toString() == "ok_signature_available") { 189 var signatureStr = response.Result.ns1::Signature.toString(); 190 if (this.verbose) { 191 GPSystem.trace("Received signature from TCC: " + signatureStr); 192 } 193 signature = new ByteString(signatureStr, BASE64); 194 if (this.verbose) { 195 GPSystem.trace("Received signature from TCC: " + signature); 196 } 197 } else { 198 this.lastError = response.Result.ns1::returnCode.toString(); 199 } 200 201 return signature; 202 } 203 204 205 206 /** 207 * Obtain a signature from the TCC for a hash or a block of data 208 * 209 * @param {PublicKeyReference} keyCHR the key to be used for signing 210 * @param {ByteString} digest the message digest or null if second variant is used 211 * @returns the signature as a concatenation of coordinates on the curve or null in case of error 212 * @type ByteString 213 */ 214 TCCConnection.prototype.getTASignature2 = function(idPICC, challengePICC, hashPK, keyCHR) { 215 216 this.lastError = null; 217 218 var ns = new Namespace("uri:EAC-PKI-TermContr-Protocol/" + this.version); 219 var ns1 = new Namespace("uri:eacBT/" + this.version); 220 221 var request = 222 <ns:GetTASignature xmlns:ns={ns} xmlns:ns1={ns1}> 223 <hashTBS> 224 </hashTBS> 225 <idPICC> 226 </idPICC> 227 <challengePICC> 228 </challengePICC> 229 <hashPK> 230 </hashPK> 231 <auxPCD> 232 </auxPCD> 233 <keyCHR>{keyCHR.getBytes().toString(BASE64)}</keyCHR> 234 </ns:GetTASignature> 235 236 request.idPICC.ns1::binary = <ns1:binary xmlns:ns1={ns1}>{idPICC.toString(BASE64)}</ns1:binary>; 237 request.challengePICC.ns1::binary = <ns1:binary xmlns:ns1={ns1}>{challengePICC.toString(BASE64)}</ns1:binary>; 238 request.hashPK.ns1::binary = <ns1:binary xmlns:ns1={ns1}>{hashPK.toString(BASE64)}</ns1:binary>; 239 240 if (this.verbose) { 241 GPSystem.trace(request.toXMLString()); 242 } 243 244 var response = this.soapcon.call(this.url, request); 245 246 if (this.verbose) { 247 GPSystem.trace(response.toXMLString()); 248 } 249 250 var signature = null; 251 252 if (response.Result.ns1::returnCode.toString() == "ok_signature_available") { 253 var signatureStr = response.Result.ns1::Signature.toString(); 254 if (this.verbose) { 255 GPSystem.trace("Received signature from TCC: " + signatureStr); 256 } 257 signature = new ByteString(signatureStr, BASE64); 258 if (this.verbose) { 259 GPSystem.trace("Received signature from TCC: " + signature); 260 } 261 } else { 262 this.lastError = response.Result.ns1::returnCode.toString(); 263 } 264 265 return signature; 266 } 267 268 269 270 /** 271 * Perform a simple test 272 */ 273 TCCConnection.test = function() { 274 var c = new TCCConnection("http://localhost:8080/se/tcc"); 275 // var c = new TCCConnection("http://demo.openscdp.org/se/tcc"); 276 277 var chr = new PublicKeyReference("UTCVCA00001"); 278 var cl = c.getCertificateChain(chr); 279 280 if (cl == null) { 281 print("GetCertificateChain reports error: " + c.getLastError()); 282 } 283 284 print("Received certificates:"); 285 for (var i = 0; i < cl.length; i++) { 286 print(cl[i]); 287 } 288 289 // Extract terminal certificate, which is always the last in the list 290 var tcert = cl[cl.length - 1]; 291 var chr = tcert.getCHR(); 292 293 var crypto = new Crypto(); 294 var message = new ByteString("Hello World", ASCII); 295 296 var digest = crypto.digest(Crypto.SHA_256, message); 297 298 var signature = c.getTASignature(chr, digest); 299 300 if (signature == null) { 301 print("GetTASignature reports error: " + c.getLastError()); 302 return; 303 } 304 305 print("Signature: " + signature); 306 var signature = ECCUtils.wrapSignature(signature); 307 308 // Important: Test only works for fixed domain parameter !!! 309 var dp = new Key(); 310 dp.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP256r1", OID)); 311 312 var puk = tcert.getPublicKey(dp); 313 var mech = CVC.getSignatureMech(tcert.getPublicKeyOID()); 314 315 print("Message: " + message); 316 print("Hash: " + digest); 317 318 print("Signature verification: " + crypto.verify(puk, mech, message, signature)); 319 } 320 321