Add ECDSA signing and verification.

Change-Id: Ic5345ebe6e79e3ee764c3a729dc551c61b87c79b
diff --git a/ecdsa_operation.cpp b/ecdsa_operation.cpp
index 4435679..321b65b 100644
--- a/ecdsa_operation.cpp
+++ b/ecdsa_operation.cpp
@@ -86,4 +86,100 @@
     return KM_ERROR_OK;
 }
 
+EcdsaOperation::EcdsaOperation(keymaster_purpose_t purpose, const KeyBlob& key)
+    : Operation(purpose), ecdsa_key_(NULL) {
+    assert(key.algorithm() == KM_ALGORITHM_ECDSA);
+
+    if ((!key.enforced().GetTagValue(TAG_DIGEST, &digest_) &&
+         !key.unenforced().GetTagValue(TAG_DIGEST, &digest_)) ||
+        digest_ != KM_DIGEST_NONE) {
+        error_ = KM_ERROR_UNSUPPORTED_DIGEST;
+        return;
+    }
+
+    if ((!key.enforced().GetTagValue(TAG_PADDING, &padding_) &&
+         !key.unenforced().GetTagValue(TAG_PADDING, &padding_)) ||
+        padding_ != KM_PAD_NONE) {
+        error_ = KM_ERROR_UNSUPPORTED_PADDING_MODE;
+        return;
+    }
+
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> evp_key(EVP_PKEY_new());
+    if (evp_key.get() == NULL) {
+        error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return;
+    }
+
+    EVP_PKEY* tmp_pkey = evp_key.get();
+    const uint8_t* key_material = key.key_material();
+    if (d2i_PrivateKey(EVP_PKEY_EC, &tmp_pkey, &key_material, key.key_material_length()) ==
+        NULL) {
+        error_ = KM_ERROR_INVALID_KEY_BLOB;
+        return;
+    }
+
+    ecdsa_key_ = EVP_PKEY_get1_EC_KEY(evp_key.get());
+    if (ecdsa_key_ == NULL) {
+        error_ = KM_ERROR_UNKNOWN_ERROR;
+        return;
+    }
+
+    // Since we're not using a digest function, we just need to store the text, up to the key
+    // size, until Finish is called, so we allocate a place to put it.
+    if (!data_.Reinitialize(512)) {
+        error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return;
+    }
+
+    error_ = KM_ERROR_OK;
+}
+
+EcdsaOperation::~EcdsaOperation() {
+    if (ecdsa_key_ != NULL)
+        EC_KEY_free(ecdsa_key_);
+}
+
+keymaster_error_t EcdsaOperation::Update(const Buffer& input, Buffer* /* output */) {
+    switch (purpose()) {
+    default:
+        return KM_ERROR_UNIMPLEMENTED;
+    case KM_PURPOSE_SIGN:
+    case KM_PURPOSE_VERIFY:
+        return StoreData(input);
+    }
+}
+
+keymaster_error_t EcdsaOperation::StoreData(const Buffer& input) {
+    if (!data_.write(input.peek_read(), input.available_read()))
+        return KM_ERROR_INVALID_INPUT_LENGTH;
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaOperation::Finish(const Buffer& signature, Buffer* output) {
+    switch (purpose()) {
+    case KM_PURPOSE_SIGN: {
+        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 KM_ERROR_UNKNOWN_ERROR;
+        output->advance_write(siglen);
+        return KM_ERROR_OK;
+    }
+    case KM_PURPOSE_VERIFY: {
+        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 KM_ERROR_UNKNOWN_ERROR;
+        else if (result == 0)
+            return KM_ERROR_VERIFICATION_FAILED;
+        else
+            return KM_ERROR_OK;
+    }
+    default:
+        return KM_ERROR_UNIMPLEMENTED;
+    }
+}
+
 }  // namespace keymaster