• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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