1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.security.keystore2;
18 
19 import android.annotation.CallSuper;
20 import android.annotation.NonNull;
21 import android.hardware.security.keymint.KeyParameter;
22 import android.security.KeyStoreException;
23 import android.security.KeyStoreOperation;
24 import android.security.keymaster.KeymasterDefs;
25 import android.security.keystore.ArrayUtils;
26 import android.security.keystore.KeyStoreCryptoOperation;
27 
28 import libcore.util.EmptyArray;
29 
30 import java.nio.ByteBuffer;
31 import java.security.InvalidKeyException;
32 import java.security.InvalidParameterException;
33 import java.security.NoSuchAlgorithmException;
34 import java.security.PrivateKey;
35 import java.security.ProviderException;
36 import java.security.PublicKey;
37 import java.security.SecureRandom;
38 import java.security.Signature;
39 import java.security.SignatureException;
40 import java.security.SignatureSpi;
41 import java.util.ArrayList;
42 import java.util.List;
43 
44 /**
45  * Base class for {@link SignatureSpi} implementations of Android KeyStore backed ciphers.
46  *
47  * @hide
48  */
49 abstract class AndroidKeyStoreSignatureSpiBase extends SignatureSpi
50         implements KeyStoreCryptoOperation {
51     private static final String TAG = "AndroidKeyStoreSignatureSpiBase";
52 
53     // Fields below are populated by SignatureSpi.engineInitSign/engineInitVerify and KeyStore.begin
54     // and should be preserved after SignatureSpi.engineSign/engineVerify finishes.
55     private boolean mSigning;
56     private AndroidKeyStoreKey mKey;
57 
58     /**
59      * Object representing this operation inside keystore service. It is initialized
60      * by {@code engineInit} and is invalidated when {@code engineDoFinal} succeeds and on some
61      * error conditions in between.
62      */
63     private KeyStoreOperation mOperation;
64     /**
65      * The operation challenge is required when an operation needs user authorization.
66      * The challenge is subjected to an authenticator, e.g., Gatekeeper or a biometric
67      * authenticator, and included in the authentication token minted by this authenticator.
68      * It may be null, if the operation does not require authorization.
69      */
70     private long mOperationChallenge;
71     private KeyStoreCryptoOperationStreamer mMessageStreamer;
72 
73     /**
74      * Encountered exception which could not be immediately thrown because it was encountered inside
75      * a method that does not throw checked exception. This exception will be thrown from
76      * {@code engineSign} or {@code engineVerify}. Once such an exception is encountered,
77      * {@code engineUpdate} starts ignoring input data.
78      */
79     private Exception mCachedException;
80 
81     /**
82      * This signature object is used for public key operations, i.e, signatrue verification.
83      * The Android Keystore backend does not perform public key operations and defers to the
84      * Highest priority provider.
85      */
86     private Signature mSignature;
87 
AndroidKeyStoreSignatureSpiBase()88     AndroidKeyStoreSignatureSpiBase() {
89         mOperation = null;
90         mOperationChallenge = 0;
91         mSigning = false;
92         mKey = null;
93         appRandom = null;
94         mMessageStreamer = null;
95         mCachedException = null;
96         mSignature = null;
97     }
98 
99     @Override
engineInitSign(PrivateKey key)100     protected final void engineInitSign(PrivateKey key) throws InvalidKeyException {
101         engineInitSign(key, null);
102     }
103 
104     @Override
engineInitSign(PrivateKey privateKey, SecureRandom random)105     protected final void engineInitSign(PrivateKey privateKey, SecureRandom random)
106             throws InvalidKeyException {
107         resetAll();
108 
109         boolean success = false;
110         try {
111             if (privateKey == null) {
112                 throw new InvalidKeyException("Unsupported key: null");
113             }
114             AndroidKeyStoreKey keystoreKey;
115             if (privateKey instanceof AndroidKeyStorePrivateKey) {
116                 keystoreKey = (AndroidKeyStoreKey) privateKey;
117             } else {
118                 throw new InvalidKeyException("Unsupported private key type: " + privateKey);
119             }
120             mSigning = true;
121             initKey(keystoreKey);
122             appRandom = random;
123             ensureKeystoreOperationInitialized();
124             success = true;
125         } finally {
126             if (!success) {
127                 resetAll();
128             }
129         }
130     }
131 
132     @Override
engineInitVerify(PublicKey publicKey)133     protected final void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
134         resetAll();
135 
136         try {
137             mSignature = Signature.getInstance(getAlgorithm());
138         } catch (NoSuchAlgorithmException e) {
139             throw new InvalidKeyException(e);
140         }
141 
142         mSignature.initVerify(publicKey);
143     }
144 
145     /**
146      * Configures this signature instance to use the provided key.
147      *
148      * @throws InvalidKeyException if the {@code key} is not suitable.
149      */
150     @CallSuper
initKey(AndroidKeyStoreKey key)151     protected void initKey(AndroidKeyStoreKey key) throws InvalidKeyException {
152         mKey = key;
153     }
154 
abortOperation()155     private void abortOperation() {
156         KeyStoreCryptoOperationUtils.abortOperation(mOperation);
157         mOperation = null;
158     }
159 
160     /**
161      * Resets this cipher to its pristine pre-init state. This must be equivalent to obtaining a new
162      * cipher instance.
163      *
164      * <p>Subclasses storing additional state should override this method, reset the additional
165      * state, and then chain to superclass.
166      */
167     @CallSuper
resetAll()168     protected void resetAll() {
169         abortOperation();
170         mOperationChallenge = 0;
171         mSigning = false;
172         mKey = null;
173         appRandom = null;
174         mMessageStreamer = null;
175         mCachedException = null;
176     }
177 
178     /**
179      * Resets this cipher while preserving the initialized state. This must be equivalent to
180      * rolling back the cipher's state to just after the most recent {@code engineInit} completed
181      * successfully.
182      *
183      * <p>Subclasses storing additional post-init state should override this method, reset the
184      * additional state, and then chain to superclass.
185      */
186     @CallSuper
resetWhilePreservingInitState()187     protected void resetWhilePreservingInitState() {
188         abortOperation();
189         mOperationChallenge = 0;
190         mMessageStreamer = null;
191         mCachedException = null;
192     }
193 
ensureKeystoreOperationInitialized()194     private void ensureKeystoreOperationInitialized() throws InvalidKeyException {
195         if (mMessageStreamer != null) {
196             return;
197         }
198         if (mCachedException != null) {
199             return;
200         }
201         if (mKey == null) {
202             throw new IllegalStateException("Not initialized");
203         }
204 
205         List<KeyParameter> parameters = new ArrayList<>();
206         addAlgorithmSpecificParametersToBegin(parameters);
207 
208         int purpose = mSigning ? KeymasterDefs.KM_PURPOSE_SIGN : KeymasterDefs.KM_PURPOSE_VERIFY;
209 
210         parameters.add(KeyStore2ParameterUtils.makeEnum(KeymasterDefs.KM_TAG_PURPOSE, purpose));
211 
212         try {
213             mOperation = mKey.getSecurityLevel().createOperation(
214                     mKey.getKeyIdDescriptor(),
215                     parameters);
216         } catch (KeyStoreException keyStoreException) {
217             throw KeyStoreCryptoOperationUtils.getInvalidKeyException(
218                     mKey, keyStoreException);
219         }
220 
221         // Now we check if we got an operation challenge. This indicates that user authorization
222         // is required. And if we got a challenge we check if the authorization can possibly
223         // succeed.
224         mOperationChallenge = KeyStoreCryptoOperationUtils.getOrMakeOperationChallenge(
225                 mOperation, mKey);
226 
227         mMessageStreamer = createMainDataStreamer(mOperation);
228     }
229 
230     /**
231      * Creates a streamer which sends the message to be signed/verified into the provided KeyStore
232      *
233      * <p>This implementation returns a working streamer.
234      */
235     @NonNull
createMainDataStreamer( @onNull KeyStoreOperation operation)236     protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
237             @NonNull KeyStoreOperation operation) {
238         return new KeyStoreCryptoOperationChunkedStreamer(
239                 new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
240                         operation));
241     }
242 
243     @Override
getOperationHandle()244     public final long getOperationHandle() {
245         return mOperationChallenge;
246     }
247 
248     @Override
engineUpdate(byte[] b, int off, int len)249     protected final void engineUpdate(byte[] b, int off, int len) throws SignatureException {
250         if (mSignature != null) {
251             mSignature.update(b, off, len);
252             return;
253         }
254 
255         if (mCachedException != null) {
256             throw new SignatureException(mCachedException);
257         }
258 
259         try {
260             ensureKeystoreOperationInitialized();
261         } catch (InvalidKeyException e) {
262             throw new SignatureException(e);
263         }
264 
265         if (len == 0) {
266             return;
267         }
268 
269         byte[] output;
270         try {
271             output = mMessageStreamer.update(b, off, len);
272         } catch (KeyStoreException e) {
273             throw new SignatureException(e);
274         }
275 
276         if (output.length != 0) {
277             throw new ProviderException(
278                     "Update operation unexpectedly produced output: " + output.length + " bytes");
279         }
280     }
281 
282     @Override
engineUpdate(byte b)283     protected final void engineUpdate(byte b) throws SignatureException {
284         engineUpdate(new byte[] {b}, 0, 1);
285     }
286 
287     @Override
engineUpdate(ByteBuffer input)288     protected final void engineUpdate(ByteBuffer input) {
289         byte[] b;
290         int off;
291         int len = input.remaining();
292         if (input.hasArray()) {
293             b = input.array();
294             off = input.arrayOffset() + input.position();
295             input.position(input.limit());
296         } else {
297             b = new byte[len];
298             off = 0;
299             input.get(b);
300         }
301 
302         try {
303             engineUpdate(b, off, len);
304         } catch (SignatureException e) {
305             mCachedException = e;
306         }
307     }
308 
309     @Override
engineSign(byte[] out, int outOffset, int outLen)310     protected final int engineSign(byte[] out, int outOffset, int outLen)
311             throws SignatureException {
312         return super.engineSign(out, outOffset, outLen);
313     }
314 
315     @Override
engineSign()316     protected final byte[] engineSign() throws SignatureException {
317         if (mCachedException != null) {
318             throw new SignatureException(mCachedException);
319         }
320 
321         byte[] signature;
322         try {
323             ensureKeystoreOperationInitialized();
324 
325             byte[] additionalEntropy =
326                     KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
327                             appRandom, getAdditionalEntropyAmountForSign());
328             signature = mMessageStreamer.doFinal(
329                     EmptyArray.BYTE, 0, 0,
330                     null); // no signature provided -- it'll be generated by this invocation
331         } catch (InvalidKeyException | KeyStoreException e) {
332             throw new SignatureException(e);
333         }
334 
335         resetWhilePreservingInitState();
336         return signature;
337     }
338 
339     @Override
engineVerify(byte[] signature)340     protected final boolean engineVerify(byte[] signature) throws SignatureException {
341         if (mSignature != null) {
342             return mSignature.verify(signature);
343         }
344         throw new IllegalStateException("Not initialised.");
345     }
346 
347     @Override
engineVerify(byte[] sigBytes, int offset, int len)348     protected final boolean engineVerify(byte[] sigBytes, int offset, int len)
349             throws SignatureException {
350         return engineVerify(ArrayUtils.subarray(sigBytes, offset, len));
351     }
352 
353     @Deprecated
354     @Override
engineGetParameter(String param)355     protected final Object engineGetParameter(String param) throws InvalidParameterException {
356         throw new InvalidParameterException();
357     }
358 
359     @Deprecated
360     @Override
engineSetParameter(String param, Object value)361     protected final void engineSetParameter(String param, Object value)
362             throws InvalidParameterException {
363         throw new InvalidParameterException();
364     }
365 
366     /**
367      * Implementations need to report the algorithm they implement so that we can delegate to the
368      * highest priority provider.
369      * @return Algorithm string.
370      */
getAlgorithm()371     protected abstract String getAlgorithm();
372 
373     /**
374      * Returns {@code true} if this signature is initialized for signing, {@code false} if this
375      * signature is initialized for verification.
376      */
isSigning()377     protected final boolean isSigning() {
378         return mSigning;
379     }
380 
381     // The methods below need to be implemented by subclasses.
382 
383     /**
384      * Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's
385      * {@code finish} operation when generating a signature.
386      *
387      * <p>This value should match (or exceed) the amount of Shannon entropy of the produced
388      * signature assuming the key and the message are known. For example, for ECDSA signature this
389      * should be the size of {@code R}, whereas for the RSA signature with PKCS#1 padding this
390      * should be {@code 0}.
391      */
getAdditionalEntropyAmountForSign()392     protected abstract int getAdditionalEntropyAmountForSign();
393 
394     /**
395      * Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation.
396      *
397      * @param parameters keystore/keymaster arguments to be populated with algorithm-specific
398      *        parameters.
399      */
addAlgorithmSpecificParametersToBegin( @onNull List<KeyParameter> parameters)400     protected abstract void addAlgorithmSpecificParametersToBegin(
401             @NonNull List<KeyParameter> parameters);
402 }
403