summaryrefslogtreecommitdiff
path: root/ecdsa_operation.cpp
diff options
context:
space:
mode:
authorShawn Willden <swillden@google.com>2015-06-01 07:07:33 -0600
committerShawn Willden <swillden@google.com>2015-06-01 08:05:52 -0600
commitefbd7e432228cf1e65abb6d85dffa38ec03f7a26 (patch)
tree7389ff2ebc3ab75effabf6e688a464a02a4ff3ba /ecdsa_operation.cpp
parent117a0cc2178ec1151562b8607182647bfb62517e (diff)
downloadkeymaster-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.cpp173
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