blob: 2031054667cad4749c070d2bbfd9296087348e46 [file] [log] [blame]
Shawn Willden19fca882015-01-22 16:35:30 -07001/*
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/err.h>
18#include <openssl/rand.h>
19
20#include "aes_key.h"
21
22namespace keymaster {
23
24AesKey* AesKey::GenerateKey(const AuthorizationSet& key_description, const Logger& logger,
25 keymaster_error_t* error) {
26 if (!error)
27 return NULL;
28
29 AuthorizationSet authorizations(key_description);
30 uint32_t key_size_bits;
31 if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size_bits) ||
32 !size_is_supported(key_size_bits)) {
33 *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
34 return NULL;
35 }
36
37 keymaster_block_mode_t block_mode;
38 if (!authorizations.GetTagValue(TAG_BLOCK_MODE, &block_mode) ||
39 !block_mode_is_supported(block_mode)) {
40 *error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
41 return NULL;
42 }
43
44 uint32_t chunk_length = 0;
45 if (block_mode >= KM_MODE_FIRST_AUTHENTICATED && block_mode < KM_MODE_FIRST_MAC) {
46 // Chunk length is required.
47 if (!authorizations.GetTagValue(TAG_CHUNK_LENGTH, &chunk_length) ||
48 !chunk_length_is_supported(chunk_length)) {
49 // TODO(swillden): Add a better error code for this.
50 *error = KM_ERROR_INVALID_INPUT_LENGTH;
51 return NULL;
52 }
53 }
54
55 // Padding is optional
56 keymaster_padding_t padding;
57 if (authorizations.GetTagValue(TAG_PADDING, &padding) && !padding_is_supported(padding)) {
58 *error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
59 return NULL;
60 }
61
62 // Verify purpose is compatible with block mode.
63 if (!ModeAndPurposesAreCompatible(authorizations, block_mode, logger)) {
64 *error = KM_ERROR_INCOMPATIBLE_BLOCK_MODE;
65 return NULL;
66 }
67
68 // All required tags seem to be present and valid. Generate the key bits.
69 size_t key_data_size = key_size_bits / 8;
70 UniquePtr<uint8_t[]> key_data(new uint8_t[key_data_size]);
71 if (!key_data.get()) {
72 *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
73 return NULL;
74 }
75
76 if (!RAND_bytes(key_data.get(), key_data_size)) {
77 logger.error("Error %ul generating %d bit AES key", ERR_get_error(), key_size_bits);
78 *error = KM_ERROR_UNKNOWN_ERROR;
79 return NULL;
80 }
81
82 *error = KM_ERROR_OK;
83 return new AesKey(key_data.release(), key_data_size, authorizations, logger);
84}
85
86bool AesKey::ModeAndPurposesAreCompatible(const AuthorizationSet& authorizations,
87 keymaster_block_mode_t block_mode, const Logger& logger) {
88 keymaster_purpose_t purpose;
89 for (size_t i = 0; authorizations.GetTagValue(TAG_PURPOSE, i, &purpose); ++i) {
90 switch (purpose) {
91 case KM_PURPOSE_SIGN:
92 case KM_PURPOSE_VERIFY:
93 if (block_mode < KM_MODE_FIRST_AUTHENTICATED) {
94 logger.error("Only MACing or authenticated modes are supported for signing and "
95 "verification purposes.");
96 return false;
97 }
98 break;
99
100 case KM_PURPOSE_ENCRYPT:
101 case KM_PURPOSE_DECRYPT:
102 if (block_mode >= KM_MODE_FIRST_MAC) {
103 logger.error("MACing modes not supported for encryption and decryption purposes.");
104 return false;
105 }
106 break;
107 }
108 }
109 return true;
110}
111
112AesKey::AesKey(uint8_t* key_data, size_t key_data_size, AuthorizationSet& auths,
113 const Logger& logger)
114 : Key(auths, logger), key_data_(key_data), key_data_size_(key_data_size) {
115}
116
117keymaster_error_t AesKey::key_material(UniquePtr<uint8_t[]>* key_material, size_t* size) const {
118 *size = key_data_size_;
119 key_material->reset(new uint8_t[*size]);
120 memcpy(key_material->get(), key_data_.get(), *size);
121 return KM_ERROR_OK;
122}
123
124} // namespace keymaster