I have a certificate in my javacard applet which the host application requests to verify challenges from the host application signed by the card applet:
The host application computes challenges for the javacard applet to sign as follows.
byte [] card_signature=null; SecureRandom random = SecureRandom . getInstance( "SHA1PRNG" ) ; byte [ ]bytes = new byte [ 20 ] ; random . nextBytes ( bytes) ; CommandAPDU challenge; ResponseAPDU resp3; challenge = new CommandAPDU(IDENTITY_CARD_CLA,SIGN_CHALLENGE, 0x00, 0x00,bytes ,20 ); resp3= c.transmit(challenge); if(resp3.getSW()==0x9000) { card_signature = resp3.getData(); String s= DatatypeConverter.printHexBinary(card_signature); System.out.println("signature: " + s); }else System.out.println("Challenge signature error " + resp3.getSW());The javacard applet signs the host application challenges and sends back the signature as follows:
private void sign(APDU apdu) { if(!pin.isValidated())ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED); else{ byte[] buffer = apdu.getBuffer(); byte [] output = new byte [64]; short length = 64; short x =0; Signature signature =Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false); signature.init(privKey, Signature.MODE_SIGN); short sigLength = signature.sign(buffer, offset,length, output, x); //This sequence of three methods sends the data contained in //'serial' with offset '0' and length 'serial.length' //to the host application. apdu.setOutgoing(); apdu.setOutgoingLength((short)output.length); apdu.sendBytesLong(output,(short)0,(short)output.length); } }To verify the javacard applet signature, the host requests the javacard applet certificate from the javacard. The certificate (as a byte array) is 256 bytes and I gather it can only be sent in blocks of lenghth 240. The javacard applet sends the certificate as follows:
private void send_certificate (APDU apdu) { if(!pin.isValidated())ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED); else{ apdu.setOutgoing(); apdu.setOutgoingLength((short)240); apdu.sendBytesLong(certificate,(short)0,(short)240); } }The host application then receives the certificate in bytes and constructs the certificate. In addition, it attempts to verify signed challenges with the certificate as follows:
//Get certificate CommandAPDU card_cert; ResponseAPDU resp4; card_cert = new CommandAPDU(IDENTITY_CARD_CLA, SEND_CERTIFICATE, 0x00, 0x00); resp4 = c.transmit(card_cert); if(resp4.getSW()==0x9000) { byte [] response = resp4.getData(); String certf= DatatypeConverter.printHexBinary(response); System.out.println("CERTIFICATE: " + certf); CertificateFactory certFac = CertificateFactory.getInstance("X.509"); InputStream is = new ByteArrayInputStream(response); X509Certificate cert = ( X509Certificate ) certFac .generateCertificate( is ) ; Signature signature = Signature.getInstance("SHA1withRSA"); signature.initVerify(cert.getPublicKey()); signature.update(card_signature); if(card_signature !=null) { boolean ok =signature.verify(card_signature); if(ok==true)System.out.println("verification completed" ); } }
I get the error below:
signature: 802800001438BBAE2CE7AD2498B0A8DA91634230A5D8324DBD4039F8376404AB1B7FF1B37DF63D22AFB2B6ABE37B31E8276B28427FA56FCF38EDF05FBC1EEF50C81A1C4F88560048D1C0E6D20B13000B384E0AE3AFED2751927F
CERTIFICATE:8030000000F0308201BD30820167A003020102020500B7D56095300D06092A864886F70D01010505003064310B3009060355040613024245310D300B06035504070C0447656E7431193017060355040A0C104B61486F2053696E742D4C696576656E31143012060355040B0C0B56616B67726F65702049543115301306035504030C0C4A616E20566F7373616572743020170D3130303232343039343330325A180F35313739303130393139323934325A3064310B3009060355040613024245310D300B06035504070C0447656E7431193017060355040A0C104B61486F2053696E742D4C696576656E31143012060355040B0C0B56
Exception in thread "main" java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Empty input
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:110)
at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
at be.msec.client.Client.main(Client.java:133)
Caused by: java.io.IOException: Empty input
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:106)
... 2 more
Is it possible that my approach to sending the certificate to the host application is wrong? Also, could I be retreiving the certficate in the host application in a wrong way? I could not get my solution here: Could not parse certificate: java.io.IOException: Empty input X509Certificate
resp2in point 4, which is where the exception is actually thrown.resp2in your code. Is that also a mistake? You should isolate your code into small methods to avoid this kind of wrong variable error at compile time.