blob: f7ec7c516fa7b3478e92f269ed1fbac01ab085ff [file] [log] [blame]
/*
* Copyright 2019, 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.
*/
#ifndef IDENTITY_SUPPORT_INCLUDE_IDENTITY_CREDENTIAL_UTILS_H_
#define IDENTITY_SUPPORT_INCLUDE_IDENTITY_CREDENTIAL_UTILS_H_
#include <cstdint>
#include <optional>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
namespace android {
namespace hardware {
namespace identity {
namespace support {
using ::std::optional;
using ::std::string;
using ::std::tuple;
using ::std::vector;
using ::std::pair;
// ---------------------------------------------------------------------------
// Miscellaneous utilities.
// ---------------------------------------------------------------------------
// Dumps the data in |data| to stderr. The written data will be of the following
// form for the call hexdump("signature", data) where |data| is of size 71:
//
// signature: dumping 71 bytes
// 0000 30 45 02 21 00 ac c6 12 60 56 a2 e9 ee 16 be 14 0E.!....`V......
// 0010 69 7f c4 00 95 8c e8 55 1f 22 de 34 0b 08 8a 3b i......U.".4...;
// 0020 a0 56 54 05 07 02 20 58 77 d9 8c f9 eb 41 df fd .VT... Xw....A..
// 0030 c1 a3 14 e0 bf b0 a2 c5 0c b6 85 8c 4a 0d f9 2b ............J..+
// 0040 b7 8f d2 1d 9b 11 ac .......
//
// This should only be used for debugging.
void hexdump(const string& name, const vector<uint8_t>& data);
string encodeHex(const string& str);
string encodeHex(const vector<uint8_t>& data);
string encodeHex(const uint8_t* data, size_t dataLen);
optional<vector<uint8_t>> decodeHex(const string& hexEncoded);
// ---------------------------------------------------------------------------
// CBOR utilities.
// ---------------------------------------------------------------------------
// Returns pretty-printed CBOR for |value|.
//
// Only valid CBOR should be passed to this function.
//
// If a byte-string is larger than |maxBStrSize| its contents will not be
// printed, instead the value of the form "<bstr size=1099016
// sha1=ef549cca331f73dfae2090e6a37c04c23f84b07b>" will be printed. Pass zero
// for |maxBStrSize| to disable this.
//
// The |mapKeysToNotPrint| parameter specifies the name of map values
// to not print. This is useful for unit tests.
string cborPrettyPrint(const vector<uint8_t>& encodedCbor, size_t maxBStrSize = 32,
const vector<string>& mapKeysToNotPrint = {});
// ---------------------------------------------------------------------------
// Crypto functionality / abstraction.
// ---------------------------------------------------------------------------
constexpr size_t kAesGcmIvSize = 12;
constexpr size_t kAesGcmTagSize = 16;
constexpr size_t kAes128GcmKeySize = 16;
// Returns |numBytes| bytes of random data.
optional<vector<uint8_t>> getRandom(size_t numBytes);
// Calculates the SHA-256 of |data|.
vector<uint8_t> sha256(const vector<uint8_t>& data);
// Decrypts |encryptedData| using |key| and |additionalAuthenticatedData|,
// returns resulting plaintext. The format of |encryptedData| must
// be as specified in the encryptAes128Gcm() function.
optional<vector<uint8_t>> decryptAes128Gcm(const vector<uint8_t>& key,
const vector<uint8_t>& encryptedData,
const vector<uint8_t>& additionalAuthenticatedData);
// Encrypts |data| with |key| and |additionalAuthenticatedData| using |nonce|,
// returns the resulting (nonce || ciphertext || tag).
optional<vector<uint8_t>> encryptAes128Gcm(const vector<uint8_t>& key, const vector<uint8_t>& nonce,
const vector<uint8_t>& data,
const vector<uint8_t>& additionalAuthenticatedData);
// ---------------------------------------------------------------------------
// EC crypto functionality / abstraction (only supports P-256).
// ---------------------------------------------------------------------------
// Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
// PKCS#8 encoded key-pair. Also generates an attestation
// certificate using the |challenge| and |applicationId|, and returns the generated
// certificate in X.509 certificate chain format.
//
// The attestation time fields used will be the current time, and expires in one year.
//
// The first parameter of the return value is the keyPair generated, second return in
// the pair is the attestation certificate generated.
optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId);
// Like createEcKeyPairAndAttestation() but allows you to choose the public key.
//
optional<vector<vector<uint8_t>>> createAttestationForEcPublicKey(
const vector<uint8_t>& publicKey, const vector<uint8_t>& challenge,
const vector<uint8_t>& applicationId);
// Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
// PKCS#8 encoded key-pair.
//
optional<vector<uint8_t>> createEcKeyPair();
// For an EC key |keyPair| encoded in PKCS#8 format, extracts the public key in
// uncompressed point form.
//
optional<vector<uint8_t>> ecKeyPairGetPublicKey(const vector<uint8_t>& keyPair);
// For an EC key |keyPair| encoded in PKCS#8 format, extracts the private key as
// an EC uncompressed key.
//
optional<vector<uint8_t>> ecKeyPairGetPrivateKey(const vector<uint8_t>& keyPair);
// Creates a PKCS#8 encoded key-pair from a private key (which must be uncompressed,
// e.g. 32 bytes). The public key is derived from the given private key..
//
optional<vector<uint8_t>> ecPrivateKeyToKeyPair(const vector<uint8_t>& privateKey);
// For an EC key |keyPair| encoded in PKCS#8 format, creates a PKCS#12 structure
// with the key-pair (not using a password to encrypt the data). The public key
// in the created structure is included as a certificate, using the given fields
// |serialDecimal|, |issuer|, |subject|, |validityNotBefore|, and
// |validityNotAfter|.
//
optional<vector<uint8_t>> ecKeyPairGetPkcs12(const vector<uint8_t>& keyPair, const string& name,
const string& serialDecimal, const string& issuer,
const string& subject, time_t validityNotBefore,
time_t validityNotAfter);
// Signs |data| with |key| (which must be in the format returned by
// ecKeyPairGetPrivateKey()). Signature is returned and will be in DER format.
//
optional<vector<uint8_t>> signEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data);
// Like signEcDsa() but instead of taking the data to be signed, takes a digest
// of it instead.
//
optional<vector<uint8_t>> signEcDsaDigest(const vector<uint8_t>& key,
const vector<uint8_t>& dataDigest);
// Calculates the HMAC with SHA-256 for |data| using |key|. The calculated HMAC
// is returned and will be 32 bytes.
//
optional<vector<uint8_t>> hmacSha256(const vector<uint8_t>& key, const vector<uint8_t>& data);
// Checks that |signature| (in DER format) is a valid signature of |digest|,
// made with |publicKey| (which must be in the format returned by
// ecKeyPairGetPublicKey()).
//
bool checkEcDsaSignature(const vector<uint8_t>& digest, const vector<uint8_t>& signature,
const vector<uint8_t>& publicKey);
// Extracts the public-key from the top-most certificate in |certificateChain|
// (which should be a concatenated chain of DER-encoded X.509 certificates).
//
// The returned public key will be in the same format as returned by
// ecKeyPairGetPublicKey().
//
optional<vector<uint8_t>> certificateChainGetTopMostKey(const vector<uint8_t>& certificateChain);
// Extracts the public-key from the top-most certificate in |certificateChain|
// (which should be a concatenated chain of DER-encoded X.509 certificates).
//
// Return offset and size of the public-key
//
optional<pair<size_t, size_t>> certificateFindPublicKey(const vector<uint8_t>& x509Certificate);
// Extracts the TbsCertificate from the top-most certificate in |certificateChain|
// (which should be a concatenated chain of DER-encoded X.509 certificates).
//
// Return offset and size of the TbsCertificate
//
optional<pair<size_t, size_t>> certificateTbsCertificate(const vector<uint8_t>& x509Certificate);
// Extracts the Signature from the top-most certificate in |certificateChain|
// (which should be a concatenated chain of DER-encoded X.509 certificates).
//
// Return offset and size of the Signature
//
optional<pair<size_t, size_t>> certificateFindSignature(const vector<uint8_t>& x509Certificate);
// Generates a X.509 certificate for |publicKey| (which must be in the format
// returned by ecKeyPairGetPublicKey()).
//
// The certificate is signed by |signingKey| (which must be in the format
// returned by ecKeyPairGetPrivateKey())
//
optional<vector<uint8_t>> ecPublicKeyGenerateCertificate(
const vector<uint8_t>& publicKey, const vector<uint8_t>& signingKey,
const string& serialDecimal, const string& issuer, const string& subject,
time_t validityNotBefore, time_t validityNotAfter);
// Performs Elliptic-curve Diffie-Helman using |publicKey| (which must be in the
// format returned by ecKeyPairGetPublicKey()) and |privateKey| (which must be
// in the format returned by ecKeyPairGetPrivateKey()).
//
// On success, the computed shared secret is returned.
//
optional<vector<uint8_t>> ecdh(const vector<uint8_t>& publicKey, const vector<uint8_t>& privateKey);
// Key derivation function using SHA-256, conforming to RFC 5869.
//
// On success, the derived key is returned.
//
optional<vector<uint8_t>> hkdf(const vector<uint8_t>& sharedSecret, const vector<uint8_t>& salt,
const vector<uint8_t>& info, size_t size);
// Returns the X and Y coordinates from |publicKey| (which must be in the format
// returned by ecKeyPairGetPublicKey()).
//
// Success is indicated by the first value in the returned tuple. If successful,
// the returned coordinates will be in uncompressed form.
//
tuple<bool, vector<uint8_t>, vector<uint8_t>> ecPublicKeyGetXandY(const vector<uint8_t>& publicKey);
// Concatenates all certificates into |certificateChain| together into a
// single bytestring.
//
// This is the reverse operation of certificateChainSplit().
vector<uint8_t> certificateChainJoin(const vector<vector<uint8_t>>& certificateChain);
// Splits all the certificates in a single bytestring into individual
// certificates.
//
// Returns nothing if |certificateChain| contains invalid data.
//
// This is the reverse operation of certificateChainJoin().
optional<vector<vector<uint8_t>>> certificateChainSplit(const vector<uint8_t>& certificateChain);
// Validates that the certificate chain is valid. In particular, checks that each
// certificate in the chain is signed by the public key in the following certificate.
//
// Returns false if |certificateChain| failed validation or if each certificate
// is not signed by its successor.
//
bool certificateChainValidate(const vector<uint8_t>& certificateChain);
// Returns true if |certificate| is signed by |publicKey|.
//
bool certificateSignedByPublicKey(const vector<uint8_t>& certificate,
const vector<uint8_t>& publicKey);
// Signs |data| and |detachedContent| with |key| (which must be in the format
// returned by ecKeyPairGetPrivateKey()).
//
// On success, the Signature is returned and will be in COSE_Sign1 format.
//
// If |certificateChain| is non-empty it's included in the 'x5chain'
// protected header element (as as described in'draft-ietf-cose-x509-04').
//
optional<vector<uint8_t>> coseSignEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data,
const vector<uint8_t>& detachedContent,
const vector<uint8_t>& certificateChain);
// Creates a COSE_Signature1 where |signatureToBeSigned| is the ECDSA signature
// of the ToBeSigned CBOR from RFC 8051 "4.4. Signing and Verification Process".
//
// The |signatureToBeSigned| is expected to be 64 bytes and contain the R value,
// then the S value.
//
// The |data| parameter will be included in the COSE_Sign1 CBOR.
//
// If |certificateChain| is non-empty it's included in the 'x5chain'
// protected header element (as as described in'draft-ietf-cose-x509-04').
//
optional<vector<uint8_t>> coseSignEcDsaWithSignature(const vector<uint8_t>& signatureToBeSigned,
const vector<uint8_t>& data,
const vector<uint8_t>& certificateChain);
// Checks that |signatureCoseSign1| (in COSE_Sign1 format) is a valid signature
// made with |public_key| (which must be in the format returned by
// ecKeyPairGetPublicKey()) where |detachedContent| is the detached content.
//
bool coseCheckEcDsaSignature(const vector<uint8_t>& signatureCoseSign1,
const vector<uint8_t>& detachedContent,
const vector<uint8_t>& publicKey);
// Converts a DER-encoded signature to the format used in 'signature' bstr in COSE_Sign1.
bool ecdsaSignatureDerToCose(const vector<uint8_t>& ecdsaDerSignature,
vector<uint8_t>& ecdsaCoseSignature);
// Converts from the format in in 'signature' bstr in COSE_Sign1 to DER encoding.
bool ecdsaSignatureCoseToDer(const vector<uint8_t>& ecdsaCoseSignature,
vector<uint8_t>& ecdsaDerSignature);
// Extracts the payload from a COSE_Sign1.
optional<vector<uint8_t>> coseSignGetPayload(const vector<uint8_t>& signatureCoseSign1);
// Extracts the signature (of the ToBeSigned CBOR) from a COSE_Sign1.
optional<vector<uint8_t>> coseSignGetSignature(const vector<uint8_t>& signatureCoseSign1);
// Extracts the signature algorithm from a COSE_Sign1.
optional<int> coseSignGetAlg(const vector<uint8_t>& signatureCoseSign1);
// Extracts the X.509 certificate chain, if present. Returns the data as a
// concatenated chain of DER-encoded X.509 certificates
//
// Returns nothing if there is no 'x5chain' element or an error occurs.
//
optional<vector<uint8_t>> coseSignGetX5Chain(const vector<uint8_t>& signatureCoseSign1);
// MACs |data| and |detachedContent| with |key| (which can be any sequence of
// bytes).
//
// If successful, the MAC is returned and will be in COSE_Mac0 format.
//
optional<vector<uint8_t>> coseMac0(const vector<uint8_t>& key, const vector<uint8_t>& data,
const vector<uint8_t>& detachedContent);
// Creates a COSE_Mac0 where |digestToBeMaced| is the HMAC-SHA256
// of the ToBeMaced CBOR from RFC 8051 "6.3. How to Compute and Verify a MAC".
//
// The |digestToBeMaced| is expected to be 32 bytes.
//
// The |data| parameter will be included in the COSE_Mac0 CBOR.
//
optional<vector<uint8_t>> coseMacWithDigest(const vector<uint8_t>& digestToBeMaced,
const vector<uint8_t>& data);
// ---------------------------------------------------------------------------
// Utility functions specific to IdentityCredential.
// ---------------------------------------------------------------------------
// Returns the testing AES-128 key where all bits are set to 0.
const vector<uint8_t>& getTestHardwareBoundKey();
// Splits the given bytestring into chunks. If the given vector is smaller or equal to
// |maxChunkSize| a vector with |content| as the only element is returned. Otherwise
// |content| is split into N vectors each of size |maxChunkSize| except the final element
// may be smaller than |maxChunkSize|.
vector<vector<uint8_t>> chunkVector(const vector<uint8_t>& content, size_t maxChunkSize);
} // namespace support
} // namespace identity
} // namespace hardware
} // namespace android
#endif // IDENTITY_SUPPORT_INCLUDE_IDENTITY_CREDENTIAL_UTILS_H_