summaryrefslogtreecommitdiffstats
path: root/keymaster/3.0/vts/functional/keymaster_tags.h
blob: f241ef1604a312f21d3d4452046b78d5417f23b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
/*
 * Copyright 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
#define SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_

/**
 * This header contains various definitions that make working with keymaster tags safer and easier.
 *
 * It makes use of a fair amount of template metaprogramming. The metaprogramming serves the purpose
 * of making it impossible to make certain classes of mistakes when operating on keymaster
 * authorizations.  For example, it's an error to create a KeyParameter with tag == Tag::PURPOSE
 * and then to assign Algorithm::RSA to algorithm element of its union. But because the user
 * must choose the union field, there could be a mismatch which the compiler has now way to
 * diagnose.
 *
 * The machinery in this header solves these problems by describing which union field corresponds
 * to which Tag. Central to this mechanism is the template TypedTag. It has zero size and binds a
 * numeric Tag to a type that the compiler understands. By means of the macro DECLARE_TYPED_TAG,
 * we declare types for each of the tags defined in hardware/interfaces/keymaster/2.0/types.hal.
 *
 * The macro DECLARE_TYPED_TAG(name) generates a typename TAG_name_t and a zero sized instance
 * TAG_name. Once these typed tags have been declared we define metafunctions mapping the each tag
 * to its value c++ type and the correct union element of KeyParameter. This is done by means of
 * the macros MAKE_TAG_*VALUE_ACCESSOR, which generates TypedTag2ValueType, a metafunction mapping
 * a typed tag to the corresponding c++ type, and access function, accessTagValue returning a
 * reference to the correct element of KeyParameter.
 * E.g.:
 *      given "KeyParameter param;" then "accessTagValue(TAG_PURPOSE, param)"
 *      yields a reference to param.f.purpose
 * If used in an assignment the compiler can now check the compatibility of the assigned value.
 *
 * For convenience we also provide the constructor like function Authorization().
 * Authorization takes a typed tag and a value and checks at compile time whether the value given
 * is suitable for the given tag. At runtime it creates a new KeyParameter initialized with the
 * given tag and value and returns it by value.
 *
 * The second convenience function, authorizationValue, allows access to the KeyParameter value in
 * a safe way. It takes a typed tag and a KeyParameter and returns a reference to the value wrapped
 * by NullOr. NullOr has out-of-band information about whether it is save to access the wrapped
 * reference.
 * E.g.:
 *      auto param = Authorization(TAG_ALGORITM, Algorithm::RSA);
 *      auto value1 = authorizationValue(TAG_PURPOSE, param);
 *      auto value2 = authorizationValue(TAG_ALGORITM, param);
 * value1.isOk() yields false, but value2.isOk() yields true, thus value2.value() is save to access.
 */

#include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h>
#include <hardware/hw_auth_token.h>
#include <type_traits>

