Search in sources :

Example 46 with KeyCharacteristics

use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by DirtyUnicorns.

the class AndroidKeyStoreKeyPairGeneratorSpi method generateKeystoreKeyPair.

private void generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args, byte[] additionalEntropy, final int flags) throws ProviderException {
    KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
    int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy, mEntryUid, flags, resultingKeyCharacteristics);
    if (errorCode != KeyStore.NO_ERROR) {
        throw new ProviderException("Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
    }
}
Also used : ProviderException(java.security.ProviderException) KeyCharacteristics(android.security.keymaster.KeyCharacteristics)

Example 47 with KeyCharacteristics

use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by DirtyUnicorns.

the class AndroidKeyStoreProvider method loadAndroidKeyStorePublicKeyFromKeystore.

@NonNull
public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(@NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid) throws UnrecoverableKeyException {
    KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
    int errorCode = keyStore.getKeyCharacteristics(privateKeyAlias, null, null, uid, keyCharacteristics);
    if (errorCode != KeyStore.NO_ERROR) {
        throw (UnrecoverableKeyException) new UnrecoverableKeyException("Failed to obtain information about private key").initCause(KeyStore.getKeyStoreException(errorCode));
    }
    ExportResult exportResult = keyStore.exportKey(privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null, uid);
    if (exportResult.resultCode != KeyStore.NO_ERROR) {
        throw (UnrecoverableKeyException) new UnrecoverableKeyException("Failed to obtain X.509 form of public key").initCause(KeyStore.getKeyStoreException(exportResult.resultCode));
    }
    final byte[] x509EncodedPublicKey = exportResult.exportData;
    Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
    if (keymasterAlgorithm == null) {
        throw new UnrecoverableKeyException("Key algorithm unknown");
    }
    String jcaKeyAlgorithm;
    try {
        jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(keymasterAlgorithm);
    } catch (IllegalArgumentException e) {
        throw (UnrecoverableKeyException) new UnrecoverableKeyException("Failed to load private key").initCause(e);
    }
    return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(privateKeyAlias, uid, jcaKeyAlgorithm, x509EncodedPublicKey);
}
Also used : UnrecoverableKeyException(java.security.UnrecoverableKeyException) KeyCharacteristics(android.security.keymaster.KeyCharacteristics) ExportResult(android.security.keymaster.ExportResult) NonNull(android.annotation.NonNull)

Example 48 with KeyCharacteristics

use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by DirtyUnicorns.

the class AndroidKeyStoreProvider method loadAndroidKeyStoreSecretKeyFromKeystore.

@NonNull
public static AndroidKeyStoreSecretKey loadAndroidKeyStoreSecretKeyFromKeystore(@NonNull KeyStore keyStore, @NonNull String secretKeyAlias, int uid) throws UnrecoverableKeyException {
    KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
    int errorCode = keyStore.getKeyCharacteristics(secretKeyAlias, null, null, uid, keyCharacteristics);
    if (errorCode != KeyStore.NO_ERROR) {
        throw (UnrecoverableKeyException) new UnrecoverableKeyException("Failed to obtain information about key").initCause(KeyStore.getKeyStoreException(errorCode));
    }
    Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
    if (keymasterAlgorithm == null) {
        throw new UnrecoverableKeyException("Key algorithm unknown");
    }
    List<Integer> keymasterDigests = keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_DIGEST);
    int keymasterDigest;
    if (keymasterDigests.isEmpty()) {
        keymasterDigest = -1;
    } else {
        // More than one digest can be permitted for this key. Use the first one to form the
        // JCA key algorithm name.
        keymasterDigest = keymasterDigests.get(0);
    }
    @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
    try {
        keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(keymasterAlgorithm, keymasterDigest);
    } catch (IllegalArgumentException e) {
        throw (UnrecoverableKeyException) new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
    }
    return new AndroidKeyStoreSecretKey(secretKeyAlias, uid, keyAlgorithmString);
}
Also used : UnrecoverableKeyException(java.security.UnrecoverableKeyException) KeyCharacteristics(android.security.keymaster.KeyCharacteristics) NonNull(android.annotation.NonNull)

