1 /*
2 * Copyright (C) 2020 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 #pragma once
18
19 #include <array>
20 #include <memory>
21 #include <optional>
22 #include <string>
23 #include <vector>
24
25 #include <cppbor.h>
26 #include <cppbor_parse.h>
27 #include <openssl/bn.h>
28 #include <openssl/cipher.h>
29 #include <openssl/curve25519.h>
30 #include <openssl/digest.h>
31 #include <openssl/ec.h>
32 #include <openssl/evp.h>
33 #include <openssl/hkdf.h>
34 #include <openssl/hmac.h>
35 #include <openssl/mem.h>
36 #include <openssl/nid.h>
37 #include <openssl/sha.h>
38
39 namespace cppcose {
40
41 using BIGNUM_Ptr = bssl::UniquePtr<BIGNUM>;
42 using EC_GROUP_Ptr = bssl::UniquePtr<EC_GROUP>;
43 using EC_POINT_Ptr = bssl::UniquePtr<EC_POINT>;
44 using BN_CTX_Ptr = bssl::UniquePtr<BN_CTX>;
45
46 template <typename T> class ErrMsgOr;
47 using bytevec = std::vector<uint8_t>;
48 using HmacSha256 = std::array<uint8_t, SHA256_DIGEST_LENGTH>;
49 using HmacSha256Function = std::function<ErrMsgOr<HmacSha256>(const bytevec&)>;
50
51 constexpr int kCoseSign1EntryCount = 4;
52 constexpr int kCoseSign1ProtectedParams = 0;
53 constexpr int kCoseSign1UnprotectedParams = 1;
54 constexpr int kCoseSign1Payload = 2;
55 constexpr int kCoseSign1Signature = 3;
56
57 constexpr int kCoseMac0EntryCount = 4;
58 constexpr int kCoseMac0ProtectedParams = 0;
59 constexpr int kCoseMac0UnprotectedParams = 1;
60 constexpr int kCoseMac0Payload = 2;
61 constexpr int kCoseMac0Tag = 3;
62
63 constexpr int kCoseEncryptEntryCount = 4;
64 constexpr int kCoseEncryptProtectedParams = 0;
65 constexpr int kCoseEncryptUnprotectedParams = 1;
66 constexpr int kCoseEncryptPayload = 2;
67 constexpr int kCoseEncryptRecipients = 3;
68
69 constexpr int kCoseMac0SemanticTag = 17;
70
71 enum Label : int {
72 ALGORITHM = 1,
73 KEY_ID = 4,
74 IV = 5,
75 COSE_KEY = -1,
76 };
77
78 enum CoseKeyAlgorithm : int {
79 AES_GCM_256 = 3,
80 HMAC_256 = 5,
81 ES256 = -7, // ECDSA with SHA-256
82 EDDSA = -8,
83 ECDH_ES_HKDF_256 = -25,
84 ES384 = -35, // ECDSA with SHA-384
85 };
86
87 enum CoseKeyCurve : int { P256 = 1, P384 = 2, X25519 = 4, ED25519 = 6 };
88 enum CoseKeyType : int { OCTET_KEY_PAIR = 1, EC2 = 2, SYMMETRIC_KEY = 4 };
89 enum CoseKeyOps : int { SIGN = 1, VERIFY = 2, ENCRYPT = 3, DECRYPT = 4 };
90
91 constexpr int kAesGcmNonceLength = 12;
92 constexpr int kAesGcmTagSize = 16;
93 constexpr int kAesGcmKeySize = 32;
94 constexpr int kAesGcmKeySizeBits = 256;
95
96 template <typename T> class ErrMsgOr {
97 public:
ErrMsgOr(std::string errMsg)98 ErrMsgOr(std::string errMsg) // NOLINT(google-explicit-constructor)
99 : errMsg_(std::move(errMsg)) {}
ErrMsgOr(const char * errMsg)100 ErrMsgOr(const char* errMsg) // NOLINT(google-explicit-constructor)
101 : errMsg_(errMsg) {}
ErrMsgOr(std::string_view errMsg)102 ErrMsgOr(std::string_view errMsg) // NOLINT(google-explicit-constructor)
103 : errMsg_(errMsg) {}
ErrMsgOr(T val)104 ErrMsgOr(T val) // NOLINT(google-explicit-constructor)
105 : value_(std::move(val)) {}
106
107 explicit operator bool() const { return value_.has_value(); }
108
109 T* operator->() & {
110 assert(value_);
111 return &value_.value();
112 }
113 T& operator*() & {
114 assert(value_);
115 return value_.value();
116 };
117 T&& operator*() && {
118 assert(value_);
119 return std::move(value_).value();
120 };
121
message()122 const std::string& message() { return errMsg_; }
moveMessage()123 std::string moveMessage() { return std::move(errMsg_); }
124
moveValue()125 T moveValue() {
126 assert(value_);
127 return std::move(value_).value();
128 }
129
130 private:
131 std::string errMsg_;
132 std::optional<T> value_;
133 };
134
135 class CoseKey {
136 public:
CoseKey()137 CoseKey() {}
138 CoseKey(const CoseKey&) = delete;
139 CoseKey(CoseKey&&) = default;
140
141 enum Label : int {
142 KEY_TYPE = 1,
143 KEY_ID = 2,
144 ALGORITHM = 3,
145 KEY_OPS = 4,
146 CURVE = -1,
147 PUBKEY_X = -2,
148 PUBKEY_Y = -3,
149 PRIVATE_KEY = -4,
150 TEST_KEY = -70000 // Application-defined
151 };
152
parse(const bytevec & coseKey)153 static ErrMsgOr<CoseKey> parse(const bytevec& coseKey) {
154 auto [parsedKey, _, errMsg] = cppbor::parse(coseKey);
155 if (!parsedKey) return errMsg + " when parsing key";
156 if (!parsedKey->asMap()) return "CoseKey must be a map";
157 return CoseKey(static_cast<cppbor::Map*>(parsedKey.release()));
158 }
159
parse(const bytevec & coseKey,CoseKeyType expectedKeyType,CoseKeyAlgorithm expectedAlgorithm,CoseKeyCurve expectedCurve)160 static ErrMsgOr<CoseKey> parse(const bytevec& coseKey, CoseKeyType expectedKeyType,
161 CoseKeyAlgorithm expectedAlgorithm, CoseKeyCurve expectedCurve) {
162 auto key = parse(coseKey);
163 if (!key) return key;
164
165 if (!key->checkIntValue(CoseKey::KEY_TYPE, expectedKeyType) ||
166 !key->checkIntValue(CoseKey::ALGORITHM, expectedAlgorithm) ||
167 !key->checkIntValue(CoseKey::CURVE, expectedCurve)) {
168 return "Unexpected key type:";
169 }
170
171 return key;
172 }
173
parseEd25519(const bytevec & coseKey)174 static ErrMsgOr<CoseKey> parseEd25519(const bytevec& coseKey) {
175 auto key = parse(coseKey, OCTET_KEY_PAIR, EDDSA, ED25519);
176 if (!key) return key;
177
178 auto& pubkey = key->getMap().get(PUBKEY_X);
179 if (!pubkey || !pubkey->asBstr() ||
180 pubkey->asBstr()->value().size() != ED25519_PUBLIC_KEY_LEN) {
181 return "Invalid Ed25519 public key";
182 }
183
184 return key;
185 }
186
parseX25519(const bytevec & coseKey,bool requireKid)187 static ErrMsgOr<CoseKey> parseX25519(const bytevec& coseKey, bool requireKid) {
188 auto key = parse(coseKey, OCTET_KEY_PAIR, ECDH_ES_HKDF_256, X25519);
189 if (!key) return key;
190
191 auto& pubkey = key->getMap().get(PUBKEY_X);
192 if (!pubkey || !pubkey->asBstr() ||
193 pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
194 return "Invalid X25519 public key";
195 }
196
197 auto& kid = key->getMap().get(KEY_ID);
198 if (requireKid && (!kid || !kid->asBstr())) {
199 return "Missing KID";
200 }
201
202 return key;
203 }
204
parseP256(const bytevec & coseKey)205 static ErrMsgOr<CoseKey> parseP256(const bytevec& coseKey) {
206 auto key = parse(coseKey, EC2, ES256, P256);
207 if (!key) return key;
208
209 auto& pubkey_x = key->getMap().get(PUBKEY_X);
210 auto& pubkey_y = key->getMap().get(PUBKEY_Y);
211 if (!pubkey_x || !pubkey_y || !pubkey_x->asBstr() || !pubkey_y->asBstr() ||
212 pubkey_x->asBstr()->value().size() != 32 || pubkey_y->asBstr()->value().size() != 32) {
213 return "Invalid P256 public key";
214 }
215
216 return key;
217 }
218
parseP384(const bytevec & coseKey)219 static ErrMsgOr<CoseKey> parseP384(const bytevec& coseKey) {
220 auto key = parse(coseKey, EC2, ES384, P384);
221 if (!key) return key;
222
223 auto& pubkey_x = key->getMap().get(PUBKEY_X);
224 auto& pubkey_y = key->getMap().get(PUBKEY_Y);
225 if (!pubkey_x || !pubkey_y || !pubkey_x->asBstr() || !pubkey_y->asBstr() ||
226 pubkey_x->asBstr()->value().size() != 48 || pubkey_y->asBstr()->value().size() != 48) {
227 return "Invalid P384 public key";
228 }
229
230 return key;
231 }
232
getEcPublicKey(const bytevec & pubX,const bytevec & pubY)233 static ErrMsgOr<bytevec> getEcPublicKey(const bytevec& pubX, const bytevec& pubY) {
234 if (pubX.empty() || pubY.empty()) {
235 return "Missing input parameters";
236 }
237 bytevec pubKey;
238 pubKey.insert(pubKey.begin(), pubX.begin(), pubX.end());
239 pubKey.insert(pubKey.end(), pubY.begin(), pubY.end());
240 return pubKey;
241 }
242
getEcPublicKey()243 ErrMsgOr<bytevec> getEcPublicKey() {
244 auto pubX = getBstrValue(PUBKEY_X);
245 auto pubY = getBstrValue(PUBKEY_Y);
246 if (!pubX.has_value() || !pubY.has_value()) {
247 return "Error while getting EC public key from CoseKey.";
248 }
249 return getEcPublicKey(pubX.value(), pubY.value());
250 }
251
getIntValue(Label label)252 std::optional<int> getIntValue(Label label) {
253 const auto& value = key_->get(label);
254 if (!value || !value->asInt()) return {};
255 return value->asInt()->value();
256 }
257
getBstrValue(Label label)258 std::optional<bytevec> getBstrValue(Label label) {
259 const auto& value = key_->get(label);
260 if (!value || !value->asBstr()) return {};
261 return value->asBstr()->value();
262 }
263
getMap()264 const cppbor::Map& getMap() const { return *key_; }
moveMap()265 cppbor::Map&& moveMap() { return std::move(*key_); }
266
checkIntValue(Label label,int expectedValue)267 bool checkIntValue(Label label, int expectedValue) {
268 const auto& value = key_->get(label);
269 return value && value->asInt() && value->asInt()->value() == expectedValue;
270 }
271
add(Label label,int value)272 void add(Label label, int value) { key_->add(label, value); }
add(Label label,bytevec value)273 void add(Label label, bytevec value) { key_->add(label, std::move(value)); }
274
encode()275 bytevec encode() { return key_->canonicalize().encode(); }
276
277 private:
CoseKey(cppbor::Map * parsedKey)278 explicit CoseKey(cppbor::Map* parsedKey) : key_(parsedKey) {}
279
280 // This is the full parsed key structure.
281 std::unique_ptr<cppbor::Map> key_;
282 };
283
284 // Utility function for generating an HMAC given a key and some input
285 // data. Returns std::nullopt on error
286 ErrMsgOr<HmacSha256> generateHmacSha256(const bytevec& key, const bytevec& data);
287
288 ErrMsgOr<HmacSha256> generateCoseMac0Mac(HmacSha256Function macFunction, const bytevec& externalAad,
289 const bytevec& payload);
290 ErrMsgOr<cppbor::Array> constructCoseMac0(HmacSha256Function macFunction,
291 const bytevec& externalAad, const bytevec& payload);
292 ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
293 const bytevec& macKey);
294
295 ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
296 const bytevec& payload, const bytevec& aad);
297 ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
298 const bytevec& aad);
299 ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map extraProtectedFields,
300 const bytevec& payload, const bytevec& aad);
301 ErrMsgOr<cppbor::Array> constructECDSACoseSign1(const bytevec& key,
302 cppbor::Map extraProtectedFields,
303 const bytevec& payload, const bytevec& aad);
304
305 /**
306 * Verify and parse a COSE_Sign1 message, returning the payload.
307 *
308 * @param coseSign1 is the COSE_Sign1 to verify and parse.
309 *
310 * @param signingCoseKey is a CBOR-encoded COSE_Key to use to verify the signature. The bytevec may
311 * be empty, in which case the function assumes that coseSign1's payload is the COSE_Key to
312 * use, i.e. that coseSign1 is a self-signed "certificate".
313 */
314 ErrMsgOr<bytevec /* payload */> verifyAndParseCoseSign1(const cppbor::Array* coseSign1,
315 const bytevec& signingCoseKey,
316 const bytevec& aad);
317
318 ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
319 const bytevec& protectedParams, const bytevec& aad);
320 ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
321 const bytevec& plaintextPayload, const bytevec& aad,
322 cppbor::Array recipients);
323 ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>>
324 getSenderPubKeyFromCoseEncrypt(const cppbor::Item* encryptItem);
325 inline ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>>
getSenderPubKeyFromCoseEncrypt(const std::unique_ptr<cppbor::Item> & encryptItem)326 getSenderPubKeyFromCoseEncrypt(const std::unique_ptr<cppbor::Item>& encryptItem) {
327 return getSenderPubKeyFromCoseEncrypt(encryptItem.get());
328 }
329
330 ErrMsgOr<bytevec /* plaintextPayload */>
331 decryptCoseEncrypt(const bytevec& key, const cppbor::Item* encryptItem, const bytevec& aad);
332
333 ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& senderPubKey, const bytevec& senderPrivKey,
334 const bytevec& recipientPubKey, bool senderIsA);
335 ErrMsgOr<bytevec> ECDH_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
336 const bytevec& pubKeyB, bool senderIsA);
337 bytevec sha256(const bytevec& data);
338 bytevec sha384(const bytevec& data);
339 ErrMsgOr<bytevec /* ciphertextWithTag */> aesGcmEncrypt(const bytevec& key, const bytevec& nonce,
340 const bytevec& aad,
341 const bytevec& plaintext);
342 ErrMsgOr<bytevec /* plaintext */> aesGcmDecrypt(const bytevec& key, const bytevec& nonce,
343 const bytevec& aad,
344 const bytevec& ciphertextWithTag);
345
346 } // namespace cppcose
347