• 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 };
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