| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_PRIVATE_CERTIFICATE_H_ |
| #define CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_PRIVATE_CERTIFICATE_H_ |
| |
| #include <memory> |
| #include <set> |
| #include <vector> |
| |
| #include "base/containers/queue.h" |
| #include "base/containers/span.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/optional.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "chrome/browser/nearby_sharing/certificates/nearby_share_encrypted_metadata_key.h" |
| #include "chrome/browser/nearby_sharing/proto/encrypted_metadata.pb.h" |
| #include "chrome/browser/nearby_sharing/proto/rpc_resources.pb.h" |
| #include "chrome/browser/ui/webui/nearby_share/public/mojom/nearby_share_settings.mojom.h" |
| |
| namespace crypto { |
| class ECPrivateKey; |
| class SymmetricKey; |
| } // namespace crypto |
| |
| // Stores metadata and crypto keys for the local device. This certificate |
| // can be converted to a public certificate and sent to select contacts, who |
| // will then use the certificate for authenticating the local device before |
| // transferring data. Provides method for signing a payload during |
| // authentication with a remote device. Provides method for encrypting the |
| // metadata encryption key, which can then be advertised. |
| class NearbySharePrivateCertificate { |
| public: |
| // Inverse operation of ToDictionary(). Returns base::nullopt if the |
| // conversion is not successful |
| static base::Optional<NearbySharePrivateCertificate> FromDictionary( |
| const base::Value& dict); |
| |
| // Generates a random EC key pair, secret key, and metadata encryption |
| // key. Derives the certificate ID from the secret key. Derives the |
| // not-after time from |not_before| and the certificate validity period fixed |
| // by the Nearby Share protocol. Visibility cannot be "no one". |
| NearbySharePrivateCertificate( |
| nearby_share::mojom::Visibility visibility, |
| base::Time not_before, |
| nearbyshare::proto::EncryptedMetadata unencrypted_metadata); |
| |
| NearbySharePrivateCertificate( |
| nearby_share::mojom::Visibility visibility, |
| base::Time not_before, |
| base::Time not_after, |
| std::unique_ptr<crypto::ECPrivateKey> key_pair, |
| std::unique_ptr<crypto::SymmetricKey> secret_key, |
| std::vector<uint8_t> metadata_encryption_key, |
| std::vector<uint8_t> id, |
| nearbyshare::proto::EncryptedMetadata unencrypted_metadata, |
| std::set<std::vector<uint8_t>> consumed_salts); |
| |
| NearbySharePrivateCertificate(const NearbySharePrivateCertificate& other); |
| NearbySharePrivateCertificate& operator=( |
| const NearbySharePrivateCertificate& other); |
| NearbySharePrivateCertificate(NearbySharePrivateCertificate&& other); |
| NearbySharePrivateCertificate& operator=( |
| NearbySharePrivateCertificate&& other); |
| |
| virtual ~NearbySharePrivateCertificate(); |
| |
| const std::vector<uint8_t>& id() const { return id_; } |
| nearby_share::mojom::Visibility visibility() const { return visibility_; } |
| base::Time not_before() const { return not_before_; } |
| base::Time not_after() const { return not_after_; } |
| const nearbyshare::proto::EncryptedMetadata& unencrypted_metadata() const { |
| return unencrypted_metadata_; |
| } |
| |
| // Encrypts |metadata_encryption_key_| with the |secret_key_|, using a |
| // randomly generated 2-byte salt that has not already been consumed. Returns |
| // base::nullopt if the encryption failed or if there are no remaining salts. |
| // Note: Due to the generation and storage of an unconsumed salt, this method |
| // is not thread safe. |
| base::Optional<NearbyShareEncryptedMetadataKey> EncryptMetadataKey(); |
| |
| // Signs the input |payload| with the private key from |key_pair_|. Returns |
| // base::nullopt if the signing was unsuccessful. |
| base::Optional<std::vector<uint8_t>> Sign( |
| base::span<const uint8_t> payload) const; |
| |
| // Creates a hash of the |authentication_token|, using |secret_key_|. The use |
| // of HKDF and the output vector size is part of the Nearby Share protocol and |
| // conforms with the GmsCore implementation. |
| std::vector<uint8_t> HashAuthenticationToken( |
| base::span<const uint8_t> authentication_token) const; |
| |
| // Converts this private certificate to a public certificate proto that can be |
| // shared with select contacts. Returns base::nullopt if the conversion was |
| // unsuccessful. |
| base::Optional<nearbyshare::proto::PublicCertificate> ToPublicCertificate() |
| const; |
| |
| // Converts this private certificate to a dictionary value for storage |
| // in Prefs. |
| base::Value ToDictionary() const; |
| |
| // For testing only. |
| base::queue<std::vector<uint8_t>>& next_salts_for_testing() { |
| return next_salts_for_testing_; |
| } |
| base::Optional<base::TimeDelta>& offset_for_testing() { |
| return offset_for_testing_; |
| } |
| |
| private: |
| // Generates a random 2-byte salt used for encrypting the metadata encryption |
| // key. Adds returned salt to |consumed_salts_|. Returns base::nullopt if the |
| // maximum number of salts have been exhausted or if an unconsumed salt cannot |
| // be found in a fixed number of attempts, though this is highly improbably. |
| // Note: This function is not thread safe. |
| base::Optional<std::vector<uint8_t>> GenerateUnusedSalt(); |
| |
| // Encrypts |unencrypted_metadata_| with the |metadata_encryption_key_|, using |
| // the |secret_key_| as salt. |
| base::Optional<std::vector<uint8_t>> EncryptMetadata() const; |
| |
| // Specifies which contacts can receive the public certificate corresponding |
| // to this private certificate. |
| nearby_share::mojom::Visibility visibility_; |
| |
| // The begin/end times of the certificate's validity period. Note: An offset |
| // is not yet applied to these values. To avoid issues with clock skew, |
| // offsets should be applied during conversion to a public certificate. |
| base::Time not_before_; |
| base::Time not_after_; |
| |
| // The public/private P-256 key pair used for verification/signing to ensure |
| // secret of public certificates. The public key is included in the |
| // public certificate, but the private key will never leave the device. |
| std::unique_ptr<crypto::ECPrivateKey> key_pair_; |
| |
| // A 32-byte AES key used, along with a salt, to encrypt the |
| // |metadata_encryption_key_|, after which it can be safely advertised. Also, |
| // used to generate an authentication token hash. Included in the public |
| // certificate. |
| std::unique_ptr<crypto::SymmetricKey> secret_key_; |
| |
| // A 14-byte symmetric key used to encrypt |unencrypted_metadata_|. Not |
| // included in public certificate. |
| std::vector<uint8_t> metadata_encryption_key_; |
| |
| // An ID for the certificate, generated from the secret key. |
| std::vector<uint8_t> id_; |
| |
| // Unencrypted device metadata. The proto name is misleading; it holds data |
| // that will eventually be serialized and encrypted. |
| nearbyshare::proto::EncryptedMetadata unencrypted_metadata_; |
| |
| // The set of 2-byte salts already used to encrypt the metadata key. |
| std::set<std::vector<uint8_t>> consumed_salts_; |
| |
| // For testing only. |
| base::queue<std::vector<uint8_t>> next_salts_for_testing_; |
| base::Optional<base::TimeDelta> offset_for_testing_; |
| |
| FRIEND_TEST_ALL_PREFIXES(NearbySharePrivateCertificateTest, ToFromDictionary); |
| }; |
| |
| #endif // CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_PRIVATE_CERTIFICATE_H_ |