Example 49 with KeyCharacteristics

use of android.security.keymaster.KeyCharacteristics in project platform_frameworks_base by android.

the class AndroidKeyStoreSpi method setSecretKeyEntry.

private void setSecretKeyEntry(String entryAlias, SecretKey key, java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
    if ((param != null) && (!(param instanceof KeyProtection))) {
        throw new KeyStoreException("Unsupported protection parameter class: " + param.getClass().getName() + ". Supported: " + KeyProtection.class.getName());
    }
    KeyProtection params = (KeyProtection) param;
    if (key instanceof AndroidKeyStoreSecretKey) {
        // KeyStore-backed secret key. It cannot be duplicated into another entry and cannot
        // overwrite its own entry.
        String keyAliasInKeystore = ((AndroidKeyStoreSecretKey) key).getAlias();
        if (keyAliasInKeystore == null) {
            throw new KeyStoreException("KeyStore-backed secret key does not have an alias");
        }
        if (!keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)) {
            throw new KeyStoreException("KeyStore-backed secret key has invalid alias: " + keyAliasInKeystore);
        }
        String keyEntryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
        if (!entryAlias.equals(keyEntryAlias)) {
            throw new KeyStoreException("Can only replace KeyStore-backed keys with same" + " alias: " + entryAlias + " != " + keyEntryAlias);
        }
        // This is the entry where this key is already stored. No need to do anything.
        if (params != null) {
            throw new KeyStoreException("Modifying KeyStore-backed key using protection" + " parameters not supported");
        }
        return;
    }
    if (params == null) {
        throw new KeyStoreException("Protection parameters must be specified when importing a symmetric key");
    }
    // Not a KeyStore-backed secret key -- import its key material into keystore.
    String keyExportFormat = key.getFormat();
    if (keyExportFormat == null) {
        throw new KeyStoreException("Only secret keys that export their key material are supported");
    } else if (!"RAW".equals(keyExportFormat)) {
        throw new KeyStoreException("Unsupported secret key material export format: " + keyExportFormat);
    }
    byte[] keyMaterial = key.getEncoded();
    if (keyMaterial == null) {
        throw new KeyStoreException("Key did not export its key material despite supporting" + " RAW format export");
    }
    KeymasterArguments args = new KeymasterArguments();
    try {
        int keymasterAlgorithm = KeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm(key.getAlgorithm());
        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);
        int[] keymasterDigests;
        if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
            // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
            // implies SHA-256 digest). Because keymaster HMAC key is authorized only for one
            // digest, we don't let import parameters override the digest implied by the key.
            // If the parameters specify digests at all, they must specify only one digest, the
            // only implied by key algorithm.
            int keymasterImpliedDigest = KeyProperties.KeyAlgorithm.toKeymasterDigest(key.getAlgorithm());
            if (keymasterImpliedDigest == -1) {
                throw new ProviderException("HMAC key algorithm digest unknown for key algorithm " + key.getAlgorithm());
            }
            keymasterDigests = new int[] { keymasterImpliedDigest };
            if (params.isDigestsSpecified()) {
                // Digest(s) explicitly specified in params -- check that the list consists of
                // exactly one digest, the one implied by key algorithm.
                int[] keymasterDigestsFromParams = KeyProperties.Digest.allToKeymaster(params.getDigests());
                if ((keymasterDigestsFromParams.length != 1) || (keymasterDigestsFromParams[0] != keymasterImpliedDigest)) {
                    throw new KeyStoreException("Unsupported digests specification: " + Arrays.asList(params.getDigests()) + ". Only " + KeyProperties.Digest.fromKeymaster(keymasterImpliedDigest) + " supported for HMAC key algorithm " + key.getAlgorithm());
                }
            }
        } else {
            // Key algorithm does not imply a digest.
            if (params.isDigestsSpecified()) {
                keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
            } else {
                keymasterDigests = EmptyArray.INT;
            }
        }
        args.addEnums(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
        @KeyProperties.PurposeEnum int purposes = params.getPurposes();
        int[] keymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(params.getBlockModes());
        if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0) && (params.isRandomizedEncryptionRequired())) {
            for (int keymasterBlockMode : keymasterBlockModes) {
                if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(keymasterBlockMode)) {
                    throw new KeyStoreException("Randomized encryption (IND-CPA) required but may be violated by" + " block mode: " + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode) + ". See KeyProtection documentation.");
                }
            }
        }
        args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, KeyProperties.Purpose.allToKeymaster(purposes));
        args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
        if (params.getSignaturePaddings().length > 0) {
            throw new KeyStoreException("Signature paddings not supported for symmetric keys");
        }
        int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(params.getEncryptionPaddings());
        args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
        KeymasterUtils.addUserAuthArgs(args, params.isUserAuthenticationRequired(), params.getUserAuthenticationValidityDurationSeconds(), params.isUserAuthenticationValidWhileOnBody(), params.isInvalidatedByBiometricEnrollment());
        KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(args, keymasterAlgorithm, keymasterBlockModes, keymasterDigests);
        args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, params.getKeyValidityStart());
        args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, params.getKeyValidityForOriginationEnd());
        args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, params.getKeyValidityForConsumptionEnd());
        if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0) && (!params.isRandomizedEncryptionRequired())) {
            // Permit caller-provided IV when encrypting with this key
            args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
        }
    } catch (IllegalArgumentException | IllegalStateException e) {
        throw new KeyStoreException(e);
    }
    Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias, mUid);
    String keyAliasInKeystore = Credentials.USER_SECRET_KEY + entryAlias;
    int errorCode = mKeyStore.importKey(keyAliasInKeystore, args, KeymasterDefs.KM_KEY_FORMAT_RAW, keyMaterial, mUid, // flags
    0, new KeyCharacteristics());
    if (errorCode != KeyStore.NO_ERROR) {
        throw new KeyStoreException("Failed to import secret key. Keystore error code: " + errorCode);
    }
}
Also used : KeymasterArguments(android.security.keymaster.KeymasterArguments) ProviderException(java.security.ProviderException) KeyStoreException(java.security.KeyStoreException) KeyProtection(android.security.keystore.KeyProtection) KeyCharacteristics(android.security.keymaster.KeyCharacteristics)

