Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f9c14b7d authored by Alex Klyubin's avatar Alex Klyubin Committed by Android Git Automerger
Browse files

am b068ae14: am e2b9bb45: Merge "No runtime exceptions during normal use of...

am b068ae14: am e2b9bb45: Merge "No runtime exceptions during normal use of AndroidKeyStore crypto."

* commit 'b068ae14':
  No runtime exceptions during normal use of AndroidKeyStore crypto.
parents 94089591 b068ae14
Loading
Loading
Loading
Loading
+0 −61
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * 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 android.security;

/**
 * Base class for exceptions during cryptographic operations which cannot throw a suitable checked
 * exception.
 *
 * <p>The contract of the majority of crypto primitives/operations (e.g. {@code Cipher} or
 * {@code Signature}) is that they can throw a checked exception during initialization, but are not
 * permitted to throw a checked exception during operation. Because crypto operations can fail
 * for a variety of reasons after initialization, this base class provides type-safety for unchecked
 * exceptions that may be thrown in those cases.
 *
 * @hide
 */
public class CryptoOperationException extends RuntimeException {

    /**
     * Constructs a new {@code CryptoOperationException} without detail message and cause.
     */
    public CryptoOperationException() {
        super();
    }

    /**
     * Constructs a new {@code CryptoOperationException} with the provided detail message and no
     * cause.
     */
    public CryptoOperationException(String message) {
        super(message);
    }

    /**
     * Constructs a new {@code CryptoOperationException} with the provided detail message and cause.
     */
    public CryptoOperationException(String message, Throwable cause) {
        super(message, cause);
    }

