Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Samsung Knox TEE integrity status #15

Closed
wants to merge 11 commits into from

Conversation

salvogiangri
Copy link
Contributor

This PR adds the ability to retrieve and show Samsung's specific device status info, this is done by using their own keystore API's to generate a "Knox protected" key. Additional code refactoring are welcome.


@salvogiangri
Copy link
Contributor Author

salvogiangri commented Jun 17, 2023

The main problem here is that keystore2 will prevent generating a SAK key if the app doesn't have one of those runtime permissions declared and granted:

<!-- android.Manifest.permission.KNOX_CCM_KEYSTORE -->
<permission
    android:label="@string/permlab_mdmCcm" 
    android:description="@string/permdesc_mdmCcm"
    android:name="com.samsung.android.knox.permission.KNOX_CCM_KEYSTORE" 
    android:permissionGroup="com.sec.enterprise.permission-group.mdm"
    android:protectionLevel="signature" />

<!-- android.Manifest.permission.KNOX_TIMA_KEYSTORE -->
<permission
    android:label="@string/permlab_mdmKeystore" 
    android:description="@string/permdesc_mdmKeystore"
    android:name="com.samsung.android.knox.permission.KNOX_TIMA_KEYSTORE"
    android:permissionGroup="com.sec.enterprise.permission-group.mdm"
    android:protectionLevel="signature" />

<!-- android.Manifest.permission.KNOX_TIMA_KEYSTORE_PER_APP -->
<permission
    android:label="@string/permlab_mdmKeystorePerApp" 
    android:description="@string/permdesc_mdmKeystorePerApp"
    android:name="com.samsung.android.knox.permission.KNOX_TIMA_KEYSTORE_PER_APP"
    android:permissionGroup="com.sec.enterprise.permission-group.mdm"
    android:protectionLevel="signature" />

<!-- android.Manifest.permission.SAMSUNG_KEYSTORE_PERMISSION -->
<permission
    android:name="com.samsung.android.security.permission.SAMSUNG_KEYSTORE_PERMISSION" 
    android:protectionLevel="signatureOrSystem" />

...and I've currently haven't found a way to grant SAMSUNG_KEYSTORE_PERMISSION permission without manually pushing the built apk to /system/priv-app, if you're interested on merging this I'd be great to get some help on how to get around this.

@vvb2060
Copy link
Owner

vvb2060 commented Jun 17, 2023

Thanks for your PR! I'm a bit surprised that Samsung has another system (even a different root of trust).
In AOSP, ID attestation also require privileges (READ_PRIVILEGED_PHONE_STATE). My idea is to support parsing them, and the generation can be done by other apps (e.g. test dpc). Because making the app privileged itself conflicts with integrity attestation.

Maybe use adb shell, which has more privileges than app and doesn't need unlock bootloader. This is in my plan, but for now I want to merge the parsing part first, hope you don't mind. Can you upload the saved pkipath file for me to test?

@vvb2060
Copy link
Owner

vvb2060 commented Jun 17, 2023

I did not find the public key published by Samsung on the Internet, can you provide the source?
https://docs.samsungknox.com/dev/knox-attestation/about-attestation.htm

@salvogiangri
Copy link
Contributor Author

salvogiangri commented Jun 17, 2023

Can you upload the saved pkipath file for me to test?

Sure! Here is it a52sxqeea-KeyAttestation.zip

I'm a bit surprised that Samsung has another system (even a different root of trust).

SKeymaster doesn't differs much from AOSP keymaster, Samsung enables Knox-specific code when asked via passing additional KeyParameters to keymaster as I discovered here:

