/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include // From https://tools.ietf.org/html/rfc8152 constexpr int COSE_LABEL_ALG = 1; constexpr int COSE_LABEL_KID = 4; constexpr int COSE_LABEL_IV = 5; constexpr int COSE_LABEL_KEY_KTY = 1; constexpr int COSE_LABEL_KEY_ALG = 3; constexpr int COSE_LABEL_KEY_SYMMETRIC_KEY = -1; constexpr int COSE_TAG_ENCRYPT = 96; constexpr int COSE_TAG_SIGN1 = 18; constexpr int COSE_KEY_TYPE_SYMMETRIC = 4; constexpr char COSE_CONTEXT_ENCRYPT[] = "Encrypt"; constexpr char COSE_CONTEXT_ENC_RECIPIENT[] = "Enc_Recipient"; // From "COSE Algorithms" registry // See: RFC9053 or https://www.iana.org/assignments/cose/cose.txt constexpr int COSE_ALG_A128GCM = 1; constexpr int COSE_ALG_A256GCM = 2; constexpr int COSE_ALG_ECDSA_256 = -7; constexpr int COSE_ALG_ECDSA_384 = -35; // Trusty-specific COSE constants constexpr int COSE_LABEL_TRUSTY = -65537; #ifdef APPLOADER_PACKAGE_CIPHER_A256 constexpr int COSE_VAL_CIPHER_ALG = COSE_ALG_A256GCM; #else constexpr int COSE_VAL_CIPHER_ALG = COSE_ALG_A128GCM; #endif #ifdef APPLOADER_PACKAGE_SIGN_P384 constexpr int COSE_VAL_SIGN_ALG = COSE_ALG_ECDSA_384; #else constexpr int COSE_VAL_SIGN_ALG = COSE_ALG_ECDSA_256; #endif constexpr size_t kAesGcmIvSize = 12; constexpr size_t kAesGcmTagSize = 16; #ifdef APPLOADER_PACKAGE_CIPHER_A256 constexpr size_t kAesGcmKeySize = 32; #else constexpr size_t kAesGcmKeySize = 16; #endif constexpr size_t kCoseEncryptArrayElements = 4; using CoseByteView = std::span; using GetKeyFn = std::function, size_t>(uint8_t)>; using DecryptFn = std::function; /** * coseSetSilenceErrors() - Enable or disable the silencing of errors; * @value: New value of the flag, %true if errors should be silenced. * * Return: the old value of the flag. */ bool coseSetSilenceErrors(bool value); /** * coseSignEcDsa() - Sign the given data using ECDSA and emit a COSE CBOR blob. * @key: * DER-encoded private key. * @keyId: * Key identifier, an unsigned 1-byte integer. * @data: * Block of data to sign and optionally encode inside the COSE signature * structure. * @protectedHeaders: * Protected headers for the COSE structure. The function may add its own * additional entries. * @unprotectedHeaders: * Unprotected headers for the COSE structure. The function may add its * own additional entries. * @detachContent: * Whether to detach the data, i.e., not include @data in the returned * ```COSE_Sign1``` structure. * @tagged: * Whether to return the tagged ```COSE_Sign1_Tagged``` or the untagged * ```COSE_Sign1``` structure. * * This function signs a given block of data with ECDSA-SHA256 and encodes both * the data and the signature using the COSE encoding from RFC 8152. The caller * may specify whether the data is included or detached from the returned * structure using the @detachContent parameter, as well as additional * context-specific header values with the @protectedHeaders and * @unprotectedHeaders parameters. * * Return: A vector containing the encoded ```COSE_Sign1``` structure if the * signing algorithm succeeds, or a nullopt otherwise. */ std::optional> coseSignEcDsa( const std::vector& key, uint8_t keyId, const std::vector& data, const std::span& encodedProtectedHeaders, std::span&, bool detachContent, bool tagged); /** * coseIsSigned() - Check if a block of bytes is a COSE signature emitted * by coseSignEcDsa(). * @data: Input data. * @signatureLength: If not NULL, output argument where the total length * of the signature structure will be stored. * * This function checks if the given data is a COSE signature structure * emitted by coseSignEcDsa(), and returns the size of the signature if needed. * * Return: %true if the signature structure is valid, %false otherwise. */ bool coseIsSigned(CoseByteView data, size_t* signatureLength); /** * coseCheckEcDsaSignature() - Check if a given COSE signature structure is * valid. * @signatureCoseSign1: Input COSE signature structure. * @detachedContent: Additional data to include in the signature. * Corresponds to the @detachedContent parameter passed to * coseSignEcDsa(). * @publicKey: Public key in DER encoding. * * Returns: %true if the signature verification passes, %false otherwise. */ bool coseCheckEcDsaSignature(const std::vector& signatureCoseSign1, const std::vector& detachedContent, const std::vector& publicKey); /** * strictCheckEcDsaSignature() - Check a given COSE signature in strict mode. * @packageStart: Pointer to the start of the signed input package. * @packageSize: Size of the signed input package. * @keyFn: Function to call with a key id that returns the public * key for that id. * @outPackageStart: If not NULL, output argument where the start of the * payload will be stored. * @outPackageSize: If not NULL, output argument where the size of the * payload will be stored. * * This function performs a strict verification of the COSE signature of a * package. Instead of parsing the COSE structure, the function compares the * raw bytes against a set of exact patterns, and fails if the bytes do not * match. The actual signature and payload are also assumed to start at fixed * offsets from @packageStart. * * Returns: %true if the signature verification passes, %false otherwise. */ bool strictCheckEcDsaSignature(const uint8_t* packageStart, size_t packageSize, GetKeyFn keyFn, const uint8_t** outPackageStart, size_t* outPackageSize); /** * coseEncryptAes128GcmKeyWrap() - Encrypt a block of data using AES-GCM * and a randomly-generated wrapped CEK. * @key: * Key encryption key (KEK), 16 or 32 bytes in size. * @keyId: * Key identifier for the KEK, an unsigned 1-byte integer. * @data: * Input data to encrypt. * @externalAad: * Additional authentication data to pass to AES-GCM. * @protectedHeaders: * Protected headers for the COSE structure. The function may add its own * additional entries. * @unprotectedHeaders: * Unprotected headers for the COSE structure. The function may add its * own additional entries. * @tagged: * Whether to return the tagged ```COSE_Encrypt_Tagged``` or the untagged * ```COSE_Encrypt``` structure. * * This function generates a random key content encryption key (CEK) and wraps * it using AES-GCM, then encrypts a given block of data with AES-GCM * with the wrapped CEK and encodes both the data and CEK using the COSE * encoding from RFC 8152. * * The key length must be 128 or 256 depending on build-time configuration. * The IV and Tag lengths are fixed (128-bit and 96-bits respectively, see * ```kAesGcmIvSize``` and ```kAesGcmTagSize```). * * The caller may specify additional context-specific header values with the * @protectedHeaders and @unprotectedHeaders parameters. * * Return: A vector of bytes containing the encoded ```COSE_Encrypt``` structure * if the encryption succeeds, or a nullopt otherwise. */ std::optional> coseEncryptAesGcmKeyWrap( const std::vector& key, uint8_t keyId, const CoseByteView& data, const std::vector& externalAad, const std::vector& encodedProtectedHeaders, const CoseByteView& unprotectedHeaders, bool tagged); /** * coseDecryptAesGcmKeyWrapInPlace() - Decrypt a block of data containing a * wrapped key using AES-GCM. * @item: CBOR item containing a ```COSE_Encrypt``` structure. * @keyFn: Function to call with a key id that returns the key * encryption key (KEK) for that id. * @externalAad: Additional authentication data to pass to AES-GCM. * @checkTag: Whether to check the CBOR semantic tag of @item. * @outPackageStart: The output argument where the start of the * payload will be stored. Must not be %NULL. * @outPackageSize: The output argument where the size of the * payload will be stored. Must not be %NULL. * * This function decrypts a ciphertext encrypted with AES-GCM and encoded * in a ```COSE_Encrypt0_Tagged``` structure. The function performs in-place * decryption and overwrites the ciphertext with the plaintext, and returns * the pointer and size of the plaintext in @outPackageStart and * @outPackageSize, respectively. * The key length is 128 or 256 depending on build-time configuration. The IV * and Tag lengths are fixed (128-bit and 96-bits respectively). * * Returns: %true if the decryption succeeds, %false otherwise. */ bool coseDecryptAesGcmKeyWrapInPlace(const CoseByteView& item, GetKeyFn keyFn, const std::vector& externalAad, bool checkTag, const uint8_t** outPackageStart, size_t* outPackageSize, DecryptFn decryptFn = DecryptFn()); /** * coseGetCipherAlg - Get the name of the cipher for package encryption. * Returns: A pointer to a static string describing the cipher. */ const char* coseGetCipherAlg(void); /** * coseGetSigningDsa() - Get the name of the signing Digital Signature Algo. * Returns: A pointer to a static string describing the signing method. */ const char* coseGetSigningDsa(void);