private static String certificateToString(CardVerifiableCertificate certificate) { try { if (certificate == null) { return "null"; } StringBuffer result = new StringBuffer(); CardVerifiableCertificate cert = (CardVerifiableCertificate) certificate; result.append("subject: "); result.append(cert.getHolderReference().getName()); result.append('\n'); result.append("issuer: "); result.append(cert.getAuthorityReference().getName()); result.append('\n'); result.append("Not before: " + cert.getNotBefore() + "\n"); result.append("Not after: " + cert.getNotAfter() + "\n"); return result.toString(); } catch (Exception ex) { ex.printStackTrace(); return "null"; } }
/** * Constructs a certificate panel from a certificate. * * @param certificate the certificate */ public CVCertificatePanel(CardVerifiableCertificate certificate) { super(new BorderLayout()); try { this.certificate = certificate; area = new JTextArea(20, 40); area.append(certificateToString(certificate)); area.setEditable(false); add(new JScrollPane(area), BorderLayout.CENTER); add(new KeyPanel(certificate.getPublicKey()), BorderLayout.SOUTH); } catch (Exception ex) { ex.printStackTrace(); } }
/** * Perform TA (Terminal Authentication) part of EAC (version 1). For details see TR-03110 ver. * 1.11. In short, we feed the sequence of terminal certificates to the card for verification, get * a challenge from the card, sign it with terminal private key, and send back to the card for * verification. * * @param caReference reference issuer * @param terminalCertificates terminal certificate chain * @param terminalKey terminal private key * @param taAlg algorithm * @param chipAuthenticationResult the chip authentication result * @param documentNumber the document number * @return the challenge from the card * @throws CardServiceException on error */ public synchronized TerminalAuthenticationResult doTA( CVCPrincipal caReference, List<CardVerifiableCertificate> terminalCertificates, PrivateKey terminalKey, String taAlg, ChipAuthenticationResult chipAuthenticationResult, String documentNumber) throws CardServiceException { try { if (terminalCertificates == null || terminalCertificates.size() < 1) { throw new IllegalArgumentException( "Need at least 1 certificate to perform TA, found: " + terminalCertificates); } byte[] caKeyHash = chipAuthenticationResult.getKeyHash(); /* The key hash that resulted from CA. */ if (caKeyHash == null) { throw new IllegalArgumentException("CA key hash is null"); } /* FIXME: check that terminalCertificates holds a (inverted, i.e. issuer before subject) chain. */ /* Check if first cert is/has the expected CVCA, and remove it from chain if it is the CVCA. */ CardVerifiableCertificate firstCert = terminalCertificates.get(0); Role firstCertRole = firstCert.getAuthorizationTemplate().getRole(); if (Role.CVCA.equals(firstCertRole)) { CVCPrincipal firstCertHolderReference = firstCert.getHolderReference(); if (caReference != null && !caReference.equals(firstCertHolderReference)) { throw new CardServiceException( "First certificate holds wrong authority, found " + firstCertHolderReference.getName() + ", expected " + caReference.getName()); } if (caReference == null) { caReference = firstCertHolderReference; } terminalCertificates.remove(0); } CVCPrincipal firstCertAuthorityReference = firstCert.getAuthorityReference(); if (caReference != null && !caReference.equals(firstCertAuthorityReference)) { throw new CardServiceException( "First certificate not signed by expected CA, found " + firstCertAuthorityReference.getName() + ", expected " + caReference.getName()); } if (caReference == null) { caReference = firstCertAuthorityReference; } /* Check if the last cert is an IS cert. */ CardVerifiableCertificate lastCert = terminalCertificates.get(terminalCertificates.size() - 1); Role lastCertRole = lastCert.getAuthorizationTemplate().getRole(); if (!Role.IS.equals(lastCertRole)) { throw new CardServiceException( "Last certificate in chain (" + lastCert.getHolderReference().getName() + ") does not have role IS, but has role " + lastCertRole); } CardVerifiableCertificate terminalCert = lastCert; /* Have the MRTD check our chain. */ for (CardVerifiableCertificate cert : terminalCertificates) { try { CVCPrincipal authorityReference = cert.getAuthorityReference(); /* Step 1: MSE:SetDST */ /* Manage Security Environment: Set for verification: Digital Signature Template, * indicate authority of cert to check. */ byte[] authorityRefBytes = Util.wrapDO((byte) 0x83, authorityReference.getName().getBytes("ISO-8859-1")); sendMSESetDST(wrapper, authorityRefBytes); /* Cert body is already in TLV format. */ byte[] body = cert.getCertBodyData(); /* Signature not yet in TLV format, prefix it with tag and length. */ byte[] signature = cert.getSignature(); ByteArrayOutputStream sigOut = new ByteArrayOutputStream(); TLVOutputStream tlvSigOut = new TLVOutputStream(sigOut); tlvSigOut.writeTag(TAG_CVCERTIFICATE_SIGNATURE); tlvSigOut.writeValue(signature); tlvSigOut.close(); signature = sigOut.toByteArray(); /* Step 2: PSO:Verify Certificate */ sendPSOExtendedLengthMode(wrapper, body, signature); } catch (CardServiceException cse) { throw cse; } catch (Exception e) { /* FIXME: Does this mean we failed to authenticate? -- MO */ throw new CardServiceException(e.getMessage()); } } if (terminalKey == null) { throw new CardServiceException("No terminal key"); } /* Step 3: MSE Set AT */ CVCPrincipal holderRef = terminalCert.getHolderReference(); byte[] holderRefBytes = Util.wrapDO((byte) 0x83, holderRef.getName().getBytes("ISO-8859-1")); /* Manage Security Environment: Set for external authentication: Authentication Template */ sendMSESetATExtAuth(wrapper, holderRefBytes); /* Step 4: send get challenge */ byte[] rPICC = sendGetChallenge(wrapper); /* Step 5: external authenticate. */ /* FIXME: idPICC should be public key in case of PACE. See BSI TR 03110 v2.03 4.4. */ byte[] idPICC = new byte[documentNumber.length() + 1]; System.arraycopy( documentNumber.getBytes("ISO-8859-1"), 0, idPICC, 0, documentNumber.length()); idPICC[idPICC.length - 1] = (byte) MRZInfo.checkDigit(documentNumber); ByteArrayOutputStream dtbs = new ByteArrayOutputStream(); dtbs.write(idPICC); dtbs.write(rPICC); dtbs.write(caKeyHash); dtbs.close(); byte[] dtbsBytes = dtbs.toByteArray(); String sigAlg = terminalCert.getSigAlgName(); if (sigAlg == null) { throw new IllegalStateException( "ERROR: Could not determine signature algorithm for terminal certificate " + terminalCert.getHolderReference().getName()); } Signature sig = Signature.getInstance(sigAlg); sig.initSign(terminalKey); sig.update(dtbsBytes); byte[] signedData = sig.sign(); if (sigAlg.toUpperCase().endsWith("ECDSA")) { int keySize = ((org.bouncycastle.jce.interfaces.ECPrivateKey) terminalKey) .getParameters() .getCurve() .getFieldSize() / 8; signedData = Util.getRawECDSASignature(signedData, keySize); } sendMutualAuthenticate(wrapper, signedData); state = TA_AUTHENTICATED_STATE; return new TerminalAuthenticationResult( chipAuthenticationResult, caReference, terminalCertificates, terminalKey, documentNumber, rPICC); } catch (CardServiceException cse) { throw cse; } catch (Exception e) { throw new CardServiceException(e.toString()); } }