Add support for PSS and PKCS1v1.5 padding for RSA signatures.

Change-Id: Ieb3c7e9ca58630aad4edc4082bd67e9872d317b8
diff --git a/google_keymaster_test.cpp b/google_keymaster_test.cpp
index 53528ed..96081ea 100644
--- a/google_keymaster_test.cpp
+++ b/google_keymaster_test.cpp
@@ -438,7 +438,8 @@
     keymaster_padding_t* modes;
     EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
                                                                  KM_PURPOSE_SIGN, &modes, &len));
-    EXPECT_TRUE(ResponseContains({KM_PAD_NONE}, modes, len));
+    EXPECT_TRUE(
+        ResponseContains({KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN, KM_PAD_RSA_PSS}, modes, len));
     free(modes);
 
     EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
@@ -491,12 +492,6 @@
                                   KM_DIGEST_SHA_2_512, KM_DIGEST_SHA1},
                                  digests, len));
     free(digests);
-
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_HMAC,
-                                                           KM_PURPOSE_SIGN, &digests, &len));
-    EXPECT_TRUE(ResponseContains({KM_DIGEST_SHA_2_224, KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384,
-                    KM_DIGEST_SHA_2_512, KM_DIGEST_SHA1}, digests, len));
-    free(digests);
 }
 
 TEST_F(CheckSupported, SupportedImportFormats) {
@@ -664,13 +659,46 @@
 
 TEST_F(SigningOperationsTest, RsaSha256DigestSuccess) {
     // Note that without padding, key size must exactly match digest size.
-    GenerateKey(ParamBuilder().RsaSigningKey(256, KM_DIGEST_SHA_2_256));
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().RsaSigningKey(256, KM_DIGEST_SHA_2_256)));
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature);
+}
+
+TEST_F(SigningOperationsTest, RsaPssSha256Success) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(ParamBuilder().RsaSigningKey(512, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS)));
     // Use large message, which won't work without digesting.
     string message(1024, 'a');
     string signature;
     SignMessage(message, &signature);
 }
 
+TEST_F(SigningOperationsTest, RsaPkcs1Sha256Success) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().RsaSigningKey(512, KM_DIGEST_SHA_2_256,
+                                                                    KM_PAD_RSA_PKCS1_1_5_SIGN)));
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature);
+}
+
+TEST_F(SigningOperationsTest, RsaPssSha256TooSmallKey) {
+    // Key must be at least 10 bytes larger than hash, to provide minimal random salt, so verify
+    // that 9 bytes larger than hash won't work.
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().RsaSigningKey(
+                               256 + 9 * 8, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS)));
+    string message(1024, 'a');
+    string signature;
+
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, FinishOperation(signature, &result));
+}
+
 TEST_F(SigningOperationsTest, EcdsaSuccess) {
     ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().EcdsaSigningKey(224)));
     string message = "123456789012345678901234567890123456789012345678";
@@ -687,22 +715,29 @@
 }
 
 TEST_F(SigningOperationsTest, RsaUnsupportedDigest) {
-    GenerateKey(ParamBuilder().RsaSigningKey(256, KM_DIGEST_MD5, KM_PAD_NONE));
+    GenerateKey(
+        ParamBuilder().RsaSigningKey(256, KM_DIGEST_MD5, KM_PAD_RSA_PSS /* supported padding */));
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST, BeginOperation(KM_PURPOSE_SIGN));
 }
 
 TEST_F(SigningOperationsTest, RsaUnsupportedPadding) {
-    GenerateKey(ParamBuilder().RsaSigningKey(256, KM_DIGEST_NONE, KM_PAD_RSA_OAEP));
+    GenerateKey(ParamBuilder().RsaSigningKey(256, KM_DIGEST_SHA_2_256 /* supported digest */,
+                                             KM_PAD_PKCS7));
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN));
 }
 
 TEST_F(SigningOperationsTest, RsaNoDigest) {
+    // Digest must be specified.
     ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().RsaKey(256).SigningKey().Option(
                                TAG_PADDING, KM_PAD_NONE)));
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST, BeginOperation(KM_PURPOSE_SIGN));
+    // PSS requires a digest.
+    GenerateKey(ParamBuilder().RsaSigningKey(256, KM_DIGEST_NONE, KM_PAD_RSA_PSS));
+    ASSERT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_SIGN));
 }
 
 TEST_F(SigningOperationsTest, RsaNoPadding) {
+    // Padding must be specified
     ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().RsaKey(256).SigningKey().Option(
                                TAG_DIGEST, KM_DIGEST_NONE)));
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN));
@@ -796,17 +831,14 @@
 TEST_F(VerificationOperationsTest, RsaSha256DigestSuccess) {
     // Note that without padding, key size must exactly match digest size.
     GenerateKey(ParamBuilder().RsaSigningKey(256, KM_DIGEST_SHA_2_256));
-    // Use large message, which won't work without digesting.
     string message(1024, 'a');
     string signature;
     SignMessage(message, &signature);
     VerifyMessage(message, signature);
 }
 