Example 50 with KeyCharacteristics

use of android.security.keymaster.KeyCharacteristics in project platform_frameworks_base by android.

the class AndroidKeyStoreSpi method setPrivateKeyEntry.

private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain, java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
    int flags = 0;
    KeyProtection spec;
    if (param == null) {
        spec = getLegacyKeyProtectionParameter(key);
    } else if (param instanceof KeyStoreParameter) {
        spec = getLegacyKeyProtectionParameter(key);
        KeyStoreParameter legacySpec = (KeyStoreParameter) param;
        if (legacySpec.isEncryptionRequired()) {
            flags = KeyStore.FLAG_ENCRYPTED;
        }
    } else if (param instanceof KeyProtection) {
        spec = (KeyProtection) param;
    } else {
        throw new KeyStoreException("Unsupported protection parameter class:" + param.getClass().getName() + ". Supported: " + KeyProtection.class.getName() + ", " + KeyStoreParameter.class.getName());
    }
    // Make sure the chain exists since this is a PrivateKey
    if ((chain == null) || (chain.length == 0)) {
        throw new KeyStoreException("Must supply at least one Certificate with PrivateKey");
    }
    // Do chain type checking.
    X509Certificate[] x509chain = new X509Certificate[chain.length];
    for (int i = 0; i < chain.length; i++) {
        if (!"X.509".equals(chain[i].getType())) {
            throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #" + i);
        }
        if (!(chain[i] instanceof X509Certificate)) {
            throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #" + i);
        }
        x509chain[i] = (X509Certificate) chain[i];
    }
    final byte[] userCertBytes;
    try {
        userCertBytes = x509chain[0].getEncoded();
    } catch (CertificateEncodingException e) {
        throw new KeyStoreException("Failed to encode certificate #0", e);
    }
    /*
         * If we have a chain, store it in the CA certificate slot for this
         * alias as concatenated DER-encoded certificates. These can be
         * deserialized by {@link CertificateFactory#generateCertificates}.
         */
    final byte[] chainBytes;
    if (chain.length > 1) {
        /*
             * The chain is passed in as {user_cert, ca_cert_1, ca_cert_2, ...}
             * so we only need the certificates starting at index 1.
             */
        final byte[][] certsBytes = new byte[x509chain.length - 1][];
        int totalCertLength = 0;
        for (int i = 0; i < certsBytes.length; i++) {
            try {
                certsBytes[i] = x509chain[i + 1].getEncoded();
                totalCertLength += certsBytes[i].length;
            } catch (CertificateEncodingException e) {
                throw new KeyStoreException("Failed to encode certificate #" + i, e);
            }
        }
        /*
             * Serialize this into one byte array so we can later call
             * CertificateFactory#generateCertificates to recover them.
             */
        chainBytes = new byte[totalCertLength];
        int outputOffset = 0;
        for (int i = 0; i < certsBytes.length; i++) {
            final int certLength = certsBytes[i].length;
            System.arraycopy(certsBytes[i], 0, chainBytes, outputOffset, certLength);
            outputOffset += certLength;
            certsBytes[i] = null;
        }
    } else {
        chainBytes = null;
    }
    final String pkeyAlias;
    if (key instanceof AndroidKeyStorePrivateKey) {
        pkeyAlias = ((AndroidKeyStoreKey) key).getAlias();
    } else {
        pkeyAlias = null;
    }
    byte[] pkcs8EncodedPrivateKeyBytes;
    KeymasterArguments importArgs;
    final boolean shouldReplacePrivateKey;
    if (pkeyAlias != null && pkeyAlias.startsWith(Credentials.USER_PRIVATE_KEY)) {
        final String keySubalias = pkeyAlias.substring(Credentials.USER_PRIVATE_KEY.length());
        if (!alias.equals(keySubalias)) {
            throw new KeyStoreException("Can only replace keys with same alias: " + alias + " != " + keySubalias);
        }
        shouldReplacePrivateKey = false;
        importArgs = null;
        pkcs8EncodedPrivateKeyBytes = null;
    } else {
        shouldReplacePrivateKey = true;
        // Make sure the PrivateKey format is the one we support.
        final String keyFormat = key.getFormat();
        if ((keyFormat == null) || (!"PKCS#8".equals(keyFormat))) {
            throw new KeyStoreException("Unsupported private key export format: " + keyFormat + ". Only private keys which export their key material in PKCS#8 format are" + " supported.");
        }
        // Make sure we can actually encode the key.
        pkcs8EncodedPrivateKeyBytes = key.getEncoded();
        if (pkcs8EncodedPrivateKeyBytes == null) {
            throw new KeyStoreException("Private key did not export any key material");
        }
        importArgs = new KeymasterArguments();
        try {
            importArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(key.getAlgorithm()));
            @KeyProperties.PurposeEnum int purposes = spec.getPurposes();
            importArgs.addEnums(KeymasterDefs.KM_TAG_PURPOSE, KeyProperties.Purpose.allToKeymaster(purposes));
            if (spec.isDigestsSpecified()) {
                importArgs.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeyProperties.Digest.allToKeymaster(spec.getDigests()));
            }
            importArgs.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes()));
            int[] keymasterEncryptionPaddings = KeyProperties.EncryptionPadding.allToKeymaster(spec.getEncryptionPaddings());
            if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0) && (spec.isRandomizedEncryptionRequired())) {
                for (int keymasterPadding : keymasterEncryptionPaddings) {
                    if (!KeymasterUtils.isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(keymasterPadding)) {
                        throw new KeyStoreException("Randomized encryption (IND-CPA) required but is violated by" + " encryption padding mode: " + KeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding) + ". See KeyProtection documentation.");
                    }
                }
            }
            importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterEncryptionPaddings);
            importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING, KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
            KeymasterUtils.addUserAuthArgs(importArgs, spec.isUserAuthenticationRequired(), spec.getUserAuthenticationValidityDurationSeconds(), spec.isUserAuthenticationValidWhileOnBody(), spec.isInvalidatedByBiometricEnrollment());
            importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart());
            importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, spec.getKeyValidityForOriginationEnd());
            importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, spec.getKeyValidityForConsumptionEnd());
        } catch (IllegalArgumentException | IllegalStateException e) {
            throw new KeyStoreException(e);
        }
    }
    boolean success = false;
    try {
        // Store the private key, if necessary
        if (shouldReplacePrivateKey) {
            // Delete the stored private key and any related entries before importing the
            // provided key
            Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
            KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
            int errorCode = mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, importArgs, KeymasterDefs.KM_KEY_FORMAT_PKCS8, pkcs8EncodedPrivateKeyBytes, mUid, flags, resultingKeyCharacteristics);
            if (errorCode != KeyStore.NO_ERROR) {
                throw new KeyStoreException("Failed to store private key", KeyStore.getKeyStoreException(errorCode));
            }
        } else {
            // Keep the stored private key around -- delete all other entry types
            Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
            Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias, mUid);
        }
        // Store the leaf certificate
        int errorCode = mKeyStore.insert(Credentials.USER_CERTIFICATE + alias, userCertBytes, mUid, flags);
        if (errorCode != KeyStore.NO_ERROR) {
            throw new KeyStoreException("Failed to store certificate #0", KeyStore.getKeyStoreException(errorCode));
        }
        // Store the certificate chain
        errorCode = mKeyStore.insert(Credentials.CA_CERTIFICATE + alias, chainBytes, mUid, flags);
        if (errorCode != KeyStore.NO_ERROR) {
            throw new KeyStoreException("Failed to store certificate chain", KeyStore.getKeyStoreException(errorCode));
        }
        success = true;
    } finally {
        if (!success) {
            if (shouldReplacePrivateKey) {
                Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
            } else {
                Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
                Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias, mUid);
            }
        }
    }
}
Also used : KeymasterArguments(android.security.keymaster.KeymasterArguments) CertificateEncodingException(java.security.cert.CertificateEncodingException) KeyStoreException(java.security.KeyStoreException) KeyProtection(android.security.keystore.KeyProtection) X509Certificate(java.security.cert.X509Certificate) KeyStoreParameter(android.security.KeyStoreParameter) KeyCharacteristics(android.security.keymaster.KeyCharacteristics)

Aggregations

KeyCharacteristics (android.security.keymaster.KeyCharacteristics)85 KeymasterArguments (android.security.keymaster.KeymasterArguments)50 ProviderException (java.security.ProviderException)20 IBinder (android.os.IBinder)15 OperationResult (android.security.keymaster.OperationResult)15 NonNull (android.annotation.NonNull)10 KeyProtection (android.security.keystore.KeyProtection)10 InvalidKeyException (java.security.InvalidKeyException)10 KeyStoreException (java.security.KeyStoreException)10 UnrecoverableKeyException (java.security.UnrecoverableKeyException)10 KeyStoreParameter (android.security.KeyStoreParameter)5 ExportResult (android.security.keymaster.ExportResult)5 KeymasterBlob (android.security.keymaster.KeymasterBlob)5 KeyGenParameterSpec (android.security.keystore.KeyGenParameterSpec)5 BigInteger (java.math.BigInteger)5 PrivateKey (java.security.PrivateKey)5 CertificateEncodingException (java.security.cert.CertificateEncodingException)5 X509Certificate (java.security.cert.X509Certificate)5 ArrayList (java.util.ArrayList)5 Date (java.util.Date)5