blob: dcbf73f26e8dee017b955169b0958a44abe3ddaa [file] [log] [blame]
Shawn Willdenc3864dd2014-08-18 15:20:01 -06001/*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Shawn Willdenefbd7e42015-06-01 07:07:33 -060017#include "ecdsa_operation.h"
18
Shawn Willdenc3864dd2014-08-18 15:20:01 -060019#include <openssl/ecdsa.h>
20
Thai Duongf862a762015-03-18 14:10:56 -070021#include "ec_key.h"
Shawn Willden567a4a02014-12-31 12:14:46 -070022#include "openssl_err.h"
Shawn Willdenc3864dd2014-08-18 15:20:01 -060023#include "openssl_utils.h"
24
25namespace keymaster {
26
Shawn Willdenefbd7e42015-06-01 07:07:33 -060027static const keymaster_digest_t supported_digests[] = {
28 KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
29 KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
Shawn Willden84b8da52015-03-11 07:21:32 -060030
Shawn Willden13e29e02015-05-08 11:02:46 -060031Operation* EcdsaOperationFactory::CreateOperation(const Key& key,
Shawn Willden226746b2015-05-08 11:36:56 -060032 const AuthorizationSet& begin_params,
Shawn Willden13e29e02015-05-08 11:02:46 -060033 keymaster_error_t* error) {
34 const EcKey* ecdsa_key = static_cast<const EcKey*>(&key);
35 if (!ecdsa_key) {
36 *error = KM_ERROR_UNKNOWN_ERROR;
37 return nullptr;
Shawn Willden63ac0432014-12-29 14:07:08 -070038 }
Shawn Willden84b8da52015-03-11 07:21:32 -060039
Shawn Willdenefbd7e42015-06-01 07:07:33 -060040 UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
41 if (!ecdsa_key->InternalToEvp(pkey.get())) {
42 *error = KM_ERROR_UNKNOWN_ERROR;
Shawn Willden226746b2015-05-08 11:36:56 -060043 return nullptr;
Shawn Willden13e29e02015-05-08 11:02:46 -060044 }
Shawn Willden226746b2015-05-08 11:36:56 -060045
Shawn Willdenefbd7e42015-06-01 07:07:33 -060046 keymaster_digest_t digest;
47 if (!GetAndValidateDigest(begin_params, key, &digest, error))
48 return nullptr;
49
50 *error = KM_ERROR_OK;
51 Operation* op = InstantiateOperation(digest, pkey.release());
Shawn Willden13e29e02015-05-08 11:02:46 -060052 if (!op)
53 *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
54 return op;
55}
56
57const keymaster_digest_t* EcdsaOperationFactory::SupportedDigests(size_t* digest_count) const {
58 *digest_count = array_length(supported_digests);
59 return supported_digests;
60}
61
Shawn Willden5ac2f8f2014-08-18 15:33:10 -060062EcdsaOperation::~EcdsaOperation() {
63 if (ecdsa_key_ != NULL)
Shawn Willdenefbd7e42015-06-01 07:07:33 -060064 EVP_PKEY_free(ecdsa_key_);
65 EVP_MD_CTX_cleanup(&digest_ctx_);
Shawn Willden5ac2f8f2014-08-18 15:33:10 -060066}
67
Shawn Willdenefbd7e42015-06-01 07:07:33 -060068keymaster_error_t EcdsaOperation::InitDigest() {
69 switch (digest_) {
70 case KM_DIGEST_NONE:
71 return KM_ERROR_OK;
72 case KM_DIGEST_MD5:
73 digest_algorithm_ = EVP_md5();
74 return KM_ERROR_OK;
75 case KM_DIGEST_SHA1:
76 digest_algorithm_ = EVP_sha1();
77 return KM_ERROR_OK;
78 case KM_DIGEST_SHA_2_224:
79 digest_algorithm_ = EVP_sha224();
80 return KM_ERROR_OK;
81 case KM_DIGEST_SHA_2_256:
82 digest_algorithm_ = EVP_sha256();
83 return KM_ERROR_OK;
84 case KM_DIGEST_SHA_2_384:
85 digest_algorithm_ = EVP_sha384();
86 return KM_ERROR_OK;
87 case KM_DIGEST_SHA_2_512:
88 digest_algorithm_ = EVP_sha512();
89 return KM_ERROR_OK;
Shawn Willden5ac2f8f2014-08-18 15:33:10 -060090 default:
Shawn Willdenefbd7e42015-06-01 07:07:33 -060091 return KM_ERROR_UNSUPPORTED_DIGEST;
Shawn Willden5ac2f8f2014-08-18 15:33:10 -060092 }
93}
94
Shawn Willdenb7361132014-12-08 08:15:14 -070095keymaster_error_t EcdsaOperation::StoreData(const Buffer& input, size_t* input_consumed) {
Shawn Willdenb3407022014-08-27 06:30:52 -060096 if (!data_.reserve(data_.available_read() + input.available_read()) ||
Shawn Willdend67afae2014-08-19 12:36:27 -060097 !data_.write(input.peek_read(), input.available_read()))
98 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
Shawn Willdenb7361132014-12-08 08:15:14 -070099 *input_consumed = input.available_read();
Shawn Willden5ac2f8f2014-08-18 15:33:10 -0600100 return KM_ERROR_OK;
101}
102
Shawn Willdenefbd7e42015-06-01 07:07:33 -0600103keymaster_error_t EcdsaSignOperation::Begin(const AuthorizationSet& /* input_params */,
104 AuthorizationSet* /* output_params */) {
105 keymaster_error_t error = InitDigest();
106 if (error != KM_ERROR_OK)
107 return error;
108
109 if (digest_ == KM_DIGEST_NONE)
110 return KM_ERROR_OK;
111
112 EVP_PKEY_CTX* pkey_ctx;
113 if (EVP_DigestSignInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */,
114 ecdsa_key_) != 1)
115 return TranslateLastOpenSslError();
116 return KM_ERROR_OK;
117}
118
119keymaster_error_t EcdsaSignOperation::Update(const AuthorizationSet& /* additional_params */,
Shawn Willdended8e7d2015-06-01 15:29:12 -0600120 const Buffer& input,
121 AuthorizationSet* /* output_params */,
122 Buffer* /* output */, size_t* input_consumed) {
Shawn Willdenefbd7e42015-06-01 07:07:33 -0600123 if (digest_ == KM_DIGEST_NONE)
124 return StoreData(input, input_consumed);
125
126 if (EVP_DigestSignUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1)
127 return TranslateLastOpenSslError();
128 *input_consumed = input.available_read();
129 return KM_ERROR_OK;
130}
131
Shawn Willden6bfbff02015-02-06 19:48:24 -0700132keymaster_error_t EcdsaSignOperation::Finish(const AuthorizationSet& /* additional_params */,
Shawn Willdended8e7d2015-06-01 15:29:12 -0600133 const Buffer& /* signature */,
134 AuthorizationSet* /* output_params */,
135 Buffer* output) {
Shawn Willdenefbd7e42015-06-01 07:07:33 -0600136 if (!output)
137 return KM_ERROR_OUTPUT_PARAMETER_NULL;
138
139 size_t siglen;
140 if (digest_ == KM_DIGEST_NONE) {
141 UniquePtr<EC_KEY, EC_Delete> ecdsa(EVP_PKEY_get1_EC_KEY(ecdsa_key_));
142 if (!ecdsa.get())
143 return TranslateLastOpenSslError();
144
145 output->Reinitialize(ECDSA_size(ecdsa.get()));
146 unsigned int siglen_tmp;
147 if (!ECDSA_sign(0 /* type -- ignored */, data_.peek_read(), data_.available_read(),
148 output->peek_write(), &siglen_tmp, ecdsa.get()))
149 return TranslateLastOpenSslError();
150 siglen = siglen_tmp;
151 } else {
152 if (EVP_DigestSignFinal(&digest_ctx_, nullptr /* signature */, &siglen) != 1)
153 return TranslateLastOpenSslError();
154 if (!output->Reinitialize(siglen))
155 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
156 if (EVP_DigestSignFinal(&digest_ctx_, output->peek_write(), &siglen) <= 0)
157 return TranslateLastOpenSslError();
158 }
Shawn Willdend67afae2014-08-19 12:36:27 -0600159 output->advance_write(siglen);
160 return KM_ERROR_OK;
161}
162
Shawn Willdenefbd7e42015-06-01 07:07:33 -0600163keymaster_error_t EcdsaVerifyOperation::Begin(const AuthorizationSet& /* input_params */,
164 AuthorizationSet* /* output_params */) {
165 keymaster_error_t error = InitDigest();
166 if (error != KM_ERROR_OK)
167 return error;
168
169 if (digest_ == KM_DIGEST_NONE)
170 return KM_ERROR_OK;
171
172 EVP_PKEY_CTX* pkey_ctx;
173 if (EVP_DigestVerifyInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */,
174 ecdsa_key_) != 1)
175 return TranslateLastOpenSslError();
176 return KM_ERROR_OK;
177}
178
179keymaster_error_t EcdsaVerifyOperation::Update(const AuthorizationSet& /* additional_params */,
Shawn Willdended8e7d2015-06-01 15:29:12 -0600180 const Buffer& input,
181 AuthorizationSet* /* output_params */,
182 Buffer* /* output */, size_t* input_consumed) {
Shawn Willdenefbd7e42015-06-01 07:07:33 -0600183 if (digest_ == KM_DIGEST_NONE)
184 return StoreData(input, input_consumed);
185
186 if (EVP_DigestVerifyUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1)
187 return TranslateLastOpenSslError();
188 *input_consumed = input.available_read();
189 return KM_ERROR_OK;
190}
191
Shawn Willden6bfbff02015-02-06 19:48:24 -0700192keymaster_error_t EcdsaVerifyOperation::Finish(const AuthorizationSet& /* additional_params */,
Shawn Willdended8e7d2015-06-01 15:29:12 -0600193 const Buffer& signature,
194 AuthorizationSet* /* output_params */,
195 Buffer* /* output */) {
Shawn Willdenefbd7e42015-06-01 07:07:33 -0600196 if (digest_ == KM_DIGEST_NONE) {
197 UniquePtr<EC_KEY, EC_Delete> ecdsa(EVP_PKEY_get1_EC_KEY(ecdsa_key_));
198 if (!ecdsa.get())
199 return TranslateLastOpenSslError();
200
201 int result =
202 ECDSA_verify(0 /* type -- ignored */, data_.peek_read(), data_.available_read(),
203 signature.peek_read(), signature.available_read(), ecdsa.get());
204 if (result < 0)
205 return TranslateLastOpenSslError();
206 else if (result == 0)
207 return KM_ERROR_VERIFICATION_FAILED;
208 } else if (!EVP_DigestVerifyFinal(&digest_ctx_, signature.peek_read(),
209 signature.available_read()))
Shawn Willdend67afae2014-08-19 12:36:27 -0600210 return KM_ERROR_VERIFICATION_FAILED;
Shawn Willdenefbd7e42015-06-01 07:07:33 -0600211
212 return KM_ERROR_OK;
Shawn Willden5ac2f8f2014-08-18 15:33:10 -0600213}
214
Shawn Willdenc3864dd2014-08-18 15:20:01 -0600215} // namespace keymaster