Source release 19.4.0

This commit is contained in:
Vicky Min
2024-11-27 00:07:23 +00:00
parent 11c108a8da
commit 22759672a8
72 changed files with 5321 additions and 2622 deletions

View File

@@ -7,15 +7,10 @@
#ifndef WVOEC_UTIL_BCC_VALIDATOR_H_
#define WVOEC_UTIL_BCC_VALIDATOR_H_
#include <inttypes.h>
#include <sstream>
#include <string>
#include <vector>
#include "cbor_validator.h"
#include "cppbor.h"
#include "wv_class_utils.h"
#include "prov4_validation_helper.h"
namespace wvoec {
namespace util {
@@ -34,11 +29,99 @@ enum BccCurve {
kBccP384 = 3
};
// Android/Widevine Dice Attestation allows two signing models. This is
// identified using MAP_KEY_DEVICE_KEY_ALGORITHM.
enum {
DEVICE_KEY_ALGORITHM_ES256 = -7, // EC key with SHA-256
DEVICE_KEY_ALGORITHM_EDDSA = -8, // Pure ED25519.
DEVICE_KEY_ALGORITHM_ES384 = -35, // EC key with SHA-384
};
// BCC definition:
// https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
// See PubKeyEd25519/PubKeyECDSA256/PubKeyECDSA384 in BCC definition.
struct BccPublicKeyInfo {
BccSignatureAlgorithm signature_algorithm;
BccCurve curve;
std::pair<FieldStatus, int> key_type;
std::pair<FieldStatus, BccSignatureAlgorithm> signature_algorithm;
std::pair<FieldStatus, BccCurve> curve;
// Raw EC key bytes extracted from BCC
std::vector<uint8_t> key_bytes;
std::pair<FieldStatus, std::vector<uint8_t>> key_bytes;
std::string ToString() const;
CborMessageStatus Validate(
std::vector<std::pair<CborMessageStatus, std::string>>& msgs) const;
};
// protected : bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / AlgorithmES384
// }
struct BccEntryProtected {
std::pair<FieldStatus, int64_t> algorithm;
std::string ToString() const;
CborMessageStatus Validate(
std::vector<std::pair<CborMessageStatus, std::string>>& msgs) const;
};
// See ConfigurationDescriptor in BCC definition.
struct ConfigurationDescriptor {
std::pair<FieldStatus, std::string> component_name;
std::pair<FieldStatus, std::string> component_version;
std::pair<FieldStatus, std::string> resettable; // null string
std::pair<FieldStatus, uint64_t> security_version;
std::pair<FieldStatus, std::string> vm_marker; // null string
std::string ToString() const;
// Validate ConfigurationDescriptor and set |is_widevine_entry| to true if the
// component_name is "widevine". Caller ensures that |is_widevine_entry| is
// not null.
CborMessageStatus Validate(
std::vector<std::pair<CborMessageStatus, std::string>>& msgs,
bool* is_widevine_entry) const;
};
// See DiceChainEntryPayload in BCC definition.
struct BccEntryPayload {
std::pair<FieldStatus, std::string> issuer;
std::pair<FieldStatus, std::string> subject;
std::pair<FieldStatus, std::string> profile_name;
std::pair<FieldStatus, BccPublicKeyInfo> subject_public_key;
std::pair<FieldStatus, std::vector<uint8_t>> key_usage;
std::pair<FieldStatus, std::vector<uint8_t>> code_hash;
std::pair<FieldStatus, std::vector<uint8_t>> code_descriptor;
std::pair<FieldStatus, std::vector<uint8_t>> config_hash;
std::pair<FieldStatus, ConfigurationDescriptor> config_descriptor;
std::pair<FieldStatus, std::vector<uint8_t>> authority_hash;
std::pair<FieldStatus, std::vector<uint8_t>> authority_descriptor;
std::pair<FieldStatus, std::vector<uint8_t>> mode;
std::string ToString() const;
// Validate BccEntryPayload and set |is_widevine_entry| to true if the payload
// contains a Widevine certificate. Caller ensures that |is_widevine_entry| is
// not null.
CborMessageStatus Validate(
std::vector<std::pair<CborMessageStatus, std::string>>& msgs,
bool is_degenerated, bool* is_widevine_entry) const;
};
// See DiceChainEntry in BCC definition.
struct BccEntry {
std::pair<FieldStatus, BccEntryProtected> protected_data;
std::pair<FieldStatus, std::string> unprotected;
std::pair<FieldStatus, BccEntryPayload> payload;
std::pair<FieldStatus, std::vector<uint8_t>> signature;
std::string ToString() const;
// Validate BccEntryPayload and set |is_widevine_entry| to true if the BCC
// entry contains a Widevine certificate. Caller ensures that
// |is_widevine_entry| is not null.
CborMessageStatus Validate(
std::vector<std::pair<CborMessageStatus, std::string>>& msgs,
bool is_degenerated, bool* is_widevine_entry) const;
};
struct Bcc {
BccPublicKeyInfo dk_pub;
std::vector<BccEntry> entries;
std::string ToString() const;
CborMessageStatus Validate(
std::vector<std::pair<CborMessageStatus, std::string>>& msgs,
bool is_degenerated) const;
};
// BccValidator processes a Provisioning 4.0 device root of trust. It extracts
@@ -52,25 +135,34 @@ class BccValidator : public CborValidator {
virtual ~BccValidator() override = default;
WVCDM_DISALLOW_COPY_AND_MOVE(BccValidator);
// Verifies the Cbor struct of a client generated root of trust. This message
// is part of an attestation model conforming to the Google Open Dice Profile.
// This message is received from a client device to attest it is a valid
// Widevine device.
// Verifies the Cbor struct of a client generated root of trust.
virtual CborMessageStatus Validate() override;
// Outputs BCC in YAML.
// Outputs formatted BCC.
virtual std::string GetFormattedMessage() const override;
private:
// Processes CoseKey PubKeyEd25519 / PubKeyECDSA256, prints into |fmt_msgs|,
// and extracts the PubKey to *|public_key_info|.
// Processes CoseKey PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384, which
// contains subject public key, and extracts the PubKey to *|public_key_info|.
// Caller ensures that all pointers are not null.
CborMessageStatus ProcessSubjectPublicKeyInfo(
const cppbor::Map& public_key_info_map,
std::vector<std::string>& fmt_msgs, BccPublicKeyInfo* public_key_info);
// Processes DiceChainEntryPayload, which contains subject public key, prints
// into |fmt_msgs|, and extracts the PubKey to *|public_key_info|.
CborMessageStatus ProcessDiceChainEntryPayload(
const std::vector<uint8_t>& payload, std::vector<std::string>& fmt_msgs,
BccPublicKeyInfo* public_key_info);
const cppbor::Map* public_key_map, BccPublicKeyInfo* public_key_info);
// Processes protected field in Bcc entry and extracts it *|protected_data|.
// Caller ensures that all pointers are not null.
CborMessageStatus ProcessBccEntryProtected(const cppbor::Map* protected_map,
BccEntryProtected* protected_data);
// Processes DiceChainEntryPayload and extracts the payload to *|payload|.
// Caller ensures that all pointers are not null.
CborMessageStatus ProcessDiceChainEntryPayload(const cppbor::Map* payload_map,
BccEntryPayload* payload);
// Processes ConfigurationDescriptor in DiceChainEntryPayload and extracts the
// ConfigurationDescriptor to *|cd|. Caller ensures that all pointers are not
// null.
CborMessageStatus ProcessConfigurationDescriptor(
const cppbor::Map* config_descriptor_map, ConfigurationDescriptor* cd);
// Verifies the raw EC signature |signature| with the public key
// |signing_key|. |signature| extracted from BCC is not ASN.1 DER encoded.
bool VerifySignature(const BccPublicKeyInfo& signing_key,

View File

@@ -7,12 +7,6 @@
#ifndef WVOEC_UTIL_CBOR_VALIDATOR_H_
#define WVOEC_UTIL_CBOR_VALIDATOR_H_
#include <inttypes.h>
#include <string>
#include <utility>
#include <vector>
#include "cppbor.h"
#include "cppbor_parse.h"
#include "wv_class_utils.h"
@@ -28,8 +22,9 @@ enum CborMessageStatus {
kCborParseError = 2,
kCborValidateOk = 3,
kCborValidateWarning = 4,
kCborValidateError = 5,
kCborValidateFatal = 6
kCborValidateError = 5, // e.g. unexpected value, signature error, etc.
kCborValidateFatal =
6, // e.g. unexpected data type, key size, or missing required field
};
std::string CppborMajorTypeToString(cppbor::MajorType type);
@@ -61,10 +56,6 @@ class CborValidator {
// first and |parse_result_| contains a valid CBOR message.
virtual std::string GetFormattedMessage() const;
const cppbor::ParseResult& parse_result() const { return parse_result_; }
const std::vector<std::pair<CborMessageStatus, std::string>>&
validate_messages() {
return validate_messages_;
}
protected:
void Reset();
@@ -77,6 +68,8 @@ class CborValidator {
static std::string CheckMapEntry(const cppbor::Map& map,
cppbor::MajorType major_type,
const std::string& entry_name);
// Formats the parsed CBOR |input| and adds identation for readability.
static std::string FormatString(const std::string& input);
CborMessageStatus message_status_ = kCborUninitialized;
private:

View File

@@ -15,10 +15,47 @@
#include "cbor_validator.h"
#include "cppbor.h"
#include "prov4_validation_helper.h"
#include "wv_class_utils.h"
namespace wvoec {
namespace util {
struct DeviceInfo {
// Version 2 and 3 fields
std::pair<FieldStatus, std::string> brand;
std::pair<FieldStatus, std::string> manufacturer;
std::pair<FieldStatus, std::string> product;
std::pair<FieldStatus, std::string> model;
std::pair<FieldStatus, std::string> device;
std::pair<FieldStatus, std::string>
vb_state; // "green" / "yellow" / "orange"
std::pair<FieldStatus, std::string>
bootloader_state; // "locked" / "unlocked"
std::pair<FieldStatus, std::vector<uint8_t>> vbmeta_digest;
std::pair<FieldStatus, std::string> os_version;
std::pair<FieldStatus, std::string> system_patch_level; // YYYYMM
std::pair<FieldStatus, std::string> boot_patch_level; // YYYYMMDD
std::pair<FieldStatus, std::string> vendor_patch_level; // YYYYMMDD
std::pair<FieldStatus, std::string> security_level; // "tee" / "strongbox"
std::pair<FieldStatus, std::string> fused; // 1 / 0
// Version 1 fields
std::pair<FieldStatus, std::string> board;
std::pair<FieldStatus, std::string> version;
std::pair<FieldStatus, std::string> att_id_state;
std::string ToString() const;
CborMessageStatus Validate(
std::vector<std::pair<CborMessageStatus, std::string>>& msgs, bool is_gms,
int version_number) const;
CborMessageStatus ValidateV3Fields(
bool is_tee_device_info,
std::vector<std::pair<CborMessageStatus, std::string>>& msgs) const;
CborMessageStatus ValidateV2Fields(
bool is_tee_device_info,
std::vector<std::pair<CborMessageStatus, std::string>>& msgs) const;
CborMessageStatus ValidateV1Fields(
std::vector<std::pair<CborMessageStatus, std::string>>& msgs) const;
};
// DeviceInfoValidator parses and validates a Cbor struct of DeviceInfo used by
// Provisioning 4.0. DeviceInfo definition:
// https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/DeviceInfoV3.cddl
@@ -27,8 +64,8 @@ class DeviceInfoValidator : public CborValidator {
DeviceInfoValidator() = delete;
WVCDM_DISALLOW_COPY_AND_MOVE(DeviceInfoValidator);
explicit DeviceInfoValidator(int version_number)
: version_number_(version_number) {}
explicit DeviceInfoValidator(int version_number = 3, bool is_gms = false)
: version_number_(version_number), is_gms_(is_gms) {}
virtual ~DeviceInfoValidator() override = default;
@@ -41,15 +78,15 @@ class DeviceInfoValidator : public CborValidator {
virtual std::string GetFormattedMessage() const override;
private:
// Checks whether a device info entry with |entry_name| and |major_type|
// exists in |device_info| map.
void CheckDeviceInfoMapEntry(const cppbor::Map& device_info,
cppbor::MajorType major_type,
const std::string& entry_name);
// Builds a struct of DeviceInfo from input CBOR map |device_info_map|.
CborMessageStatus BuildDeviceInfo(DeviceInfo& device_info,
const cppbor::Map* device_info_map);
// Used to generate formatted message.
std::stringstream msg_ss_;
// Device info version. Validations are done based on the version number.
int version_number_;
// Whether the device is a GMS device.
bool is_gms_;
// Saved Cbor-encoded device info.
std::vector<uint8_t> device_info_bytes_;
}; // class DeviceInfoValidator

View File

@@ -0,0 +1,96 @@
// Copyright 2024 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
#ifndef WVOEC_UTIL_PROV4_VALIDATION_HELPER_H_
#define WVOEC_UTIL_PROV4_VALIDATION_HELPER_H_
#include <sstream>
#include "cbor_validator.h"
#include "string_conversions.h"
namespace wvoec {
namespace util {
enum FieldStatus {
kAbsent = 0, // field key doesn't exist
kEmpty = 1, // field value is empty, e.g. empty string, map, array, etc.
kPresent = 2 // present and non-empty
};
std::string StatusToString(FieldStatus status);
// Apply a new status to current status if it is more severe.
void ApplyStatus(CborMessageStatus& status, CborMessageStatus new_status);
// Validates that the given field name is present, and prints error messages
// if not.
template <typename T>
CborMessageStatus ValidateRequiredField(
const std::string& name, const std::string& component,
const std::pair<FieldStatus, T>& p,
std::vector<std::pair<CborMessageStatus, std::string>>& msgs) {
if (p.first != kPresent) {
msgs.push_back(std::make_pair(
kCborValidateError, component + ": missing required field " + name));
return kCborValidateError;
}
return kCborValidateOk;
}
// Validates that the given field name is present, and prints warning messages
// if not.
template <typename T>
CborMessageStatus ValidateImportantField(
const std::string& name, const std::string& component,
const std::pair<FieldStatus, T>& p,
std::vector<std::pair<CborMessageStatus, std::string>>& msgs) {
if (p.first != kPresent) {
msgs.push_back(std::make_pair(
kCborValidateWarning, component + ": missing important field " + name));
return kCborValidateWarning;
}
return kCborValidateOk;
}
// Print a field value with a built-in type in component with |name| to
// stringstream.
template <typename T>
void PrintField(std::stringstream& ss, const std::string& name,
const std::pair<FieldStatus, T>& p) {
ss << " " << name << ":";
if (p.first != kPresent) {
ss << StatusToString(p.first) << ",";
} else {
ss << p.second << ",";
}
}
// Print a field encoded as a CBOR bstr in component with |name| to
// stringstream.
template <typename T>
void PrintBstrField(std::stringstream& ss, const std::string& name,
const std::pair<FieldStatus, T>& p) {
ss << " " << name << ":";
if (p.first != kPresent) {
ss << StatusToString(p.first) << ",";
} else {
ss << wvutil::b2a_hex(p.second) << ",";
}
}
// Print a field encoded as CBOR structure in component with |name| to
// stringstream.
template <typename T>
void PrintCborField(std::stringstream& ss, const std::string& name,
const std::pair<FieldStatus, T>& p) {
ss << " " << name << ":";
if (p.first != kPresent) {
ss << StatusToString(p.first) << ",";
} else {
ss << p.second.ToString() << ",";
}
}
} // namespace util
} // namespace wvoec
#endif // WVOEC_UTIL_PROV4_VALIDATION_HELPER_H_

View File

@@ -8,10 +8,12 @@
#define WVOEC_UTIL_SIGNED_CSR_PAYLOAD_VALIDATOR_H_
#include <sstream>
#include <string>
#include "bcc_validator.h"
#include "cbor_validator.h"
#include "cppbor.h"
#include "device_info_validator.h"
#include "prov4_validation_helper.h"
#include "wv_class_utils.h"
namespace wvoec {
@@ -20,6 +22,67 @@ namespace util {
// SignedData<CsrPayload>. The definition of SignedData<T> and CsrPayload can be
// found at:
// https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
struct CertificateType {
std::pair<FieldStatus, std::string> type;
std::string ToString() const;
CborMessageStatus Validate(
std::vector<std::pair<CborMessageStatus, std::string>>& msgs) const;
};
// CsrPayload = [ ; CBOR Array defining the payload for Csr
// version: 3, ; The CsrPayload CDDL Schema version.
// CertificateType, ; The type of certificate being requested.
// DeviceInfo, ; Defined in the relevant DeviceInfoV*.cddl file.
// KeysToSign, ; Provided by the method parameters
// ]
struct CsrPayload {
std::pair<FieldStatus, std::string> version;
std::pair<FieldStatus, CertificateType> certificate_type;
std::pair<FieldStatus, DeviceInfo> device_info;
std::vector<BccPublicKeyInfo> keys_to_sign; // always empty
std::string ToString() const;
CborMessageStatus Validate(
std::vector<std::pair<CborMessageStatus, std::string>>& msgs) const;
};
struct SignedDataProtected {
std::pair<FieldStatus, int64_t> algorithm;
std::string ToString() const;
CborMessageStatus Validate(
std::vector<std::pair<CborMessageStatus, std::string>>& msgs) const;
};
// SignedData<[
// challenge: bstr .size (0..64), ; Provided by the method parameters
// bstr .cbor T,
// ]>,
struct DataToBeSigned {
std::pair<FieldStatus, std::vector<uint8_t>> challenge;
std::pair<FieldStatus, CsrPayload> csr_payload;
std::string ToString() const;
CborMessageStatus Validate(
std::vector<std::pair<CborMessageStatus, std::string>>& msgs) const;
};
// clang-format off
// SignedData<Data> = [
// protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / AlgorithmES384 },
// unprotected: {},
// payload: bstr .cbor Data / nil,
// signature: bstr ; PureEd25519(CDI_Leaf_Priv, SignedDataSigStruct<Data>) /
// ; ECDSA(CDI_Leaf_Priv, SignedDataSigStruct<Data>)
// ]
// clang-format on
struct SignedCsrPayload {
std::pair<FieldStatus, SignedDataProtected> protected_data;
std::pair<FieldStatus, std::string> unprotected;
std::pair<FieldStatus, DataToBeSigned> payload;
std::pair<FieldStatus, std::vector<uint8_t>> signature;
std::string ToString() const;
CborMessageStatus Validate(
std::vector<std::pair<CborMessageStatus, std::string>>& msgs) const;
};
class SignedCsrPayloadValidator : public CborValidator {
public:
explicit SignedCsrPayloadValidator() {}
@@ -32,9 +95,20 @@ class SignedCsrPayloadValidator : public CborValidator {
virtual std::string GetFormattedMessage() const override;
private:
CborMessageStatus ValidateProtectedParams(
const cppbor::Bstr* protected_params);
CborMessageStatus ValidateDataToBeSigned(const cppbor::Bstr* data);
// Processes protected field in signed csr payload and extracts it to
// *|protected_data|.
// Caller ensures that all pointers are not null.
CborMessageStatus ProcessSignedDataProtected(
const cppbor::Map* protected_map, SignedDataProtected* protected_data);
// Processes the data to be signed and extracts it to *|payload_to_be_signed|.
// Caller ensures that all pointers are not null.
CborMessageStatus ProcessDataToBeSigned(
const cppbor::Array* payload_to_be_signed_array,
DataToBeSigned* payload_to_be_signed);
// Processes csr payload field and extracts it to *|csr_payload|.
// Caller ensures that all pointers are not null.
CborMessageStatus ProcessCsrPayload(const cppbor::Array* csr_payload_array,
CsrPayload* csr_payload);
// Used to generate formatted message.
std::stringstream msg_ss_;
}; // class SignedCsrPayloadValidator