package de.persosim.simulator.test.globaltester; import static org.junit.Assert.fail; import java.io.IOException; import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import org.globaltester.logging.InfoSource; import org.globaltester.simulator.Simulator; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import de.persosim.simulator.Activator; import de.persosim.simulator.PersoSim; import de.persosim.simulator.cardobjects.AuthObjectIdentifier; import de.persosim.simulator.cardobjects.CardFile; import de.persosim.simulator.cardobjects.CardObject; import de.persosim.simulator.cardobjects.DedicatedFileIdentifier; import de.persosim.simulator.cardobjects.ElementaryFile; import de.persosim.simulator.cardobjects.FileIdentifier; import de.persosim.simulator.cardobjects.MasterFile; import de.persosim.simulator.cardobjects.MrzAuthObject; import de.persosim.simulator.cardobjects.PasswordAuthObject; import de.persosim.simulator.exception.AccessDeniedException; import de.persosim.simulator.perso.DefaultPersonalization; import de.persosim.simulator.perso.Personalization; import de.persosim.simulator.platform.CommandProcessor; import de.persosim.simulator.platform.Iso7816; import de.persosim.simulator.platform.PersonalizationHelper; import de.persosim.simulator.protocols.Tr03110; import de.persosim.simulator.utils.HexString; public abstract class GlobalTesterTest implements InfoSource, Iso7816, Tr03110 { private static final String GT_SERVER_HOST = "localhost"; private static final int GT_SERVER_PORT = 6789; private static final int GT_SERVER_RESULT_PORT = 6788; // private static final String BASE_PATH = "\\persosim_servermode_tests"; // private static final String PATH_LOGGING = BASE_PATH + "\\logging"; protected static GtServerConnection gtServer; protected static final int WAITING_TIME_BETWEEN_SERVER_MODE_RETRIES = 10; protected static final int SERVER_MODE_RETRIES = 60; protected Personalization persoCache = null; private static ServiceRegistration<Simulator> registration = null; @Override public String getIDString() { return getClass().getCanonicalName(); } @BeforeClass public static void setUpSuite() throws Exception { // initialize GT server connection gtServer = new GtServerConnection(GT_SERVER_HOST, GT_SERVER_PORT, GT_SERVER_RESULT_PORT); registration = Activator.getContext().registerService(Simulator.class, new PersoSim(), null); int retries = 0; while (!gtServer.connect()){ retries++; Thread.sleep(WAITING_TIME_BETWEEN_SERVER_MODE_RETRIES); if (retries > SERVER_MODE_RETRIES){ break; } } } @AfterClass public static void tearDownSuite() { registration.unregister(); // disconnect GT server connection if (gtServer != null) { gtServer.closeConnection(); } } @Before public void setUp() throws Exception { resetSimulator(); configureGtServer(); } @After public void tearDown(){ getSimulator().stopSimulator(); } protected void resetSimulator() throws AccessDeniedException{ //load the personalization (implicitly restarts the simulator) resetPersonalization(); getSimulator().startSimulator(); getSimulator().loadPersonalization(getPersonalization()); } @Test public void testAllApplicableTests() throws Exception { gtServer.clearCollectedResults(); Collection<JobDescriptor> suites = getAllApplicableGtTests(); for (JobDescriptor curSuite : suites) { if (curSuite instanceof SimulatorReset){ resetSimulator(); } else if (curSuite instanceof GtSuiteDescriptor){ gtServer.runSuiteAndSaveResults((GtSuiteDescriptor)curSuite); } } gtServer.checkAndClearResults(0, 0); } private PersoSim getSimulator() { Simulator simulator = null; ServiceReference<?> reference = Activator.getContext(). getServiceReference(Simulator.class.getName()); simulator = (Simulator) Activator.getContext().getService(reference); // ensure that simulator service is available if (simulator == null) { fail("no simulator service available"); } // ensure that simulator service is available if (!(simulator instanceof PersoSim)) { fail("simulator service not of type PersoSim"); } return (PersoSim) simulator; } private void configureGtServer() throws Exception { //disable dialogs gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_TESTMANAGER, "PROFILES_SHOW_DIALOG", "false"); gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_TESTMANAGER, "INTEGRITY_WARNING_DIALOG", "false"); //set logging options gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_LOGGING, "GT Test - Logging level", "0"); gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_LOGGING, "GT Simulator - Logging level", "0"); // gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_LOGGING, "manualDirSettings", "true"); // gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_LOGGING, "GT Test - Add single logfiles for Testcases", "false"); // gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_LOGGING, "GT Test - Logging directory", gtServer.getWorkspaceDir()+PATH_LOGGING); //configure profiles gtServer.setSupportedProfiles(getSupportedProfiles()); //TODO configureGtServer transmitPasswords(); transmitEidData(); // configureCertificates(); // transmitCertificates(); // generateCertificatesIfNeeded(); } private void transmitEidData() { CardFile dg18 = getEidDg(0x0112); if(dg18 instanceof ElementaryFile) { try { Field f = ElementaryFile.class.getDeclaredField("content"); f.setAccessible(true); byte[] content = (byte[]) f.get(dg18); content = Arrays.copyOfRange(content, 4, content.length); gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_EAC2, "pref_epa_communityID", HexString.encode(content)); } catch (IOException | NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { // ignore communityId if it can't be extracted } } } private CardFile getEidDg(int fid) { MasterFile mf = PersonalizationHelper.getUniqueCompatibleLayer(getPersonalization().getLayerList(), CommandProcessor.class).getObjectTree(); Collection<CardObject> cardApplications = mf.findChildren(new DedicatedFileIdentifier(HexString .toByteArray(DefaultPersonalization.AID_EID))); for (Iterator<CardObject> iterator = cardApplications.iterator(); iterator.hasNext();) { CardObject eidApplication = iterator.next(); Collection<CardObject> cardFiles = eidApplication.findChildren(new FileIdentifier(fid)); if (!cardFiles.isEmpty()) { return (CardFile) cardFiles.iterator().next(); } } return null; } private void transmitPasswords() throws IOException { String mrz = getMrz(); byte[] can = getPassword(ID_CAN); byte[] pin = getPassword(ID_PIN); byte[] puk = getPassword(ID_PUK); if (mrz != null) { gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_SECUREMESSAGING, "Use MRZ Reader", "false"); String mrz1 = null; String mrz2 = null; String mrz3 = null; switch (mrz.length()) { case 74: mrz1 = mrz.substring(0, 36); mrz2 = mrz.substring(36, 74); mrz3 = ""; break; case 88: mrz1 = mrz.substring(0, 44); mrz2 = mrz.substring(44, 88); mrz3 = ""; break; case 90: mrz1 = mrz.substring(0, 30); mrz2 = mrz.substring(30, 60); mrz3 = mrz.substring(60, 90); break; default: break; } gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_SECUREMESSAGING, "Default definition of first line in MRZ", mrz1); gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_SECUREMESSAGING, "Default definition of second line in MRZ", mrz2); gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_SECUREMESSAGING, "Default definition of third line in MRZ", mrz3); gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_SECUREMESSAGING, "Activate third MRZ line", mrz3.length() > 0 ? "true" : "false"); } if (can != null) { gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_SECUREMESSAGING, "pref_epa_can", new String(can)); } if (pin != null) { gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_SECUREMESSAGING, "pref_epa_pin", new String(pin)); } if (puk != null) { gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_SECUREMESSAGING, "pref_epa_puk", new String(puk)); } } protected void setRiKey(byte keyId, boolean authorizedOnly) throws IOException { gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_EAC2, "pref_epa_RI_keyID", "0x" + HexString.encode(keyId)); String authorizedOnlyString; if(authorizedOnly) { authorizedOnlyString = "true"; } else { authorizedOnlyString = "false"; } gtServer.setPreferences(GtServerConnection.PREF_QUALIFIER_EAC2, "pref_epa_RI_keyAuthorized", authorizedOnlyString); } /** * This method returns the MRZ used for personalization. If no MRZ is set null is returned. * @return the MRZ used for personalization * @throws AccessDeniedException */ protected String getMrz() { PasswordAuthObject pwdAuthObject = getPasswordAuthObject(Tr03110.ID_MRZ); if((pwdAuthObject == null) || (!(pwdAuthObject instanceof MrzAuthObject))) { return null; } return ((MrzAuthObject) pwdAuthObject).getMrz(); } /** * This method returns the requested password as set during personalization. * If no such password is set null is returned. * Valid password identifiers as set in {@link Tr03110} e.g. are ID_MRZ, ID_CA, ID_PIN, ID_PUK. * @param passwordIdentifier the password identifier * @return the requested password as set during personalization * @throws AccessDeniedException */ protected byte[] getPassword(int passwordIdentifier) { PasswordAuthObject pwdAuthObject = getPasswordAuthObject(passwordIdentifier); if(pwdAuthObject == null) { return null; } return pwdAuthObject.getPassword(); } /** * This method returns the {@link PasswordAuthObject} identified by the provided password identifier. * @param passwordIdentifier the password identifier to identify a password auth object * @return the identified password auth object if found, otherwise null */ protected PasswordAuthObject getPasswordAuthObject(int passwordIdentifier) { Personalization testP = getPersonalization(); MasterFile mf = PersonalizationHelper.getUniqueCompatibleLayer(testP.getLayerList(), CommandProcessor.class).getObjectTree(); Collection<CardObject> cardObjects = mf.findChildren(new AuthObjectIdentifier(passwordIdentifier)); if(cardObjects.isEmpty()) { return null; } CardObject cardObject = cardObjects.iterator().next(); if(cardObject instanceof PasswordAuthObject) { return (PasswordAuthObject) cardObject; } else{ return null; } } /** * Sets a new {@link Personalization} instance to be used within the * GlobalTester test cases * @throws AccessDeniedException */ public abstract void resetPersonalization(); /** * @return the currently cached {@link Personalization} */ public Personalization getPersonalization() { return persoCache; } /** * Returns all GlobalTester profiles that the current personalization * supports. * <p/> * In order to ensure that no tests are missed abstract superclasses are * expected to either don't implement this method at all or implement it in * a way that provides all possible profiles so that subclasses are required * to call the super implementation and restrict the returned Collection. * * @return */ public abstract Collection<String> getSupportedProfiles(); /** * Return a collection of applicable GlobalTester test suites/test cases * represented by their according {@link GtSuiteDescriptor}s. These are * executed by {@link #testAllApplicableTests()} and expected to return * Failures. * * This must not return an empty List as the number of executed test cases is * expected to be larger than 0. * * @return */ public abstract Collection<JobDescriptor> getAllApplicableGtTests(); }