namespace android {
namespace hardware {
namespace keymaster {
namespace V3_0 {

// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have.  We
// need these old values to be able to support old keys that use them.
static const int32_t KM_TAG_DIGEST_OLD = static_cast<int32_t>(TagType::ENUM) | 5;
static const int32_t KM_TAG_PADDING_OLD = static_cast<int32_t>(TagType::ENUM) | 7;

constexpr TagType typeFromTag(Tag tag) {
    return static_cast<TagType>(static_cast<uint32_t>(tag) & static_cast<uint32_t>(0xf0000000));
}

/**
 * TypedTag is a templatized version of Tag, which provides compile-time checking of keymaster tag
 * types. Instances are convertible to Tag, so they can be used wherever Tag is expected, and
 * because they encode the tag type it's possible to create function overloads that only operate on
 * tags with a particular type.
 */
template <TagType tag_type, Tag tag> struct TypedTag {
    inline TypedTag() {
        // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type
        // 'tag_type'.  Attempting to instantiate a tag with the wrong type will result in a compile
        // error (no match for template specialization StaticAssert<false>), with no run-time cost.
        static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type");
    }
    constexpr operator Tag() { return tag; }
    constexpr long maskedTag() {
        return static_cast<long>(static_cast<uint32_t>(tag) & static_cast<uint32_t>(0x0fffffff));
    }
};

template <Tag tag> struct Tag2TypedTag { typedef TypedTag<typeFromTag(tag), tag> type; };

template <Tag tag> struct Tag2String;

#define _TAGS_STRINGIFY(x) #x
#define TAGS_STRINGIFY(x) _TAGS_STRINGIFY(x)

#define DECLARE_TYPED_TAG(name)                                                                    \
    typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t;                                 \
    extern TAG_##name##_t TAG_##name;                                                              \
    template <> struct Tag2String<Tag::name> {                                                     \
        static const char* value() { return "Tag::" TAGS_STRINGIFY(name); }                        \
    }

DECLARE_TYPED_TAG(INVALID);
DECLARE_TYPED_TAG(KEY_SIZE);
DECLARE_TYPED_TAG(MAC_LENGTH);
DECLARE_TYPED_TAG(CALLER_NONCE);
DECLARE_TYPED_TAG(MIN_MAC_LENGTH);
DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT);
DECLARE_TYPED_TAG(ECIES_SINGLE_HASH_MODE);
DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID);
DECLARE_TYPED_TAG(ACTIVE_DATETIME);
DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME);
DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME);
DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS);
DECLARE_TYPED_TAG(MAX_USES_PER_BOOT);
DECLARE_TYPED_TAG(ALL_USERS);
DECLARE_TYPED_TAG(USER_ID);
DECLARE_TYPED_TAG(USER_SECURE_ID);
DECLARE_TYPED_TAG(NO_AUTH_REQUIRED);
DECLARE_TYPED_TAG(AUTH_TIMEOUT);
DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY);
DECLARE_TYPED_TAG(ALL_APPLICATIONS);
DECLARE_TYPED_TAG(APPLICATION_ID);
DECLARE_TYPED_TAG(APPLICATION_DATA);
DECLARE_TYPED_TAG(CREATION_DATETIME);
DECLARE_TYPED_TAG(ROLLBACK_RESISTANT);
DECLARE_TYPED_TAG(ROOT_OF_TRUST);
DECLARE_TYPED_TAG(ASSOCIATED_DATA);
DECLARE_TYPED_TAG(NONCE);
DECLARE_TYPED_TAG(AUTH_TOKEN);
DECLARE_TYPED_TAG(BOOTLOADER_ONLY);
DECLARE_TYPED_TAG(OS_VERSION);
DECLARE_TYPED_TAG(OS_PATCHLEVEL);
DECLARE_TYPED_TAG(UNIQUE_ID);
DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE);
DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID);
DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION);

DECLARE_TYPED_TAG(PURPOSE);
DECLARE_TYPED_TAG(ALGORITHM);
DECLARE_TYPED_TAG(BLOCK_MODE);
DECLARE_TYPED_TAG(DIGEST);
DECLARE_TYPED_TAG(PADDING);
DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS);
DECLARE_TYPED_TAG(ORIGIN);
DECLARE_TYPED_TAG(USER_AUTH_TYPE);
DECLARE_TYPED_TAG(KDF);
DECLARE_TYPED_TAG(EC_CURVE);

template <typename... Elems> struct MetaList {};

using all_tags_t = MetaList<
    TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t,
    TAG_RSA_PUBLIC_EXPONENT_t, TAG_ECIES_SINGLE_HASH_MODE_t, TAG_INCLUDE_UNIQUE_ID_t,
    TAG_ACTIVE_DATETIME_t, TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t,
    TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_ALL_USERS_t, TAG_USER_ID_t,
    TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t,
    TAG_ALL_APPLICATIONS_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t, TAG_CREATION_DATETIME_t,
    TAG_ROLLBACK_RESISTANT_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t,
    TAG_AUTH_TOKEN_t, TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t,
    TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t,
    TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t,
    TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_KDF_t, TAG_EC_CURVE_t>;

/* implementation in keystore_utils.cpp */
extern const char* stringifyTag(Tag tag);

template <typename TypedTagType> struct TypedTag2ValueType;

