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(T val)102 ErrMsgOr(T val) // NOLINT(google-explicit-constructor)
103 : value_(std::move(val)) {}
104
105 explicit operator bool() const { return value_.has_value(); }
106
107 T* operator->() & {
108 assert(value_);
109 return &value_.value();
110 }
111 T& operator*() & {
112 assert(value_);
113 return value_.value();
114 };
115 T&& operator*() && {
116 assert(value_);
117 return std::move(value_).value();
118 };
119
message()120 const std::string& message() { return errMsg_; }
moveMessage()121 std::string moveMessage() { return std::move(errMsg_); }
122
moveValue()123 T moveValue() {
124 assert(value_);
125 return std::move(value_).value();
126 }
127
128 private:
129 std::string errMsg_;
130 std::optional<T> value_;
131 };
132
133 class CoseKey {
134 public:
CoseKey()135 CoseKey() {}
136 CoseKey(const CoseKey&) = delete;
137 CoseKey(CoseKey&&) = default;
138
139 enum Label : int {
140 KEY_TYPE = 1,
141 KEY_ID = 2,
142 ALGORITHM = 3,
143 KEY_OPS = 4,
144 CURVE = -1,
145 PUBKEY_X = -2,
146 PUBKEY_Y = -3,
147 PRIVATE_KEY = -4,
148 TEST_KEY = -70000 // Application-defined
149 };
150
parse(const bytevec & coseKey)151 static ErrMsgOr<CoseKey> parse(const bytevec& coseKey) {
152 auto [parsedKey, _, errMsg] = cppbor::parse(coseKey);
153 if (!parsedKey) return errMsg + " when parsing key";
154 if (!parsedKey->asMap()) return "CoseKey must be a map";
155 return CoseKey(static_cast<cppbor::Map*>(parsedKey.release()));
156 }
157
parse(const bytevec & coseKey,CoseKeyType expectedKeyType,CoseKeyAlgorithm expectedAlgorithm,CoseKeyCurve expectedCurve)158 static ErrMsgOr<CoseKey> parse(const bytevec& coseKey, CoseKeyType expectedKeyType,
159 CoseKeyAlgorithm expectedAlgorithm, CoseKeyCurve expectedCurve) {
160 auto key = parse(coseKey);
161 if (!key) return key;
162
163 if (!key->checkIntValue(CoseKey::KEY_TYPE, expectedKeyType) ||
164 !key->checkIntValue(CoseKey::ALGORITHM, expectedAlgorithm) ||
165 !key->checkIntValue(CoseKey::CURVE, expectedCurve)) {
166 return "Unexpected key type:";
167 }
168
169 return key;
170 }
171
parseEd25519(const bytevec & coseKey)172 static ErrMsgOr<CoseKey> parseEd25519(const bytevec& coseKey) {
173 auto key = parse(coseKey, OCTET_KEY_PAIR, EDDSA, ED25519);
174 if (!key) return key;
175
176 auto& pubkey = key->getMap().get(PUBKEY_X);
177 if (!pubkey || !pubkey->asBstr() ||
178 pubkey->asBstr()->value().size() != ED25519_PUBLIC_KEY_LEN) {
179 return "Invalid Ed25519 public key";
180 }
181
182 return key;
183 }
184
parseX25519(const bytevec & coseKey,bool requireKid)185 static ErrMsgOr<CoseKey> parseX25519(const bytevec& coseKey, bool requireKid) {
186 auto key = parse(coseKey, OCTET_KEY_PAIR, ECDH_ES_HKDF_256, X25519);
187 if (!key) return key;
188
189 auto& pubkey = key->getMap().get(PUBKEY_X);
190 if (!pubkey || !pubkey->asBstr() ||
191 pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
192 return "Invalid X25519 public key";
193 }
194
195 auto& kid = key->getMap().get(KEY_ID);
196 if (requireKid && (!kid || !kid->asBstr())) {
197 return "Missing KID";
198 }
199
200 return key;
201 }
202
parseP256(const bytevec & coseKey)203 static ErrMsgOr<CoseKey> parseP256(const bytevec& coseKey) {
204 auto key = parse(coseKey, EC2, ES256, P256);
205 if (!key) return key;
206
207 auto& pubkey_x = key->getMap().get(PUBKEY_X);
208 auto& pubkey_y = key->getMap().get(PUBKEY_Y);
209 if (!pubkey_x || !pubkey_y || !pubkey_x->asBstr() || !pubkey_y->asBstr() ||
210 pubkey_x->asBstr()->value().size() != 32 || pubkey_y->asBstr()->value().size() != 32) {
211 return "Invalid P256 public key";
212 }
213
214 return key;
215 }
216
parseP384(const bytevec & coseKey)217 static ErrMsgOr<CoseKey> parseP384(const bytevec& coseKey) {
218 auto key = parse(coseKey, EC2, ES384, P384);
219 if (!key) return key;
220
221 auto& pubkey_x = key->getMap().get(PUBKEY_X);
222 auto& pubkey_y = key->getMap().get(PUBKEY_Y);
223 if (!pubkey_x || !pubkey_y || !pubkey_x->asBstr() || !pubkey_y->asBstr() ||
224 pubkey_x->asBstr()->value().size() != 48 || pubkey_y->asBstr()->value().size() != 48) {
225 return "Invalid P384 public key";
226 }
227
228 return key;
229 }
230
getEcPublicKey(const bytevec & pubX,const bytevec & pubY)231 static ErrMsgOr<bytevec> getEcPublicKey(const bytevec& pubX, const bytevec& pubY) {
232 if (pubX.empty() || pubY.empty()) {
233 return "Missing input parameters";
234 }
235 bytevec pubKey;
236 pubKey.insert(pubKey.begin(), pubX.begin(), pubX.end());
237 pubKey.insert(pubKey.end(), pubY.begin(), pubY.end());
238 return pubKey;
239 }
240
getEcPublicKey()241 ErrMsgOr<bytevec> getEcPublicKey() {
242 auto pubX = getBstrValue(PUBKEY_X);
243 auto pubY = getBstrValue(PUBKEY_Y);
244 if (!pubX.has_value() || !pubY.has_value()) {
245 return "Error while getting EC public key from CoseKey.";
246 }
247 return getEcPublicKey(pubX.value(), pubY.value());
248 }
249
getIntValue(Label label)250 std::optional<int> getIntValue(Label label) {
251 const auto& value = key_->get(label);
252 if (!value || !value->asInt()) return {};
253 return value->asInt()->value();
254 }
255
getBstrValue(Label label)256 std::optional<bytevec> getBstrValue(Label label) {
257 const auto& value = key_->get(label);
258 if (!value || !value->asBstr()) return {};
259 return value->asBstr()->value();
260 }
261
getMap()262 const cppbor::Map& getMap() const { return *key_; }
moveMap()263 cppbor::Map&& moveMap() { return std::move(*key_); }
264
checkIntValue(Label label,int expectedValue)265 bool checkIntValue(Label label, int expectedValue) {
266 const auto& value = key_->get(label);
267 return value && value->asInt() && value->asInt()->value() == expectedValue;
268 }
269
add(Label label,int value)270 void add(Label label, int value) { key_->add(label, value); }
add(Label label,bytevec value)271 void add(Label label, bytevec value) { key_->add(label, std::move(value)); }
272
encode()273 bytevec encode() { return key_->canonicalize().encode(); }
274
275 private:
CoseKey(cppbor::Map * parsedKey)276 explicit CoseKey(cppbor::Map* parsedKey) : key_(parsedKey) {}
277
278 // This is the full parsed key structure.
279 std::unique_ptr<cppbor::Map> key_;
280 };
281
282 // Utility function for generating an HMAC given a key and some input
283 // data. Returns std::nullopt on error
284 ErrMsgOr<HmacSha256> generateHmacSha256(const bytevec& key, const bytevec& data);
285
286 ErrMsgOr<HmacSha256> generateCoseMac0Mac(HmacSha256Function macFunction, const bytevec& externalAad,
287 const bytevec& payload);
288 ErrMsgOr<cppbor::Array> constructCoseMac0(HmacSha256Function macFunction,
289 const bytevec& externalAad, const bytevec& payload);
290 ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
291 const bytevec& macKey);
292
293 ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
294 const bytevec& payload, const bytevec& aad);
295 ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
296 const bytevec& aad);
297 ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map extraProtectedFields,
298 const bytevec& payload, const bytevec& aad);
299 ErrMsgOr<cppbor::Array> constructECDSACoseSign1(const bytevec& key,
300 cppbor::Map extraProtectedFields,
301 const bytevec& payload, const bytevec& aad);
302
303 /**
304 * Verify and parse a COSE_Sign1 message, returning the payload.
305 *
306 * @param coseSign1 is the COSE_Sign1 to verify and parse.
307 *
308 * @param signingCoseKey is a CBOR-encoded COSE_Key to use to verify the signature. The bytevec may
309 * be empty, in which case the function assumes that coseSign1's payload is the COSE_Key to
310 * use, i.e. that coseSign1 is a self-signed "certificate".
311 */
312 ErrMsgOr<bytevec /* payload */> verifyAndParseCoseSign1(const cppbor::Array* coseSign1,
313 const bytevec& signingCoseKey,
314 const bytevec& aad);
315
316 ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
317 const bytevec& protectedParams, const bytevec& aad);
318 ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
319 const bytevec& plaintextPayload, const bytevec& aad,
320 cppbor::Array recipients);
321 ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>>
322 getSenderPubKeyFromCoseEncrypt(const cppbor::Item* encryptItem);
323 inline ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>>
getSenderPubKeyFromCoseEncrypt(const std::unique_ptr<cppbor::Item> & encryptItem)324 getSenderPubKeyFromCoseEncrypt(const std::unique_ptr<cppbor::Item>& encryptItem) {
325 return getSenderPubKeyFromCoseEncrypt(encryptItem.get());
326 }
327
328 ErrMsgOr<bytevec /* plaintextPayload */>
329 decryptCoseEncrypt(const bytevec& key, const cppbor::Item* encryptItem, const bytevec& aad);
330
331 ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& senderPubKey, const bytevec& senderPrivKey,
332 const bytevec& recipientPubKey, bool senderIsA);
333 ErrMsgOr<bytevec> ECDH_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
334 const bytevec& pubKeyB, bool senderIsA);
335 bytevec sha256(const bytevec& data);
336 bytevec sha384(const bytevec& data);
337 ErrMsgOr<bytevec /* ciphertextWithTag */> aesGcmEncrypt(const bytevec& key, const bytevec& nonce,
338 const bytevec& aad,
339 const bytevec& plaintext);
340 ErrMsgOr<bytevec /* plaintext */> aesGcmDecrypt(const bytevec& key, const bytevec& nonce,
341 const bytevec& aad,
342 const bytevec& ciphertextWithTag);
343
344 } // namespace cppcose
345