Refactor operation creation to use an operation factory registry.
Also modify GoogleKeymaster to query the operation factories to get
lists of supported modes and digests.
Change-Id: Ied30185df5dddaeaeb1106df63237757896d77db
diff --git a/Android.mk b/Android.mk
index 7f8b663..1dc16e3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -62,6 +62,7 @@
key.cpp \
key_blob.cpp \
ocb.c \
+ operation.cpp \
rsa_key.cpp \
rsa_operation.cpp \
serializable.cpp \
diff --git a/Makefile b/Makefile
index 97faa61..a4cf3f8 100644
--- a/Makefile
+++ b/Makefile
@@ -148,6 +148,7 @@
key.o \
key_blob.o \
ocb.o \
+ operation.o \
rsa_key.o \
rsa_operation.o \
serializable.o \
diff --git a/abstract_factory_registry.h b/abstract_factory_registry.h
index 719e5f0..954bc7d 100644
--- a/abstract_factory_registry.h
+++ b/abstract_factory_registry.h
@@ -45,9 +45,9 @@
* d. Factory methods (likely all pure virtual).
*
* 2. Create one or more concrete subclasses of AbstractFactory. The concrete factories must have
- * failure-proof no-argument constructors. Note that by design it is impossible to register two
- * factories which return the same value from registry_key(). Attempting to do so will cause
- * both to be removed.
+ * failure-proof, no-argument constructors. Note that by design it is impossible to register
+ * two factories which return the same value from registry_key(). Attempting to do so will
+ * cause both to be removed.
*
* 3. Define the registry instance pointer using the DEFINE_ABSTRACT_FACTORY_REGISTRY_INSTANCE
* macro.
diff --git a/aead_mode_operation.h b/aead_mode_operation.h
index 40196f7..cb976a2 100644
--- a/aead_mode_operation.h
+++ b/aead_mode_operation.h
@@ -23,6 +23,7 @@
class AeadModeOperation : public Operation {
public:
+ static const size_t MAX_CHUNK_LENGTH = 64 * 1024;
static const size_t MAX_NONCE_LENGTH = 12;
static const size_t MAX_TAG_LENGTH = 16;
static const size_t MAX_KEY_LENGTH = 32;
diff --git a/aes_key.cpp b/aes_key.cpp
index e692711..87a63a7 100644
--- a/aes_key.cpp
+++ b/aes_key.cpp
@@ -39,68 +39,6 @@
return new AesKey(auths, logger);
}
};
-
static KeyFactoryRegistry::Registration<AesKeyFactory> registration;
-Operation* AesKey::CreateOperation(keymaster_purpose_t purpose, keymaster_error_t* error) {
- keymaster_block_mode_t block_mode;
- if (!authorizations().GetTagValue(TAG_BLOCK_MODE, &block_mode)) {
- *error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
- return NULL;
- }
-
- switch (block_mode) {
- case KM_MODE_OCB:
- return CreateOcbOperation(purpose, error);
- default:
- *error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
- return NULL;
- }
-}
-
-Operation* AesKey::CreateOcbOperation(keymaster_purpose_t purpose, keymaster_error_t* error) {
- *error = KM_ERROR_OK;
-
- if (key_data_size() != 16 && key_data_size() != 24 && key_data_size() != 32)
- *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
-
- uint32_t chunk_length;
- if (!authorizations().GetTagValue(TAG_CHUNK_LENGTH, &chunk_length))
- // TODO(swillden): Create and use a better return code.
- *error = KM_ERROR_INVALID_ARGUMENT;
-
- uint32_t tag_length;
- if (!authorizations().GetTagValue(TAG_MAC_LENGTH, &tag_length))
- // TODO(swillden): Create and use a better return code.
- *error = KM_ERROR_INVALID_ARGUMENT;
-
- keymaster_padding_t padding;
- if (authorizations().GetTagValue(TAG_PADDING, &padding) && padding != KM_PAD_NONE) {
- *error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
- }
-
- if (*error != KM_ERROR_OK)
- return NULL;
-
- keymaster_blob_t additional_data = {0, 0};
- authorizations().GetTagValue(TAG_ASSOCIATED_DATA, &additional_data);
-
- UniquePtr<Operation> op;
- switch (purpose) {
- case KM_PURPOSE_ENCRYPT:
- case KM_PURPOSE_DECRYPT:
- op.reset(new AesOcbOperation(purpose, logger_, key_data(), key_data_size(), chunk_length,
- tag_length, additional_data));
- break;
- default:
- *error = KM_ERROR_UNSUPPORTED_PURPOSE;
- return NULL;
- }
-
- if (!op.get())
- *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- return op.release();
-}
-
} // namespace keymaster
diff --git a/aes_key.h b/aes_key.h
index af80e12..bd6d905 100644
--- a/aes_key.h
+++ b/aes_key.h
@@ -28,12 +28,6 @@
AesKey(const AuthorizationSet& auths, const Logger& logger) : SymmetricKey(auths, logger) {}
AesKey(const UnencryptedKeyBlob& blob, const Logger& logger, keymaster_error_t* error)
: SymmetricKey(blob, logger, error) {}
-
-
- virtual Operation* CreateOperation(keymaster_purpose_t, keymaster_error_t* error);
-
- private:
- Operation* CreateOcbOperation(keymaster_purpose_t, keymaster_error_t* error);
};
} // namespace keymaster
diff --git a/aes_operation.cpp b/aes_operation.cpp
index 0c7a86c..0b17249 100644
--- a/aes_operation.cpp
+++ b/aes_operation.cpp
@@ -19,13 +19,111 @@
#include <openssl/aes.h>
#include <openssl/rand.h>
+#include "aes_key.h"
#include "aes_operation.h"
namespace keymaster {
+/**
+ * Abstract base for AES OCB mode operation factories. This class does all of the work to create
+ * OCB mode operations.
+ */
+class AesOcbOperationFactory : public OperationFactory {
+ public:
+ virtual KeyType registry_key() const { return KeyType(KM_ALGORITHM_AES, purpose()); }
+
+ virtual Operation* CreateOperation(const Key& key, const Logger& logger,
+ keymaster_error_t* error);
+ virtual const keymaster_block_mode_t* SupportedBlockModes(size_t* block_mode_count) const;
+
+ virtual keymaster_purpose_t purpose() const = 0;
+};
+
+Operation* AesOcbOperationFactory::CreateOperation(const Key& key, const Logger& logger,
+ keymaster_error_t* error) {
+ *error = KM_ERROR_OK;
+
+ keymaster_block_mode_t block_mode;
+ if (!key.authorizations().GetTagValue(TAG_BLOCK_MODE, &block_mode) ||
+ block_mode != KM_MODE_OCB) {
+ *error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
+ return NULL;
+ }
+
+ uint32_t chunk_length;
+ if (!key.authorizations().GetTagValue(TAG_CHUNK_LENGTH, &chunk_length) ||
+ chunk_length > AeadModeOperation::MAX_CHUNK_LENGTH)
+ // TODO(swillden): Create and use a better return code.
+ *error = KM_ERROR_INVALID_ARGUMENT;
+
+ uint32_t tag_length;
+ if (!key.authorizations().GetTagValue(TAG_MAC_LENGTH, &tag_length) ||
+ tag_length > AeadModeOperation::MAX_TAG_LENGTH)
+ // TODO(swillden): Create and use a better return code.
+ *error = KM_ERROR_INVALID_ARGUMENT;
+
+ keymaster_padding_t padding;
+ if (key.authorizations().GetTagValue(TAG_PADDING, &padding) && padding != KM_PAD_NONE)
+ *error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
+
+ const SymmetricKey* symmetric_key = static_cast<const SymmetricKey*>(&key);
+ if (!symmetric_key) {
+ *error = KM_ERROR_UNKNOWN_ERROR;
+ return NULL;
+ }
+
+ switch (symmetric_key->key_data_size()) {
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ }
+
+ if (*error != KM_ERROR_OK)
+ return NULL;
+
+ keymaster_blob_t additional_data = {0, 0};
+ symmetric_key->authorizations().GetTagValue(TAG_ASSOCIATED_DATA, &additional_data);
+
+ Operation* op = new AesOcbOperation(purpose(), logger, symmetric_key->key_data(),
+ symmetric_key->key_data_size(), chunk_length, tag_length,
+ additional_data);
+ if (!op)
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return op;
+}
+
+static const keymaster_block_mode_t supported_block_modes[] = {KM_MODE_OCB};
+
+const keymaster_block_mode_t*
+AesOcbOperationFactory::SupportedBlockModes(size_t* block_mode_count) const {
+ *block_mode_count = array_length(supported_block_modes);
+ return supported_block_modes;
+}
+
+/**
+ * Concrete factory for AES OCB mode encryption operations.
+ */
+class AesOcbEncryptionOperationFactory : public AesOcbOperationFactory {
+ keymaster_purpose_t purpose() const { return KM_PURPOSE_ENCRYPT; }
+};
+static OperationFactoryRegistry::Registration<AesOcbEncryptionOperationFactory>
+ encrypt_registration;
+
+/**
+ * Concrete factory for AES OCB mode decryption operations.
+ */
+class AesOcbDecryptionOperationFactory : public AesOcbOperationFactory {
+ keymaster_purpose_t purpose() const { return KM_PURPOSE_DECRYPT; }
+};
+static OperationFactoryRegistry::Registration<AesOcbDecryptionOperationFactory>
+ decrypt_registration;
+
keymaster_error_t AesOcbOperation::Initialize(uint8_t* key, size_t key_size, size_t nonce_length,
size_t tag_length) {
- if (tag_length > MAX_TAG_LENGTH ||nonce_length > MAX_NONCE_LENGTH)
+ if (tag_length > MAX_TAG_LENGTH || nonce_length > MAX_NONCE_LENGTH)
return KM_ERROR_INVALID_KEY_BLOB;
if (ae_init(ctx(), key, key_size, nonce_length, tag_length) != AE_SUCCESS) {
diff --git a/ecdsa_key.cpp b/ecdsa_key.cpp
index b499fdb..448374f 100644
--- a/ecdsa_key.cpp
+++ b/ecdsa_key.cpp
@@ -191,23 +191,6 @@
*error = LoadKey(blob);
}
-Operation* EcdsaKey::CreateOperation(keymaster_purpose_t purpose, keymaster_error_t* error) {
- Operation* op;
- switch (purpose) {
- case KM_PURPOSE_SIGN:
- op = new EcdsaSignOperation(purpose, logger_, ecdsa_key_.release());
- break;
- case KM_PURPOSE_VERIFY:
- op = new EcdsaVerifyOperation(purpose, logger_, ecdsa_key_.release());
- break;
- default:
- *error = KM_ERROR_UNIMPLEMENTED;
- return NULL;
- }
- *error = op ? KM_ERROR_OK : KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return op;
-}
-
bool EcdsaKey::EvpToInternal(const EVP_PKEY* pkey) {
ecdsa_key_.reset(EVP_PKEY_get1_EC_KEY(const_cast<EVP_PKEY*>(pkey)));
return ecdsa_key_.get() != NULL;
diff --git a/ecdsa_key.h b/ecdsa_key.h
index 19df1ed..3b7b563 100644
--- a/ecdsa_key.h
+++ b/ecdsa_key.h
@@ -24,13 +24,14 @@
namespace keymaster {
class EcdsaKeyFactory;
+class EcdsaSignOperationFactory;
+class EcdsaVerifyOperationFactory;
class EcdsaKey : public AsymmetricKey {
- public:
- virtual Operation* CreateOperation(keymaster_purpose_t purpose, keymaster_error_t* error);
-
private:
friend EcdsaKeyFactory;
+ friend EcdsaSignOperationFactory;
+ friend EcdsaVerifyOperationFactory;
EcdsaKey(const UnencryptedKeyBlob& blob, const Logger& logger, keymaster_error_t* error);
EcdsaKey(EC_KEY* ecdsa_key, const AuthorizationSet auths, const Logger& logger)
@@ -44,6 +45,8 @@
void operator()(EC_KEY* p) { EC_KEY_free(p); }
};
+ EC_KEY* key() const { return EC_KEY_dup(ecdsa_key_.get()); }
+
UniquePtr<EC_KEY, ECDSA_Delete> ecdsa_key_;
};
diff --git a/ecdsa_operation.cpp b/ecdsa_operation.cpp
index a2dbc4d..3bc0d88 100644
--- a/ecdsa_operation.cpp
+++ b/ecdsa_operation.cpp
@@ -16,11 +16,68 @@
#include <openssl/ecdsa.h>
+#include "ecdsa_key.h"
#include "ecdsa_operation.h"
#include "openssl_utils.h"
namespace keymaster {
+class EcdsaSignOperationFactory : public OperationFactory {
+ public:
+ virtual KeyType registry_key() const { return KeyType(KM_ALGORITHM_ECDSA, KM_PURPOSE_SIGN); }
+
+ virtual Operation* CreateOperation(const Key& key, const Logger& logger,
+ keymaster_error_t* error){
+ const EcdsaKey* ecdsa_key = static_cast<const EcdsaKey*>(&key);
+ if (!ecdsa_key) {
+ *error = KM_ERROR_UNKNOWN_ERROR;
+ return NULL;
+ }
+
+ Operation* op = new EcdsaSignOperation(KM_PURPOSE_SIGN, logger, ecdsa_key->key());
+ if (!op)
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return op;
+ }
+};
+static OperationFactoryRegistry::Registration<EcdsaSignOperationFactory> sign_registration;
+
+class EcdsaVerifyOperationFactory : public OperationFactory {
+ public:
+ virtual KeyType registry_key() const { return KeyType(KM_ALGORITHM_ECDSA, KM_PURPOSE_VERIFY); }
+
+ virtual Operation* CreateOperation(const Key& key, const Logger& logger,
+ keymaster_error_t* error){
+ const EcdsaKey* ecdsa_key = static_cast<const EcdsaKey*>(&key);
+ if (!ecdsa_key) {
+ *error = KM_ERROR_UNKNOWN_ERROR;
+ return NULL;
+ }
+
+ Operation* op = new EcdsaVerifyOperation(KM_PURPOSE_VERIFY, logger, ecdsa_key->key());
+ if (!op)
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return op;
+ }
+
+ // Informational methods
+ virtual const keymaster_padding_t* SupportedPaddingModes(size_t* padding_count) const {
+ *padding_count = 0;
+ return NULL;
+ }
+
+ virtual const keymaster_block_mode_t* SupportedBlockModes(size_t* block_mode_count) const {
+ *block_mode_count = 0;
+ return NULL;
+ }
+
+ virtual const keymaster_digest_t* SupportedDigests(size_t* digest_count) const {
+ *digest_count = 0;
+ return NULL;
+ }
+};
+static OperationFactoryRegistry::Registration<EcdsaVerifyOperationFactory> verify_registration;
+
EcdsaOperation::~EcdsaOperation() {
if (ecdsa_key_ != NULL)
EC_KEY_free(ecdsa_key_);
diff --git a/google_keymaster.cpp b/google_keymaster.cpp
index 2024c90..cda181d 100644
--- a/google_keymaster.cpp
+++ b/google_keymaster.cpp
@@ -108,66 +108,54 @@
response->error = KM_ERROR_OK;
}
-void GoogleKeymaster::SupportedBlockModes(
- keymaster_algorithm_t algorithm, keymaster_purpose_t /* purpose */,
- SupportedResponse<keymaster_block_mode_t>* response) const {
- if (response == NULL || !check_supported(algorithm, response))
- return;
- response->error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
+static OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ keymaster_error_t* error) {
+ assert(error);
+ if (error)
+ *error = KM_ERROR_OK;
+
+ OperationFactory* factory =
+ OperationFactoryRegistry::Get(OperationFactory::KeyType(algorithm, purpose));
+ if (factory == NULL && error)
+ *error = KM_ERROR_UNSUPPORTED_PURPOSE;
+
+ return factory;
}
-keymaster_padding_t supported_rsa_crypt_padding[] = {KM_PAD_RSA_OAEP, KM_PAD_RSA_PKCS1_1_5_ENCRYPT};
-keymaster_padding_t supported_rsa_sign_padding[] = {KM_PAD_NONE};
-keymaster_padding_t supported_padding[] = {KM_PAD_NONE};
+template <typename T>
+void GetSupported(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
+ const T* (OperationFactory::*get_supported_method)(size_t* count) const,
+ SupportedResponse<T>* response) {
+ if (response == NULL || !check_supported(algorithm, response))
+ return;
+
+ OperationFactory* factory = GetOperationFactory(algorithm, purpose, &response->error);
+ if (!factory) {
+ response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
+ return;
+ }
+
+ size_t count;
+ const T* supported = (factory->*get_supported_method)(&count);
+ response->SetResults(supported, count);
+}
+
+void GoogleKeymaster::SupportedBlockModes(
+ keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
+ SupportedResponse<keymaster_block_mode_t>* response) const {
+ GetSupported(algorithm, purpose, &OperationFactory::SupportedBlockModes, response);
+}
void GoogleKeymaster::SupportedPaddingModes(
keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
SupportedResponse<keymaster_padding_t>* response) const {
- if (response == NULL || !check_supported(algorithm, response))
- return;
-
- response->error = KM_ERROR_OK;
- switch (algorithm) {
- case KM_ALGORITHM_RSA:
- switch (purpose) {
- case KM_PURPOSE_ENCRYPT:
- case KM_PURPOSE_DECRYPT:
- response->SetResults(supported_rsa_crypt_padding);
- break;
- case KM_PURPOSE_SIGN:
- case KM_PURPOSE_VERIFY:
- response->SetResults(supported_rsa_sign_padding);
- break;
- }
- break;
- case KM_ALGORITHM_DSA:
- case KM_ALGORITHM_ECDSA:
- response->SetResults(supported_padding);
- break;
- default:
- response->results_length = 0;
- break;
- }
+ GetSupported(algorithm, purpose, &OperationFactory::SupportedPaddingModes, response);
}
-keymaster_digest_t supported_digests[] = {KM_DIGEST_NONE};
-void GoogleKeymaster::SupportedDigests(keymaster_algorithm_t algorithm,
- keymaster_purpose_t /* purpose */,
+void GoogleKeymaster::SupportedDigests(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
SupportedResponse<keymaster_digest_t>* response) const {
- if (response == NULL || !check_supported(algorithm, response))
- return;
-
- response->error = KM_ERROR_OK;
- switch (algorithm) {
- case KM_ALGORITHM_RSA:
- case KM_ALGORITHM_DSA:
- case KM_ALGORITHM_ECDSA:
- response->SetResults(supported_digests);
- break;
- default:
- response->results_length = 0;
- break;
- }
+ GetSupported(algorithm, purpose, &OperationFactory::SupportedDigests, response);
}
void GoogleKeymaster::SupportedImportFormats(
@@ -235,11 +223,20 @@
return;
response->op_handle = 0;
- UniquePtr<Key> key(LoadKey(request.key_blob, request.additional_params, &response->error));
+ keymaster_algorithm_t algorithm;
+ UniquePtr<Key> key(
+ LoadKey(request.key_blob, request.additional_params, &algorithm, &response->error));
if (key.get() == NULL)
return;
- UniquePtr<Operation> operation(key->CreateOperation(request.purpose, &response->error));
+ OperationFactory::KeyType op_type(algorithm, request.purpose);
+ OperationFactory* factory = OperationFactoryRegistry::Get(op_type);
+ if (!factory) {
+ response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
+ return;
+ }
+
+ UniquePtr<Operation> operation(factory->CreateOperation(*key, logger(), &response->error));
if (operation.get() == NULL)
return;
@@ -301,8 +298,9 @@
if (response == NULL)
return;
+ keymaster_algorithm_t algorithm;
UniquePtr<Key> to_export(
- LoadKey(request.key_blob, request.additional_params, &response->error));
+ LoadKey(request.key_blob, request.additional_params, &algorithm, &response->error));
if (to_export.get() == NULL)
return;
@@ -382,13 +380,16 @@
}
Key* GoogleKeymaster::LoadKey(const keymaster_key_blob_t& key,
- const AuthorizationSet& client_params, keymaster_error_t* error) {
+ const AuthorizationSet& client_params,
+ keymaster_algorithm_t* algorithm, keymaster_error_t* error) {
UniquePtr<UnencryptedKeyBlob> blob(LoadKeyBlob(key, client_params, error));
if (*error != KM_ERROR_OK)
return NULL;
+ *algorithm = blob->algorithm();
+
KeyFactory* factory = 0;
- if ((factory = KeyFactoryRegistry::Get(blob->algorithm())))
+ if ((factory = KeyFactoryRegistry::Get(*algorithm)))
return factory->LoadKey(*blob, logger(), error);
*error = KM_ERROR_UNSUPPORTED_ALGORITHM;
return NULL;
diff --git a/google_keymaster_test.cpp b/google_keymaster_test.cpp
index f16b6f8..9306143 100644
--- a/google_keymaster_test.cpp
+++ b/google_keymaster_test.cpp
@@ -44,6 +44,18 @@
return result;
}
+template <typename T> std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec) {
+ os << "{ ";
+ bool first = true;
+ for (T t : vec) {
+ os << (first ? "" : ", ") << t;
+ if (first)
+ first = false;
+ }
+ os << " }";
+ return os;
+}
+
namespace keymaster {
namespace test {
@@ -279,19 +291,23 @@
}
void SignMessage(const string& message, string* signature) {
+ SCOPED_TRACE("SignMessage");
*signature = ProcessMessage(KM_PURPOSE_SIGN, message);
EXPECT_GT(signature->size(), 0);
}
void VerifyMessage(const string& message, const string& signature) {
+ SCOPED_TRACE("VerifyMessage");
ProcessMessage(KM_PURPOSE_VERIFY, message, signature);
}
string EncryptMessage(const string& message) {
+ SCOPED_TRACE("EncryptMessage");
return ProcessMessage(KM_PURPOSE_ENCRYPT, message);
}
string DecryptMessage(const string& ciphertext) {
+ SCOPED_TRACE("DecryptMessage");
return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext);
}
@@ -392,21 +408,23 @@
size_t len;
keymaster_block_mode_t* modes;
- EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE,
- device()->get_supported_block_modes(device(), KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT,
- &modes, &len));
+ EXPECT_EQ(KM_ERROR_OK, device()->get_supported_block_modes(device(), KM_ALGORITHM_RSA,
+ KM_PURPOSE_ENCRYPT, &modes, &len));
+ EXPECT_EQ(0, len);
+ free(modes);
EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM,
device()->get_supported_block_modes(device(), KM_ALGORITHM_DSA, KM_PURPOSE_ENCRYPT,
&modes, &len));
- EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE,
+ EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE,
device()->get_supported_block_modes(device(), KM_ALGORITHM_ECDSA, KM_PURPOSE_ENCRYPT,
&modes, &len));
- EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE,
- device()->get_supported_block_modes(device(), KM_ALGORITHM_AES, KM_PURPOSE_ENCRYPT,
- &modes, &len));
+ EXPECT_EQ(KM_ERROR_OK, device()->get_supported_block_modes(device(), KM_ALGORITHM_AES,
+ KM_PURPOSE_ENCRYPT, &modes, &len));
+ EXPECT_TRUE(ResponseContains({KM_MODE_OCB}, modes, len));
+ free(modes);
}
TEST_F(CheckSupported, SupportedPaddingModes) {
@@ -418,7 +436,12 @@
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}, modes, len));
+ free(modes);
+
+ EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
+ KM_PURPOSE_ENCRYPT, &modes, &len));
+ EXPECT_TRUE(ResponseContains({KM_PAD_RSA_OAEP, KM_PAD_RSA_PKCS1_1_5_ENCRYPT}, modes, len));
free(modes);
EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM,
@@ -427,13 +450,12 @@
EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_ECDSA,
KM_PURPOSE_SIGN, &modes, &len));
- EXPECT_TRUE(ResponseContains(KM_PAD_NONE, modes, len));
- free(modes);
-
- EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_AES,
- KM_PURPOSE_SIGN, &modes, &len));
EXPECT_EQ(0, len);
free(modes);
+
+ EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE,
+ device()->get_supported_padding_modes(device(), KM_ALGORITHM_AES, KM_PURPOSE_SIGN,
+ &modes, &len));
}
TEST_F(CheckSupported, SupportedDigests) {
@@ -445,7 +467,7 @@
keymaster_digest_t* digests;
EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_RSA,
KM_PURPOSE_SIGN, &digests, &len));
- EXPECT_TRUE(ResponseContains(KM_DIGEST_NONE, digests, len));
+ EXPECT_TRUE(ResponseContains({KM_DIGEST_NONE}, digests, len));
free(digests);
EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM,
@@ -454,12 +476,18 @@
EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_ECDSA,
KM_PURPOSE_SIGN, &digests, &len));
- EXPECT_TRUE(ResponseContains(KM_DIGEST_NONE, digests, len));
+ EXPECT_EQ(0, len);
free(digests);
- EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_AES,
+ EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE,
+ device()->get_supported_digests(device(), KM_ALGORITHM_AES, KM_PURPOSE_SIGN, &digests,
+ &len));
+
+ EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_HMAC,
KM_PURPOSE_SIGN, &digests, &len));
- EXPECT_EQ(0, 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);
}
@@ -473,19 +501,6 @@
device()->get_supported_import_formats(device(), KM_ALGORITHM_RSA, &formats, &len));
EXPECT_TRUE(ResponseContains(KM_KEY_FORMAT_PKCS8, formats, len));
free(formats);
-
- EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM,
- device()->get_supported_import_formats(device(), KM_ALGORITHM_DSA, &formats, &len));
-
- EXPECT_EQ(KM_ERROR_OK,
- device()->get_supported_import_formats(device(), KM_ALGORITHM_ECDSA, &formats, &len));
- EXPECT_TRUE(ResponseContains(KM_KEY_FORMAT_PKCS8, formats, len));
- free(formats);
-
- EXPECT_EQ(KM_ERROR_OK,
- device()->get_supported_import_formats(device(), KM_ALGORITHM_AES, &formats, &len));
- EXPECT_EQ(0, len);
- free(formats);
}
TEST_F(CheckSupported, SupportedExportFormats) {
@@ -1212,8 +1227,8 @@
}
TEST_F(EncryptionOperationsTest, AesOcbInvalidMacLength) {
- GenerateKey(ParamBuilder().AesEncryptionKey(128).OcbMode(4096, 17));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT));
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder().AesEncryptionKey(128).OcbMode(4096, 17)));
+ EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, BeginOperation(KM_PURPOSE_ENCRYPT));
}
} // namespace test
diff --git a/hmac_key.cpp b/hmac_key.cpp
index d49f32c..278fa6d 100644
--- a/hmac_key.cpp
+++ b/hmac_key.cpp
@@ -39,36 +39,4 @@
static KeyFactoryRegistry::Registration<HmacKeyFactory> registration;
-Operation* HmacKey::CreateOperation(keymaster_purpose_t purpose, keymaster_error_t* error) {
- *error = KM_ERROR_OK;
-
- uint32_t tag_length;
- if (!authorizations().GetTagValue(TAG_MAC_LENGTH, &tag_length))
- *error = KM_ERROR_UNSUPPORTED_MAC_LENGTH;
-
- keymaster_digest_t digest;
- if (!authorizations().GetTagValue(TAG_DIGEST, &digest))
- *error = KM_ERROR_UNSUPPORTED_DIGEST;
-
- if (*error != KM_ERROR_OK)
- return NULL;
-
- UniquePtr<Operation> op;
- switch (purpose) {
- case KM_PURPOSE_SIGN:
- case KM_PURPOSE_VERIFY:
- op.reset(
- new HmacOperation(purpose, logger_, key_data(), key_data_size(), digest, tag_length));
- break;
- default:
- *error = KM_ERROR_UNSUPPORTED_PURPOSE;
- return NULL;
- }
-
- if (!op.get())
- *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- return op.release();
-}
-
} // namespace keymaster
diff --git a/hmac_key.h b/hmac_key.h
index d60c848..afb877c 100644
--- a/hmac_key.h
+++ b/hmac_key.h
@@ -26,8 +26,6 @@
HmacKey(const AuthorizationSet& auths, const Logger& logger) : SymmetricKey(auths, logger) {}
HmacKey(const UnencryptedKeyBlob& blob, const Logger& logger, keymaster_error_t* error)
: SymmetricKey(blob, logger, error) {}
-
- virtual Operation* CreateOperation(keymaster_purpose_t purpose, keymaster_error_t* error);
};
} // namespace keymaster
diff --git a/hmac_operation.cpp b/hmac_operation.cpp
index 74c65b9..8e67624 100644
--- a/hmac_operation.cpp
+++ b/hmac_operation.cpp
@@ -19,6 +19,8 @@
#include <openssl/evp.h>
#include <openssl/hmac.h>
+#include "symmetric_key.h"
+
#if defined(OPENSSL_IS_BORINGSSL)
typedef size_t openssl_size_t;
#else
@@ -27,6 +29,74 @@
namespace keymaster {
+/**
+ * Abstract base for HMAC operation factories. This class does all of the work to create
+ * HMAC operations.
+ */
+class HmacOperationFactory : public OperationFactory {
+ public:
+ virtual KeyType registry_key() const { return KeyType(KM_ALGORITHM_HMAC, purpose()); }
+
+ virtual Operation* CreateOperation(const Key& key, const Logger& logger,
+ keymaster_error_t* error);
+
+ virtual const keymaster_digest_t* SupportedDigests(size_t* digest_count) const;
+
+ virtual keymaster_purpose_t purpose() const = 0;
+};
+
+Operation* HmacOperationFactory::CreateOperation(const Key& key, const Logger& logger,
+ keymaster_error_t* error) {
+ *error = KM_ERROR_OK;
+
+ uint32_t tag_length;
+ if (!key.authorizations().GetTagValue(TAG_MAC_LENGTH, &tag_length))
+ *error = KM_ERROR_UNSUPPORTED_MAC_LENGTH;
+
+ keymaster_digest_t digest;
+ if (!key.authorizations().GetTagValue(TAG_DIGEST, &digest))
+ *error = KM_ERROR_UNSUPPORTED_DIGEST;
+
+ if (*error != KM_ERROR_OK)
+ return NULL;
+
+ const SymmetricKey* symmetric_key = static_cast<const SymmetricKey*>(&key);
+ if (!symmetric_key) {
+ *error = KM_ERROR_UNKNOWN_ERROR;
+ return NULL;
+ }
+
+ Operation* op = new HmacOperation(purpose(), logger, symmetric_key->key_data(),
+ symmetric_key->key_data_size(), digest, tag_length);
+ if (!op)
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return op;
+}
+
+static keymaster_digest_t supported_digests[] = {KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
+ KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384,
+ KM_DIGEST_SHA_2_512};
+const keymaster_digest_t* HmacOperationFactory::SupportedDigests(size_t* digest_count) const {
+ *digest_count = array_length(supported_digests);
+ return supported_digests;
+}
+
+/**
+ * Concrete factory for creating HMAC signing operations.
+ */
+class HmacSignOperationFactory : public HmacOperationFactory {
+ keymaster_purpose_t purpose() const { return KM_PURPOSE_SIGN; }
+};
+static OperationFactoryRegistry::Registration<HmacSignOperationFactory> sign_registration;
+
+/**
+ * Concrete factory for creating HMAC verification operations.
+ */
+class HmacVerifyOperationFactory : public HmacOperationFactory {
+ keymaster_purpose_t purpose() const { return KM_PURPOSE_VERIFY; }
+};
+static OperationFactoryRegistry::Registration<HmacVerifyOperationFactory> verify_registration;
+
HmacOperation::HmacOperation(keymaster_purpose_t purpose, const Logger& logger,
const uint8_t* key_data, size_t key_data_size,
keymaster_digest_t digest, size_t tag_length)
diff --git a/include/keymaster/google_keymaster.h b/include/keymaster/google_keymaster.h
index e340ff5..dfff076 100644
--- a/include/keymaster/google_keymaster.h
+++ b/include/keymaster/google_keymaster.h
@@ -91,7 +91,7 @@
keymaster_key_blob_t* keymaster_blob, AuthorizationSet* enforced,
AuthorizationSet* unenforced);
Key* LoadKey(const keymaster_key_blob_t& key, const AuthorizationSet& client_params,
- keymaster_error_t* error);
+ keymaster_algorithm_t* algorithm, keymaster_error_t* error);
UnencryptedKeyBlob* LoadKeyBlob(const keymaster_key_blob_t& key,
const AuthorizationSet& client_params,
keymaster_error_t* error);
diff --git a/key.h b/key.h
index 77a8d96..96200bd 100644
--- a/key.h
+++ b/key.h
@@ -64,7 +64,6 @@
class Key {
public:
virtual ~Key() {}
- virtual Operation* CreateOperation(keymaster_purpose_t purpose, keymaster_error_t* error) = 0;
/**
* Return a copy of raw key material, in the key's preferred binary format.
diff --git a/operation.cpp b/operation.cpp
new file mode 100644
index 0000000..7c3e2af
--- /dev/null
+++ b/operation.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include "operation.h"
+
+namespace keymaster {
+
+DEFINE_ABSTRACT_FACTORY_REGISTRY_INSTANCE(OperationFactory);
+
+} // namespace keymaster
diff --git a/operation.h b/operation.h
index 836b7d1..594adb4 100644
--- a/operation.h
+++ b/operation.h
@@ -25,9 +25,53 @@
#include <hardware/keymaster_defs.h>
#include <keymaster/logger.h>
+#include "abstract_factory_registry.h"
+
namespace keymaster {
class AuthorizationSet;
+class Key;
+class Operation;
+
+class OperationFactory {
+ public:
+ virtual ~OperationFactory() {}
+
+ // Required for registry
+ struct KeyType {
+ KeyType(keymaster_algorithm_t alg, keymaster_purpose_t purp)
+ : algorithm(alg), purpose(purp) {}
+
+ keymaster_algorithm_t algorithm;
+ keymaster_purpose_t purpose;
+
+ bool operator==(const KeyType& rhs) const {
+ return algorithm == rhs.algorithm && purpose == rhs.purpose;
+ }
+ };
+ virtual KeyType registry_key() const = 0;
+
+ // Factory methods
+ virtual Operation* CreateOperation(const Key& key, const Logger& logger,
+ keymaster_error_t* error) = 0;
+
+ // Informational methods. The returned arrays reference static memory and must not be
+ // deallocated or modified.
+ virtual const keymaster_padding_t* SupportedPaddingModes(size_t* padding_count) const {
+ *padding_count = 0;
+ return NULL;
+ }
+ virtual const keymaster_block_mode_t* SupportedBlockModes(size_t* block_mode_count) const {
+ *block_mode_count = 0;
+ return NULL;
+ }
+ virtual const keymaster_digest_t* SupportedDigests(size_t* digest_count) const {
+ *digest_count = 0;
+ return NULL;
+ }
+};
+
+typedef AbstractFactoryRegistry<OperationFactory> OperationFactoryRegistry;
/**
* Abstract base for all cryptographic operations.
diff --git a/rsa_key.cpp b/rsa_key.cpp
index 35fe82e..f060274 100644
--- a/rsa_key.cpp
+++ b/rsa_key.cpp
@@ -155,46 +155,8 @@
*error = LoadKey(blob);
}
-Operation* RsaKey::CreateOperation(keymaster_purpose_t purpose, keymaster_error_t* error) {
- *error = KM_ERROR_OK;
-
- keymaster_padding_t padding = static_cast<keymaster_padding_t>(-1);
- authorizations().GetTagValue(TAG_PADDING, &padding);
- if (!SupportedMode(purpose, padding)) {
- *error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
- return NULL;
- }
-
- keymaster_digest_t digest = static_cast<keymaster_digest_t>(-1);
- authorizations().GetTagValue(TAG_DIGEST, &digest);
- if (!SupportedMode(purpose, digest)) {
- *error = KM_ERROR_UNSUPPORTED_DIGEST;
- return NULL;
- }
-
- Operation* op = NULL;
- switch (purpose) {
- case KM_PURPOSE_SIGN:
- op = new RsaSignOperation(logger_, digest, padding, rsa_key_.release());
- break;
- case KM_PURPOSE_VERIFY:
- op = new RsaVerifyOperation(logger_, digest, padding, rsa_key_.release());
- break;
- case KM_PURPOSE_ENCRYPT:
- op = new RsaEncryptOperation(logger_, padding, rsa_key_.release());
- break;
- case KM_PURPOSE_DECRYPT:
- op = new RsaDecryptOperation(logger_, padding, rsa_key_.release());
- break;
- default:
- *error = KM_ERROR_UNSUPPORTED_PURPOSE;
- return NULL;
- }
-
- if (!op)
- *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- return op;
+RSA* RsaKey::key() const {
+ return rsa_key_.get();
}
bool RsaKey::EvpToInternal(const EVP_PKEY* pkey) {
diff --git a/rsa_key.h b/rsa_key.h
index e98ece3..b218e89 100644
--- a/rsa_key.h
+++ b/rsa_key.h
@@ -24,13 +24,12 @@
namespace keymaster {
class RsaKeyFactory;
+class RsaOperationFactory;
class RsaKey : public AsymmetricKey {
- public:
- virtual Operation* CreateOperation(keymaster_purpose_t purpose, keymaster_error_t* error);
-
private:
friend class RsaKeyFactory;
+ friend class RsaOperationFactory;
RsaKey(const UnencryptedKeyBlob& blob, const Logger& logger, keymaster_error_t* error);
RsaKey(RSA* rsa_key, const AuthorizationSet& auths, const Logger& logger)
@@ -47,7 +46,9 @@
void operator()(RSA* p) { RSA_free(p); }
};
- UniquePtr<RSA, RSA_Delete> rsa_key_;
+ RSA* key() const;
+
+ mutable UniquePtr<RSA, RSA_Delete> rsa_key_;
};
} // namespace keymaster
diff --git a/rsa_operation.cpp b/rsa_operation.cpp
index 4ca7812..27394a6 100644
--- a/rsa_operation.cpp
+++ b/rsa_operation.cpp
@@ -14,17 +14,212 @@
* limitations under the License.
*/
+#include "rsa_operation.h"
+
#include <limits.h>
#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/rsa.h>
-#include "rsa_operation.h"
#include "openssl_utils.h"
+#include "rsa_key.h"
namespace keymaster {
+/**
+ * Abstract base for all RSA operation factories. This class exists mainly to centralize some code
+ * common to all RSA operation factories.
+ */
+class RsaOperationFactory : public OperationFactory {
+ public:
+ virtual KeyType registry_key() const { return KeyType(KM_ALGORITHM_RSA, purpose()); }
+ virtual keymaster_purpose_t purpose() const = 0;
+
+ protected:
+ bool GetAndValidatePadding(const Key& key, keymaster_padding_t* padding,
+ keymaster_error_t* error) const;
+ bool GetAndValidateDigest(const Key& key, keymaster_digest_t* digest,
+ keymaster_error_t* error) const;
+ static RSA* GetRsaKey(const Key& key, keymaster_error_t* error);
+};
+
+bool RsaOperationFactory::GetAndValidatePadding(const Key& key, keymaster_padding_t* padding,
+ keymaster_error_t* error) const {
+ *error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
+ if (!key.authorizations().GetTagValue(TAG_PADDING, padding))
+ return false;
+
+ size_t padding_count;
+ const keymaster_padding_t* supported_paddings = SupportedPaddingModes(&padding_count);
+ for (size_t i = 0; i < padding_count; ++i) {
+ if (*padding == supported_paddings[i]) {
+ *error = KM_ERROR_OK;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool RsaOperationFactory::GetAndValidateDigest(const Key& key, keymaster_digest_t* digest,
+ keymaster_error_t* error) const {
+ *error = KM_ERROR_UNSUPPORTED_DIGEST;
+ if (!key.authorizations().GetTagValue(TAG_DIGEST, digest))
+ return false;
+
+ size_t digest_count;
+ const keymaster_digest_t* supported_digests = SupportedDigests(&digest_count);
+ for (size_t i = 0; i < digest_count; ++i) {
+ if (*digest == supported_digests[i]) {
+ *error = KM_ERROR_OK;
+ return true;
+ }
+ }
+ return false;
+}
+
+/* static */
+RSA* RsaOperationFactory::GetRsaKey(const Key& key, keymaster_error_t* error) {
+ const RsaKey* rsa_key = static_cast<const RsaKey*>(&key);
+ assert(rsa_key);
+ if (!rsa_key || !rsa_key->key()) {
+ *error = KM_ERROR_UNKNOWN_ERROR;
+ return NULL;
+ }
+ return RSAPrivateKey_dup(rsa_key->key());
+}
+
+static const keymaster_digest_t supported_digests[] = {KM_DIGEST_NONE};
+static const keymaster_padding_t supported_sig_padding[] = {KM_PAD_NONE};
+
+/**
+ * Abstract base for RSA operations that digest their input (signing and verification). This class
+ * does most of the work of creation of RSA digesting operations, delegating only the actual
+ * operation instantiation.
+ */
+class RsaDigestingOperationFactory : public RsaOperationFactory {
+ public:
+ virtual Operation* CreateOperation(const Key& key, const Logger& logger,
+ keymaster_error_t* error);
+
+ virtual const keymaster_digest_t* SupportedDigests(size_t* digest_count) const {
+ *digest_count = array_length(supported_digests);
+ return supported_digests;
+ }
+
+ virtual const keymaster_padding_t* SupportedPaddingModes(size_t* padding_mode_count) const {
+ *padding_mode_count = array_length(supported_sig_padding);
+ return supported_sig_padding;
+ }
+
+ private:
+ virtual Operation* InstantiateOperation(const Logger& logger, keymaster_digest_t digest,
+ keymaster_padding_t padding, RSA* key) = 0;
+};
+
+Operation* RsaDigestingOperationFactory::CreateOperation(const Key& key, const Logger& logger,
+ keymaster_error_t* error) {
+ keymaster_padding_t padding;
+ keymaster_digest_t digest;
+ RSA* rsa;
+ if (!GetAndValidateDigest(key, &digest, error) ||
+ !GetAndValidatePadding(key, &padding, error) || !(rsa = GetRsaKey(key, error)))
+ return NULL;
+
+ Operation* op = InstantiateOperation(logger, digest, padding, rsa);
+ if (!op)
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return op;
+}
+
+static const keymaster_padding_t supported_crypt_padding[] = {KM_PAD_RSA_OAEP,
+ KM_PAD_RSA_PKCS1_1_5_ENCRYPT};
+
+/**
+ * Abstract base for en/de-crypting RSA operation factories. This class does most of the work of
+ * creating such operations, delegating only the actual operation instantiation.
+ */
+class RsaCryptingOperationFactory : public RsaOperationFactory {
+ public:
+ virtual Operation* CreateOperation(const Key& key, const Logger& logger,
+ keymaster_error_t* error);
+
+ virtual const keymaster_padding_t* SupportedPaddingModes(size_t* padding_mode_count) const {
+ *padding_mode_count = array_length(supported_crypt_padding);
+ return supported_crypt_padding;
+ }
+
+ virtual const keymaster_digest_t* SupportedDigests(size_t* digest_count) const {
+ *digest_count = 0;
+ return NULL;
+ }
+
+ private:
+ virtual Operation* InstantiateOperation(const Logger& logger, keymaster_padding_t padding,
+ RSA* key) = 0;
+};
+
+Operation* RsaCryptingOperationFactory::CreateOperation(const Key& key, const Logger& logger,
+ keymaster_error_t* error) {
+ keymaster_padding_t padding;
+ RSA* rsa;
+ if (!GetAndValidatePadding(key, &padding, error) || !(rsa = GetRsaKey(key, error)))
+ return NULL;
+
+ Operation* op = InstantiateOperation(logger, padding, rsa);
+ if (!op)
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return op;
+}
+
+/**
+ * Concrete factory for RSA signing operations.
+ */
+class RsaSigningOperationFactory : public RsaDigestingOperationFactory {
+ public:
+ virtual keymaster_purpose_t purpose() const { return KM_PURPOSE_SIGN; }
+ virtual Operation* InstantiateOperation(const Logger& logger, keymaster_digest_t digest,
+ keymaster_padding_t padding, RSA* key) {
+ return new RsaSignOperation(logger, digest, padding, key);
+ }
+};
+static OperationFactoryRegistry::Registration<RsaSigningOperationFactory> sign_registration;
+
+/**
+ * Concrete factory for RSA signing operations.
+ */
+class RsaVerificationOperationFactory : public RsaDigestingOperationFactory {
+ virtual keymaster_purpose_t purpose() const { return KM_PURPOSE_VERIFY; }
+ virtual Operation* InstantiateOperation(const Logger& logger, keymaster_digest_t digest,
+ keymaster_padding_t padding, RSA* key) {
+ return new RsaVerifyOperation(logger, digest, padding, key);
+ }
+};
+static OperationFactoryRegistry::Registration<RsaVerificationOperationFactory> verify_registration;
+
+/**
+ * Concrete factory for RSA signing operations.
+ */
+class RsaEncryptionOperationFactory : public RsaCryptingOperationFactory {
+ virtual keymaster_purpose_t purpose() const { return KM_PURPOSE_ENCRYPT; }
+ virtual Operation* InstantiateOperation(const Logger& logger, keymaster_padding_t padding,
+ RSA* key) {
+ return new RsaEncryptOperation(logger, padding, key);
+ }
+};
+static OperationFactoryRegistry::Registration<RsaEncryptionOperationFactory> encrypt_registration;
+
+/**
+ * Concrete factory for RSA signing operations.
+ */
+class RsaDecryptionOperationFactory : public RsaCryptingOperationFactory {
+ virtual keymaster_purpose_t purpose() const { return KM_PURPOSE_DECRYPT; }
+ virtual Operation* InstantiateOperation(const Logger& logger, keymaster_padding_t padding,
+ RSA* key) {
+ return new RsaDecryptOperation(logger, padding, key);
+ }
+};
+
+static OperationFactoryRegistry::Registration<RsaDecryptionOperationFactory> decrypt_registration;
+
struct RSA_Delete {
void operator()(RSA* p) const { RSA_free(p); }
};
diff --git a/rsa_operation.h b/rsa_operation.h
index 14a66c1..2c9680f 100644
--- a/rsa_operation.h
+++ b/rsa_operation.h
@@ -19,6 +19,9 @@
#include <UniquePtr.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+
#include <keymaster/key_blob.h>
#include "operation.h"
diff --git a/symmetric_key.h b/symmetric_key.h
index bef921f..48895d8 100644
--- a/symmetric_key.h
+++ b/symmetric_key.h
@@ -61,14 +61,11 @@
return KM_ERROR_UNIMPLEMENTED;
}
- protected:
- keymaster_error_t error_;
-
- SymmetricKey(const UnencryptedKeyBlob& blob, const Logger& logger, keymaster_error_t* error);
-
const uint8_t* key_data() const { return key_data_; }
size_t key_data_size() const { return key_data_size_; }
+ protected:
+ SymmetricKey(const UnencryptedKeyBlob& blob, const Logger& logger, keymaster_error_t* error);
SymmetricKey(const AuthorizationSet& auths, const Logger& logger) : Key(auths, logger) {}
private: