package mixconfig.tools.dataretention.smartcard; import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.bouncycastle.crypto.encodings.ISO9796d1Encoding; import anon.crypto.MyRSAPublicKey; import mixconfig.tools.dataretention.smartcard.commands.AbortTransactionCommand; import mixconfig.tools.dataretention.smartcard.commands.AbstractCommand; import mixconfig.tools.dataretention.smartcard.commands.AddAdministatorCommand; import mixconfig.tools.dataretention.smartcard.commands.AddOperatorCommand; import mixconfig.tools.dataretention.smartcard.commands.ChangeAdministratorPinCommand; import mixconfig.tools.dataretention.smartcard.commands.ChangeOperatorPinCommand; import mixconfig.tools.dataretention.smartcard.commands.DataTransmissionCommand; import mixconfig.tools.dataretention.smartcard.commands.ErrorCodeException; import mixconfig.tools.dataretention.smartcard.commands.GetDateCommand; import mixconfig.tools.dataretention.smartcard.commands.GetLogEntryCommand; import mixconfig.tools.dataretention.smartcard.commands.GetLogSizeCommand; import mixconfig.tools.dataretention.smartcard.commands.GetNameOfAdministratorCommand; import mixconfig.tools.dataretention.smartcard.commands.GetNameOfOperatorCommand; import mixconfig.tools.dataretention.smartcard.commands.GetNeededNumberOfAdministratorsCommand; import mixconfig.tools.dataretention.smartcard.commands.GetNeededNumberOfOperatorsCommand; import mixconfig.tools.dataretention.smartcard.commands.GetNextDataPackageCommand; import mixconfig.tools.dataretention.smartcard.commands.GetNumberOfAdministratorsCommand; import mixconfig.tools.dataretention.smartcard.commands.GetNumberOfOperatorsCommand; import mixconfig.tools.dataretention.smartcard.commands.GetPublicKeyCommand; import mixconfig.tools.dataretention.smartcard.commands.GetVersionCommand; import mixconfig.tools.dataretention.smartcard.commands.IsAllowedToModifyAdministratorsCommand; import mixconfig.tools.dataretention.smartcard.commands.IsAllowedToModifyOperatorsCommand; import mixconfig.tools.dataretention.smartcard.commands.IsAllowedToModifyTimeserversCommand; import mixconfig.tools.dataretention.smartcard.commands.IsInitializedCommand; import mixconfig.tools.dataretention.smartcard.commands.RemoveAdministatorCommand; import mixconfig.tools.dataretention.smartcard.commands.RemoveOperatorCommand; import mixconfig.tools.dataretention.smartcard.commands.SetDateCommand; import mixconfig.tools.dataretention.smartcard.commands.SetNeededNumberOfAdministratorsCommand; import mixconfig.tools.dataretention.smartcard.commands.SetNeededNumberOfOperatorsCommand; import mixconfig.tools.dataretention.smartcard.commands.SetPermissionChangeSettingsCommand; import mixconfig.tools.dataretention.smartcard.commands.StartDataTransmissionCommand; import mixconfig.tools.dataretention.smartcard.commands.StartTransactionCommand; public class SmartCardProxy implements ISmartCard { private ConnectionManager connectionManager; public SmartCardProxy(ConnectionManager connectionManager) { this.connectionManager = connectionManager; } public void finalize() { connectionManager.disconnect(); } @Override public String getVersion() throws ErrorCodeException { GetVersionCommand command = new GetVersionCommand(); connectionManager.processCommand(command); return command.getVersion(); } @Override public void setNeededNumberOfAdministrators(int number) throws ErrorCodeException, IllegalArgumentException { if (number > ApduConstants.MAXIMAL_NUMBER_OF_ADMINISTRATORS || number <= 0) { throw new IllegalArgumentException("Needed Number of Administrators must be smaller equal " + ApduConstants.MAXIMAL_NUMBER_OF_ADMINISTRATORS + " and greater 0."); } SetNeededNumberOfAdministratorsCommand setNeededNumberOfAdministratorsCommand = new SetNeededNumberOfAdministratorsCommand((byte) number); connectionManager.processCommand(setNeededNumberOfAdministratorsCommand); } private static void checkAdministratorMap(Map administrators) { if (administrators == null) { return; } if (administrators.size() > ApduConstants.MAXIMAL_NUMBER_OF_ADMINISTRATORS || administrators.size() == 0) { throw new IllegalArgumentException("Invalid number of administrators (" + administrators.size() + "). Must be smaller equal " + ApduConstants.MAXIMAL_NUMBER_OF_ADMINISTRATORS + " and greater 0."); } for (String administrator : administrators.keySet()) { if (administrator.length() > ApduConstants.MAX_LENGTH_OF_ADMINISTRATOR_NAME) { throw new IllegalArgumentException("Name of Administrator " + administrator + " is to long (max. " + ApduConstants.MAX_LENGTH_OF_ADMINISTRATOR_NAME + ")."); } if (administrator.length() == 0) { throw new IllegalArgumentException("Names of Administrator must not be empty"); } if (administrators.get(administrator).length() != ApduConstants.LENGTH_OF_ADMINISTRATOR_PIN && (!administrators.get(administrator).equals(ApduConstants.PIN_NOT_SET))) { throw new IllegalArgumentException("PIN of Administrator " + administrator + " has invalid length (is " + administrators.get(administrator).length() + ", but should be " + ApduConstants.LENGTH_OF_ADMINISTRATOR_PIN + "). The PIN must not be " + ApduConstants.PIN_NOT_SET + "(Pin not set signal)."); } } } /** * * @param instruction * @param data * @return the last command, which contains the reply * @throws ErrorCodeException */ private AbstractCommand doDataTransmission(byte instruction, byte[] data) throws ErrorCodeException { int numberOfPackages = StartDataTransmissionCommand.getNumberOfPackages(data.length); System.out.println("Sending extended argument data in " + numberOfPackages + " packages."); // send header AbstractCommand dataTransmissionCommand = new StartDataTransmissionCommand(instruction, data); connectionManager.processCommand(dataTransmissionCommand); // send tail if (numberOfPackages > 1) { dataTransmissionCommand = new DataTransmissionCommand(data, StartDataTransmissionCommand.bytesPerStartDataTransmisionCommand); connectionManager.processCommand(dataTransmissionCommand); for (int i = 1; i < numberOfPackages; i++) { dataTransmissionCommand = new DataTransmissionCommand(data, i * DataTransmissionCommand.bytesPerDataTransmisionCommand); connectionManager.processCommand(dataTransmissionCommand); } } return dataTransmissionCommand; } @Override public void addAdministrator(String name, String pin) throws ErrorCodeException, IllegalArgumentException { checkUser(name, pin, ApduConstants.MAX_LENGTH_OF_ADMINISTRATOR_NAME, ApduConstants.LENGTH_OF_ADMINISTRATOR_PIN); AddAdministatorCommand addAdministatorCommand = new AddAdministatorCommand(name, pin); connectionManager.processCommand(addAdministatorCommand); } /** * Checks, if name and pin have the right length. * * @param name * @param pin * @param max_length_name * @param length_pin * @throws IllegalArgumentException */ private void checkUser(String name, String pin, int max_length_name, int length_pin) throws IllegalArgumentException { if (name.length() > max_length_name || name.length() == 0) { throw new IllegalArgumentException("Invalid length of username (" + name.length() + "). Must be smaller equal " + max_length_name + " and greater 0."); } if (pin.length() != length_pin) { throw new IllegalArgumentException("Invalid length of pin for user " + name + " (PIN Length: " + pin.length() + "). Must be " + length_pin + "."); } } @Override public void addOperator(String name, String pin) throws ErrorCodeException, IllegalArgumentException { checkUser(name, pin, ApduConstants.MAX_LENGTH_OF_OPERATOR_NAME, ApduConstants.LENGTH_OF_OPERATOR_PIN); AddOperatorCommand addOperatorCommand = new AddOperatorCommand(name, pin); connectionManager.processCommand(addOperatorCommand); } @Override public void changeAdministratorPin(String name, String oldPin, String newPin) throws ErrorCodeException { ChangeAdministratorPinCommand changeAdministratorPinCommand = new ChangeAdministratorPinCommand(name, oldPin, newPin); connectionManager.processCommand(changeAdministratorPinCommand); } @Override public void changeOperatorPin(String name, String oldPin, String newPin) throws ErrorCodeException { ChangeOperatorPinCommand changeOperatorPinCommand = new ChangeOperatorPinCommand(name, oldPin, newPin); connectionManager.processCommand(changeOperatorPinCommand); } @Override public void commitTransaction(Map administrators) throws ErrorCodeException, IllegalArgumentException { checkAdministratorMap(administrators); doDataTransmission(ApduConstants.INSTRUCTION_COMMIT_TRANSACTION, Helpers.packUsers(administrators)); } @Override public int getRandomNumberForTimeServerCommunication() { // TODO Auto-generated method stub return 0; } @Override public void removeAdministrator(String name) throws ErrorCodeException { RemoveAdministatorCommand removeAdministatorCommand = new RemoveAdministatorCommand(name); connectionManager.processCommand(removeAdministatorCommand); } @Override public void removeOperator(String name) throws ErrorCodeException { RemoveOperatorCommand removeOperatorCommand = new RemoveOperatorCommand(name); connectionManager.processCommand(removeOperatorCommand); } @Override public void setNeededNumberOfOperators(int number) throws ErrorCodeException, IllegalArgumentException { if (number > ApduConstants.MAXIMAL_NUMBER_OF_OPERATORS || number <= 0) { throw new IllegalArgumentException("Needed Number of Operators must be smaller equal " + ApduConstants.MAX_LENGTH_OF_OPERATOR_NAME + " and greater 0."); } SetNeededNumberOfOperatorsCommand setNeededNumberOfOperatorsCommand = new SetNeededNumberOfOperatorsCommand((byte) number); connectionManager.processCommand(setNeededNumberOfOperatorsCommand); } @Override public void setPermissionChangeSettings(boolean allowedToModifyAdministrators, boolean allowedToModifyOperators, boolean allowedToModifyTimeServers) throws ErrorCodeException { SetPermissionChangeSettingsCommand setPermissionChangeSettingsCommand = new SetPermissionChangeSettingsCommand(allowedToModifyAdministrators, allowedToModifyOperators, allowedToModifyTimeServers); connectionManager.processCommand(setPermissionChangeSettingsCommand); } @Override public void startTransaction() { StartTransactionCommand startTransactionCommand = new StartTransactionCommand(); try { connectionManager.processCommand(startTransactionCommand); } catch (ErrorCodeException e) { // impossible e.printStackTrace(); } } @Override public List getAdministrators() { GetNumberOfAdministratorsCommand getNumberOfAdministratorsCommand = new GetNumberOfAdministratorsCommand(); try { connectionManager.processCommand(getNumberOfAdministratorsCommand); } catch (ErrorCodeException e) { // impossible e.printStackTrace(); } List administrators = new LinkedList(); for (int i = 0; i < getNumberOfAdministratorsCommand.getNumberOfAdministrators(); i++) { GetNameOfAdministratorCommand getNameOfAdministratorCommand = new GetNameOfAdministratorCommand(i); try { connectionManager.processCommand(getNameOfAdministratorCommand); administrators.add(getNameOfAdministratorCommand.getName()); } catch (ErrorCodeException e) { // should not happen e.printStackTrace(); } } return administrators; } @Override public List getOperators() { GetNumberOfOperatorsCommand getNumberOfOperatorsCommand = new GetNumberOfOperatorsCommand(); try { connectionManager.processCommand(getNumberOfOperatorsCommand); } catch (ErrorCodeException e) { // impossible e.printStackTrace(); } List operators = new LinkedList(); for (int i = 0; i < getNumberOfOperatorsCommand.getNumberOfOperators(); i++) { GetNameOfOperatorCommand getNameOfOperatorCommand = new GetNameOfOperatorCommand(i); try { connectionManager.processCommand(getNameOfOperatorCommand); operators.add(getNameOfOperatorCommand.getName()); } catch (ErrorCodeException e) { // should not happen e.printStackTrace(); } } return operators; } @Override public boolean isAllowedToModifyAdministrators() { IsAllowedToModifyAdministratorsCommand isAllowedToModifyAdministratorsCommand = new IsAllowedToModifyAdministratorsCommand(); try { connectionManager.processCommand(isAllowedToModifyAdministratorsCommand); } catch (ErrorCodeException e) { // impossible e.printStackTrace(); } return isAllowedToModifyAdministratorsCommand.isAllowed(); } @Override public boolean isAllowedToModifyOperators() { IsAllowedToModifyOperatorsCommand isAllowedToModifyOperatorsCommand = new IsAllowedToModifyOperatorsCommand(); try { connectionManager.processCommand(isAllowedToModifyOperatorsCommand); } catch (ErrorCodeException e) { // impossible e.printStackTrace(); } return isAllowedToModifyOperatorsCommand.isAllowed(); } @Override public boolean isAllowedToModifyTimeServers() { IsAllowedToModifyTimeserversCommand isAllowedToModifyTimeserversCommand = new IsAllowedToModifyTimeserversCommand(); try { connectionManager.processCommand(isAllowedToModifyTimeserversCommand); } catch (ErrorCodeException e) { // impossible e.printStackTrace(); } return isAllowedToModifyTimeserversCommand.isAllowed(); } @Override public MyRSAPublicKey getPublicKey() throws ErrorCodeException { GetPublicKeyCommand getPublicKeyCommand = new GetPublicKeyCommand(); connectionManager.processCommand(getPublicKeyCommand); byte[] response = getExtendedResponse(getPublicKeyCommand.size()); return getPublicKeyCommand.getPublicKey(response); } @Override public boolean isInitialized() { IsInitializedCommand isInitializedCommand = new IsInitializedCommand(); try { connectionManager.processCommand(isInitializedCommand); } catch (ErrorCodeException e) { // impossible e.printStackTrace(); } return isInitializedCommand.isInitialized(); } @Override public void abortTransaction() { AbortTransactionCommand abortTransactionCommand = new AbortTransactionCommand(); try { connectionManager.processCommand(abortTransactionCommand); } catch (ErrorCodeException e) { // impossible e.printStackTrace(); } } @Override public List getLog() { GetLogSizeCommand getLogSizeCommand = new GetLogSizeCommand(); try { connectionManager.processCommand(getLogSizeCommand); } catch (ErrorCodeException e) { // impossible e.printStackTrace(); } List log = new LinkedList(); for (int i = 0; i < getLogSizeCommand.getSize(); i++) { GetLogEntryCommand getLogEntryCommand = new GetLogEntryCommand(i); try { connectionManager.processCommand(getLogEntryCommand); int logEntryLength = getLogEntryCommand.getLength(); byte[] response = getExtendedResponse(logEntryLength); log.add(new LogEntry(response[0] + "", Helpers.utf8BytesToString(Helpers.copyOfRange(response, 2, response.length - 2)), (response[1] == ApduConstants.TRUE))); } catch (ErrorCodeException e) { // should not happen e.printStackTrace(); } } return log; } private byte[] getExtendedResponse(int length) throws ErrorCodeException { byte[] response = new byte[length]; int offset = 0; while (offset < length) { GetNextDataPackageCommand getNextDataPackageCommand = new GetNextDataPackageCommand(); connectionManager.processCommand(getNextDataPackageCommand); byte[] data = getNextDataPackageCommand.getData(); for (int i = 0; i < data.length; i++) { response[offset + i] = data[i]; } offset += data.length; } return response; } @Override public int getNeededNumberOfAdministrators() { GetNeededNumberOfAdministratorsCommand getNeededNumberOfAdministratorsCommand = new GetNeededNumberOfAdministratorsCommand(); try { connectionManager.processCommand(getNeededNumberOfAdministratorsCommand); } catch (ErrorCodeException e) { // impossible e.printStackTrace(); } return getNeededNumberOfAdministratorsCommand.getNeededNumber(); } @Override public int getNeededNumberOfOperators() { GetNeededNumberOfOperatorsCommand getNeededNumberOfOperatorsCommand = new GetNeededNumberOfOperatorsCommand(); try { connectionManager.processCommand(getNeededNumberOfOperatorsCommand); } catch (ErrorCodeException e) { // impossible e.printStackTrace(); } return getNeededNumberOfOperatorsCommand.getNeededNumber(); } @Override public Map getTimeServers() { // TODO Auto-generated method stub return null; } @Override public void addTimeServer(String uri, String publicKey) { // TODO Auto-generated method stub } @Override public void removeTimeServer(String uri) { // TODO Auto-generated method stub } @Override public int getNeededNumberOfTimeservers() { // TODO Auto-generated method stub return 0; } @Override public void setNeededNumberOfTimeServers(int number) { // TODO Auto-generated method stub } @Override public int getSymmetricKeyForLogFiles(int encryptedSymmetricKey, Map operators) { //TODO: implement return 0; } @Override public void resetLog(Map administrators) throws ErrorCodeException, IllegalArgumentException { checkAdministratorMap(administrators); doDataTransmission(ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_LOG, Helpers.packUsers(administrators)); } @Override public void resetCard(Map administrators) throws ErrorCodeException, IllegalArgumentException { checkAdministratorMap(administrators); doDataTransmission(ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_CARD, Helpers.packUsers(administrators)); } @Override public Date getDate() throws ErrorCodeException { GetDateCommand getDateCommand = new GetDateCommand(); connectionManager.processCommand(getDateCommand); return getDateCommand.getDate(); } @Override public void setDate(Date date) throws IllegalArgumentException, ErrorCodeException { if (date == null) { throw new IllegalArgumentException("Date must not be null."); } SetDateCommand setDateCommand = new SetDateCommand(date); connectionManager.processCommand(setDateCommand); } }