1 /*
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 <keymaster/authorization_set.h>
18 #include <keymaster/key.h>
19 #include <keymaster/operation.h>
20 
21 
22 namespace keymaster {
23 
24 bool OperationFactory::supported(keymaster_padding_t padding) const {
25     size_t padding_count;
26     const keymaster_padding_t* supported_paddings = SupportedPaddingModes(&padding_count);
27     for (size_t i = 0; i < padding_count; ++i)
28         if (padding == supported_paddings[i])
29             return true;
30     return false;
31 }
32 
33 bool OperationFactory::supported(keymaster_block_mode_t block_mode) const {
34     size_t block_mode_count;
35     const keymaster_block_mode_t* supported_block_modes = SupportedBlockModes(&block_mode_count);
36     for (size_t i = 0; i < block_mode_count; ++i)
37         if (block_mode == supported_block_modes[i])
38             return true;
39     return false;
40 }
41 
42 bool OperationFactory::supported(keymaster_digest_t digest) const {
43     size_t digest_count;
44     const keymaster_digest_t* supported_digests = SupportedDigests(&digest_count);
45     for (size_t i = 0; i < digest_count; ++i)
46         if (digest == supported_digests[i])
47             return true;
48     return false;
49 }
50 
51 inline bool is_public_key_algorithm(keymaster_algorithm_t algorithm) {
52     switch (algorithm) {
53     case KM_ALGORITHM_HMAC:
54     case KM_ALGORITHM_AES:
55     case KM_ALGORITHM_TRIPLE_DES:
56         return false;
57     case KM_ALGORITHM_RSA:
58     case KM_ALGORITHM_EC:
59         return true;
60     }
61 
62     // Unreachable.
63     assert(false);
64     return false;
65 }
66 
67 bool OperationFactory::is_public_key_operation() const {
68     KeyType key_type = registry_key();
69 
70     if (!is_public_key_algorithm(key_type.algorithm))
71         return false;
72 
73     switch (key_type.purpose) {
74     case KM_PURPOSE_VERIFY:
75     case KM_PURPOSE_ENCRYPT:
76     case KM_PURPOSE_WRAP:
77         return true;
78     case KM_PURPOSE_SIGN:
79     case KM_PURPOSE_DECRYPT:
80     case KM_PURPOSE_DERIVE_KEY:
81         return false;
82     };
83 
84     // Unreachable.
85     assert(false);
86     return false;
87 }
88 
89 bool OperationFactory::GetAndValidatePadding(const AuthorizationSet& begin_params, const Key& key,
90                                              keymaster_padding_t* padding,
91                                              keymaster_error_t* error) const {
92     *error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
93     if (!begin_params.GetTagValue(TAG_PADDING, padding)) {
94         LOG_E("%d padding modes specified in begin params", begin_params.GetTagCount(TAG_PADDING));
95         return false;
96     } else if (!supported(*padding)) {
97         LOG_E("Padding mode %d not supported", *padding);
98         return false;
99     } else if (
100         // If it's a public key operation, all padding modes are authorized.
101         !is_public_key_operation() &&
102         // Otherwise the key needs to authorize the specific mode.
103         !key.authorizations().Contains(TAG_PADDING, *padding) &&
104         !key.authorizations().Contains(TAG_PADDING_OLD, *padding)) {
105         LOG_E("Padding mode %d was specified, but not authorized by key", *padding);
106         *error = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
107         return false;
108     }
109 
110     *error = KM_ERROR_OK;
111     return true;
112 }
113 
114 bool OperationFactory::GetAndValidateDigest(const AuthorizationSet& begin_params, const Key& key,
115                                             keymaster_digest_t* digest,
116                                             keymaster_error_t* error) const {
117     *error = KM_ERROR_UNSUPPORTED_DIGEST;
118     if (!begin_params.GetTagValue(TAG_DIGEST, digest)) {
119         LOG_E("%d digests specified in begin params", begin_params.GetTagCount(TAG_DIGEST));
120         return false;
121     } else if (!supported(*digest)) {
122         LOG_E("Digest %d not supported", *digest);
123         return false;
124     } else if (
125         // If it's a public key operation, all digests are authorized.
126         !is_public_key_operation() &&
127         // Otherwise the key needs to authorize the specific digest.
128         !key.authorizations().Contains(TAG_DIGEST, *digest) &&
129         !key.authorizations().Contains(TAG_DIGEST_OLD, *digest)) {
130         LOG_E("Digest %d was specified, but not authorized by key", *digest);
131         *error = KM_ERROR_INCOMPATIBLE_DIGEST;
132         return false;
133     }
134     *error = KM_ERROR_OK;
135     return true;
136 }
137 
138 keymaster_error_t Operation::UpdateForFinish(const AuthorizationSet& input_params,
139                                              const Buffer& input) {
140     if (!input_params.empty() || input.available_read()) {
141         size_t input_consumed;
142         Buffer output;
143         AuthorizationSet output_params;
144         keymaster_error_t error =
145             Update(input_params, input, &output_params, &output, &input_consumed);
146         if (error != KM_ERROR_OK)
147             return error;
148         assert(input_consumed == input.available_read());
149         assert(output_params.empty());
150         assert(output.available_read() == 0);
151     }
152 
153     return KM_ERROR_OK;
154 }
155 
156 }  // namespace keymaster
157