1*e7b1675dSTing-Kang Chang // Copyright 2017 Google Inc.
2*e7b1675dSTing-Kang Chang //
3*e7b1675dSTing-Kang Chang // Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang // you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang // You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang //
7*e7b1675dSTing-Kang Chang // http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang //
9*e7b1675dSTing-Kang Chang // Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang // distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang // See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang // limitations under the License.
14*e7b1675dSTing-Kang Chang //
15*e7b1675dSTing-Kang Chang ///////////////////////////////////////////////////////////////////////////////
16*e7b1675dSTing-Kang Chang
17*e7b1675dSTing-Kang Chang #include "tink/util/validation.h"
18*e7b1675dSTing-Kang Chang
19*e7b1675dSTing-Kang Chang #include "absl/status/status.h"
20*e7b1675dSTing-Kang Chang #include "tink/util/errors.h"
21*e7b1675dSTing-Kang Chang #include "tink/util/status.h"
22*e7b1675dSTing-Kang Chang #include "proto/tink.pb.h"
23*e7b1675dSTing-Kang Chang
24*e7b1675dSTing-Kang Chang using google::crypto::tink::KeyData;
25*e7b1675dSTing-Kang Chang using google::crypto::tink::Keyset;
26*e7b1675dSTing-Kang Chang using google::crypto::tink::KeyStatusType;
27*e7b1675dSTing-Kang Chang
28*e7b1675dSTing-Kang Chang namespace crypto {
29*e7b1675dSTing-Kang Chang namespace tink {
30*e7b1675dSTing-Kang Chang
ValidateAesKeySize(uint32_t key_size)31*e7b1675dSTing-Kang Chang util::Status ValidateAesKeySize(uint32_t key_size) {
32*e7b1675dSTing-Kang Chang if (key_size != 16 && key_size != 32) {
33*e7b1675dSTing-Kang Chang return ToStatusF(absl::StatusCode::kInvalidArgument,
34*e7b1675dSTing-Kang Chang "AES key has %d bytes; supported sizes: 16 or 32 bytes.",
35*e7b1675dSTing-Kang Chang key_size);
36*e7b1675dSTing-Kang Chang }
37*e7b1675dSTing-Kang Chang return util::OkStatus();
38*e7b1675dSTing-Kang Chang }
39*e7b1675dSTing-Kang Chang
ValidateKey(const Keyset::Key & key)40*e7b1675dSTing-Kang Chang util::Status ValidateKey(const Keyset::Key& key) {
41*e7b1675dSTing-Kang Chang if (!key.has_key_data()) {
42*e7b1675dSTing-Kang Chang return ToStatusF(absl::StatusCode::kInvalidArgument,
43*e7b1675dSTing-Kang Chang "key %d, has no key data", key.key_id());
44*e7b1675dSTing-Kang Chang }
45*e7b1675dSTing-Kang Chang
46*e7b1675dSTing-Kang Chang if (key.output_prefix_type() ==
47*e7b1675dSTing-Kang Chang google::crypto::tink::OutputPrefixType::UNKNOWN_PREFIX) {
48*e7b1675dSTing-Kang Chang return ToStatusF(absl::StatusCode::kInvalidArgument,
49*e7b1675dSTing-Kang Chang "key %d has unknown prefix", key.key_id());
50*e7b1675dSTing-Kang Chang }
51*e7b1675dSTing-Kang Chang
52*e7b1675dSTing-Kang Chang if (key.status() == google::crypto::tink::KeyStatusType::UNKNOWN_STATUS) {
53*e7b1675dSTing-Kang Chang return ToStatusF(absl::StatusCode::kInvalidArgument,
54*e7b1675dSTing-Kang Chang "key %d has unknown status", key.key_id());
55*e7b1675dSTing-Kang Chang }
56*e7b1675dSTing-Kang Chang return util::OkStatus();
57*e7b1675dSTing-Kang Chang }
58*e7b1675dSTing-Kang Chang
ValidateKeyset(const Keyset & keyset)59*e7b1675dSTing-Kang Chang util::Status ValidateKeyset(const Keyset& keyset) {
60*e7b1675dSTing-Kang Chang if (keyset.key_size() < 1) {
61*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
62*e7b1675dSTing-Kang Chang "A valid keyset must contain at least one key.");
63*e7b1675dSTing-Kang Chang }
64*e7b1675dSTing-Kang Chang
65*e7b1675dSTing-Kang Chang uint32_t primary_key_id = keyset.primary_key_id();
66*e7b1675dSTing-Kang Chang bool has_primary_key = false;
67*e7b1675dSTing-Kang Chang bool contains_only_public_key_material = true;
68*e7b1675dSTing-Kang Chang int enabled_keys = 0;
69*e7b1675dSTing-Kang Chang
70*e7b1675dSTing-Kang Chang for (int i = 0; i < keyset.key_size(); i++) {
71*e7b1675dSTing-Kang Chang const Keyset::Key& key = keyset.key(i);
72*e7b1675dSTing-Kang Chang
73*e7b1675dSTing-Kang Chang
74*e7b1675dSTing-Kang Chang if (key.status() != KeyStatusType::ENABLED) {
75*e7b1675dSTing-Kang Chang continue;
76*e7b1675dSTing-Kang Chang }
77*e7b1675dSTing-Kang Chang enabled_keys += 1;
78*e7b1675dSTing-Kang Chang
79*e7b1675dSTing-Kang Chang auto validation_result = ValidateKey(key);
80*e7b1675dSTing-Kang Chang if (!validation_result.ok()) {
81*e7b1675dSTing-Kang Chang return validation_result;
82*e7b1675dSTing-Kang Chang }
83*e7b1675dSTing-Kang Chang
84*e7b1675dSTing-Kang Chang if (key.status() == KeyStatusType::ENABLED &&
85*e7b1675dSTing-Kang Chang key.key_id() == primary_key_id) {
86*e7b1675dSTing-Kang Chang if (has_primary_key) {
87*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
88*e7b1675dSTing-Kang Chang "keyset contains multiple primary keys");
89*e7b1675dSTing-Kang Chang }
90*e7b1675dSTing-Kang Chang has_primary_key = true;
91*e7b1675dSTing-Kang Chang }
92*e7b1675dSTing-Kang Chang
93*e7b1675dSTing-Kang Chang if (key.key_data().key_material_type() != KeyData::ASYMMETRIC_PUBLIC) {
94*e7b1675dSTing-Kang Chang contains_only_public_key_material = false;
95*e7b1675dSTing-Kang Chang }
96*e7b1675dSTing-Kang Chang }
97*e7b1675dSTing-Kang Chang
98*e7b1675dSTing-Kang Chang if (enabled_keys == 0) {
99*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
100*e7b1675dSTing-Kang Chang "keyset must contain at least one ENABLED key");
101*e7b1675dSTing-Kang Chang }
102*e7b1675dSTing-Kang Chang
103*e7b1675dSTing-Kang Chang // A public key can be used for verification without being set as the primary
104*e7b1675dSTing-Kang Chang // key. Therefore, it is okay to have a keyset that contains public but
105*e7b1675dSTing-Kang Chang // doesn't have a primary key set.
106*e7b1675dSTing-Kang Chang if (!has_primary_key && !contains_only_public_key_material) {
107*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
108*e7b1675dSTing-Kang Chang "keyset doesn't contain a valid primary key");
109*e7b1675dSTing-Kang Chang }
110*e7b1675dSTing-Kang Chang
111*e7b1675dSTing-Kang Chang return util::OkStatus();
112*e7b1675dSTing-Kang Chang }
113*e7b1675dSTing-Kang Chang
ValidateVersion(uint32_t candidate,uint32_t max_expected)114*e7b1675dSTing-Kang Chang util::Status ValidateVersion(uint32_t candidate, uint32_t max_expected) {
115*e7b1675dSTing-Kang Chang if (candidate > max_expected) {
116*e7b1675dSTing-Kang Chang return ToStatusF(absl::StatusCode::kInvalidArgument,
117*e7b1675dSTing-Kang Chang "Key has version '%d'; "
118*e7b1675dSTing-Kang Chang "only keys with version in range [0..%d] are supported.",
119*e7b1675dSTing-Kang Chang candidate, max_expected);
120*e7b1675dSTing-Kang Chang }
121*e7b1675dSTing-Kang Chang return util::OkStatus();
122*e7b1675dSTing-Kang Chang }
123*e7b1675dSTing-Kang Chang
124*e7b1675dSTing-Kang Chang } // namespace tink
125*e7b1675dSTing-Kang Chang } // namespace crypto
126