private KeyParameter[] constructAttestationArguments(AttestParameterSpec spec) throws IllegalArgumentException, NullPointerException {
    if (spec.getChallenge() == null) {
        throw new IllegalArgumentException("The challenge cannot be null");
    }

    ArrayList<KeyParameter> args = new ArrayList<>();

    args.add(makeBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, spec.getChallenge()));

    if (spec.isDeviceAttestation()) {
        args.add(makeBytes(KeymasterDefs.KM_TAG_SAMSUNG_ATTESTATION_ROOT, SAMSUNG_ATTESTESTATION_DEVICE_IDS_ROOT.getBytes()));
    } else {
        args.add(makeBytes(KeymasterDefs.KM_TAG_SAMSUNG_ATTESTATION_ROOT, SAMSUNG_ATTESTESTATION_ROOT.getBytes()));
    }

    X500Principal certificateSubject = spec.getCertificateSubject();
    if (certificateSubject != null && !TextUtils.isEmpty(certificateSubject.getName("RFC1779"))) {
        args.add(makeBytes(KeymasterDefs.KM_TAG_SAMSUNG_CERTIFICATE_SUBJECT, certificateSubject.getName("RFC1779").getBytes()));
    }

    if (spec.isVerifiableIntegrity()) {
        args.add(makeBool(KeymasterDefs.KM_TAG_SAMSUNG_ATTEST_INTEGRITY));
        
        Application application = ActivityThread.currentApplication();
        if (application == null) {
            Log.w(TAG, "can not found application");
        } else {
            String packageName = spec.getPackageName();
            if (TextUtils.isEmpty(packageName)) {
                packageName = application.getPackageName();
            }
            
            byte[] bytesAuthPkg = getBytesAuthenticatePackage(packageName, application);
            if (bytesAuthPkg == null) {
                Log.w(TAG, "Auth package byte is null");
            } else {
                args.add(makeBytes(KeymasterDefs.KM_TAG_SAMSUNG_AUTHENTICATE_PACKAGE, bytesAuthPkg));
            }
        }
    }

    if (spec.isDevicePropertiesAttestationIncluded()) {
        args.add(makeBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND, Build.BRAND.getBytes(StandardCharsets.UTF_8)));
        args.add(makeBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE, Build.DEVICE.getBytes(StandardCharsets.UTF_8)));
        args.add(makeBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT, Build.PRODUCT.getBytes(StandardCharsets.UTF_8)));
        args.add(makeBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MANUFACTURER, Build.MANUFACTURER.getBytes(StandardCharsets.UTF_8)));
        args.add(makeBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL, Build.MODEL.getBytes(StandardCharsets.UTF_8)));
    }

    return (KeyParameter[]) args.toArray(new KeyParameter[args.size()]);
}

@salvogiangri
Copy link
Contributor Author

I did not find the public key published by Samsung on the Internet, can you provide the source?

I was able to get it thanks to the debug logs in your app:

Log.w(AppApplication.TAG, Base64.encodeToString(rootPublicKey, Base64.NO_WRAP));

I've added it to hide the "not trusted" header in the app.

@vvb2060
Copy link
Owner

vvb2060 commented Jun 17, 2023

Due to the significance of root of trust, the app can only accept official public data, such as Google.
Also, if using AOSP API, is the root certificate signed by Google?

@salvogiangri
Copy link
Contributor Author

salvogiangri commented Jun 17, 2023

Due to the significance of root of trust, the app can only accept official public data, such as Google.

Afaict SAK is only used by Samsung Knox powered apps (except for Samsung Pay/Wallet and Pass), mostly to verify whether or not the device is tampered (the key generation fails when ICD status is abnormal unless isVerifyIntegrity is true), probably the reason why Samsung didn't publish their public key anywhere.

Also, if using AOSP API, is the root certificate signed by Google?

Yes (a52sxqeea-KeyAttestation.zip).

@vvb2060
Copy link
Owner

vvb2060 commented Jun 17, 2023

I guess it might be in the internal Samsung Knox SDK doc, if you can confirm the public key is the same for all Samsung devices, I will add it.

@salvogiangri
Copy link
Contributor Author

I guess it might be in the internal Samsung Knox SDK doc, if you can confirm the public key is the same for all Samsung devices, I will add it.

Tested myself on two devices (Galaxy A52s 5G with Android 13, Galaxy A71 with Android 11) and the public key is the same.

@vvb2060
Copy link
Owner

vvb2060 commented Nov 15, 2023

critical(false) 1.3.6.1.4.1.236.11.3.23.7 value = Sequence
    Tagged [CONTEXT 0]
        PrintableString(Sat Jun 17 18:20:41 GMT+02:00 2023) 
    Tagged [CONTEXT 5]
        Sequence
            Tagged [CONTEXT 0]
                DER Enumerated(1)
            Tagged [CONTEXT 1]
                DER Enumerated(1)
            Tagged [CONTEXT 2]
                DER Enumerated(1)
            Tagged [CONTEXT 3]
                DER Enumerated(1)
            Tagged [CONTEXT 4]
                DER Enumerated(0)
            Tagged [CONTEXT 5]
                Sequence
                    Tagged [CONTEXT 0]
                        DER Enumerated(1048592)
                    Tagged [CONTEXT 1]
                        PrintableString(io.github.vvb2060.keyattestation) 
                    Tagged [CONTEXT 2]
                        PrintableString(6oIZkx9nsdHbEgbCgmbuQfWJf5kUUPBVexPiK8OQSZ8=) 
                    Tagged [CONTEXT 3]
                        DER Enumerated(1048592)
    Tagged [CONTEXT 6]
        DER Octet String[32] 

