diff options
author | Ruchi Kandoi <kandoiruchi@google.com> | 2019-03-14 00:50:38 -0700 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2019-03-14 00:50:38 -0700 |
commit | 15122d4b9fda183895a171407afd2dd0ed2f16b3 (patch) | |
tree | 8553cc7906833620fab452a2be223911a533d8c2 | |
parent | f3329c09bf6ef38e411dabec0852f06a3ec07f3b (diff) | |
parent | 572f77a0b230988771486ef8923e931d15905d42 (diff) | |
download | SecureElement-15122d4b9fda183895a171407afd2dd0ed2f16b3.tar.gz |
Add support for SHA-256 Hash_REF_DO am: 88f6153514 am: 957011da50
am: 572f77a0b2
Change-Id: I88044ca0cfad8e2e20ae45a37d8005c1e7570929
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()); |