-TEST_F(VerificationOperationsTest, RsaSha256DigestCorruptSignature) {
-    // Note that without padding, key size must exactly match digest size.
+TEST_F(VerificationOperationsTest, RsaSha256CorruptSignature) {
     GenerateKey(ParamBuilder().RsaSigningKey(256, KM_DIGEST_SHA_2_256));
-    // Use large message, which won't work without digesting.
     string message(1024, 'a');
     string signature;
     SignMessage(message, &signature);
@@ -821,9 +853,35 @@
     EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
 }
 
-TEST_F(VerificationOperationsTest, RsaSha256DigestCorruptInput) {
-    // Note that without padding, key size must exactly match digest size.
-    GenerateKey(ParamBuilder().RsaSigningKey(256, KM_DIGEST_SHA_2_256));
+TEST_F(VerificationOperationsTest, RsaPssSha256Success) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(ParamBuilder().RsaSigningKey(512, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS)));
+    // Use large message, which won't work without digesting.
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature);
+    VerifyMessage(message, signature);
+}
+
+TEST_F(VerificationOperationsTest, RsaPssSha256CorruptSignature) {
+    GenerateKey(ParamBuilder().RsaSigningKey(512, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS));
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature);
+    ++signature[signature.size() / 2];
+
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+}
+
+TEST_F(VerificationOperationsTest, RsaPssSha256CorruptInput) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(ParamBuilder().RsaSigningKey(512, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS)));
     // Use large message, which won't work without digesting.
     string message(1024, 'a');
     string signature;
@@ -839,6 +897,123 @@
     EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
 }
 
+TEST_F(VerificationOperationsTest, RsaPkcs1Sha256Success) {
+    GenerateKey(ParamBuilder().RsaSigningKey(512, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN));
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature);
+    VerifyMessage(message, signature);
+}
+
+TEST_F(VerificationOperationsTest, RsaPkcs1Sha256CorruptSignature) {
+    GenerateKey(ParamBuilder().RsaSigningKey(512, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN));
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature);
+    ++signature[signature.size() / 2];
+
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+}
+
+TEST_F(VerificationOperationsTest, RsaPkcs1Sha256CorruptInput) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().RsaSigningKey(512, KM_DIGEST_SHA_2_256,
+                                                                    KM_PAD_RSA_PKCS1_1_5_SIGN)));
+    // Use large message, which won't work without digesting.
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature);
+    ++message[message.size() / 2];
+
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+}
+
+template <typename T> vector<T> make_vector(const T* array, size_t len) {
+    return vector<T>(array, array + len);
+}
+
+TEST_F(VerificationOperationsTest, RsaAllDigestAndPadCombinations) {
+    // Get all supported digests and padding modes.
+    size_t digests_len;
+    keymaster_digest_t* digests;
+    EXPECT_EQ(KM_ERROR_OK,
+              device()->get_supported_digests(device(), KM_ALGORITHM_RSA, KM_PURPOSE_SIGN, &digests,
+                                              &digests_len));
+
+    size_t padding_modes_len;
+    keymaster_padding_t* padding_modes;
+    EXPECT_EQ(KM_ERROR_OK,
+              device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA, KM_PURPOSE_SIGN,
+                                                    &padding_modes, &padding_modes_len));
+
+    // Try them.
+    for (keymaster_padding_t padding_mode : make_vector(padding_modes, padding_modes_len)) {
+        for (keymaster_digest_t digest : make_vector(digests, digests_len)) {
+            // Compute key & message size that will work.
+            size_t key_bits = 256;
+            size_t message_len = 1000;
+            switch (digest) {
+            case KM_DIGEST_NONE:
+                switch (padding_mode) {
+                case KM_PAD_NONE:
+                    // Match key size.
+                    message_len = key_bits / 8;
+                    break;
+                case KM_PAD_RSA_PKCS1_1_5_SIGN:
+                    message_len = key_bits / 8 - 11;
+                    break;
+                case KM_PAD_RSA_PSS:
+                    // PSS requires a digest.
+                    continue;
+                default:
+                    FAIL() << "Missing padding";
+                    break;
+                }
+                break;
+
+            case KM_DIGEST_SHA_2_256:
+                switch (padding_mode) {
+                case KM_PAD_NONE:
+                    // Key size matches digest size
+                    break;
+                case KM_PAD_RSA_PKCS1_1_5_SIGN:
+                    key_bits += 8 * 11;
+                    break;
+                case KM_PAD_RSA_PSS:
+                    key_bits += 8 * 10;
+                    break;
+                default:
+                    FAIL() << "Missing padding";
+                    break;
+                }
+                break;
+            default:
+                FAIL() << "Missing digest";
+            }
+
+            GenerateKey(ParamBuilder().RsaSigningKey(key_bits, digest, padding_mode));
+            string message(message_len, 'a');
+            string signature;
+            SignMessage(message, &signature);
+            VerifyMessage(message, signature);
+        }
+    }
+
+    free(padding_modes);
+    free(digests);
+}
+
 TEST_F(VerificationOperationsTest, EcdsaSuccess) {
     ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().EcdsaSigningKey(256)));
     string message = "123456789012345678901234567890123456789012345678";