The data cannot be fully parsed.

@salvogiangri
Copy link
Contributor Author

salvogiangri commented Nov 15, 2023

Are you talking about the 6th entry? I didn't include that on purpose as it isn't relevant

private static final int AUTH_RESULT = 5;

private AuthResult mAuthResult = null;

public IntegrityStatus(ASN1Primitive asn1Encodable) {
    ASN1Sequence sequence = (ASN1Sequence) asn1Encodable;

    Enumeration<?> seqEnum = sequence.getObjects();
    while (seqEnum.hasMoreElements()) {
        ASN1TaggedObject derObj = (ASN1TaggedObject) seqEnum.nextElement();

        switch (derObj.getTagNo()) {
            // ...
            case AUTH_RESULT:
                mAuthResult = new AuthResult(derObj.getObject());
                break;
        }
    }
}

@Override
public String toString() {
    // ...
        .append("Caller auth (with PROCA) status:").append('\n');
    sb.append(mAuthResult == null ? "Not performed" : mAuthResult.toString());
    return sb.toString();
}

This is how the AuthResult class looks like:

package com.android.server.knox.dar;

import android.util.Log;
import org.bouncycastle.asn1.ASN1Enumerated;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import java.security.cert.CertificateParsingException;
import java.util.Enumeration;

public class AuthResult {
    private static final String TAG = "AuthResult";

    private static final int CALLER_AUTH_RESULT = 0;
    private static final int CALLING_PACKAGE = 1;
    private static final int CALLING_PACKAGE_SIGS = 2;
    private static final int CALLING_PACKAGE_AUTH_RESULT = 3;

    public static final int STATUS_NORMAL = 0;
    public static final int STATUS_ABNORMAL = 1;
    public static final int STATUS_NOT_SUPPORT = 2;

    private int mCallerAuthResult = -1;
    private byte[] mCallingPackage = new byte[]{0};
    private byte[] mCallingPackageSigs = new byte[]{0};
    private int mCallingPackageAuthResult = -1;

    public AuthResult(ASN1Primitive asn1Encodable) throws CertificateParsingException {
        if (!(asn1Encodable instanceof ASN1Sequence)) {
            throw new CertificateParsingException("Expected sequence for root of trust, found " + asn1Encodable.getClass().getName());
        }

        ASN1Sequence sequence = (ASN1Sequence) asn1Encodable;
        Enumeration seqEnum = sequence.getObjects();
        while (seqEnum.hasMoreElements()) {
            ASN1TaggedObject derObj = (ASN1TaggedObject) seqEnum.nextElement();

            switch (derObj.getTagNo()) {
                case CALLER_AUTH_RESULT:
                    mCallerAuthResult = ((ASN1Enumerated) derObj.getObject()).getValue().intValue();
                    break;
                case CALLING_PACKAGE:
                    mCallingPackage = Asn1Utils.getByteArrayFromAsn1(derObj);
                    break;
                case CALLING_PACKAGE_SIGS:
                    mCallingPackageSigs = Asn1Utils.getByteArrayFromAsn1(derObj);
                    break;
                case CALLING_PACKAGE_AUTH_RESULT:
                    mCallingPackageAuthResult = ((ASN1Enumerated) derObj.getObject()).getValue().intValue();
                    break;
                default:
                    Log.e(TAG, "invalid tag no : " + derObj.getTagNo());
                    break;
            }
        }
    }

    public int getCallerAuthResult() {
        return mCallerAuthResult;
    }

    public byte[] getCallingPackage() {
        return mCallingPackage;
    }

    public byte[] getCallingPackageSigs() {
        return mCallingPackageSigs;
    }

    public int getCallingPackageAuthResult() {
        return mCallingPackageAuthResult;
    }

