Merge c1a54fcde9aafe092ae341870fb3a1779072829f on remote branch
Change-Id: Ic41d94fcbe2fb61453ab7b7b40185f7d80ec924e
diff --git a/README.md b/README.md
index ca5588c..bd86d4f 100644
--- a/README.md
+++ b/README.md
@@ -1,34 +1,34 @@
# nfcandroid_frameworks
-#### Supported Versions on "br_android_ncihalx_q branch
-
+#### Supported Version on "br_android_ncihalx_comm_13" branch
| Android Version | NXP Release | NXP Tag |
| :-------------: |:---------------------:| :-----:|
-| aosp-master | 10.00.04 (SN100x) | NFC_AR_00_2000_10.00.04_OpnSrc |
-| aosp-master | 10.00.06 (SN100x) | NFC_AR_00_6000_10.00.06_OpnSrc |
-| aosp-master | 10.00.08 (SN100x) | NFC_AR_00_6000_10.00.08_OpnSrc |
-| aosp-master | 10.00.0A (SN110) | NFC_AR_00_6000_10.00.0A_OpnSrc |
-| aosp-master | 10.00.0B (SN100) | NFC_AR_00_6000_10.00.0B_OpnSrc |
-| aosp-master | 10.00.0C (SN110) | NFC_AR_00_6000_10.00.0C_OpnSrc |
-| android-10.0.0_r2 | 10.00.0D (SN110) | NFC_AR_00_6000_10.00.0D_OpnSrc |
-| android-10.0.0_r2 | 10.00.0F (SN110) | NFC_AR_00_6000_10.00.0F_OpnSrc |
-
-#### Supported Version on "br_android_ncihalx_11" branch
-| Android Version | NXP Release | NXP Tag |
-| :-------------: |:---------------------:| :-----:|
-| aosp-master | 11.01.00 (SN110) | NFC_AR_00_6000_11.01.00_OpnSrc |
-| aosp-master | 11.02.00 (SN110) | NFC_AR_00_6000_11.02.00_OpnSrc |
+| aosp-master | 13.02.01 (SN100/SN110/SN220) | NFC_AR_00_E800_13.02.01_OpnSrc |
+| aosp-master | 13.03.00 (SN100/SN110/SN220) | NFC_AR_00_E800_13.03.00_OpnSrc || AOSP-MASTER | 13.03.00 (SN100/SN110/SN220) | NFC_AR_00_E800_13.03.00_OpnSrc |
-#### Supported Version on "br_android_ncihalx_comm_12" branch
-| Android Version | NXP Release | NXP Tag |
-| :-------------: |:---------------------:| :-----:|
-| aosp-master | 12.51.00 (SN110) | NFC_AR_00_02.00_6000_12.51.00_OpnSrc |
-| aosp-master | 12.02.01 (SN100/SN110/SN220) | NFC_AR_00_E000_12.02.01_OpnSrc |
-| aosp-master | 12.04.01 (SN100/SN110/SN220)| NFC_AR_00_E000_12.04.01_OpnSrc |
-#### Supported Version on "br_android_ncihalx_row_12" branch
-| Android Version | NXP Release | NXP Tag |
-| :-------------: |:---------------------:| :-----:|
-| aosp-master | 12.01.00 (PN80T/PN81T/PN553/PN557) | NFC_AR_00_18C0_12.01.00_OpnSrc |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/com/nxp/nfc/INxpNfcAdapter.aidl b/com/nxp/nfc/INxpNfcAdapter.aidl
index c5d4719..f53d942 100644
--- a/com/nxp/nfc/INxpNfcAdapter.aidl
+++ b/com/nxp/nfc/INxpNfcAdapter.aidl
@@ -33,8 +33,6 @@
void changeDiscoveryTech(IBinder binder, int pollTech, int listenTech);
void startPoll(String pkg);
byte[] getFWVersion();
- byte[] readerPassThruMode(byte status, byte modulationTyp);
- byte[] transceiveAppData(in byte[] data);
int setConfig(String configs , String pkg);
int selectUicc(int uiccSlot);
int getMaxAidRoutingTableSize();
@@ -48,4 +46,9 @@
byte[] doReadT4tData(in byte[] fileId);
int nfcSelfTest(int type);
int configureSecureReader(boolean on, String readerType);
+ int startExtendedFieldDetectMode(int detectionTimeout);
+ int stopExtendedFieldDetectMode();
+ int startRssiMode(int rssiNtfTimeIntervalInMillisec);
+ int stopRssiMode();
+ boolean isRssiEnabled();
}
diff --git a/com/nxp/nfc/NxpNfcAdapter.java b/com/nxp/nfc/NxpNfcAdapter.java
index 93d58c2..e6cc80a 100644
--- a/com/nxp/nfc/NxpNfcAdapter.java
+++ b/com/nxp/nfc/NxpNfcAdapter.java
@@ -110,6 +110,7 @@
*/
private static void attemptDeadServiceRecovery(Exception e) {
Log.e(TAG, "Service dead - attempting to recover",e);
+ sIsInitialized = false;
INfcAdapter service = getServiceInterface();
if (service == null) {
Log.e(TAG, "could not retrieve NFC service during service recovery");
@@ -121,6 +122,9 @@
// and on a well-behaved system should never happen
sService = service;
sNxpService = getNxpNfcAdapterInterface();
+ if (sNxpService != null) {
+ sIsInitialized = true;
+ }
return;
}
/**
@@ -558,24 +562,6 @@
}
}
- public byte[] readerPassThruMode(byte status, byte modulationTyp)
- throws IOException {
- try {
- return sNxpService.readerPassThruMode(status, modulationTyp);
- } catch (RemoteException e) {
- Log.e(TAG, "Remote exception in readerPassThruMode(): ", e);
- throw new IOException("Remote exception in readerPassThruMode()");
- }
- }
-
- public byte[] transceiveAppData(byte[] data) throws IOException {
- try {
- return sNxpService.transceiveAppData(data);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in transceiveAppData(): ", e);
- throw new IOException("RemoteException in transceiveAppData()");
- }
- }
/**
* This api is called by applications to update the NFC configurations which
* are already part of libnfc-nxp.conf and libnfc-brcm.conf <p>Requires
@@ -698,6 +684,84 @@
}
/**
+ * This api is called by applications to start RSSI mode.
+ * Once RSSI is enabled, RSSI data notifications are broadcasted to registered
+ * application when the device is in the reader field. Application can then
+ * analyze this data and find best position for transaction.
+ * <p>Requires {@link android.Manifest.permission#NFC} permission.<ul>
+ * <li>This api shall be called only after Nfcservice is enabled.
+
+ * </ul>
+ * @param rssiNtfTimeIntervalInMillisec to set time interval between RSSI
+ * notification in milliseconds. It is recommended that this value is
+ * greater than 10 millisecs and multiple of 10.
+ * @return whether the update of configuration is
+ * success or not with reason.
+ * 0x01 - NFC_IS_OFF,
+ * 0x02 - NFC_BUSY_IN_MPOS
+ * 0x03 - ERROR_UNKNOWN
+ * 0x00 - SUCCESS
+ * @throws IOException if any exception occurs during setting the NFC configuration.
+ */
+ public int startRssiMode(int rssiNtfTimeIntervalInMillisec) {
+ try {
+ return sNxpService.startRssiMode(rssiNtfTimeIntervalInMillisec);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ attemptDeadServiceRecovery(e);
+ return 0x03; /*ERROR_UNKNOWN*/
+ }
+ }
+
+ /**
+ * This api is called by applications to stop RSSI mode
+ * <p>Requires {@link android.Manifest.permission#NFC} permission.<ul>
+ * <li>This api shall be called only after Nfcservice is enabled.
+
+ * </ul>
+ * @param None
+ * @return whether the update of configuration is
+ * success or not with reason.
+ * 0x01 - NFC_IS_OFF,
+ * 0x02 - NFC_BUSY_IN_MPOS
+ * 0x03 - ERROR_UNKNOWN
+ * 0x00 - SUCCESS
+ * @throws IOException if any exception occurs during setting the NFC configuration.
+ */
+ public int stopRssiMode() {
+ try {
+ return sNxpService.stopRssiMode();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ attemptDeadServiceRecovery(e);
+ return 0x03; /*ERROR_UNKNOWN*/
+ }
+ }
+
+ /**
+ * This api is called by applications to check whether RSSI is enabled or not
+ * <p>Requires {@link android.Manifest.permission#NFC} permission.<ul>
+ * <li>This api shall be called only after Nfcservice is enabled.
+
+ * </ul>
+ * @param None
+ * @return whether the feature is enabled(true) disabled (false)
+ * success or not.
+ * Enabled - true
+ * Disabled - false
+ * @throws IOException if any exception occurs during setting the NFC configuration.
+ */
+ public boolean isRssiEnabled() {
+ try {
+ return sNxpService.isRssiEnabled();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ attemptDeadServiceRecovery(e);
+ return false;
+ }
+ }
+
+ /**
* This api is called by applications to Activate Secure Element Interface.
* <p>Requires {@link android.Manifest.permission#NFC} permission.<ul>
* <li>This api shall be called only Nfcservice is enabled.
@@ -787,4 +851,44 @@
return null;
}
}
+ /**
+ * This API starts extended field detect mode.
+ * @param detectionTimeout : The time after 1st RF ON to
+ * exit extended filed detect mode(msec).
+ * @return status :-0x00 :EFDSTATUS_SUCCESS
+ * 0x01 :EFDSTATUS_FAILED
+ * 0x02 :EFDSTATUS_ERROR_ALREADY_STARTED
+ * 0x03 :EFDSTATUS_ERROR_FEATURE_NOT_SUPPORTED
+ * 0x04 :EFDSTATUS_ERROR_FEATURE_DISABLED_IN_CONFIG
+ * 0x05 :EFDSTATUS_ERROR_NFC_IS_OFF
+ * 0x06 :EFDSTATUS_ERROR_UNKNOWN
+ * <p>Requires {@link android.Manifest.permission#NFC} permission.
+ */
+ public int startExtendedFieldDetectMode(int detectionTimeout) {
+ try {
+ return sNxpService.startExtendedFieldDetectMode(detectionTimeout);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ attemptDeadServiceRecovery(e);
+ return 0x06; /*EFDSTATUS_ERROR_UNKNOWN*/
+ }
+ }
+ /**
+ * This API stops extended field detect mode.
+ * @return status :-0x00 :EFDSTATUS_SUCCESS
+ * 0x01 :EFDSTATUS_FAILED
+ * 0x05 :EFDSTATUS_ERROR_NFC_IS_OFF
+ * 0x06 :EFDSTATUS_ERROR_UNKNOWN
+ * 0x07 :EFDSTATUS_ERROR_NOT_STARTED
+ * <p>Requires {@link android.Manifest.permission#NFC} permission.
+ */
+ public int stopExtendedFieldDetectMode() {
+ try {
+ return sNxpService.stopExtendedFieldDetectMode();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ attemptDeadServiceRecovery(e);
+ return 0x06; /*EFDSTATUS_ERROR_UNKNOWN*/
+ }
+ }
}
diff --git a/sems/com/nxp/sems/SemsAgent.java b/sems/com/nxp/sems/SemsAgent.java
index 350bc08..4a15f35 100644
--- a/sems/com/nxp/sems/SemsAgent.java
+++ b/sems/com/nxp/sems/SemsAgent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2021 NXP
+ * Copyright 2019-2022 NXP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,8 +39,11 @@
public static final byte SEMS_STATUS_BUSY = 0x02;
public static final byte SEMS_STATUS_DENIED = 0x03;
public static final byte SEMS_STATUS_UNKNOWN = 0x0F;
+ public static final byte SEMS_STATUS_HASH_INVALID = 0x04;
+ public String SEMS_HASH_TYPE_SHA1 = "SHA1";
+ public String SEMS_HASH_TYPE_SHA256 = "SHA256";
public static final short major = 1;
- public static final short minor = 1;
+ public static final short minor = 3;
private static final byte DEFAULT_TERMINAL_ID = 1;
private static SemsAgent sInstance;
@@ -50,7 +53,6 @@
private SemsExecutor mExecutor = null;
public static Object semsObj = new Object();
public static boolean flagSemsObj = false;
-
/**
* Returns SemsAgent singleton object
* <br/>
@@ -63,14 +65,16 @@
if (context == null) {
throw new SemsException("Context information invalid/null");
}
- if (sInstance == null) {
- synchronized (SemsAgent.class) { sInstance = new SemsAgent(); }
+ synchronized (SemsAgent.class) {
+ if (sInstance == null) {
+ sInstance = new SemsAgent();
+ }
+ if (context != sContext) {
+ sContext = context;
+ }
+ Log.d(TAG, "Sems Agent version " + major + "." + minor);
+ return sInstance;
}
- if (context != sContext) {
- sContext = context;
- }
- Log.d(TAG, "Sems Agent version " + major + "." + minor);
- return sInstance;
}
private SemsAgent() {}
@@ -199,4 +203,50 @@
throw new SemsException("Unable to get last sems execute status");
}
}
+
+ /**
+ * Get Hash type of the algorithm execution.
+ * <br/>
+ * Returns response SHAType to Application
+ * From SEMS
+ *
+ * @return Hash algorithm type used by SEMS
+ * script.
+ */
+ public String GetHashAlgorithm() throws SemsException {
+ Log.d(TAG, "GetHashAlgorithm");
+ try {
+ mSemsApduChannel = SemsApduChannelFactory.getInstance(
+ SemsApduChannelFactory.OMAPI_CHANNEL, sContext, sTerminalID);
+ mExecutor = SemsExecutor.getInstance(mSemsApduChannel, sContext);
+ return mExecutor.getHashAlgorithm();
+ } catch (Exception e) {
+ throw new SemsException("Unable to get Hash type");
+ }
+ }
+
+ /**
+ * Set Hash type of the algorithm execution.
+ * <br/>
+ * Set response SHAType to Application
+ * From SEMS
+ * @param Hash algorithm type used by SEMS
+ * to set
+ * @return {@code status} 0 in SUCCESS, otherwise SEMS_STATUS_HASH_INVALID in failure
+ */
+ public int SetHashAlgorithm(String semsHashAlgoType) throws SemsException {
+ Log.d(TAG, "SetHashAlgorithm");
+ try {
+ if ((semsHashAlgoType != SEMS_HASH_TYPE_SHA1)
+ && (semsHashAlgoType != SEMS_HASH_TYPE_SHA256)) {
+ return SEMS_STATUS_HASH_INVALID;
+ }
+ mSemsApduChannel = SemsApduChannelFactory.getInstance(
+ SemsApduChannelFactory.OMAPI_CHANNEL, sContext, sTerminalID);
+ mExecutor = SemsExecutor.getInstance(mSemsApduChannel, sContext);
+ return mExecutor.setHashAlgorithm(semsHashAlgoType);
+ } catch (Exception e) {
+ throw new SemsException("Unable to set Hash type");
+ }
+ }
}
diff --git a/sems/com/nxp/sems/channel/SemsApduChannelFactory.java b/sems/com/nxp/sems/channel/SemsApduChannelFactory.java
index db8170a..d64fc8e 100644
--- a/sems/com/nxp/sems/channel/SemsApduChannelFactory.java
+++ b/sems/com/nxp/sems/channel/SemsApduChannelFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 NXP
+ * Copyright 2019,2022 NXP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,16 +29,14 @@
public static ISemsApduChannel getInstance(byte type, Context context,
byte terminalID) throws SemsException{
- if(mChannelFactory == null) {
synchronized (SemsApduChannelFactory.class) {
if(mChannelFactory == null) {
Log.d(TAG, "SemsApduChannelFactory Initialization");
mChannelFactory = (ISemsApduChannel) SemsApduChannelFactory.
createApduChannel(type, context, terminalID);
}
+ return mChannelFactory;
}
- }
- return mChannelFactory;
}
private SemsApduChannelFactory() {}
diff --git a/sems/com/nxp/sems/semscore/SemsAppletIdentifier.java b/sems/com/nxp/sems/semscore/SemsAppletIdentifier.java
new file mode 100644
index 0000000..57ff3b6
--- /dev/null
+++ b/sems/com/nxp/sems/semscore/SemsAppletIdentifier.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2021-2022 NXP
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.nxp.sems;
+
+import android.util.Log;
+import com.nxp.sems.SemsTLV;
+import com.nxp.sems.SemsUtil;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class SemsAppletIdentifier {
+ public static final String TAG = "SemsAppletIdentifier";
+ private static SemsTLV tlv5D, tlv5E;
+
+ /*Track line number in script Apdu.*/
+ private static int lineCounter;
+ private static boolean isTAG73Supported;
+ private static int tag73Len;
+ private static int commandNumber;
+ private static int delayInMillsec;
+
+ /*Strong Box Applet Identifier ASCII value*/
+ private static final byte[] SEMS_SB_APP_ID = SemsUtil.parseHexString("5374726F6E67426F78");
+
+ /**
+ * Validate TAG and subtag support.
+ * And, set flag as true if pre-condition meet.
+ * <br/>
+ * Sems Agent shall introduce delay on Nth Command.
+ * @param TLV certifacte in ScriptTLV.
+ *
+ * @return void.
+ */
+ protected static void validateTag73Support(SemsTLV tlvCertInScript) throws Exception {
+ Log.d(TAG, "***Initalize the variable to default values..**");
+ lineCounter = 0;
+ isTAG73Supported = false;
+ tlv5D = null;
+ tlv5E = null;
+ tag73Len = 0;
+ SemsTLV tlv5C, tlv73;
+ List<SemsTLV> tlvs = SemsTLV.parse(tlvCertInScript.getValue());
+ if (tlvs == null) {
+ Log.d(TAG, "tlvCertInScript null");
+ return;
+ }
+ tlv73 = SemsTLV.find(tlvs, 0x73);
+ if (tlv73 == null) {
+ Log.d(TAG, "tag73 is null");
+ return;
+ }
+ // Parse outer T-L-V TAG73 for inner tags 5C, 5D and 5E
+ tlvs = SemsTLV.parse(tlv73.getValue());
+ tlv5C = SemsTLV.find(tlvs, 0x5C);
+ if (tlv5C == null) {
+ Log.d(TAG, "tlv5C is null");
+ return;
+ }
+ if (!Arrays.equals(tlv5C.getValue(), SEMS_SB_APP_ID)) {
+ Log.d(TAG, "Is not SB Applet");
+ return;
+ }
+ tlv5D = SemsTLV.find(tlvs, 0x5D);
+ if (tlv5D == null) {
+ Log.d(TAG, "tlv5D is null");
+ return;
+ }
+ commandNumber = arrayToValue(tlv5D.getValue());
+ tlv5E = SemsTLV.find(tlvs, 0x5E);
+ if (tlv5E == null) {
+ Log.d(TAG, "tlv5E is null");
+ return;
+ }
+ delayInMillsec = arrayToValue(tlv5E.getValue());
+ if (delayInMillsec != 0x00) {
+ Log.d(TAG,
+ "***TAG 73 and sub-tag 5C,5D " + commandNumber + " 5E " + delayInMillsec
+ + " are supported.**");
+ isTAG73Supported = true;
+ return;
+ } else {
+ Log.d(TAG, "Invalid delayInMillsec");
+ }
+ }
+
+ /**
+ * No of command in the script before sending it to SEMS applet,
+ * introduce delay (Delay in msec).
+ * <br/>
+ *
+ * @return void.
+ */
+ protected static void delayNthCommand() {
+ try {
+ if (isTAG73Supported) {
+ lineCounter++;
+ if (lineCounter == commandNumber) {
+ Log.d(TAG, " Add Delay " + delayInMillsec);
+ TimeUnit.MILLISECONDS.sleep(delayInMillsec);
+ }
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Get TAG 73 Length(Inclusive of TAG and Length field).
+ * <br/>
+ *
+ * @return int: TAG73 Length.
+ */
+ protected static int getTag73Len() {
+ /*Include TAG & LENGTH field 2 bytes*/
+ return (isTAG73Supported ? (tag73Len + 2) : 0);
+ }
+
+ /**
+ * Calculate integer from byte array.
+ * <br/>
+ *
+ * @return int: summed up array value
+ */
+ protected static int arrayToValue(byte[] arr) {
+ int temp = 0;
+ int len = arr.length;
+ /*Length cannot be more than 4 bytes*/
+ if (len > 4)
+ return 0;
+
+ if (len == 1)
+ temp = (arr[0] & 0xFF);
+ else if (len == 2)
+ temp = (arr[0] << 8) & 0xFF00 | (arr[1] & 0xFF);
+ else if (len == 3)
+ temp = (arr[0] << 16) & 0xFF0000 | (arr[1] << 8) & 0xFF00 | (arr[2] & 0xFF);
+ else if (len == 4)
+ temp = (arr[0] << 24) | (arr[1] << 16) & 0xFF0000 | (arr[2] << 8) & 0xFF00 | (arr[3] & 0xFF);
+
+ return temp;
+ }
+}
diff --git a/sems/com/nxp/sems/semscore/SemsExecutor.java b/sems/com/nxp/sems/semscore/SemsExecutor.java
index 5cc7ec9..fe1ab11 100644
--- a/sems/com/nxp/sems/semscore/SemsExecutor.java
+++ b/sems/com/nxp/sems/semscore/SemsExecutor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2021 NXP
+ * Copyright 2019-2022 NXP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,26 +16,20 @@
package com.nxp.sems;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Vector;
-
+import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;
+import com.nxp.sems.ISemsCallback;
+import com.nxp.sems.SemsFileOperation;
+import com.nxp.sems.SemsGetLastExecStatus;
+import com.nxp.sems.SemsStatus;
import com.nxp.sems.SemsTLV;
import com.nxp.sems.SemsUtil;
import com.nxp.sems.channel.ISemsApduChannel;
-import com.nxp.sems.ISemsCallback;
-import com.nxp.sems.SemsStatus;
-import com.nxp.sems.SemsGetLastExecStatus;
-import android.content.Context;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
public class SemsExecutor {
@@ -51,18 +45,19 @@
public static final byte SEMS_CERTIFICATE_SIGNATURE_5F37_LEN = 64;
public static final byte SEMS_CERTIFICATE_SIGNATURE_7F49_86_LEN = 67;
+ public static final short MAX_FRAME_SIZE = 255;
+ public static final int TAG73 = 0x73;
+ public static final int TAG5F37 = 0x5F37;
private static ISemsApduChannel sChannel;
private final byte basicChannel = 0x00;
- private String callerPackageName;
- private static String sRespOutlog;
+ private String shatype;
private byte[] AID_MEM;
- private String encryptedScriptDirectory = "";
- private String outDirectory = "";
+ private ISemsCallback mSemsCallback;
+ private static Context sContext;
+ private SemsFileOperation mSemsFileOp;
private String inputScript;
private String outputScript;
- private ISemsCallback mSemsCallback;
- private static Context mContext;
private int certIndex = -1;
private byte[] rapduSelect;
@@ -73,6 +68,8 @@
private boolean lsCommandSeen = false;
private byte mState;
private static SemsExecutor sSemsExecutor;
+ public String SEMS_HASH_TYPE_SHA1 = "SHA1";
+ public String SEMS_HASH_TYPE_SHA256 = "SHA256";
/**
* AID of the SEMS Application Instance.
*/
@@ -106,8 +103,7 @@
public static SemsExecutor getInstance(ISemsApduChannel semsChannel,
Context context) {
sChannel = semsChannel;
- mContext = context;
- sRespOutlog = "";
+ sContext = context;
if (sSemsExecutor == null) {
sSemsExecutor = new SemsExecutor();
}
@@ -115,150 +111,47 @@
}
private SemsExecutor() {
this.AID_MEM = SEMS_APP_AID;
+ this.shatype = SEMS_HASH_TYPE_SHA1;
+ mSemsFileOp = new SemsFileOperation();
}
/**
- * Logging the response APDU received during SEMS execution
+ * Set Hash type of the algorithm execution.
* <br/>
- * The Input type of response,
- * The Input status bytes
- * Agent to provide the SEMS Application with an identifier
- * @param void
- *
- * @return {@code true} if the SW returned is 9000, {@code false} otherwise.
+ * @param Hash algorithm type used by SEMS
+ * to set
+ * @return {@code status} 0 in SUCCESS, otherwise -1 in failure
*/
- private void putIntoLog(byte[] what, byte type) {
- byte[] data;
-
- /*Skip responses ending with SW '6310'*/
- if ((what[what.length - 2] == 0x63) && (what[what.length - 1] == 0x10)) {
- return;
- }
-
- switch (type) {
- case ErrorResponse:
- return;
- default:
- return;
-
- case SemsCertResponse:
- data = new byte[] {0x7F, 0x21};
- break;
- case SemsAuthResponse:
- data = new byte[] {0x60};
- break;
- case SemsResponse:
- data = new byte[] {0x40};
- break;
- }
-
- data = SemsTLV.make(0x61, SemsUtil.append(SemsTLV.make(0x43, data),
- SemsTLV.make(0x44, what)));
- sRespOutlog = sRespOutlog + SemsUtil.toHexString(data) + "\r\n";
+ public synchronized int setHashAlgorithm(String shaType) {
+ this.shatype = shaType;
+ return 0;
}
/**
- * Set the current application directory & caller information
+ * Get Hash type of the algorithm execution.
* <br/>
- * The Input Logical channel,
- * The Input the AID to be selected
- * Agent to provide the SEMS Application with an identifier
- * @param void
+ * Returns response SHAType to Application
+ * From SEMS
*
- * @return {@code true} if the SW returned is 9000, {@code false} otherwise.
+ * @return SHAType use for Hash
+ * script.
*/
- private SemsStatus setDirectories() {
- SemsStatus status = SemsStatus.SEMS_STATUS_FAILED;
- PackageInfo pInfo;
- PackageManager pm = mContext.getPackageManager();
- String str = mContext.getPackageName();
-
- try {
- pInfo = pm.getPackageInfo(str, 0);
- str = pInfo.applicationInfo.dataDir;
- this.callerPackageName = pInfo.packageName;
- this.encryptedScriptDirectory = str;
- this.outDirectory = str;
- status = SemsStatus.SEMS_STATUS_SUCCESS;
- } catch (Exception e) {
- e.printStackTrace();
- }
- return status;
- }
-
- private static Path getPath(String dir, String file) {
- return (dir != null) ? FileSystems.getDefault().getPath(dir, file)
- : FileSystems.getDefault().getPath(file);
- }
- /**
- * Write the content of String buffer to out file
- * <br/>
- * The Input Logical channel,
- * The Input the AID to be selected
- * Agent to provide the SEMS Application with an identifier
- * @param void
- *
- * @return {@code true} if the SW returned is 9000, {@code false} otherwise.
- */
- private byte[] writeScriptOutFile(String scriptOut) {
- Path p = getPath(outDirectory, scriptOut);
- try {
- Files.write(p, sRespOutlog.getBytes());
- } catch (IOException e) {
- Log.e(TAG, "IOException during writeScriptOutfile: ");
- }
- return sRespOutlog.getBytes();
+ public synchronized String getHashAlgorithm() {
+ return shatype;
}
/**
- * Write the content of String buffer to backup file
+ * Check Hash type of the algorithm execution.
* <br/>
- * The Input Logical channel,
- * The Input the AID to be selected
- * Agent to provide the SEMS Application with an identifier
- * @param void
+ * Returns response True if shatype is SHA256
*
- * @return {@code true} if the SW returned is 9000, {@code false} otherwise.
- */
- private byte[] writeScriptInputFile(String filename, String scriptBuffer) {
- Path p = getPath(outDirectory, filename);
- try {
- Files.write(p, scriptBuffer.getBytes());
- } catch (IOException e) {
- Log.e(TAG, "IOException during writeScriptInputfile: ");
- }
- return scriptBuffer.getBytes();
- }
-
- /**
- * Read the file content to String format
- * <br/>
- * The Input path of the SEMS encrypted script stored,
- * Agent to provide the SEMS Application with an identifier
- * @param void
- *
- * @return {@code true} if the SW returned is 9000, {@code false} otherwise.
+ * @return boolean TRUE for SHA256 ShaHash type
*/
- private String readScriptFile(String scriptIn) throws Exception {
- Path p = getPath(encryptedScriptDirectory, scriptIn);
- String script = "";
- Iterator<String> i;
- try {
- List<String> lines = Files.readAllLines(p, Charset.defaultCharset());
- i = lines.iterator();
- while (i.hasNext()) {
- String s = i.next();
- if (!s.startsWith("%%%")) {
- script += s;
- }
- }
- } catch (IOException e) {
- Log.e(TAG, "IOException during reading script: ");
- throw new Exception();
- }
- return script;
+ private synchronized boolean isSemsHashAlgoSHA256() {
+ return (shatype == SEMS_HASH_TYPE_SHA256);
}
+
/**
* Close the session with Application selected
* <br/>
@@ -319,15 +212,37 @@
*/
private byte[] sendSHA1OfCallerPackage(byte channel, byte[] callerPackage) throws Exception{
byte[] SHA1ofCallerPackage = SemsUtil.SHA1(callerPackage);
+
final byte[] header = {(byte)0x80, (byte)0xE2, (byte)0x00, 0x00,
(byte)0x16, (byte)0x4F, (byte)0x14};
- Log.d(TAG, "Register Caller: ");
+ Log.d(TAG, "Register Caller for SHA1: "+ SHA1ofCallerPackage.length);
return sChannel.transmit(SemsUtil.append(header, SHA1ofCallerPackage));
}
/**
* Performs store data operation of caller information.
* <br/>
+ * The Input SHA-256 digest of caller package name,
+ * The STORE DATA APDU command is used by the SEMS Device
+ * Agent to provide the SEMS Application with an identifier
+ * of the caller (SP Device Application), e.g.
+ * the digest value of the SP Device Application package name
+ * @param void
+ *
+ * @return {@code true} if the SW returned is 9000, {@code false} otherwise.
+ */
+ private byte[] sendSHA256OfCallerPackage(byte channel, byte[] callerPackage) throws Exception{
+ byte[] SHA256ofCallerPackage = SemsUtil.SHA256(callerPackage);
+ final byte[] header = {(byte)0x80, (byte)0xE2, (byte)0x00, 0x00,
+ (byte)0x22, (byte)0x4F, (byte)0x20};
+ Log.d(TAG, "Register Caller for SHA256: "+ SHA256ofCallerPackage.length);
+ return sChannel.transmit(SemsUtil.append(header, SHA256ofCallerPackage));
+ }
+
+
+ /**
+ * Performs store data operation of caller information.
+ * <br/>
* The Input SHA-1 digest of caller package name,
* The STORE DATA APDU command is used by the SEMS Device
* Agent to provide the SEMS Application with an identifier
@@ -339,7 +254,8 @@
*/
private byte[] sendAPCertificate(byte channel, byte[] APCert) {
try {
- if (APCert.length < 255) {
+ SemsAppletIdentifier.delayNthCommand();
+ if (APCert.length < MAX_FRAME_SIZE) {
// One command
byte[] header = {(byte)0x80, (byte)0xA0, (byte)0x01, (byte)0x00};
byte[] len = new byte[1];
@@ -348,45 +264,83 @@
byte[] command = SemsUtil.append(SemsUtil.append(header, len), APCert);
Log.d(TAG, "******* Processing LS Certificate 1/1 command");
+
byte[] rapdu = sChannel.transmit(command);
- putIntoLog(rapdu, SemsCertResponse);
+ mSemsFileOp.putIntoLog(rapdu, SemsCertResponse);
return rapdu;
- } else {
- // Two commands
+ } else { // Two/Three commands based on tag length
byte[] rapdu;
- /* static length because of Brainpool curve*/
- int signAndPubKeyLen = SEMS_CERTIFICATE_SIGNATURE_5F37_LEN +
- SEMS_CERTIFICATE_SIGNATURE_7F49_86_LEN + 6;
+ byte[] commandHeader = {(byte) 0x80, (byte) 0xA0, (byte) 0x01, (byte) 0x00};
+ byte[] cmdLen = new byte[1];
+ int tag73Offset = 0, tag5F37Offset = 0;
- byte[] firstCommandData =
- Arrays.copyOfRange(APCert, 0, APCert.length - signAndPubKeyLen);
- byte[] secondCommandData = Arrays.copyOfRange(
- APCert, APCert.length - signAndPubKeyLen, APCert.length);
+ int signAndPubKeyLen;
- byte[] firstHeader = {(byte)0x80, (byte)0xA0, (byte)0x01, (byte)0x00};
- byte[] secondHeader = {(byte)0x80, (byte)0xA0, (byte)0x00, (byte)0x00};
+ /*If TAG73 does not exists*/
+ if (SemsAppletIdentifier.getTag73Len() == 0) {
+ /* static length because of Brainpool curve*/
+ signAndPubKeyLen =
+ (SEMS_CERTIFICATE_SIGNATURE_5F37_LEN + SEMS_CERTIFICATE_SIGNATURE_7F49_86_LEN + 6);
+ } else {
+ tag73Offset = SemsTLV.getTagOffset(APCert, TAG73);
+ tag5F37Offset = SemsTLV.getTagOffset(APCert, TAG5F37);
+ /* Length of remaining frame from TAG73 onwards*/
+ signAndPubKeyLen = (APCert.length - tag73Offset);
+ }
- byte[] firstLen = new byte[1];
- byte[] secondLen = new byte[1];
+ /*First frame till either start of (TAG73 or TAG5F37)*/
+ byte[] commandData = Arrays.copyOfRange(APCert, 0, APCert.length - signAndPubKeyLen);
+ cmdLen[0] = (byte) commandData.length;
- firstLen[0] = (byte)firstCommandData.length;
- secondLen[0] = (byte)secondCommandData.length;
+ byte[] firstCommand = SemsUtil.append(SemsUtil.append(commandHeader, cmdLen), commandData);
- byte[] firstCommand = SemsUtil.append(
- SemsUtil.append(firstHeader, firstLen), firstCommandData);
- byte[] secondCommand = SemsUtil.append(
- SemsUtil.append(secondHeader, secondLen), secondCommandData);
-
- Log.d(TAG, "******* Processing LS Certificate 1/2 command");
+ Log.d(TAG,
+ "******* Processing LS Certificate 1st Frame APCert " + APCert.length
+ + " signAndPubKeyLen " + signAndPubKeyLen + " tag73Offset " + tag73Offset
+ + " tag5F37Offset " + tag5F37Offset);
rapdu = sChannel.transmit(firstCommand);
- if (SemsUtil.getSW(rapdu) != (short)0x9000) {
- putIntoLog(rapdu, SemsCertResponse);
+ mSemsFileOp.putIntoLog(rapdu, SemsCertResponse);
+ if (SemsUtil.getSW(rapdu) != (short) 0x9000) {
return Arrays.copyOfRange(rapdu, rapdu.length - 2, rapdu.length);
}
- Log.d(TAG, "******* Processing LS Certificate 2/2 command");
- rapdu = sChannel.transmit(secondCommand);
- putIntoLog(rapdu, SemsCertResponse);
+ /*If the second frame is greater than 255*/
+ if (signAndPubKeyLen > MAX_FRAME_SIZE) {
+ /*2nd Frame shall be only TAG73*/
+ commandData = Arrays.copyOfRange(APCert, (tag73Offset), (tag5F37Offset));
+ cmdLen[0] = (byte) (commandData.length);
+ commandHeader[2] = 0x00;
+ byte[] secondCommand =
+ SemsUtil.append(SemsUtil.append(commandHeader, cmdLen), commandData);
+ Log.d(TAG, "******* Processing LS Certificate 2nd/3 Frame cmdLen " + commandData.length);
+ rapdu = sChannel.transmit(secondCommand);
+ mSemsFileOp.putIntoLog(rapdu, SemsCertResponse);
+ if (SemsUtil.getSW(rapdu) != (short) 0x9000) {
+ return Arrays.copyOfRange(rapdu, rapdu.length - 2, rapdu.length);
+ }
+
+ /*3rd Frame shall be remaining from TAG5F37 onwards till end*/
+ commandData = Arrays.copyOfRange(APCert, tag5F37Offset, APCert.length);
+ cmdLen[0] = (byte) (commandData.length);
+
+ byte[] thirdCommand =
+ SemsUtil.append(SemsUtil.append(commandHeader, cmdLen), commandData);
+
+ Log.d(TAG, "******* Processing LS Certificate 3rd/3 Frame");
+ rapdu = sChannel.transmit(thirdCommand);
+ mSemsFileOp.putIntoLog(rapdu, SemsCertResponse);
+ } else {
+ /*2nd Frame shall be remaining (TAG73 or TAG5F37) onwards*/
+ commandData = Arrays.copyOfRange(APCert, APCert.length - signAndPubKeyLen, APCert.length);
+ cmdLen[0] = (byte) commandData.length;
+ commandHeader[2] = 0x00;
+ byte[] secondCommand =
+ SemsUtil.append(SemsUtil.append(commandHeader, cmdLen), commandData);
+
+ Log.d(TAG, "******* Processing LS Certificate 2nd Frame");
+ rapdu = sChannel.transmit(secondCommand);
+ mSemsFileOp.putIntoLog(rapdu, SemsCertResponse);
+ }
return Arrays.copyOfRange(rapdu, rapdu.length - 2, rapdu.length);
}
@@ -463,7 +417,7 @@
} catch (IOException e) {
e.printStackTrace();
}
- putIntoLog(rapdu, SEResponse);
+ mSemsFileOp.putIntoLog(rapdu, SEResponse);
return rapdu;
}
@@ -509,8 +463,8 @@
public String getSemsOutputResponse(String fileName) throws Exception {
SemsStatus status = SemsStatus.SEMS_STATUS_FAILED;
Log.d(TAG, "******* Read response output APDU data");
- status = setDirectories();
- return readScriptFile(fileName);
+ status = mSemsFileOp.setDirectories(SemsExecutor.sContext);
+ return mSemsFileOp.readScriptFile(fileName);
}
/**
@@ -526,12 +480,12 @@
public SemsStatus executeScript(String scriptIn, String scriptOut,
ISemsCallback callback) {
SemsStatus status = SemsStatus.SEMS_STATUS_FAILED;
- this.inputScript = scriptIn;
- this.outputScript = scriptOut;
+ inputScript = scriptIn;
+ outputScript = scriptOut;
this.mSemsCallback = callback;
- status = setDirectories();
+ status = mSemsFileOp.setDirectories(SemsExecutor.sContext);
if (status == SemsStatus.SEMS_STATUS_SUCCESS) {
- writeScriptInputFile("encrypted_script.txt", scriptIn);
+ mSemsFileOp.writeScriptInputFile("encrypted_script.txt", scriptIn);
new SemsAsyncExecutor().start();
} else {
Log.e(TAG, "Setting SEMS script path failed, package not found");
@@ -550,22 +504,20 @@
* @return {@code true} if the SW returned is 9000, {@code false} otherwise.
*/
private void executeScript() {
-
- String scriptIn = this.inputScript;
- String scriptOut = this.outputScript;
+ String scriptIn = inputScript;
+ String scriptOut = outputScript;
byte[] swReturned = sw9000;
+ response = sw6987;
byte channelNumber = 0;
SemsStatus status = SemsStatus.SEMS_STATUS_FAILED;
mState = SEMS_STATE_SELECT;
try {
-
/*To handle If input is given as path
String script = readScriptFile(scriptIn);*/
String script = scriptIn;
byte[] data = SemsUtil.parseHexString(script);
if (data == null) {
- putIntoLog(sw6987, ErrorResponse);
- updateSemsStatus(sw6987);
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
Log.e(TAG, ">>>>>>>>>> parseHexString returned NULL <<<<<<<<<<");
return;
}
@@ -574,8 +526,7 @@
byte[] rapdu;
if ((scriptTlvs == null) || scriptTlvs.size() == 0) {
- putIntoLog(sw6987, ErrorResponse);
- updateSemsStatus(sw6987);
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
Log.e(TAG, ">>>>>>>>>> Error : Script size 0 <<<<<<<<<<");
return;
}
@@ -593,8 +544,7 @@
case SEMS_STATE_SELECT: {
status = SelectSems();
if (status != SemsStatus.SEMS_STATUS_SUCCESS) {
- closeLogicalChannel(channelNumber);
- updateSemsStatus(sw6987);
+ response = sw6987;
return;
}
}
@@ -603,17 +553,26 @@
/*
* STEP 3 of executeScript - Sending SHA1 of Caller package
*/
- rapdu = sendSHA1OfCallerPackage(channelNumber,
- callerPackageName.getBytes());
+ synchronized (SemsExecutor.this) {
+ if (shatype == "SHA256") {
+ synchronized (SemsFileOperation.class) {
+ rapdu = sendSHA256OfCallerPackage(
+ channelNumber, mSemsFileOp.mCallerPackageName.getBytes());
+ }
+ } else {
+ synchronized (SemsFileOperation.class) {
+ rapdu = sendSHA1OfCallerPackage(
+ channelNumber, mSemsFileOp.mCallerPackageName.getBytes());
+ }
+ }
+ }
if (rapdu == null) {
Log.e(TAG, "sendSHA1OfCallerPackage received incorrect rapdu");
- closeLogicalChannel(channelNumber);
- updateSemsStatus(rapdu);
+ response = rapdu;
return;
}
- if (SemsUtil.getSW(rapdu) != (short)0x9000) {
- closeLogicalChannel(channelNumber);
- updateSemsStatus(rapdu);
+ if (SemsUtil.getSW(rapdu) != (short) 0x9000) {
+ response = rapdu;
return;
}
}
@@ -650,23 +609,23 @@
*/
} catch (Exception e) {
e.printStackTrace();
- putIntoLog(sw6F00, ErrorResponse);
- closeLogicalChannel(channelNumber);
- updateSemsStatus(sw6F00);
+ mSemsFileOp.putIntoLog(sw6F00, ErrorResponse);
+ response = sw6F00;
return;
}
- putIntoLog(response, SWResponse);
- closeLogicalChannel(channelNumber);
- updateSemsStatus(response);
+ mSemsFileOp.putIntoLog(response, SWResponse);
return;
}catch(Exception e) {
- putIntoLog(sw6987, ErrorResponse);
- updateSemsStatus(sw6987);
- Log.e(TAG, ">>>>>>>>>> Error : Invalid Script <<<<<<<<<<");
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
+ response = sw6987;
+ Log.e(TAG, ">>>>>>>>>> Error : Invalid Script <<<<<<<<<< ");
+ e.printStackTrace();
return;
} finally {
+ closeLogicalChannel(channelNumber);
+ updateSemsStatus(response);
/*Always write log file*/
- writeScriptOutFile(scriptOut);
+ mSemsFileOp.writeScriptOutFile(scriptOut);
}
}
@@ -703,11 +662,11 @@
if (secureCommand.getLength() > 4 /* DDD: was 32 */) {
byte[] secCmd = secureCommand.getValue();
-
+ SemsAppletIdentifier.delayNthCommand();
rapdu = sendProcessScript(channelNumber, secCmd);
if (rapdu == null) {
Log.e(TAG, "sendProcessScript received incorrect rapdu");
- putIntoLog(sw6987, ErrorResponse);
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
rapdu = sw6987;
break;
}
@@ -716,37 +675,37 @@
/*
* STEP 8 of executeScript - Process SE Response
*/
- putIntoLog(rapdu, SemsResponse);
+ mSemsFileOp.putIntoLog(rapdu, SemsResponse);
if ((rapdu = sendToSE(rapdu)) == null) {
- putIntoLog(sw6987, ErrorResponse);
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
rapdu = sw6987;
break;
}
- putIntoLog(rapdu, SEResponse);
+ mSemsFileOp.putIntoLog(rapdu, SEResponse);
{
rapdu = sendProcessSEResponse(channelNumber, rapdu);
- putIntoLog(rapdu, SemsResponse);
+ mSemsFileOp.putIntoLog(rapdu, SemsResponse);
while (SemsUtil.getSW(rapdu) == (short)0x6310) {
if ((rapdu = sendToSE(rapdu)) == null) {
- putIntoLog(sw6987, ErrorResponse);
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
rapdu = sw6987;
break;
}
- putIntoLog(rapdu, SEResponse);
+ mSemsFileOp.putIntoLog(rapdu, SEResponse);
rapdu = sendProcessSEResponse(channelNumber, rapdu);
- putIntoLog(rapdu, SemsResponse);
+ mSemsFileOp.putIntoLog(rapdu, SemsResponse);
}
}
if ((SemsUtil.getSW(rapdu) != (short)0x9000) &&
(SemsUtil.getSW(rapdu) != (short)0x6300)) {
- putIntoLog(rapdu, ErrorResponse);
+ mSemsFileOp.putIntoLog(rapdu, ErrorResponse);
break;
}
} else if (sw == (short)0x6320) {
- putIntoLog(rapdu, SemsResponse);
+ mSemsFileOp.putIntoLog(rapdu, SemsResponse);
closeLogicalChannel(channelNumber);
AID_MEM = SemsUtil.getRDATA(rapdu);
Log.d(TAG, "Received new AID need to switch");
@@ -771,14 +730,14 @@
/*continue restart_execute_script;*/
break;
} else if ((sw != (short)0x9000) && (sw != (short)0x6300)) {
- putIntoLog(rapdu, SemsResponse);
+ mSemsFileOp.putIntoLog(rapdu, SemsResponse);
break;
} else {
- putIntoLog(rapdu, SemsResponse);
+ mSemsFileOp.putIntoLog(rapdu, SemsResponse);
}
} else {
Log.e(TAG, "Invalid length for secure command");
- putIntoLog(sw6987, ErrorResponse);
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
rapdu = sw6987;
break;
}
@@ -786,7 +745,7 @@
!(secureCommand.getTLV()[0] == (byte)0x7F &&
secureCommand.getTLV()[1] == (byte)0x21)) {
Log.e(TAG, "Invalid tag found secure script");
- putIntoLog(sw6987, ErrorResponse);
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
rapdu = sw6987;
break;
} else if (lsCommandSeen) {
@@ -803,7 +762,7 @@
* there may be an issue in the LS Applet)*/
rapdu = selectApplication(channelNumber, AID_MEM);
if(rapdu == null) {
- putIntoLog(sw6987, ErrorResponse);
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
rapdu = sw6987;
break;
}
@@ -855,7 +814,11 @@
if (scriptTlvs.get(i).getTag() == 0x7F21) {
certIndex = i;
tlvCertInScript = scriptTlvs.get(i);
-
+ try {
+ SemsAppletIdentifier.validateTag73Support(tlvCertInScript);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception in parsing TAG73 in CERT frame");
+ }
byte[] cert = tlvCertInScript.getTLV();
tlvs = SemsTLV.parse(tlvCertInScript.getValue());
tlvSC42 = SemsTLV.find(tlvs, 0x42);
@@ -919,22 +882,19 @@
rapdu = sendAPCertificate(channelNumber, APCert);
if (rapdu == null) {
Log.e(TAG, "sendAPCertificate received incorrect rapdu");
- closeLogicalChannel(channelNumber);
- updateSemsStatus(rapdu);
+ response = rapdu;
return SemsStatus.SEMS_STATUS_FAILED;
}
if (SemsUtil.getSW(rapdu) != (short)0x9000) {
Log.e(TAG, "certificate frame command failed");
- putIntoLog(rapdu, ErrorResponse);
- closeLogicalChannel(channelNumber);
- updateSemsStatus(rapdu);
+ mSemsFileOp.putIntoLog(rapdu, ErrorResponse);
+ response = rapdu;
stat = SemsStatus.SEMS_STATUS_FAILED;
}
} else {
Log.e(TAG, "No valid certificate frame found");
- closeLogicalChannel(channelNumber);
- putIntoLog(sw6987, ErrorResponse);
- updateSemsStatus(sw6987);
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
+ response = sw6987;
}
Log.d(TAG, "Exit Certificate frame validation");
return stat;
@@ -1039,57 +999,52 @@
if (authFrame.getTag() != 0x60) {
Log.e(TAG, "Authentication frame not found");
- closeLogicalChannel(channelNumber);
- putIntoLog(sw6987, ErrorResponse);
- updateSemsStatus(sw6987);
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
+ response = sw6987;
return stat;
}
authFrame = SemsTLV.parse(authFrame.getValue()).get(0);
+ SemsAppletIdentifier.delayNthCommand();
rapdu = sendAuthenticationFrame(channelNumber, authFrame.getValue());
if (rapdu == null) {
Log.e(TAG, "sendAuthenticationFrame received incorrect rapdu");
- closeLogicalChannel(channelNumber);
- putIntoLog(sw6987, ErrorResponse);
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
updateSemsStatus(sw6987);
return stat;
}
- putIntoLog(rapdu, SemsAuthResponse);
+ mSemsFileOp.putIntoLog(rapdu, SemsAuthResponse);
if (SemsUtil.getSW(rapdu) == (short)0x6310) { // begin_perso cleanup
int i = 0;
if ((rapdu = sendToSE(rapdu)) == null) {
- putIntoLog(sw6987, ErrorResponse);
- closeLogicalChannel(channelNumber);
- updateSemsStatus(sw6987);
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
+ response = sw6987;
return stat;
}
- putIntoLog(rapdu, SEResponse);
+ mSemsFileOp.putIntoLog(rapdu, SEResponse);
rapdu = sendProcessSEResponse(channelNumber, rapdu);
- putIntoLog(rapdu, SemsResponse);
+ mSemsFileOp.putIntoLog(rapdu, SemsResponse);
while (SemsUtil.getSW(rapdu) == (short)0x6310) {
if ((rapdu = sendToSE(rapdu)) == null) {
- putIntoLog(sw6987, ErrorResponse);
- closeLogicalChannel(channelNumber);
- updateSemsStatus(sw6987);
+ mSemsFileOp.putIntoLog(sw6987, ErrorResponse);
+ response = sw6987;
return stat;
}
- putIntoLog(rapdu, SEResponse);
+ mSemsFileOp.putIntoLog(rapdu, SEResponse);
rapdu = sendProcessSEResponse(channelNumber, rapdu);
- putIntoLog(rapdu, SemsResponse);
+ mSemsFileOp.putIntoLog(rapdu, SemsResponse);
i++;
}
} else if (SemsUtil.getSW(rapdu) != (short)0x9000) {
Log.e(TAG, "Processing Authentication frame failed");
- putIntoLog(rapdu, SemsResponse);
- closeLogicalChannel(channelNumber);
- updateSemsStatus(rapdu);
- return stat;
+ mSemsFileOp.putIntoLog(rapdu, SemsResponse);
} else if (SemsUtil.getSW(rapdu) == (short)0x9000) {
stat = SemsStatus.SEMS_STATUS_SUCCESS;
}
+ response = rapdu;
return stat;
}
@@ -1134,7 +1089,7 @@
}
if (this.mSemsCallback != null) {
this.mSemsCallback.onSemsComplete(updateStatus);
- this.mSemsCallback.onSemsComplete(updateStatus, sRespOutlog);
+ this.mSemsCallback.onSemsComplete(updateStatus, mSemsFileOp.getRespOutLog());
}
}
/**
diff --git a/sems/com/nxp/sems/semscore/SemsFileOperation.java b/sems/com/nxp/sems/semscore/SemsFileOperation.java
new file mode 100644
index 0000000..c695c4a
--- /dev/null
+++ b/sems/com/nxp/sems/semscore/SemsFileOperation.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.nxp.sems;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+public class SemsFileOperation {
+ public static final String TAG = "SEMS-SemsFileOperation";
+
+ private String mRespOutlog;
+ private String mEncryptedScriptDirectory = "";
+ private String mOutDirectory = "";
+ public String mCallerPackageName;
+
+ private static final byte SEMS_RESPONSE = 0x01;
+ //private static final byte SEResponse = 0x02;
+ private static final byte ERROR_RESPONSE = 0x03;
+ //private static final byte SWResponse = 0x04;
+ private static final byte SEMS_CERT_RESPONSE = 0x05;
+ private static final byte SEMS_AUTH_RESPONSE = 0x06;
+ private static final byte SEMS_RESPONSE_LOG_TAG = 0x61;
+ private static final byte SEMS_FRAME_TYPE_TAG = 0x44; // (CERT/AUTH/SECURE_CMD frame)
+ private static final byte SEMS_RESPONSE_DATA_TAG = 0x43;
+
+ /**
+ * SemsFileOperation Constructor
+ * <br/>
+ * @param void
+ *
+ * @return void.
+ */
+ SemsFileOperation() {
+ // Update start time stamp at beginning
+ mRespOutlog = getCurrentTimeStamp();
+ }
+
+ /**
+ * Get current date and time stamp
+ * <br/>
+ * Used in response log for debug purpose
+ * @param void
+ *
+ * @return String current data and time stamp.
+ */
+ private String getCurrentTimeStamp() {
+ DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
+ LocalDateTime now = LocalDateTime.now();
+ return "#######" + dtf.format(now) + "#######"
+ + "\r\n";
+ }
+
+ /**
+ * Logging the response APDU received during SEMS execution
+ * <br/>
+ * Agent to provide the SEMS Application with an identifier
+ * @param byte[] what The Input status bytes
+ * Byte type The Input type of response
+ *
+ * @return void.
+ */
+ public void putIntoLog(byte[] what, byte type) {
+ byte[] data;
+
+ /*Skip SW "6310" as this is not relevant for debug */
+ if ((what[what.length - 2] == 0x63) && (what[what.length - 1] == 0x10)) {
+ return;
+ }
+
+ switch (type) {
+ case ERROR_RESPONSE:
+ return;
+ default:
+ return;
+ case SEMS_CERT_RESPONSE:
+ data = new byte[] {0x7F, 0x21};
+ break;
+ case SEMS_AUTH_RESPONSE:
+ data = new byte[] {0x60};
+ break;
+ case SEMS_RESPONSE:
+ data = new byte[] {0x40};
+ break;
+ }
+
+ data = SemsTLV.make(SEMS_RESPONSE_LOG_TAG,
+ SemsUtil.append(SemsTLV.make(SEMS_RESPONSE_DATA_TAG, data),
+ SemsTLV.make(SEMS_RESPONSE_DATA_TAG, what)));
+ mRespOutlog = mRespOutlog + SemsUtil.toHexString(data) + "\r\n";
+ }
+
+ /**
+ * Set the current application directory & caller information
+ * <br/>
+ * @param context caller application context info
+ *
+ * @return {@code SemsStatus} returns SEMS_STATUS_SUCCESS on success
+ * otherwise SEMS_STATUS_FAILED.
+ */
+ public SemsStatus setDirectories(Context context) {
+ SemsStatus status = SemsStatus.SEMS_STATUS_FAILED;
+ PackageInfo pInfo;
+ PackageManager pm = context.getPackageManager();
+ String str = context.getPackageName();
+ synchronized (SemsFileOperation.class) {
+ try {
+ pInfo = pm.getPackageInfo(str, 0);
+ str = pInfo.applicationInfo.dataDir;
+ mCallerPackageName = pInfo.packageName;
+ mEncryptedScriptDirectory = str;
+ mOutDirectory = str;
+ status = SemsStatus.SEMS_STATUS_SUCCESS;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return status;
+ }
+
+ /**
+ * Get path to locate and access file
+ * <br/>
+ * @param String dir initial part of path string
+ * String file filename in the path
+ *
+ * @return Path The resulting path.
+ */
+ public Path getPath(String dir, String file) {
+ return (dir != null) ? FileSystems.getDefault().getPath(dir, file)
+ : FileSystems.getDefault().getPath(file);
+ }
+
+ /**
+ * Write the content of accumulated response buffer to out file
+ * <br/>
+ * Agent to provide the SEMS Application with an identifier
+ * @param String scriptOut The file name to write response
+ *
+ * @return byte[] Response byte array.
+ */
+ public byte[] writeScriptOutFile(String scriptOut) {
+ Path p = getPath(mOutDirectory, scriptOut);
+ // Update finish time stamp at end
+ mRespOutlog = mRespOutlog + getCurrentTimeStamp();
+ try {
+ Files.write(p, mRespOutlog.getBytes());
+ } catch (IOException e) {
+ Log.e(TAG, "IOException during writeScriptOutfile: ");
+ }
+ return mRespOutlog.getBytes();
+ }
+
+ /**
+ * Write the content of String buffer to backup file
+ * <br/>
+ * @param String filename to which the buffer contents to be copied
+ * String scriptBuffer input buffer content
+ *
+ * @return byte[] response buffer.
+ */
+ public byte[] writeScriptInputFile(String filename, String scriptBuffer) {
+ Path p = getPath(mOutDirectory, filename);
+ try {
+ Files.write(p, scriptBuffer.getBytes());
+ } catch (IOException e) {
+ Log.e(TAG, "IOException during writeScriptInputfile: ");
+ }
+ return scriptBuffer.getBytes();
+ }
+
+ /**
+ * Read the file content to String format
+ * <br/>
+ * The Input path of the SEMS encrypted script stored,
+ * @param String scriptIn input SEMS script with metadata
+ *
+ * @return String plain script with metadata removed.
+ */
+
+ public String readScriptFile(String scriptIn) throws Exception {
+ Path p = getPath(mEncryptedScriptDirectory, scriptIn);
+ String script = "";
+ Iterator<String> i;
+ try {
+ List<String> lines = Files.readAllLines(p, Charset.defaultCharset());
+ i = lines.iterator();
+ while (i.hasNext()) {
+ String s = i.next();
+ if (!s.startsWith("%%%")) {
+ script += s;
+ }
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "IOException during reading script: ");
+ throw new Exception();
+ }
+ return script;
+ }
+
+ /**
+ * Get response log buffer string
+ * <br/>
+ * @param void
+ *
+ * @return String response log buffer.
+ */
+ public String getRespOutLog() {
+ return mRespOutlog;
+ }
+}
+
diff --git a/sems/com/nxp/sems/semscore/SemsTLV.java b/sems/com/nxp/sems/semscore/SemsTLV.java
index 6dbe9ac..4d4a608 100644
--- a/sems/com/nxp/sems/semscore/SemsTLV.java
+++ b/sems/com/nxp/sems/semscore/SemsTLV.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 NXP
+ * Copyright 2019, 2021 NXP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -192,4 +192,73 @@
return null;
}
}
+
+ public static int getTagOffset(byte[] buff, int tagReq) {
+ int sOffset = 0;
+ int nextOffset = 0;
+ ByteBuffer bb = ByteBuffer.wrap(buff);
+ for (;;) {
+ int tag;
+
+ try {
+ tag = bb.get() & 0xFF;
+ nextOffset++;
+ } catch (BufferUnderflowException e) {
+ Log.e("SemsTLV", "BufferUnderFlowException occured");
+ break;
+ }
+
+ boolean isPrimitive = (tag & 0x20) == 0x00;
+
+ if ((tag & 0x1F) == 0x1F) {
+ /* 2-byte tag*/
+ tag = (tag << 8) + (bb.get() & 0xFF);
+ nextOffset++;
+ }
+ if (tag == tagReq) {
+ return sOffset;
+ }
+
+ int length = bb.get() & 0xFF;
+ if (length <= 0x7F) {
+ /* 1-byte length*/
+ nextOffset++;
+ } else if (length == 0x81) {
+ length = bb.get() & 0xFF;
+ nextOffset += 2;
+ } else if (length == 0x82) {
+ int length1 = bb.get() & 0xFF;
+ int length2 = bb.get() & 0xFF;
+ length = (length1 << 8) + length2;
+ nextOffset += 3;
+ } else if (length == 0x83) {
+ int length1 = bb.get() & 0xFF;
+ int length2 = bb.get() & 0xFF;
+ int length3 = bb.get() & 0xFF;
+ length = (length1 << 16) + (length2 << 8) + length3;
+ nextOffset += 4;
+ } else if (length == 0x84) {
+ int length1 = bb.get() & 0xFF;
+ int length2 = bb.get() & 0xFF;
+ int length3 = bb.get() & 0xFF;
+ int length4 = bb.get() & 0xFF;
+ length = (length1 << 24) + (length2 << 16) + (length3 << 8) + length4;
+ nextOffset += 5;
+ } else {
+ throw new RuntimeException("Bad length field");
+ }
+
+ if (isPrimitive) {
+ byte[] value = new byte[length];
+ nextOffset += length;
+ bb.get(value, 0, value.length);
+ } else {
+ /* In case of constructed TLV only tag, length counted, value skipped
+ for offset calculation*/
+ }
+ // Update offset pointing to next tag
+ sOffset = nextOffset;
+ }
+ return -1;
+ }
}
diff --git a/sems/com/nxp/sems/semscore/SemsUtil.java b/sems/com/nxp/sems/semscore/SemsUtil.java
index 28274ad..c54dd79 100644
--- a/sems/com/nxp/sems/semscore/SemsUtil.java
+++ b/sems/com/nxp/sems/semscore/SemsUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 NXP
+ * Copyright 2019,2021 NXP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -92,6 +92,19 @@
return sha1.digest();
}
+ public static byte[] SHA256(byte[] in) {
+ MessageDigest sha256 = null;
+ try {
+ sha256 = MessageDigest.getInstance("SHA256");
+ } catch (Exception e) {
+ System.err.println("SHA-256 not supported");
+ System.exit(1);
+ }
+ sha256.reset();
+ sha256.update(in);
+ return sha256.digest();
+ }
+
public static byte[] toUTF8(String s) {
if (s != null) {
try {
diff --git a/sems/sems.jar b/sems/sems.jar
index 66184ae..20d23cc 100644
--- a/sems/sems.jar
+++ b/sems/sems.jar
Binary files differ