    /**
     * Constructs a new {@code CryptoOperationException} with the provided cause.
     */
    public CryptoOperationException(Throwable cause) {
        super(cause);
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -16,13 +16,15 @@

package android.security;

import java.security.InvalidKeyException;

/**
 * Indicates that a cryptographic operation failed because the employed key's validity end date
 * is in the past.
 *
 * @hide
 */
public class KeyExpiredException extends CryptoOperationException {
public class KeyExpiredException extends InvalidKeyException {

    /**
     * Constructs a new {@code KeyExpiredException} without detail message and cause.
+3 −1
Original line number Diff line number Diff line
@@ -16,13 +16,15 @@

package android.security;

import java.security.InvalidKeyException;

/**
 * Indicates that a cryptographic operation failed because the employed key's validity start date
 * is in the future.
 *
 * @hide
 */
public class KeyNotYetValidException extends CryptoOperationException {
public class KeyNotYetValidException extends InvalidKeyException {

    /**
     * Constructs a new {@code KeyNotYetValidException} without detail message and cause.
+18 −5
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.security.keymaster.KeymasterDefs;
import android.security.keymaster.OperationResult;
import android.util.Log;

import java.security.InvalidKeyException;
import java.util.Locale;

/**
@@ -508,7 +509,11 @@ public class KeyStore {
        }
    }

    public static KeyStoreException getKeyStoreException(int errorCode) {
    /**
     * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
     * code.
     */
    static KeyStoreException getKeyStoreException(int errorCode) {
        if (errorCode > 0) {
            // KeyStore layer error
            switch (errorCode) {
@@ -544,7 +549,11 @@ public class KeyStore {
        }
    }

    public static CryptoOperationException getCryptoOperationException(KeyStoreException e) {
    /**
     * Returns an {@link InvalidKeyException} corresponding to the provided
     * {@link KeyStoreException}.
     */
    static InvalidKeyException getInvalidKeyException(KeyStoreException e) {
        switch (e.getErrorCode()) {
            case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
                return new KeyExpiredException();
@@ -553,11 +562,15 @@ public class KeyStore {
            case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
                return new UserNotAuthenticatedException();
            default:
                return new CryptoOperationException("Crypto operation failed", e);
                return new InvalidKeyException("Keystore operation failed", e);
        }
    }

    public static CryptoOperationException getCryptoOperationException(int errorCode) {
        return getCryptoOperationException(getKeyStoreException(errorCode));
    /**
     * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
     * code.
     */
    static InvalidKeyException getInvalidKeyException(int errorCode) {
        return getInvalidKeyException(getKeyStoreException(errorCode));
    }
}
+50 −10
Original line number Diff line number Diff line
@@ -136,6 +136,14 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
    private Long mOperationHandle;
    private KeyStoreCryptoOperationChunkedStreamer mMainDataStreamer;

    /**
     * Encountered exception which could not be immediately thrown because it was encountered inside
     * a method that does not throw checked exception. This exception will be thrown from
     * {@code engineDoFinal}. Once such an exception is encountered, {@code engineUpdate} and
     * {@code engineDoFinal} start ignoring input data.
     */
    private Exception mCachedException;

    protected KeyStoreCipherSpi(
            int keymasterAlgorithm,
            int keymasterBlockMode,
@@ -158,7 +166,11 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
        try {
            init(opmode, key, random);
            initAlgorithmSpecificParameters();
            try {
                ensureKeystoreOperationInitialized();
            } catch (InvalidAlgorithmParameterException e) {
                throw new InvalidKeyException(e);
            }
            success = true;
        } finally {
            if (!success) {
@@ -236,6 +248,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
        mOperationToken = null;
        mOperationHandle = null;
        mMainDataStreamer = null;
        mCachedException = null;
    }

    private void resetWhilePreservingInitState() {
@@ -247,12 +260,17 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
        mOperationHandle = null;
        mMainDataStreamer = null;
        mAdditionalEntropyForBegin = null;
        mCachedException = null;
    }

    private void ensureKeystoreOperationInitialized() {
    private void ensureKeystoreOperationInitialized() throws InvalidKeyException,
            InvalidAlgorithmParameterException {
        if (mMainDataStreamer != null) {
            return;
        }
        if (mCachedException != null) {
            return;
        }
        if (mKey == null) {
            throw new IllegalStateException("Not initialized");
        }
@@ -281,11 +299,15 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
        if (opResult == null) {
            throw new KeyStoreConnectException();
        } else if (opResult.resultCode != KeyStore.NO_ERROR) {
            throw KeyStore.getCryptoOperationException(opResult.resultCode);
            switch (opResult.resultCode) {
                case KeymasterDefs.KM_ERROR_INVALID_NONCE:
                    throw new InvalidAlgorithmParameterException("Invalid IV");
            }
            throw KeyStore.getInvalidKeyException(opResult.resultCode);
        }

        if (opResult.token == null) {
            throw new CryptoOperationException("Keystore returned null operation token");
            throw new IllegalStateException("Keystore returned null operation token");
        }
        mOperationToken = opResult.token;
        mOperationHandle = opResult.operationHandle;
@@ -299,7 +321,15 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry

    @Override
    protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
        if (mCachedException != null) {
            return null;
        }
        try {
            ensureKeystoreOperationInitialized();
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            mCachedException = e;
            return null;
        }

        if (inputLen == 0) {
            return null;
@@ -309,7 +339,8 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
        try {
            output = mMainDataStreamer.update(input, inputOffset, inputLen);
        } catch (KeyStoreException e) {
            throw KeyStore.getCryptoOperationException(e);
            mCachedException = e;
            return null;
        }

        if (output.length == 0) {
@@ -338,7 +369,16 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
    @Override
    protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
            throws IllegalBlockSizeException, BadPaddingException {
        if (mCachedException != null) {
            throw (IllegalBlockSizeException)
                    new IllegalBlockSizeException().initCause(mCachedException);
        }

        try {
            ensureKeystoreOperationInitialized();
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
        }

        byte[] output;
        try {
@@ -352,7 +392,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
                case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
                    throw new AEADBadTagException();
                default:
                    throw KeyStore.getCryptoOperationException(e);
                    throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
            }
        }

@@ -613,11 +653,11 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
            if (mIv == null) {
                mIv = returnedIv;
            } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
                throw new CryptoOperationException("IV in use differs from provided IV");
                throw new IllegalStateException("IV in use differs from provided IV");
            }
        } else {
            if (returnedIv != null) {
                throw new CryptoOperationException(
                throw new IllegalStateException(
                        "IV in use despite IV not being used by this transformation");
            }
        }
Loading