Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
      5  * in compliance with the License. You may obtain a copy of the License at
      6  *
      7  * http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the License
     10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
     11  * or implied. See the License for the specific language governing permissions and limitations under
     12  * the License.
     13  */
     14 
     15 package android.keystore.cts;
     16 
     17 import java.security.InvalidKeyException;
     18 import java.security.KeyPair;
     19 import java.security.PrivateKey;
     20 import java.security.Provider;
     21 import java.security.PublicKey;
     22 import java.security.Security;
     23 import java.security.Signature;
     24 import java.security.SignatureException;
     25 import java.security.interfaces.RSAKey;
     26 import java.util.ArrayList;
     27 import java.util.Arrays;
     28 import java.util.Collection;
     29 import java.util.List;
     30 
     31 import android.keystore.cts.R;
     32 
     33 import android.content.Context;
     34 import android.security.keystore.KeyProperties;
     35 import android.security.keystore.KeyProtection;
     36 import android.test.AndroidTestCase;
     37 
     38 public class RSASignatureTest extends AndroidTestCase {
     39 
     40     private static final String EXPECTED_PROVIDER_NAME = SignatureTest.EXPECTED_PROVIDER_NAME;
     41 
     42     private static final String[] SIGNATURE_ALGORITHMS;
     43 
     44     static {
     45         List<String> sigAlgs = new ArrayList<>();
     46         for (String algorithm : SignatureTest.EXPECTED_SIGNATURE_ALGORITHMS) {
     47             String keyAlgorithm = TestUtils.getSignatureAlgorithmKeyAlgorithm(algorithm);
     48             if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
     49                 sigAlgs.add(algorithm);
     50             }
     51         }
     52         SIGNATURE_ALGORITHMS = sigAlgs.toArray(new String[sigAlgs.size()]);
     53     }
     54 
     55     public void testMaxMessageSizeWhenNoDigestUsed() throws Exception {
     56         Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
     57         assertNotNull(provider);
     58 
     59         for (ImportedKey keyPair : importKatKeyPairs("NONEwithRSA")) {
     60             PublicKey publicKey = keyPair.getKeystoreBackedKeyPair().getPublic();
     61             PrivateKey privateKey = keyPair.getKeystoreBackedKeyPair().getPrivate();
     62             int modulusSizeBits = ((RSAKey) publicKey).getModulus().bitLength();
     63             try {
     64                 int modulusSizeBytes = (modulusSizeBits + 7) / 8;
     65                 // PKCS#1 signature padding must be at least 11 bytes long (00 || 01 || PS || 00)
     66                 // where PS must be at least 8 bytes long).
     67                 int expectedMaxMessageSizeBytes = modulusSizeBytes - 11;
     68                 byte[] msg = new byte[expectedMaxMessageSizeBytes + 1];
     69                 Arrays.fill(msg, (byte) 0xf0);
     70 
     71                 // Assert that a message of expected maximum length is accepted
     72                 Signature signature = Signature.getInstance("NONEwithRSA", provider);
     73                 signature.initSign(privateKey);
     74                 signature.update(msg, 0, expectedMaxMessageSizeBytes);
     75                 byte[] sigBytes = signature.sign();
     76 
     77                 signature.initVerify(publicKey);
     78                 signature.update(msg, 0, expectedMaxMessageSizeBytes);
     79                 assertTrue(signature.verify(sigBytes));
     80 
     81                 // Assert that a message longer than expected maximum length is rejected
     82                 signature = Signature.getInstance(signature.getAlgorithm(), provider);
     83                 signature.initSign(privateKey);
     84                 try {
     85                     signature.update(msg, 0, expectedMaxMessageSizeBytes + 1);
     86                     signature.sign();
     87                     fail();
     88                 } catch (SignatureException expected) {
     89                 }
     90 
     91                 signature.initVerify(publicKey);
     92                 try {
     93                     signature.update(msg, 0, expectedMaxMessageSizeBytes + 1);
     94                     signature.verify(sigBytes);
     95                     fail();
     96                 } catch (SignatureException expected) {
     97                 }
     98             } catch (Throwable e) {
     99                 throw new RuntimeException("Failed for " + modulusSizeBits + " bit key", e);
    100             }
    101         }
    102     }
    103 
    104     public void testSmallKeyRejected() throws Exception {
    105         // Use a 512 bit key which should prevent the use of any digests larger than SHA-256
    106         // because the padded form of the digested message will be larger than modulus size.
    107         Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
    108         assertNotNull(provider);
    109 
    110         for (String algorithm : SIGNATURE_ALGORITHMS) {
    111             try {
    112                 String digest = TestUtils.getSignatureAlgorithmDigest(algorithm);
    113                 if (KeyProperties.DIGEST_NONE.equalsIgnoreCase(digest)) {
    114                     // Ignore signature algorithms without digest -- this is tested in a separate
    115                     // test above.
    116                     continue;
    117                 }
    118                 int digestOutputSizeBits = TestUtils.getDigestOutputSizeBits(digest);
    119                 if (digestOutputSizeBits <= 256) {
    120                     // 256-bit and shorter digests are short enough to work with a 512 bit key.
    121                     continue;
    122                 }
    123 
    124                 KeyPair keyPair = TestUtils.importIntoAndroidKeyStore("test1",
    125                         getContext(),
    126                         R.raw.rsa_key5_512_pkcs8,
    127                         R.raw.rsa_key5_512_cert,
    128                         TestUtils.getMinimalWorkingImportParametersForSigningingWith(algorithm))
    129                         .getKeystoreBackedKeyPair();
    130                 assertEquals(512, ((RSAKey) keyPair.getPrivate()).getModulus().bitLength());
    131                 assertEquals(512, ((RSAKey) keyPair.getPublic()).getModulus().bitLength());
    132 
    133                 Signature signature = Signature.getInstance(algorithm, provider);
    134                 // Assert that either initSign or sign fails. We don't expect all keymaster
    135                 // implementations to fail early, during initSign.
    136                 try {
    137                     signature.initSign(keyPair.getPrivate());
    138                     signature.update("A message".getBytes("UTF-8"));
    139                     byte[] sigBytes = signature.sign();
    140                     fail("Unexpectedly generated a signature (" + sigBytes.length + " bytes): "
    141                             + HexEncoding.encode(sigBytes));
    142                 } catch (InvalidKeyException | SignatureException expected) {
    143                 }
    144             } catch (Throwable e) {
    145                 throw new RuntimeException("Failed for " + algorithm, e);
    146             }
    147         }
    148     }
    149 
    150     private Collection<ImportedKey> importKatKeyPairs(String signatureAlgorithm)
    151             throws Exception {
    152         KeyProtection params =
    153                 TestUtils.getMinimalWorkingImportParametersForSigningingWith(signatureAlgorithm);
    154         return importKatKeyPairs(getContext(), params);
    155     }
    156 
    157     static Collection<ImportedKey> importKatKeyPairs(
    158             Context context, KeyProtection importParams) throws Exception {
    159         return Arrays.asList(new ImportedKey[] {
    160                 TestUtils.importIntoAndroidKeyStore("testRSA512", context,
    161                         R.raw.rsa_key5_512_pkcs8, R.raw.rsa_key5_512_cert, importParams),
    162                 TestUtils.importIntoAndroidKeyStore("testRSA768", context,
    163                         R.raw.rsa_key6_768_pkcs8, R.raw.rsa_key6_768_cert, importParams),
    164                 TestUtils.importIntoAndroidKeyStore("testRSA1024", context,
    165                         R.raw.rsa_key3_1024_pkcs8, R.raw.rsa_key3_1024_cert, importParams),
    166                 TestUtils.importIntoAndroidKeyStore("testRSA2048", context,
    167                         R.raw.rsa_key8_2048_pkcs8, R.raw.rsa_key8_2048_cert, importParams),
    168                 TestUtils.importIntoAndroidKeyStore("testRSA3072", context,
    169                         R.raw.rsa_key7_3072_pksc8, R.raw.rsa_key7_3072_cert, importParams),
    170                 TestUtils.importIntoAndroidKeyStore("testRSA4096", context,
    171                         R.raw.rsa_key4_4096_pkcs8, R.raw.rsa_key4_4096_cert, importParams),
    172                 });
    173     }
    174 }
    175