blob: 321b65bfac8712f7d9140e6db46063ab2760d996 [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
17#include <openssl/ecdsa.h>
18
19#include "ecdsa_operation.h"
20#include "openssl_utils.h"
21
22namespace keymaster {
23
24struct ECDSA_Delete {
25 void operator()(EC_KEY* p) { EC_KEY_free(p); }
26};
27
28struct EC_GROUP_Delete {
29 void operator()(EC_GROUP* p) { EC_GROUP_free(p); }
30};
31
32/* static */
33keymaster_error_t EcdsaOperation::Generate(uint32_t key_size_bits, UniquePtr<uint8_t[]>* key_data,
34 size_t* key_data_size) {
35 if (key_data == NULL || key_data_size == NULL)
36 return KM_ERROR_OUTPUT_PARAMETER_NULL;
37
38 UniquePtr<EC_KEY, ECDSA_Delete> ecdsa_key(EC_KEY_new());
39 UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
40 if (ecdsa_key.get() == NULL || pkey.get() == NULL)
41 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
42
43 UniquePtr<EC_GROUP, EC_GROUP_Delete> group;
44 switch (key_size_bits) {
45 case 192:
46 group.reset(EC_GROUP_new_by_curve_name(NID_X9_62_prime192v1));
47 break;
48 case 224:
49 group.reset(EC_GROUP_new_by_curve_name(NID_secp224r1));
50 break;
51 case 256:
52 group.reset(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
53 break;
54 case 384:
55 group.reset(EC_GROUP_new_by_curve_name(NID_secp384r1));
56 break;
57 case 521:
58 group.reset(EC_GROUP_new_by_curve_name(NID_secp521r1));
59 break;
60 default:
61 break;
62 }
63
64 if (group.get() == NULL)
65 // Technically, could also have been a memory allocation problem.
66 return KM_ERROR_UNSUPPORTED_KEY_SIZE;
67
68 EC_GROUP_set_point_conversion_form(group.get(), POINT_CONVERSION_UNCOMPRESSED);
69 EC_GROUP_set_asn1_flag(group.get(), OPENSSL_EC_NAMED_CURVE);
70
71 if (EC_KEY_set_group(ecdsa_key.get(), group.get()) != 1 ||
72 EC_KEY_generate_key(ecdsa_key.get()) != 1 || EC_KEY_check_key(ecdsa_key.get()) < 0 ||
73 !EVP_PKEY_assign_EC_KEY(pkey.get(), ecdsa_key.get()))
74 return KM_ERROR_UNKNOWN_ERROR;
75 else
76 release_because_ownership_transferred(ecdsa_key);
77
78 *key_data_size = i2d_PrivateKey(pkey.get(), NULL);
79 if (*key_data_size <= 0)
80 return KM_ERROR_UNKNOWN_ERROR;
81
82 key_data->reset(new uint8_t[*key_data_size]);
83 uint8_t* tmp = key_data->get();
84 i2d_PrivateKey(pkey.get(), &tmp);
85
86 return KM_ERROR_OK;
87}
88
Shawn Willden5ac2f8f2014-08-18 15:33:10 -060089EcdsaOperation::EcdsaOperation(keymaster_purpose_t purpose, const KeyBlob& key)
90 : Operation(purpose), ecdsa_key_(NULL) {
91 assert(key.algorithm() == KM_ALGORITHM_ECDSA);
92
93 if ((!key.enforced().GetTagValue(TAG_DIGEST, &digest_) &&
94 !key.unenforced().GetTagValue(TAG_DIGEST, &digest_)) ||
95 digest_ != KM_DIGEST_NONE) {
96 error_ = KM_ERROR_UNSUPPORTED_DIGEST;
97 return;
98 }
99
100 if ((!key.enforced().GetTagValue(TAG_PADDING, &padding_) &&
101 !key.unenforced().GetTagValue(TAG_PADDING, &padding_)) ||
102 padding_ != KM_PAD_NONE) {
103 error_ = KM_ERROR_UNSUPPORTED_PADDING_MODE;
104 return;
105 }
106
107 UniquePtr<EVP_PKEY, EVP_PKEY_Delete> evp_key(EVP_PKEY_new());
108 if (evp_key.get() == NULL) {
109 error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
110 return;
111 }
112
113 EVP_PKEY* tmp_pkey = evp_key.get();
114 const uint8_t* key_material = key.key_material();
115 if (d2i_PrivateKey(EVP_PKEY_EC, &tmp_pkey, &key_material, key.key_material_length()) ==
116 NULL) {
117 error_ = KM_ERROR_INVALID_KEY_BLOB;
118 return;
119 }
120
121 ecdsa_key_ = EVP_PKEY_get1_EC_KEY(evp_key.get());
122 if (ecdsa_key_ == NULL) {
123 error_ = KM_ERROR_UNKNOWN_ERROR;
124 return;
125 }
126
127 // Since we're not using a digest function, we just need to store the text, up to the key
128 // size, until Finish is called, so we allocate a place to put it.
129 if (!data_.Reinitialize(512)) {
130 error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
131 return;
132 }
133
134 error_ = KM_ERROR_OK;
135}
136
137EcdsaOperation::~EcdsaOperation() {
138 if (ecdsa_key_ != NULL)
139 EC_KEY_free(ecdsa_key_);
140}
141
142keymaster_error_t EcdsaOperation::Update(const Buffer& input, Buffer* /* output */) {
143 switch (purpose()) {
144 default:
145 return KM_ERROR_UNIMPLEMENTED;
146 case KM_PURPOSE_SIGN:
147 case KM_PURPOSE_VERIFY:
148 return StoreData(input);
149 }
150}
151
152keymaster_error_t EcdsaOperation::StoreData(const Buffer& input) {
153 if (!data_.write(input.peek_read(), input.available_read()))
154 return KM_ERROR_INVALID_INPUT_LENGTH;
155 return KM_ERROR_OK;
156}
157
158keymaster_error_t EcdsaOperation::Finish(const Buffer& signature, Buffer* output) {
159 switch (purpose()) {
160 case KM_PURPOSE_SIGN: {
161 output->Reinitialize(ECDSA_size(ecdsa_key_));
162 unsigned int siglen;
163 if (!ECDSA_sign(0 /* type -- ignored */, data_.peek_read(), data_.available_read(),
164 output->peek_write(), &siglen, ecdsa_key_))
165 return KM_ERROR_UNKNOWN_ERROR;
166 output->advance_write(siglen);
167 return KM_ERROR_OK;
168 }
169 case KM_PURPOSE_VERIFY: {
170 int result =
171 ECDSA_verify(0 /* type -- ignored */, data_.peek_read(), data_.available_read(),
172 signature.peek_read(), signature.available_read(), ecdsa_key_);
173 if (result < 0)
174 return KM_ERROR_UNKNOWN_ERROR;
175 else if (result == 0)
176 return KM_ERROR_VERIFICATION_FAILED;
177 else
178 return KM_ERROR_OK;
179 }
180 default:
181 return KM_ERROR_UNIMPLEMENTED;
182 }
183}
184
Shawn Willdenc3864dd2014-08-18 15:20:01 -0600185} // namespace keymaster