diff options
author | Shawn Willden <swillden@google.com> | 2015-06-01 07:07:33 -0600 |
---|---|---|
committer | Shawn Willden <swillden@google.com> | 2015-06-01 08:05:52 -0600 |
commit | efbd7e432228cf1e65abb6d85dffa38ec03f7a26 (patch) | |
tree | 7389ff2ebc3ab75effabf6e688a464a02a4ff3ba /ecdsa_operation.cpp | |
parent | 117a0cc2178ec1151562b8607182647bfb62517e (diff) | |
download | keymaster-efbd7e432228cf1e65abb6d85dffa38ec03f7a26.tar.gz |
Add support for all digests for ECDSA.
Also, switch to useing the EVP API rather than the ECDSA API.
Bug: 21048758
Change-Id: I088b3332285ce2060cac5a7282ec42bea2fa5950
Diffstat (limited to 'ecdsa_operation.cpp')
-rw-r--r-- | ecdsa_operation.cpp | 173 |
1 files changed, 134 insertions, 39 deletions
diff --git a/ecdsa_operation.cpp b/ecdsa_operation.cpp index a28209a..5f9767f 100644 --- a/ecdsa_operation.cpp +++ b/ecdsa_operation.cpp @@ -14,16 +14,19 @@ * limitations under the License. */ +#include "ecdsa_operation.h" + #include <openssl/ecdsa.h> #include "ec_key.h" -#include "ecdsa_operation.h" #include "openssl_err.h" #include "openssl_utils.h" namespace keymaster { -static const keymaster_digest_t supported_digests[] = {KM_DIGEST_NONE}; +static const keymaster_digest_t supported_digests[] = { + KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224, + KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512}; Operation* EcdsaOperationFactory::CreateOperation(const Key& key, const AuthorizationSet& begin_params, @@ -34,23 +37,18 @@ Operation* EcdsaOperationFactory::CreateOperation(const Key& key, return nullptr; } - *error = KM_ERROR_UNSUPPORTED_DIGEST; - keymaster_digest_t digest; - if (!begin_params.GetTagValue(TAG_DIGEST, &digest)) { - LOG_E("%d digests specified in begin params", begin_params.GetTagCount(TAG_DIGEST)); - return nullptr; - } else if (!supported(digest)) { - LOG_E("Digest %d not supported", digest); + UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new()); + if (!ecdsa_key->InternalToEvp(pkey.get())) { + *error = KM_ERROR_UNKNOWN_ERROR; return nullptr; - } else if (!ecdsa_key->authorizations().Contains(TAG_DIGEST, digest) && - !ecdsa_key->authorizations().Contains(TAG_DIGEST_OLD, digest)) { - LOG_E("Digest %d was specified, but not authorized by key", digest); - *error = KM_ERROR_INCOMPATIBLE_DIGEST; - return NULL; } - *error = KM_ERROR_OK; - Operation* op = InstantiateOperation(digest, ecdsa_key->key()); + keymaster_digest_t digest; + if (!GetAndValidateDigest(begin_params, key, &digest, error)) + return nullptr; + + *error = KM_ERROR_OK; + Operation* op = InstantiateOperation(digest, pkey.release()); if (!op) *error = KM_ERROR_MEMORY_ALLOCATION_FAILED; return op; @@ -63,19 +61,34 @@ const keymaster_digest_t* EcdsaOperationFactory::SupportedDigests(size_t* digest EcdsaOperation::~EcdsaOperation() { if (ecdsa_key_ != NULL) - EC_KEY_free(ecdsa_key_); + EVP_PKEY_free(ecdsa_key_); + EVP_MD_CTX_cleanup(&digest_ctx_); } -keymaster_error_t EcdsaOperation::Update(const AuthorizationSet& /* additional_params */, - const Buffer& input, Buffer* /* output */, - size_t* input_consumed) { - assert(input_consumed); - switch (purpose()) { +keymaster_error_t EcdsaOperation::InitDigest() { + switch (digest_) { + case KM_DIGEST_NONE: + return KM_ERROR_OK; + case KM_DIGEST_MD5: + digest_algorithm_ = EVP_md5(); + return KM_ERROR_OK; + case KM_DIGEST_SHA1: + digest_algorithm_ = EVP_sha1(); + return KM_ERROR_OK; + case KM_DIGEST_SHA_2_224: + digest_algorithm_ = EVP_sha224(); + return KM_ERROR_OK; + case KM_DIGEST_SHA_2_256: + digest_algorithm_ = EVP_sha256(); + return KM_ERROR_OK; + case KM_DIGEST_SHA_2_384: + digest_algorithm_ = EVP_sha384(); + return KM_ERROR_OK; + case KM_DIGEST_SHA_2_512: + digest_algorithm_ = EVP_sha512(); + return KM_ERROR_OK; default: - return KM_ERROR_UNIMPLEMENTED; - case KM_PURPOSE_SIGN: - case KM_PURPOSE_VERIFY: - return StoreData(input, input_consumed); + return KM_ERROR_UNSUPPORTED_DIGEST; } } @@ -87,28 +100,110 @@ keymaster_error_t EcdsaOperation::StoreData(const Buffer& input, size_t* input_c return KM_ERROR_OK; } +keymaster_error_t EcdsaSignOperation::Begin(const AuthorizationSet& /* input_params */, + AuthorizationSet* /* output_params */) { + keymaster_error_t error = InitDigest(); + if (error != KM_ERROR_OK) + return error; + + if (digest_ == KM_DIGEST_NONE) + return KM_ERROR_OK; + + EVP_PKEY_CTX* pkey_ctx; + if (EVP_DigestSignInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */, + ecdsa_key_) != 1) + return TranslateLastOpenSslError(); + return KM_ERROR_OK; +} + +keymaster_error_t EcdsaSignOperation::Update(const AuthorizationSet& /* additional_params */, + const Buffer& input, Buffer* /* output */, + size_t* input_consumed) { + if (digest_ == KM_DIGEST_NONE) + return StoreData(input, input_consumed); + + if (EVP_DigestSignUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1) + return TranslateLastOpenSslError(); + *input_consumed = input.available_read(); + return KM_ERROR_OK; +} + keymaster_error_t EcdsaSignOperation::Finish(const AuthorizationSet& /* additional_params */, const Buffer& /* signature */, Buffer* output) { - assert(output); - output->Reinitialize(ECDSA_size(ecdsa_key_)); - unsigned int siglen; - if (!ECDSA_sign(0 /* type -- ignored */, data_.peek_read(), data_.available_read(), - output->peek_write(), &siglen, ecdsa_key_)) - return TranslateLastOpenSslError(); + if (!output) + return KM_ERROR_OUTPUT_PARAMETER_NULL; + + size_t siglen; + if (digest_ == KM_DIGEST_NONE) { + UniquePtr<EC_KEY, EC_Delete> ecdsa(EVP_PKEY_get1_EC_KEY(ecdsa_key_)); + if (!ecdsa.get()) + return TranslateLastOpenSslError(); + + output->Reinitialize(ECDSA_size(ecdsa.get())); + unsigned int siglen_tmp; + if (!ECDSA_sign(0 /* type -- ignored */, data_.peek_read(), data_.available_read(), + output->peek_write(), &siglen_tmp, ecdsa.get())) + return TranslateLastOpenSslError(); + siglen = siglen_tmp; + } else { + if (EVP_DigestSignFinal(&digest_ctx_, nullptr /* signature */, &siglen) != 1) + return TranslateLastOpenSslError(); + if (!output->Reinitialize(siglen)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + if (EVP_DigestSignFinal(&digest_ctx_, output->peek_write(), &siglen) <= 0) + return TranslateLastOpenSslError(); + } output->advance_write(siglen); return KM_ERROR_OK; } +keymaster_error_t EcdsaVerifyOperation::Begin(const AuthorizationSet& /* input_params */, + AuthorizationSet* /* output_params */) { + keymaster_error_t error = InitDigest(); + if (error != KM_ERROR_OK) + return error; + + if (digest_ == KM_DIGEST_NONE) + return KM_ERROR_OK; + + EVP_PKEY_CTX* pkey_ctx; + if (EVP_DigestVerifyInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */, + ecdsa_key_) != 1) + return TranslateLastOpenSslError(); + return KM_ERROR_OK; +} + +keymaster_error_t EcdsaVerifyOperation::Update(const AuthorizationSet& /* additional_params */, + const Buffer& input, Buffer* /* output */, + size_t* input_consumed) { + if (digest_ == KM_DIGEST_NONE) + return StoreData(input, input_consumed); + + if (EVP_DigestVerifyUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1) + return TranslateLastOpenSslError(); + *input_consumed = input.available_read(); + return KM_ERROR_OK; +} + keymaster_error_t EcdsaVerifyOperation::Finish(const AuthorizationSet& /* additional_params */, const Buffer& signature, Buffer* /* output */) { - int result = ECDSA_verify(0 /* type -- ignored */, data_.peek_read(), data_.available_read(), - signature.peek_read(), signature.available_read(), ecdsa_key_); - if (result < 0) - return TranslateLastOpenSslError(); - else if (result == 0) + if (digest_ == KM_DIGEST_NONE) { + UniquePtr<EC_KEY, EC_Delete> ecdsa(EVP_PKEY_get1_EC_KEY(ecdsa_key_)); + if (!ecdsa.get()) + return TranslateLastOpenSslError(); + + int result = + ECDSA_verify(0 /* type -- ignored */, data_.peek_read(), data_.available_read(), + signature.peek_read(), signature.available_read(), ecdsa.get()); + if (result < 0) + return TranslateLastOpenSslError(); + else if (result == 0) + return KM_ERROR_VERIFICATION_FAILED; + } else if (!EVP_DigestVerifyFinal(&digest_ctx_, signature.peek_read(), + signature.available_read())) return KM_ERROR_VERIFICATION_FAILED; - else - return KM_ERROR_OK; + + return KM_ERROR_OK; } } // namespace keymaster |