1/*
2 * Copyright 2015 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 "integrity_assured_key_blob.h"
18
19#include <assert.h>
20
21#include <new>
22
23#include <openssl/hmac.h>
24#include <openssl/mem.h>
25
26#include <keymaster/android_keymaster_utils.h>
27#include <keymaster/authorization_set.h>
28
29#include "openssl_err.h"
30
31namespace keymaster {
32
33static const uint8_t BLOB_VERSION = 0;
34static const size_t HMAC_SIZE = 8;
35static const char HMAC_KEY[] = "IntegrityAssuredBlob0";
36
37inline size_t min(size_t a, size_t b) {
38    if (a < b)
39        return a;
40    return b;
41}
42
43class HmacCleanup {
44  public:
45    HmacCleanup(HMAC_CTX* ctx) : ctx_(ctx) {}
46    ~HmacCleanup() { HMAC_CTX_cleanup(ctx_); }
47
48  private:
49    HMAC_CTX* ctx_;
50};
51
52static keymaster_error_t ComputeHmac(const uint8_t* serialized_data, size_t serialized_data_size,
53                                     const AuthorizationSet& hidden, uint8_t hmac[HMAC_SIZE]) {
54    size_t hidden_bytes_size = hidden.SerializedSize();
55    UniquePtr<uint8_t[]> hidden_bytes(new (std::nothrow) uint8_t[hidden_bytes_size]);
56    if (!hidden_bytes.get())
57        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
58    hidden.Serialize(hidden_bytes.get(), hidden_bytes.get() + hidden_bytes_size);
59
60    HMAC_CTX ctx;
61    HMAC_CTX_init(&ctx);
62    const EVP_MD* md = EVP_sha256();
63    if (!HMAC_Init_ex(&ctx, HMAC_KEY, sizeof(HMAC_KEY), md, NULL /* engine */))
64        return TranslateLastOpenSslError();
65    HmacCleanup cleanup(&ctx);
66
67    uint8_t tmp[EVP_MAX_MD_SIZE];
68    unsigned tmp_len;
69    if (!HMAC_Update(&ctx, serialized_data, serialized_data_size) ||
70        !HMAC_Update(&ctx, hidden_bytes.get(), hidden_bytes_size) ||  //
71        !HMAC_Final(&ctx, tmp, &tmp_len))
72        return TranslateLastOpenSslError();
73
74    assert(tmp_len >= HMAC_SIZE);
75    memcpy(hmac, tmp, min(HMAC_SIZE, tmp_len));
76
77    return KM_ERROR_OK;
78}
79
80keymaster_error_t SerializeIntegrityAssuredBlob(const KeymasterKeyBlob& key_material,
81                                                const AuthorizationSet& hidden,
82                                                const AuthorizationSet& hw_enforced,
83                                                const AuthorizationSet& sw_enforced,
84                                                KeymasterKeyBlob* key_blob) {
85    size_t size = 1 /* version */ +                //
86                  key_material.SerializedSize() +  //
87                  hw_enforced.SerializedSize() +   //
88                  sw_enforced.SerializedSize() +   //
89                  HMAC_SIZE;
90
91    if (!key_blob->Reset(size))
92        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
93
94    uint8_t* p = key_blob->writable_data();
95    *p++ = BLOB_VERSION;
96    p = key_material.Serialize(p, key_blob->end());
97    p = hw_enforced.Serialize(p, key_blob->end());
98    p = sw_enforced.Serialize(p, key_blob->end());
99
100    return ComputeHmac(key_blob->key_material, p - key_blob->key_material, hidden, p);
101}
102
103keymaster_error_t DeserializeIntegrityAssuredBlob(const KeymasterKeyBlob& key_blob,
104                                                  const AuthorizationSet& hidden,
105                                                  KeymasterKeyBlob* key_material,
106                                                  AuthorizationSet* hw_enforced,
107                                                  AuthorizationSet* sw_enforced) {
108    const uint8_t* p = key_blob.begin();
109    const uint8_t* end = key_blob.end();
110
111    if (p > end || p + HMAC_SIZE > end)
112        return KM_ERROR_INVALID_KEY_BLOB;
113
114    uint8_t computed_hmac[HMAC_SIZE];
115    keymaster_error_t error = ComputeHmac(key_blob.begin(), key_blob.key_material_size - HMAC_SIZE,
116                                          hidden, computed_hmac);
117    if (error != KM_ERROR_OK)
118        return error;
119
120    if (CRYPTO_memcmp(key_blob.end() - HMAC_SIZE, computed_hmac, HMAC_SIZE) != 0)
121        return KM_ERROR_INVALID_KEY_BLOB;
122
123    return DeserializeIntegrityAssuredBlob_NoHmacCheck(key_blob, key_material, hw_enforced,
124                                                       sw_enforced);
125}
126
127keymaster_error_t DeserializeIntegrityAssuredBlob_NoHmacCheck(const KeymasterKeyBlob& key_blob,
128                                                              KeymasterKeyBlob* key_material,
129                                                              AuthorizationSet* hw_enforced,
130                                                              AuthorizationSet* sw_enforced) {
131    const uint8_t* p = key_blob.begin();
132    const uint8_t* end = key_blob.end() - HMAC_SIZE;
133
134    if (p > end)
135        return KM_ERROR_INVALID_KEY_BLOB;
136
137    if (*p != BLOB_VERSION)
138        return KM_ERROR_INVALID_KEY_BLOB;
139    ++p;
140
141    if (!key_material->Deserialize(&p, end) ||  //
142        !hw_enforced->Deserialize(&p, end) ||   //
143        !sw_enforced->Deserialize(&p, end))
144        return KM_ERROR_INVALID_KEY_BLOB;
145
146    return KM_ERROR_OK;
147}
148
149}  // namespace keymaster;
150