    public String statusToString(int status, boolean isCallingPackageAuthResult) {
        switch (status) {
            case STATUS_NORMAL:
                return "Normal";
            case STATUS_ABNORMAL:
                return "Abnormal";
            case STATUS_NOT_SUPPORT:
                return "Not support";
            default:
                if (isCallingPackageAuthResult) {
                    return "Not support";
                }
                return Integer.toHexString(status);
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("        Caller Auth Result : ")
                .append(statusToString(mCallerAuthResult, false))
                .append("\n        Calling Package : ")
                .append(new String(mCallingPackage))
                .append("\n        Calling Package Signatures : ")
                .append(new String(mCallingPackageSigs))
                .append("\n        Calling Package Auth Result : ")
                .append(statusToString(mCallingPackageAuthResult, true));
        return sb.toString();
    }
}

@salvogiangri
Copy link
Contributor Author

@vvb2060
Copy link
Owner

vvb2060 commented Nov 15, 2023

    Tagged [CONTEXT 6]
        DER Octet String[32] 

what about this?

@salvogiangri
Copy link
Contributor Author

typedef struct KnoxTEEProperties {
    ASN1_PRINTABLESTRING *challenge;
    ACCESSOR *creator;
    ACCESSOR_SET *administrators;
    ACCESSOR_SET *accessors;
    ASN1_PRINTABLESTRING *id_attest;
    INTEGRITY_STATUS *integrity;
    ASN1_OCTET_STRING *attestation_record_hash;
} KNOX_TEE_PROPERTIES;

ASN1_SEQUENCE(KNOX_TEE_PROPERTIES) = {
    ASN1_EXP_OPT(KNOX_TEE_PROPERTIES, challenge, ASN1_PRINTABLESTRING, 0),
    ASN1_EXP_OPT(KNOX_TEE_PROPERTIES, creator, ACCESSOR, 1),
    ASN1_EXP_SET_OF_OPT(KNOX_TEE_PROPERTIES, administrators, ACCESSOR, 2),
    ASN1_EXP_SET_OF_OPT(KNOX_TEE_PROPERTIES, accessors, ACCESSOR, 3),
    ASN1_EXP_OPT(KNOX_TEE_PROPERTIES, id_attest, ASN1_PRINTABLESTRING, 4),
    ASN1_EXP_OPT(KNOX_TEE_PROPERTIES, integrity, INTEGRITY_STATUS, 5),
    ASN1_EXP_OPT(KNOX_TEE_PROPERTIES, attestation_record_hash, ASN1_OCTET_STRING, 6),
} ASN1_SEQUENCE_END(KNOX_TEE_PROPERTIES)

So Tagged [CONTEXT 0] is simply the challenge, while Tagged [CONTEXT 6] is internally referenced as ATN_BLOB_HASH, looks like a SHA256 digest of the TA requesting the integrity status data from ICCC

@salvogiangri
Copy link
Contributor Author

Updated the PR to adapt to the latest source changes, also did some minor code cleanup. However, it looks like the app generated attest key feature isn't working correctly (signature error:error decoding signature bytes.)


a54xnaeea-KeyAttestation.zip

@vvb2060
Copy link
Owner

vvb2060 commented Nov 16, 2023

You are in app attest key mode, it looks like Samsung does not support it, you need to remove this feature for Samsung service.

@salvogiangri
Copy link
Contributor Author

Added a toggle to switch between SAK and GAK, this will also disable app generated attest key feature when SAK is enabled.

@chiteroman
Copy link

chiteroman commented Dec 25, 2023

@blackmesa123 Samsung uses Google private key to sign the leaf certificate? Or it uses Samsung custom one?

EDIT: They use their private key :(

@salvogiangri
Copy link
Contributor Author

@blackmesa123 Samsung uses Google private key to sign the leaf certificate? Or it uses Samsung custom one?

EDIT: They use their private key :(

r11sxeea-KeyAttestation.zip

@vvb2060
Copy link
Owner

vvb2060 commented Jan 21, 2024

ASN1_PRINTABLESTRING challenge

public Builder(String alias, byte[] challenge)

What happens if fill it with a random byte array? This is a non-printable string.

ACCESSOR *creator;
ACCESSOR_SET *administrators;
ACCESSOR_SET *accessors;
ASN1_PRINTABLESTRING *id_attest;

Have they been deprecated and removed? I only find them in KnoxKeyInfo

@vvb2060
Copy link
Owner

vvb2060 commented Jan 22, 2024

https://docs.samsungknox.com/devref/knox-sdk/reference/com/samsung/android/knox/integrity/EnhancedAttestationPolicy.html

nonce
A nonce value that must be unique for each request. Nonce length can be 32 bytes string. Alphanumeric and underscore(_), dash(-), dot(.) characters are allowed for nonce.

public static final int ERROR_INVALID_NONCE
Since: API level 29 KNOX 3.4
Invalid nonce error occurred. Nonce length can be 32 bytes string. Alphanumeric and underscore(_), dash(-), dot(.) characters are allowed for nonce. Possible value for errorCode.

byte[] challenge It just follows the aosp api

last-modified: Fri, 15 Dec 2023 14:48:00 GMT
last-modified: Mon, 22 Jan 2024 17:18:00 GMT
@salvogiangri
Copy link
Contributor Author

ACCESSOR *creator;
ACCESSOR_SET *administrators;
ACCESSOR_SET *accessors;
ASN1_PRINTABLESTRING *id_attest;

Have they been deprecated and removed? I only find them in KnoxKeyInfo

Seems like it. The keymaster TA source code I checked, which is part of the Samsung 2022 leak, is based off a very old version (4.2.19, used in Android 11 Samsung OS), each of these values are respectly set via the KM_TAG_KNOX_CREATOR_ID, KM_TAG_KNOX_ACCESSOR_ID, KM_TAG_KNOX_ADMINISTRATOR_ID and KM_TAG_ATTESTATION_ID_DEVICE tags

@salvogiangri
Copy link
Contributor Author

About the recent pushes in master branch:

All the rest seems okay

@vvb2060
Copy link
Owner

vvb2060 commented Jan 23, 2024

What is the difference between sakmv1 and sakv1? Do they still sign certs without tags 1-4 (creator,administrators,accessors,id_attest) like v2?

@salvogiangri
Copy link
Contributor Author

What is the difference between sakmv1 and sakv1? Do they still sign certs without tags 1-4 (creator,administrators,accessors,id_attest) like v2?

Certificate probably doesn't matters, what matters is the Knox SDK the device is running on (Android version). I couldn't find any mention to these tags from Android 12 onwards and I think this is the reason: https://docs.samsungknox.com/dev/knox-sdk/features/mdm-providers/keystores/tima-ccm-keystores/deprecation-of-tima-ccm-keystore-support/

These tags are controlled via the com.samsung.android.knox.keystore.KnoxKeyGenParameterSpec class (https://github.com/corsicanu/random_dumps/releases/download/20221212203608/A505FDDS9CVJ1-app_frame.zip)

@salvogiangri
Copy link
Contributor Author

salvogiangri commented Jan 24, 2024

SAKm_V1 cert seems to be used on Samsung JDM devices (eg. SM-T505)

@vvb2060
Copy link
Owner

vvb2060 commented Jan 30, 2024

hldr4@6180e50 🤦

@vvb2060
Copy link
Owner

vvb2060 commented Nov 21, 2024

    public boolean isSupportDevicePropertiesAttestation(Context context) {
        return context.getPackageManager().hasSystemFeature("samsung.software.device_id_attestation");
    }

    public boolean isSupportSAKUidRequired(Context context) {
        return context.getPackageManager().hasSystemFeature("samsung.software.sakm_uid");
    }

https://gitgud.io/Van-Firmware-Dumps/samsung/a16xm/-/blob/a16xmnsxx-user-14-UP1A.231005.007-A166PXXU1AXIC-release-keys/vendor/etc/permissions/samsung.software.sakm_uid.xml
https://gitgud.io/Van-Firmware-Dumps/samsung/a16xm/-/blob/a16xmnsxx-user-14-UP1A.231005.007-A166PXXU1AXIC-release-keys/vendor/etc/permissions/android.software.device_id_attestation.xml?ref_type=heads

I don't know why

@salvogiangri
Copy link
Contributor Author

    public boolean isSupportDevicePropertiesAttestation(Context context) {
        return context.getPackageManager().hasSystemFeature("samsung.software.device_id_attestation");
    }

    public boolean isSupportSAKUidRequired(Context context) {
        return context.getPackageManager().hasSystemFeature("samsung.software.sakm_uid");
    }

https://gitgud.io/Van-Firmware-Dumps/samsung/a16xm/-/blob/a16xmnsxx-user-14-UP1A.231005.007-A166PXXU1AXIC-release-keys/vendor/etc/permissions/samsung.software.sakm_uid.xml https://gitgud.io/Van-Firmware-Dumps/samsung/a16xm/-/blob/a16xmnsxx-user-14-UP1A.231005.007-A166PXXU1AXIC-release-keys/vendor/etc/permissions/android.software.device_id_attestation.xml?ref_type=heads

I don't know why

First one is probably a leftover since the feature name is "android.software.device_id_attestation" just like on AOSP.

I never saw the second one and I can't seem to find it in Samsung in-house devices, so that code might be exclusive to Samsung JDM devices/firmwares (https://gitgud.io/Van-Firmware-Dumps/samsung/a16xm/-/blob/a16xmnsxx-user-14-UP1A.231005.007-A166PXXU1AXIC-release-keys/system/system/etc/floating_feature.xml?ref_type=heads#L66):

<SEC_FLOATING_FEATURE_COMMON_CONFIG_DEVICE_MANUFACTURING_TYPE>jdm</SEC_FLOATING_FEATURE_COMMON_CONFIG_DEVICE_MANUFACTURING_TYPE>
public static final int KM_TAG_SAMSUNG_UID_REQUIRED = 0x700009c4; // KM_BOOL | 2500;
if (spec.isSAKUidRequired()) {
    Log.w(TAG, "constructAttestationArguments : set SAK UID required");
    args.add(makeBool(KeymasterDefs.KM_TAG_SAMSUNG_UID_REQUIRED));
}

SAK UID can be seen in the intermediate cert (eg. "SAK_V2:20211230082636:520:v0MGMlvJ_ExyvfGKYqGa4YwNrr0C0jUesO3BCqhcpVA=:wUxAmaFZhPUS8SR62oJns3jToAme0Gwj1jEH4sDcSAE="), perhaps this works differently on JDM devices with SAKm cert? Gotta inspect the KeyMint TA.

@salvogiangri
Copy link
Contributor Author

SAK UID check takes place when requesting key attestation with setDeviceAttestation(true) in AttestParameterSpec.Builder, one of the two base64 encoded strings in the UID is a SHA256 digest of a 64 chars string containing device's IMEI and S/N

@vvb2060
Copy link
Owner

vvb2060 commented Jan 8, 2025

The app only supports Knox attestation on Android 10+. I'm not sure if I should add SAKv1 certificates. I haven't seen any other root public key signed certificates.

@salvogiangri
Copy link
Contributor Author

The app only supports Knox attestation on Android 10+. I'm not sure if I should add SAKv1 certificates. I haven't seen any other root public key signed certificates.

#15 (comment)

@vvb2060
Copy link
Owner

vvb2060 commented Jan 8, 2025

All merged, please check if there is anything missing

@salvogiangri
Copy link
Contributor Author

Tested upstream commit (b5d4675) on both my A52s and A54 (Keymaster vs. KeyMint 2) and everything seems fine



Unfortunately just like before Shizuku alone isn't enough to grant the SAMSUNG_KEYSTORE_PERMISSION permission (#15 (comment)) so I still had to push the apk to priv-app to allow using the Samsung attestation SDK

@vvb2060
Copy link
Owner

vvb2060 commented Jan 8, 2025

You can start shizuku with root instead of adb shell.

From the screenshot it looks like you have already done this, try moving the app out of priv-app and it should still work.

@salvogiangri
Copy link
Contributor Author

I confirm using Shizuku with root permissions also works without the requirement of having to push the apk in priv-app, looks good for a final release to me! I'd keep the ro.security.keystore.keytype prop check just in case tho

@vvb2060
Copy link
Owner

vvb2060 commented Jan 9, 2025

While I was searching for this prop to make sure its selinux context allowed user app to read it, I found some posts about remove sak.

image

So I ignore this check, and if the device really doesn't support it, then the exception will be caught, just like gak.

try {
keyPairGenerator.initialize(params);
keyPairGenerator.generateKeyPair();
if (useSak) {
var utils = new com.samsung.android.security.keystore.AttestationUtils();
var spec = genSakParameter(params);
Iterable<byte[]> certChain;
if (spec.isDeviceAttestation()) {
certChain = utils.attestDevice(spec);
} else {
certChain = utils.attestKey(spec);
}
utils.storeCertificateChain(alias, certChain);
}
return null;
} catch (Exception exception) {
Log.e(AppApplication.TAG, "generateKeyPair", exception);

@salvogiangri
Copy link
Contributor Author

This is erroneously done to "bypass" security checks in some Knox apps which can work without Samsung attestation (eg. Samsung Health), but shouldn't be done as it breaks some core system features which instead heavily rely on SAK to work (eg. FMM), so I wouldn't account the user stupidity to touch stuff they shouldn't. KnoxPatch/OS patches should be used instead to bypass Samsung Knox security checks in such apps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants