blob: 00188d90d9d1da3eca2b1f17522c8fcc18446a16 [file] [log] [blame]
Shawn Willden28e41472014-08-18 13:35:22 -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/bn.h>
18
19#include "dsa_operation.h"
20#include "openssl_utils.h"
21
22namespace keymaster {
23
24struct DSA_Delete {
25 void operator()(DSA* p) { DSA_free(p); }
26};
27
28/* static */
29keymaster_error_t DsaOperation::Generate(uint32_t key_size_bits, keymaster_blob_t* g,
30 keymaster_blob_t* p, keymaster_blob_t* q,
31 UniquePtr<uint8_t[]>* key_data, size_t* key_data_size) {
32 if (g == NULL || p == NULL || q == NULL || key_data == NULL || key_data_size == NULL)
33 return KM_ERROR_OUTPUT_PARAMETER_NULL;
34
35 UniquePtr<DSA, DSA_Delete> dsa_key(DSA_new());
36 UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
37 if (dsa_key.get() == NULL || pkey.get() == NULL)
38 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
39
40 if (g->data == NULL && p->data == NULL && q->data == NULL) {
41 // No params provided, generate them.
42 if (!DSA_generate_parameters_ex(dsa_key.get(), key_size_bits, NULL /* seed */,
43 0 /* seed_len */, NULL /* counter_ret */, NULL /* h_ret */,
44 NULL /* callback */)) {
45 // TODO(swillden): return a more precise error, depending on ERR_get_error();
46 return KM_ERROR_INVALID_DSA_PARAMS;
47 }
48 convert_bn_to_blob(dsa_key->g, g);
49 convert_bn_to_blob(dsa_key->p, p);
50 convert_bn_to_blob(dsa_key->q, q);
51 } else if (g->data == NULL || p->data == NULL || q->data == NULL) {
52 // Some params provided, that's an error. Provide them all or provide none.
53 return KM_ERROR_INVALID_DSA_PARAMS;
54 } else {
55 // All params provided. Use them.
56 dsa_key->g = BN_bin2bn(g->data, g->data_length, NULL);
57 dsa_key->p = BN_bin2bn(p->data, p->data_length, NULL);
58 dsa_key->q = BN_bin2bn(q->data, q->data_length, NULL);
59
60 if (dsa_key->g == NULL || dsa_key->p == NULL || dsa_key->q == NULL)
61 return KM_ERROR_INVALID_DSA_PARAMS;
62 }
63
64 if (!DSA_generate_key(dsa_key.get()) || !EVP_PKEY_assign_DSA(pkey.get(), dsa_key.get()))
65 return KM_ERROR_UNKNOWN_ERROR;
66 release_because_ownership_transferred(dsa_key);
67
68 *key_data_size = i2d_PrivateKey(pkey.get(), NULL);
69 if (*key_data_size <= 0)
70 return KM_ERROR_UNKNOWN_ERROR;
71
72 key_data->reset(new uint8_t[*key_data_size]);
73 uint8_t* tmp = key_data->get();
74 i2d_PrivateKey(pkey.get(), &tmp);
75
76 return KM_ERROR_OK;
77}
78
Shawn Willden5b41ca22014-08-18 14:29:14 -060079DsaOperation::DsaOperation(keymaster_purpose_t purpose, const KeyBlob& key)
80 : Operation(purpose), dsa_key_(NULL) {
81 assert(key.algorithm() == KM_ALGORITHM_DSA);
82
83 if ((!key.enforced().GetTagValue(TAG_DIGEST, &digest_) &&
84 !key.unenforced().GetTagValue(TAG_DIGEST, &digest_)) ||
85 digest_ != KM_DIGEST_NONE) {
86 error_ = KM_ERROR_UNSUPPORTED_DIGEST;
87 return;
88 }
89
90 if ((!key.enforced().GetTagValue(TAG_PADDING, &padding_) &&
91 !key.unenforced().GetTagValue(TAG_PADDING, &padding_)) ||
92 padding_ != KM_PAD_NONE) {
93 error_ = KM_ERROR_UNSUPPORTED_PADDING_MODE;
94 return;
95 }
96
97 UniquePtr<EVP_PKEY, EVP_PKEY_Delete> evp_key(EVP_PKEY_new());
98 if (evp_key.get() == NULL) {
99 error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
100 return;
101 }
102
103 EVP_PKEY* tmp_pkey = evp_key.get();
104 const uint8_t* key_material = key.key_material();
105 if (d2i_PrivateKey(EVP_PKEY_DSA, &tmp_pkey, &key_material, key.key_material_length()) == NULL) {
106 error_ = KM_ERROR_INVALID_KEY_BLOB;
107 return;
108 }
109
110 dsa_key_ = EVP_PKEY_get1_DSA(evp_key.get());
111 if (dsa_key_ == NULL) {
112 error_ = KM_ERROR_UNKNOWN_ERROR;
113 return;
114 }
115
116 // Since we're not using a digest function, we just need to store the text, up to the key
117 // size, until Finish is called, so we allocate a place to put it.
118 if (!data_.Reinitialize(DSA_size(dsa_key_))) {
119 error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
120 return;
121 }
122 error_ = KM_ERROR_OK;
123}
124
125DsaOperation::~DsaOperation() {
126 if (dsa_key_ != NULL)
127 DSA_free(dsa_key_);
128}
129
130keymaster_error_t DsaOperation::Update(const Buffer& input, Buffer* /* output */) {
131 switch (purpose()) {
132 default:
133 return KM_ERROR_UNIMPLEMENTED;
134 case KM_PURPOSE_SIGN:
135 case KM_PURPOSE_VERIFY:
136 return StoreData(input);
137 }
138}
139
140keymaster_error_t DsaOperation::StoreData(const Buffer& input) {
141 if (!data_.write(input.peek_read(), input.available_read()))
142 return KM_ERROR_INVALID_INPUT_LENGTH;
143 return KM_ERROR_OK;
144}
145
146keymaster_error_t DsaOperation::Finish(const Buffer& signature, Buffer* output) {
147 switch (purpose()) {
148 case KM_PURPOSE_SIGN: {
149 output->Reinitialize(DSA_size(dsa_key_));
150 if (data_.available_read() != output->buffer_size())
151 return KM_ERROR_INVALID_INPUT_LENGTH;
152
153 unsigned int siglen;
154 if (!DSA_sign(0 /* type -- ignored */, data_.peek_read(), data_.available_read(),
155 output->peek_write(), &siglen, dsa_key_))
156 return KM_ERROR_UNKNOWN_ERROR;
157 output->advance_write(siglen);
158 return KM_ERROR_OK;
159 }
160 case KM_PURPOSE_VERIFY: {
161 if ((int)data_.available_read() != DSA_size(dsa_key_))
162 return KM_ERROR_INVALID_INPUT_LENGTH;
163
164 int result = DSA_verify(0 /* type -- ignored */, data_.peek_read(), data_.available_read(),
165 signature.peek_read(), signature.available_read(), dsa_key_);
166 if (result< 0)
167 return KM_ERROR_UNKNOWN_ERROR;
168 else if (result == 0)
169 return KM_ERROR_VERIFICATION_FAILED;
170 else
171 return KM_ERROR_OK;
172 }
173 default:
174 return KM_ERROR_UNIMPLEMENTED;
175 }
176}
177
Shawn Willden28e41472014-08-18 13:35:22 -0600178} // namespace keymaster