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