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