#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name)                                              \
    template <Tag tag> struct TypedTag2ValueType<TypedTag<tag_type, tag>> {                        \
        typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type;                    \
    };                                                                                             \
    template <Tag tag>                                                                             \
    inline auto accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param)                 \
        ->const decltype(param.field_name)& {                                                      \
        return param.field_name;                                                                   \
    }                                                                                              \
    template <Tag tag>                                                                             \
    inline auto accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param)                       \
        ->decltype(param.field_name)& {                                                            \
        return param.field_name;                                                                   \
    }

MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, f.longInteger)
MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, f.longInteger)
MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, f.dateTime)
MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, f.integer)
MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, f.integer)
MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, f.boolValue)
MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob)
MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob)

#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name)                                        \
    template <> struct TypedTag2ValueType<decltype(typed_tag)> {                                   \
        typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type;                    \
    };                                                                                             \
    inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param)                     \
        ->const decltype(param.field_name)& {                                                      \
        return param.field_name;                                                                   \
    }                                                                                              \
    inline auto accessTagValue(decltype(typed_tag), KeyParameter& param)                           \
        ->decltype(param.field_name)& {                                                            \
        return param.field_name;                                                                   \
    }

MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, f.algorithm)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOB_USAGE_REQUIREMENTS, f.keyBlobUsageRequirements)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, f.blockMode)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, f.digest)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, f.ecCurve)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_KDF, f.keyDerivationFunction)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, f.origin)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, f.paddingMode)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, f.purpose)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, f.hardwareAuthenticatorType)

template <TagType tag_type, Tag tag, typename ValueT>
inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) {
    KeyParameter param;
    param.tag = tag;
    param.f.longInteger = 0;
    accessTagValue(ttag, param) = std::forward<ValueT>(value);
    return param;
}

// the boolean case
template <Tag tag> inline KeyParameter makeKeyParameter(TypedTag<TagType::BOOL, tag>) {
    KeyParameter param;
    param.tag = tag;
    param.f.boolValue = true;
    return param;
}

template <typename... Pack> struct FirstOrNoneHelper;
template <typename First> struct FirstOrNoneHelper<First> { typedef First type; };
template <> struct FirstOrNoneHelper<> {
    struct type {};
};

template <typename... Pack> using FirstOrNone = typename FirstOrNoneHelper<Pack...>::type;

template <TagType tag_type, Tag tag, typename... Args>
inline KeyParameter Authorization(TypedTag<tag_type, tag> ttag, Args&&... args) {
    static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0),
                  "TagType::BOOL Authorizations do not take parameters. Presence is truth.");
    static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1),
                  "Authorization other then TagType::BOOL take exactly one parameter.");
    static_assert(
        tag_type == TagType::BOOL ||
            std::is_convertible<std::remove_cv_t<std::remove_reference_t<FirstOrNone<Args...>>>,
                                typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>::value,
        "Invalid argument type for given tag.");

    return makeKeyParameter(ttag, std::forward<Args>(args)...);
}

/**
 * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out
 * of band. Note that if the wrapped value is a reference it is unsafe to access the value if
 * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the
 * wrapped value. In this case the pointer will be NULL though, and the value will be default
 * constructed.
 */
template <typename ValueT> class NullOr {
    template <typename T> struct reference_initializer {
        static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); }
    };
    template <typename T> struct pointer_initializer {
        static T init() { return nullptr; }
    };
    template <typename T> struct value_initializer {
        static T init() { return T(); }
    };
    template <typename T>
    using initializer_t =
        std::conditional_t<std::is_lvalue_reference<T>::value, reference_initializer<T>,
                           std::conditional_t<std::is_pointer<T>::value, pointer_initializer<T>,
                                              value_initializer<T>>>;

  public:
    NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {}
    NullOr(ValueT&& value) : value_(std::forward<ValueT>(value)), null_(false) {}

    bool isOk() const { return !null_; }

    const ValueT& value() const & { return value_; }
    ValueT& value() & { return value_; }
    ValueT&& value() && { return std::move(value_); }

  private:
    ValueT value_;
    bool null_;
};

template <typename T> std::remove_reference_t<T> NullOrOr(NullOr<T>&& v) {
    if (v.isOk()) return v;
    return {};
}

