summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuchi Kandoi <kandoiruchi@google.com>2019-03-14 00:40:31 -0700
committerandroid-build-merger <android-build-merger@google.com>2019-03-14 00:40:31 -0700
commit957011da50d45bc42ba5d146e1ea49dc7717caad (patch)
tree8553cc7906833620fab452a2be223911a533d8c2
parent866e529f6ef1b427a16bc3c75ae300499d64a3a1 (diff)
parent88f615351443d295d82aeb494ac421626c22076d (diff)
downloadSecureElement-957011da50d45bc42ba5d146e1ea49dc7717caad.tar.gz
Add support for SHA-256 Hash_REF_DO
am: 88f6153514 Change-Id: I975a7c5f866b5e601f9d51b427b436845107de67
-rw-r--r--src/com/android/se/security/AccessControlEnforcer.java69
-rw-r--r--src/com/android/se/security/AccessRuleCache.java85
-rw-r--r--src/com/android/se/security/arf/PKCS15/EFACConditions.java3
-rw-r--r--src/com/android/se/security/gpac/Hash_REF_DO.java27
4 files changed, 81 insertions, 103 deletions
diff --git a/src/com/android/se/security/AccessControlEnforcer.java b/src/com/android/se/security/AccessControlEnforcer.java
index 99ec165..2366ce7 100644
--- a/src/com/android/se/security/AccessControlEnforcer.java
+++ b/src/com/android/se/security/AccessControlEnforcer.java
@@ -50,18 +50,13 @@ import com.android.se.security.ChannelAccess.ACCESS;
import com.android.se.security.ara.AraController;
import com.android.se.security.arf.ArfController;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.AccessControlException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
import java.util.ArrayList;
+import java.util.List;
import java.util.MissingResourceException;
import java.util.NoSuchElementException;
@@ -91,28 +86,6 @@ public class AccessControlEnforcer {
return AraController.getAraMAid();
}
- private static Certificate decodeCertificate(byte[] certData) throws CertificateException {
- CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- X509Certificate cert =
- (X509Certificate) certFactory.generateCertificate(
- new ByteArrayInputStream(certData));
- return cert;
- }
-
- /** Returns the Hash of the Application */
- public static byte[] getAppCertHash(Certificate appCert) throws CertificateEncodingException {
- MessageDigest md = null;
- try {
- md = MessageDigest.getInstance("SHA");
- } catch (NoSuchAlgorithmException e) {
- throw new AccessControlException("Exception getting SHA for the signature");
- }
- if (md == null) {
- throw new AccessControlException("Hash can not be computed");
- }
- return md.digest(appCert.getEncoded());
- }
-
public PackageManager getPackageManager() {
return mPackageManager;
}
@@ -323,17 +296,17 @@ public class AccessControlEnforcer {
throw new AccessControlException("package names must be specified");
}
try {
- // estimate SHA-1 hash value of the device application's certificate.
- Certificate[] appCerts = getAPPCerts(packageName);
+ // estimate SHA-1 and SHA-256 hash values of the device application's certificate.
+ List<byte[]> appCertHashes = getAppCertHashes(packageName);
// APP certificates must be available => otherwise Exception
- if (appCerts == null || appCerts.length == 0) {
+ if (appCertHashes == null || appCertHashes.size() == 0) {
throw new AccessControlException(
"Application certificates are invalid or do not exist.");
}
if (checkRefreshTag) {
updateAccessRuleIfNeed();
}
- return getAccessRule(aid, appCerts);
+ return getAccessRule(aid, appCertHashes);
} catch (IOException | MissingResourceException e) {
throw e;
} catch (Throwable exp) {
@@ -343,13 +316,13 @@ public class AccessControlEnforcer {
/** Fetches the Access Rules for the given application and AID pair */
public ChannelAccess getAccessRule(
- byte[] aid, Certificate[] appCerts)
- throws AccessControlException, CertificateEncodingException {
+ byte[] aid, List<byte []> appCertHashes)
+ throws AccessControlException {
ChannelAccess channelAccess = null;
// if read all is true get rule from cache.
if (mRulesRead) {
// get rules from internal storage
- channelAccess = mAccessRuleCache.findAccessRule(aid, appCerts);
+ channelAccess = mAccessRuleCache.findAccessRule(aid, appCertHashes);
}
// if no rule was found return an empty access rule
// with all access denied.
@@ -363,10 +336,10 @@ public class AccessControlEnforcer {
}
/**
- * Returns Certificate chain for one package.
+ * Returns hashes of certificate chain for one package.
*/
- private Certificate[] getAPPCerts(String packageName)
- throws CertificateException, NoSuchAlgorithmException, AccessControlException {
+ private List<byte[]> getAppCertHashes(String packageName)
+ throws NoSuchAlgorithmException, AccessControlException {
if (packageName == null || packageName.length() == 0) {
throw new AccessControlException("Package Name not defined");
}
@@ -380,11 +353,17 @@ public class AccessControlEnforcer {
if (foundPkgInfo == null) {
throw new AccessControlException("Package does not exist");
}
- ArrayList<Certificate> appCerts = new ArrayList<Certificate>();
+ MessageDigest md = MessageDigest.getInstance("SHA");
+ MessageDigest md256 = MessageDigest.getInstance("SHA-256");
+ if (md == null || md256 == null) {
+ throw new AccessControlException("Hash can not be computed");
+ }
+ List<byte[]> appCertHashes = new ArrayList<byte[]>();
for (Signature signature : foundPkgInfo.signatures) {
- appCerts.add(decodeCertificate(signature.toByteArray()));
+ appCertHashes.add(md.digest(signature.toByteArray()));
+ appCertHashes.add(md256.digest(signature.toByteArray()));
}
- return appCerts.toArray(new Certificate[appCerts.size()]);
+ return appCertHashes;
}
/** Returns true if the given application is allowed to recieve NFC Events */
@@ -409,14 +388,14 @@ public class AccessControlEnforcer {
int i = 0;
boolean[] nfcEventFlags = new boolean[packageNames.length];
for (String packageName : packageNames) {
- // estimate SHA-1 hash value of the device application's certificate.
+ // estimate hash value of the device application's certificate.
try {
- Certificate[] appCerts = getAPPCerts(packageName);
+ List<byte[]> appCertHashes = getAppCertHashes(packageName);
// APP certificates must be available => otherwise Exception
- if (appCerts == null || appCerts.length == 0) {
+ if (appCertHashes == null || appCertHashes.size() == 0) {
nfcEventFlags[i] = false;
} else {
- ChannelAccess channelAccess = getAccessRule(aid, appCerts);
+ ChannelAccess channelAccess = getAccessRule(aid, appCertHashes);
nfcEventFlags[i] =
(channelAccess.getNFCEventAccess() == ChannelAccess.ACCESS.ALLOWED);
}
diff --git a/src/com/android/se/security/AccessRuleCache.java b/src/com/android/se/security/AccessRuleCache.java
index 8e93e58..8461c49 100644
--- a/src/com/android/se/security/AccessRuleCache.java
+++ b/src/com/android/se/security/AccessRuleCache.java
@@ -45,12 +45,11 @@ import com.android.se.security.gpac.REF_DO;
import java.io.PrintWriter;
import java.security.AccessControlException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -248,7 +247,7 @@ public class AccessRuleCache {
}
/** Find Access Rule for the given AID and Application */
- public ChannelAccess findAccessRule(byte[] aid, Certificate[] appCerts)
+ public ChannelAccess findAccessRule(byte[] aid, List<byte[]> appCertHashes)
throws AccessControlException {
// TODO: check difference between DeviceCertHash and Certificate Chain (EndEntityCertHash,
@@ -264,29 +263,25 @@ public class AccessRuleCache {
AID_REF_DO aid_ref_do = getAidRefDo(aid);
REF_DO ref_do;
Hash_REF_DO hash_ref_do;
- for (Certificate appCert : appCerts) {
- try {
- hash_ref_do = new Hash_REF_DO(AccessControlEnforcer.getAppCertHash(appCert));
- ref_do = new REF_DO(aid_ref_do, hash_ref_do);
-
- if (mRuleCache.containsKey(ref_do)) {
- // let's take care about the undefined rules, according to the GP specification:
- ChannelAccess ca = mRuleCache.get(ref_do);
- if (ca.getApduAccess() == ChannelAccess.ACCESS.UNDEFINED) {
- ca.setApduAccess(ChannelAccess.ACCESS.DENIED);
- }
- if ((ca.getNFCEventAccess() == ChannelAccess.ACCESS.UNDEFINED)
- && (ca.getApduAccess() != ChannelAccess.ACCESS.UNDEFINED)) {
- ca.setNFCEventAccess(ca.getApduAccess());
- }
- if (DEBUG) {
- Log.i(mTag, "findAccessRule() " + ref_do.toString() + ", "
- + mRuleCache.get(ref_do).toString());
- }
- return mRuleCache.get(ref_do);
+ for (byte[] appCertHash : appCertHashes) {
+ hash_ref_do = new Hash_REF_DO(appCertHash);
+ ref_do = new REF_DO(aid_ref_do, hash_ref_do);
+
+ if (mRuleCache.containsKey(ref_do)) {
+ // let's take care about the undefined rules, according to the GP specification:
+ ChannelAccess ca = mRuleCache.get(ref_do);
+ if (ca.getApduAccess() == ChannelAccess.ACCESS.UNDEFINED) {
+ ca.setApduAccess(ChannelAccess.ACCESS.DENIED);
+ }
+ if ((ca.getNFCEventAccess() == ChannelAccess.ACCESS.UNDEFINED)
+ && (ca.getApduAccess() != ChannelAccess.ACCESS.UNDEFINED)) {
+ ca.setNFCEventAccess(ca.getApduAccess());
+ }
+ if (DEBUG) {
+ Log.i(mTag, "findAccessRule() " + ref_do.toString() + ", "
+ + mRuleCache.get(ref_do).toString());
}
- } catch (CertificateEncodingException e) {
- throw new AccessControlException("Problem with Application Certificate.");
+ return mRuleCache.get(ref_do);
}
}
// no rule found,
@@ -328,29 +323,25 @@ public class AccessRuleCache {
// Search Rule C ( Certificate(s); <AllSEApplications> )
aid_ref_do = new AID_REF_DO(AID_REF_DO.TAG);
- for (Certificate appCert : appCerts) {
- try {
- hash_ref_do = new Hash_REF_DO(AccessControlEnforcer.getAppCertHash(appCert));
- ref_do = new REF_DO(aid_ref_do, hash_ref_do);
-
- if (mRuleCache.containsKey(ref_do)) {
- // let's take care about the undefined rules, according to the GP specification:
- ChannelAccess ca = mRuleCache.get(ref_do);
- if (ca.getApduAccess() == ChannelAccess.ACCESS.UNDEFINED) {
- ca.setApduAccess(ChannelAccess.ACCESS.DENIED);
- }
- if ((ca.getNFCEventAccess() == ChannelAccess.ACCESS.UNDEFINED)
- && (ca.getApduAccess() != ChannelAccess.ACCESS.UNDEFINED)) {
- ca.setNFCEventAccess(ca.getApduAccess());
- }
- if (DEBUG) {
- Log.i(mTag, "findAccessRule() " + ref_do.toString() + ", "
- + mRuleCache.get(ref_do).toString());
- }
- return mRuleCache.get(ref_do);
+ for (byte[] appCertHash : appCertHashes) {
+ hash_ref_do = new Hash_REF_DO(appCertHash);
+ ref_do = new REF_DO(aid_ref_do, hash_ref_do);
+
+ if (mRuleCache.containsKey(ref_do)) {
+ // let's take care about the undefined rules, according to the GP specification:
+ ChannelAccess ca = mRuleCache.get(ref_do);
+ if (ca.getApduAccess() == ChannelAccess.ACCESS.UNDEFINED) {
+ ca.setApduAccess(ChannelAccess.ACCESS.DENIED);
+ }
+ if ((ca.getNFCEventAccess() == ChannelAccess.ACCESS.UNDEFINED)
+ && (ca.getApduAccess() != ChannelAccess.ACCESS.UNDEFINED)) {
+ ca.setNFCEventAccess(ca.getApduAccess());
+ }
+ if (DEBUG) {
+ Log.i(mTag, "findAccessRule() " + ref_do.toString() + ", "
+ + mRuleCache.get(ref_do).toString());
}
- } catch (CertificateEncodingException e) {
- throw new AccessControlException("Problem with Application Certificate.");
+ return mRuleCache.get(ref_do);
}
}
diff --git a/src/com/android/se/security/arf/PKCS15/EFACConditions.java b/src/com/android/se/security/arf/PKCS15/EFACConditions.java
index 1068969..26b150a 100644
--- a/src/com/android/se/security/arf/PKCS15/EFACConditions.java
+++ b/src/com/android/se/security/arf/PKCS15/EFACConditions.java
@@ -149,8 +149,9 @@ public class EFACConditions extends EF {
certificateHash = derRule.getTLVData();
if (certificateHash.length != Hash_REF_DO.SHA1_LEN
+ && certificateHash.length != Hash_REF_DO.SHA256_LEN
&& certificateHash.length != 0) {
- // other hash than SHA-1 hash values are not supported.
+ // other hash than SHA-1 and SHA-256 hash values are not supported.
throw new PKCS15Exception("Invalid hash found!");
} else {
hash_ref_do = new Hash_REF_DO(certificateHash);
diff --git a/src/com/android/se/security/gpac/Hash_REF_DO.java b/src/com/android/se/security/gpac/Hash_REF_DO.java
index 7b8a861..edd019a 100644
--- a/src/com/android/se/security/gpac/Hash_REF_DO.java
+++ b/src/com/android/se/security/gpac/Hash_REF_DO.java
@@ -47,6 +47,7 @@ public class Hash_REF_DO extends BerTlv {
public static final int TAG = 0xC1;
public static final int SHA1_LEN = 20;
+ public static final int SHA256_LEN = 32;
private byte[] mHash = new byte[0];
@@ -92,12 +93,14 @@ public class Hash_REF_DO extends BerTlv {
}
/**
- * Tags: C1 Length: 0 or SHA1_LEN bytes
+ * Tags: C1 Length: 0 or SHA1_LEN or SHA256_LEN bytes
*
* <p>Value: Hash: identifies a specific device application Empty: refers to all device
* applications
*
- * <p>Length: SHA1_LEN for 20 bytes SHA-1 hash value 0 for empty value field
+ * <p>Length: SHA1_LEN for 20 bytes SHA-1 hash value
+ * SHA256_LEN for 32 bytes SHA-256 hash value
+ * 0 for empty value field
*/
@Override
public void interpret() throws ParserException {
@@ -106,19 +109,20 @@ public class Hash_REF_DO extends BerTlv {
byte[] data = getRawData();
int index = getValueIndex();
+ int length = getValueLength();
// sanity checks
- if (getValueLength() != 0 && getValueLength() != SHA1_LEN) {
+ if (length != 0 && length != SHA1_LEN && length != SHA256_LEN) {
throw new ParserException("Invalid value length for Hash-REF-DO!");
}
- if (getValueLength() == SHA1_LEN) {
- if (index + getValueLength() > data.length) {
+ if (length != 0) {
+ if (index + length > data.length) {
throw new ParserException("Not enough data for Hash-REF-DO!");
}
- mHash = new byte[getValueLength()];
- System.arraycopy(data, index, mHash, 0, getValueLength());
+ mHash = new byte[length];
+ System.arraycopy(data, index, mHash, 0, length);
}
}
@@ -128,14 +132,17 @@ public class Hash_REF_DO extends BerTlv {
* <p>Value: Hash: identifies a specific device application Empty: refers to all device
* applications
*
- * <p>Length: SHA1_LEN for 20 bytes SHA-1 hash value 0 for empty value field
+ * <p>Length: 20 for SHA-1 hash or
+ * 32 bytes for SHA-256 hash or
+ * 0 for empty value field
*/
@Override
public void build(ByteArrayOutputStream stream) throws DO_Exception {
// sanity checks
- if (!(mHash.length != SHA1_LEN || mHash.length != 0)) {
- throw new DO_Exception("Hash value must be " + SHA1_LEN + " bytes in length!");
+ if (mHash.length != SHA1_LEN && mHash.length != SHA256_LEN && mHash.length != 0) {
+ throw new DO_Exception("Hash value must be " + SHA1_LEN + " or " + SHA256_LEN
+ + " bytes in length!");
}
stream.write(getTag());