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 "hmac_key.h"
18
19#include <new>
20
21#include <openssl/err.h>
22#include <openssl/rand.h>
23
24#include "hmac_operation.h"
25
26namespace keymaster {
27
28static HmacSignOperationFactory sign_factory;
29static HmacVerifyOperationFactory verify_factory;
30
31OperationFactory* HmacKeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
32    switch (purpose) {
33    case KM_PURPOSE_SIGN:
34        return &sign_factory;
35    case KM_PURPOSE_VERIFY:
36        return &verify_factory;
37    default:
38        return nullptr;
39    }
40}
41
42keymaster_error_t HmacKeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
43                                          const AuthorizationSet& hw_enforced,
44                                          const AuthorizationSet& sw_enforced,
45                                          UniquePtr<Key>* key) const {
46    if (!key)
47        return KM_ERROR_OUTPUT_PARAMETER_NULL;
48
49    uint32_t min_mac_length;
50    if (!hw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length) &&
51        !sw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length)) {
52        LOG_E("HMAC key must have KM_TAG_MIN_MAC_LENGTH", 0);
53        return KM_ERROR_INVALID_KEY_BLOB;
54    }
55
56    keymaster_error_t error;
57    key->reset(new (std::nothrow) HmacKey(key_material, hw_enforced, sw_enforced, &error));
58    if (!key->get())
59        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
60    return error;
61}
62
63keymaster_error_t HmacKeyFactory::validate_algorithm_specific_new_key_params(
64    const AuthorizationSet& key_description) const {
65    uint32_t min_mac_length_bits;
66    if (!key_description.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length_bits))
67        return KM_ERROR_MISSING_MIN_MAC_LENGTH;
68
69    keymaster_digest_t digest;
70    if (!key_description.GetTagValue(TAG_DIGEST, &digest)) {
71        LOG_E("%d digests specified for HMAC key", key_description.GetTagCount(TAG_DIGEST));
72        return KM_ERROR_UNSUPPORTED_DIGEST;
73    }
74
75    size_t hash_size_bits = 0;
76    switch (digest) {
77    case KM_DIGEST_NONE:
78        return KM_ERROR_UNSUPPORTED_DIGEST;
79    case KM_DIGEST_MD5:
80        hash_size_bits = 128;
81        break;
82    case KM_DIGEST_SHA1:
83        hash_size_bits = 160;
84        break;
85    case KM_DIGEST_SHA_2_224:
86        hash_size_bits = 224;
87        break;
88    case KM_DIGEST_SHA_2_256:
89        hash_size_bits = 256;
90        break;
91    case KM_DIGEST_SHA_2_384:
92        hash_size_bits = 384;
93        break;
94    case KM_DIGEST_SHA_2_512:
95        hash_size_bits = 512;
96        break;
97    };
98
99    if (hash_size_bits == 0) {
100        // digest was not matched
101        return KM_ERROR_UNSUPPORTED_DIGEST;
102    }
103
104    if (min_mac_length_bits % 8 != 0 || min_mac_length_bits > hash_size_bits)
105        return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
106
107    if (min_mac_length_bits < kMinHmacLengthBits)
108        return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
109
110    return KM_ERROR_OK;
111}
112
113}  // namespace keymaster
114