template <typename Head, typename... Tail>
std::remove_reference_t<Head> NullOrOr(Head&& head, Tail&&... tail) {
    if (head.isOk()) return head;
    return NullOrOr(std::forward<Tail>(tail)...);
}

template <typename Default, typename Wrapped>
std::remove_reference_t<Wrapped> defaultOr(NullOr<Wrapped>&& optional, Default&& def) {
    static_assert(std::is_convertible<std::remove_reference_t<Default>,
                                      std::remove_reference_t<Wrapped>>::value,
                  "Type of default value must match the type wrapped by NullOr");
    if (optional.isOk()) return optional.value();
    return def;
}

template <TagType tag_type, Tag tag>
inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&>
authorizationValue(TypedTag<tag_type, tag> ttag, const KeyParameter& param) {
    if (tag != param.tag) return {};
    return accessTagValue(ttag, param);
}

inline const char* stringify(Digest digest) {
    switch (digest) {
    case Digest::NONE:
        return "None";
    case Digest::MD5:
        return "Md5";
    case Digest::SHA1:
        return "Sha1";
    case Digest::SHA_2_224:
        return "Sha224";
    case Digest::SHA_2_256:
        return "Sha256";
    case Digest::SHA_2_384:
        return "Sha384";
    case Digest::SHA_2_512:
        return "Sha512";
    }
    return "UNKNOWN DIGEST!";
}

inline const char* stringify(Algorithm algorithm) {
    switch (algorithm) {
    case Algorithm::RSA:
        return "Rsa";
    case Algorithm::EC:
        return "Ec";
    case Algorithm::AES:
        return "Aes";
    case Algorithm::HMAC:
        return "Hmac";
    }
    return "UNKNOWN ALGORITHM";
}

inline const char* stringify(BlockMode block_mode) {
    switch (block_mode) {
    case BlockMode::ECB:
        return "Ecb";
    case BlockMode::CBC:
        return "Cbc";
    case BlockMode::CTR:
        return "Ctr";
    case BlockMode::GCM:
        return "Gcm";
    }
    return "UNKNOWN BLOCK MODE";
}

inline const char* stringify(PaddingMode padding) {
    switch (padding) {
    case PaddingMode::NONE:
        return "None";
    case PaddingMode::RSA_OAEP:
        return "RsaOaep";
    case PaddingMode::RSA_PSS:
        return "RsaPss";
    case PaddingMode::RSA_PKCS1_1_5_ENCRYPT:
        return "RsaPkcs115Encrypt";
    case PaddingMode::RSA_PKCS1_1_5_SIGN:
        return "RsaPkcs115Sign";
    case PaddingMode::PKCS7:
        return "Pkcs7";
    }
    return "UNKNOWN PADDING MODE";
}

inline const char* stringify(KeyOrigin origin) {
    switch (origin) {
    case KeyOrigin::GENERATED:
        return "Generated";
    case KeyOrigin::DERIVED:
        return "Derived";
    case KeyOrigin::IMPORTED:
        return "Imported";
    case KeyOrigin::UNKNOWN:
        return "UNKNOWN (keymaster0 didn't record it)";
    }
    return "UNKOWN KEY ORIGIN VALUE";
}

inline const char* stringify(KeyPurpose purpose) {
    switch (purpose) {
    case KeyPurpose::ENCRYPT:
        return "Encrypt";
    case KeyPurpose::DECRYPT:
        return "Decrypt";
    case KeyPurpose::SIGN:
        return "Sign";
    case KeyPurpose::VERIFY:
        return "Verify";
    case KeyPurpose::DERIVE_KEY:
        return "DeriveKey";
    case KeyPurpose::WRAP_KEY:
        return "WrapKey";
    };
    return "UNKNOWN KEY PURPOSE";
}

inline const char* stringify(EcCurve curve) {
    switch (curve) {
    case EcCurve::P_224:
        return "P_224";
    case EcCurve::P_256:
        return "P_256";
    case EcCurve::P_384:
        return "P_384";
    case EcCurve::P_521:
        return "P_521";
    }
    return "UNKNOWN EC CURVE";
}

}  // namespace V3_0
}  // namespace keymaster
}  // namespace hardware
}  // namespace android

#endif  // SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_