Add RemotelyProvisionedComponent HAL.

Test: VtsHalRemotelyProvisionedComponentTargetTest
Change-Id: I51fb01f4c52949c81f3ad2d694a4afdf0fa67788
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index fde6b57..efdff2b 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -37,3 +37,40 @@
         "libutils",
     ],
 }
+
+cc_library {
+    name: "libkeymint_remote_prov_support",
+    vendor_available: true,
+    srcs: [
+        "remote_prov_utils.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    shared_libs: [
+        "libcppcose",
+        "libcppbor_external",
+        "libcrypto",
+    ],
+}
+
+cc_library {
+    name: "libcppcose",
+    vendor_available: true,
+    srcs: [
+        "cppcose.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcppbor_external",
+        "libcrypto",
+        "liblog",
+    ],
+    static_libs: [
+        // TODO(swillden): Remove keymint NDK
+        "android.hardware.security.keymint-unstable-ndk_platform",
+    ],
+}
diff --git a/security/keymint/support/cppcose.cpp b/security/keymint/support/cppcose.cpp
new file mode 100644
index 0000000..c626ade
--- /dev/null
+++ b/security/keymint/support/cppcose.cpp
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <cppcose/cppcose.h>
+
+#include <stdio.h>
+#include <iostream>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <openssl/err.h>
+
+namespace cppcose {
+
+namespace {
+
+ErrMsgOr<bssl::UniquePtr<EVP_CIPHER_CTX>> aesGcmInitAndProcessAad(const bytevec& key,
+                                                                  const bytevec& nonce,
+                                                                  const bytevec& aad,
+                                                                  bool encrypt) {
+    if (key.size() != kAesGcmKeySize) return "Invalid key size";
+
+    bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new());
+    if (!ctx) return "Failed to allocate cipher context";
+
+    if (!EVP_CipherInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr /* engine */, key.data(),
+                           nonce.data(), encrypt ? 1 : 0)) {
+        return "Failed to initialize cipher";
+    }
+
+    int outlen;
+    if (!aad.empty() && !EVP_CipherUpdate(ctx.get(), nullptr /* out; null means AAD */, &outlen,
+                                          aad.data(), aad.size())) {
+        return "Failed to process AAD";
+    }
+
+    return std::move(ctx);
+}
+
+}  // namespace
+
+ErrMsgOr<bytevec> generateCoseMac0Mac(const bytevec& macKey, const bytevec& externalAad,
+                                      const bytevec& payload) {
+    auto macStructure = cppbor::Array()
+                                .add("MAC0")
+                                .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
+                                .add(externalAad)
+                                .add(payload)
+                                .encode();
+
+    bytevec macTag(SHA256_DIGEST_LENGTH);
+    uint8_t* out = macTag.data();
+    unsigned int outLen;
+    out = HMAC(EVP_sha256(),                              //
+               macKey.data(), macKey.size(),              //
+               macStructure.data(), macStructure.size(),  //
+               out, &outLen);
+
+    assert(out != nullptr && outLen == macTag.size());
+    if (out == nullptr || outLen != macTag.size()) {
+        return "Error computing public key MAC";
+    }
+
+    return macTag;
+}
+
+ErrMsgOr<cppbor::Array> constructCoseMac0(const bytevec& macKey, const bytevec& externalAad,
+                                          const bytevec& payload) {
+    auto tag = generateCoseMac0Mac(macKey, externalAad, payload);
+    if (!tag) return tag.moveMessage();
+
+    return cppbor::Array()
+            .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
+            .add(cppbor::Bstr() /* unprotected */)
+            .add(payload)
+            .add(tag.moveValue());
+}
+
+ErrMsgOr<bytevec /* payload */> parseCoseMac0(const cppbor::Item* macItem) {
+    auto mac = macItem ? macItem->asArray() : nullptr;
+    if (!mac || mac->size() != kCoseMac0EntryCount) {
+        return "Invalid COSE_Mac0";
+    }
+
+    auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr();
+    auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asBstr();
+    auto payload = mac->get(kCoseMac0Payload)->asBstr();
+    auto tag = mac->get(kCoseMac0Tag)->asBstr();
+    if (!protectedParms || !unprotectedParms || !payload || !tag) {
+        return "Invalid COSE_Mac0 contents";
+    }
+
+    return payload->value();
+}
+
+ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
+                                                       const bytevec& macKey) {
+    auto mac = macItem ? macItem->asArray() : nullptr;
+    if (!mac || mac->size() != kCoseMac0EntryCount) {
+        return "Invalid COSE_Mac0";
+    }
+
+    auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr();
+    auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asBstr();
+    auto payload = mac->get(kCoseMac0Payload)->asBstr();
+    auto tag = mac->get(kCoseMac0Tag)->asBstr();
+    if (!protectedParms || !unprotectedParms || !payload || !tag) {
+        return "Invalid COSE_Mac0 contents";
+    }
+
+    auto [protectedMap, _, errMsg] = cppbor::parse(protectedParms);
+    if (!protectedMap || !protectedMap->asMap()) {
+        return "Invalid Mac0 protected: " + errMsg;
+    }
+    auto& algo = protectedMap->asMap()->get(ALGORITHM);
+    if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) {
+        return "Unsupported Mac0 algorithm";
+    }
+
+    auto macTag = generateCoseMac0Mac(macKey, {} /* external_aad */, payload->value());
+    if (!macTag) return macTag.moveMessage();
+
+    if (macTag->size() != tag->value().size() ||
+        CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) {
+        return "MAC tag mismatch";
+    }
+
+    return payload->value();
+}
+
+ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
+                                           const bytevec& payload, const bytevec& aad) {
+    bytevec signatureInput = cppbor::Array()
+                                     .add("Signature1")  //
+                                     .add(protectedParams)
+                                     .add(aad)
+                                     .add(payload)
+                                     .encode();
+
+    if (key.size() != ED25519_PRIVATE_KEY_LEN) return "Invalid signing key";
+    bytevec signature(ED25519_SIGNATURE_LEN);
+    if (!ED25519_sign(signature.data(), signatureInput.data(), signatureInput.size(), key.data())) {
+        return "Signing failed";
+    }
+
+    return signature;
+}
+
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map protectedParams,
+                                           const bytevec& payload, const bytevec& aad) {
+    bytevec protParms = protectedParams.add(ALGORITHM, EDDSA).canonicalize().encode();
+    auto signature = createCoseSign1Signature(key, protParms, payload, aad);
+    if (!signature) return signature.moveMessage();
+
+    return cppbor::Array()
+            .add(protParms)
+            .add(bytevec{} /* unprotected parameters */)
+            .add(payload)
+            .add(*signature);
+}
+
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
+                                           const bytevec& aad) {
+    return constructCoseSign1(key, {} /* protectedParams */, payload, aad);
+}
+
+ErrMsgOr<bytevec> verifyAndParseCoseSign1(bool ignoreSignature, const cppbor::Array* coseSign1,
+                                          const bytevec& signingCoseKey, const bytevec& aad) {
+    if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
+        return "Invalid COSE_Sign1";
+    }
+
+    const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
+    const cppbor::Bstr* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asBstr();
+    const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
+    const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
+
+    if (!protectedParams || !unprotectedParams || !payload || !signature) {
+        return "Invalid COSE_Sign1";
+    }
+
+    auto [parsedProtParams, _, errMsg] = cppbor::parse(protectedParams);
+    if (!parsedProtParams) {
+        return errMsg + " when parsing protected params.";
+    }
+    if (!parsedProtParams->asMap()) {
+        return "Protected params must be a map";
+    }
+
+    auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
+    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
+        return "Unsupported signature algorithm";
+    }
+
+    if (!ignoreSignature) {
+        bool selfSigned = signingCoseKey.empty();
+        auto key = CoseKey::parseEd25519(selfSigned ? payload->value() : signingCoseKey);
+        if (!key) return "Bad signing key: " + key.moveMessage();
+
+        bytevec signatureInput = cppbor::Array()
+                                         .add("Signature1")
+                                         .add(*protectedParams)
+                                         .add(aad)
+                                         .add(*payload)
+                                         .encode();
+
+        if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
+                            key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
+            return "Signature verification failed";
+        }
+    }
+
+    return payload->value();
+}
+
+ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
+                                              const bytevec& protectedParams,
+                                              const bytevec& plaintextPayload, const bytevec& aad) {
+    auto ciphertext = aesGcmEncrypt(key, nonce,
+                                    cppbor::Array()                // Enc strucure as AAD
+                                            .add("Encrypt")        // Context
+                                            .add(protectedParams)  // Protected
+                                            .add(aad)              // External AAD
+                                            .encode(),
+                                    plaintextPayload);
+
+    if (!ciphertext) return ciphertext.moveMessage();
+    return ciphertext.moveValue();
+}
+
+ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
+                                             const bytevec& plaintextPayload, const bytevec& aad,
+                                             cppbor::Array recipients) {
+    auto encryptProtectedHeader = cppbor::Map()  //
+                                          .add(ALGORITHM, AES_GCM_256)
+                                          .canonicalize()
+                                          .encode();
+
+    auto ciphertext =
+            createCoseEncryptCiphertext(key, nonce, encryptProtectedHeader, plaintextPayload, aad);
+    if (!ciphertext) return ciphertext.moveMessage();
+
+    return cppbor::Array()
+            .add(encryptProtectedHeader)                       // Protected
+            .add(cppbor::Map().add(IV, nonce).canonicalize())  // Unprotected
+            .add(*ciphertext)                                  // Payload
+            .add(std::move(recipients));
+}
+
+ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>> getSenderPubKeyFromCoseEncrypt(
+        const cppbor::Item* coseEncrypt) {
+    if (!coseEncrypt || !coseEncrypt->asArray() ||
+        coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
+        return "Invalid COSE_Encrypt";
+    }
+
+    auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
+    if (!recipients || !recipients->asArray() || recipients->asArray()->size() != 1) {
+        return "Invalid recipients list";
+    }
+
+    auto& recipient = recipients->asArray()->get(0);
+    if (!recipient || !recipient->asArray() || recipient->asArray()->size() != 3) {
+        return "Invalid COSE_recipient";
+    }
+
+    auto& ciphertext = recipient->asArray()->get(2);
+    if (!ciphertext->asSimple() || !ciphertext->asSimple()->asNull()) {
+        return "Unexpected value in recipients ciphertext field " +
+               cppbor::prettyPrint(ciphertext.get());
+    }
+
+    auto& protParms = recipient->asArray()->get(0);
+    if (!protParms || !protParms->asBstr()) return "Invalid protected params";
+    auto [parsedProtParms, _, errMsg] = cppbor::parse(protParms->asBstr());
+    if (!parsedProtParms) return "Failed to parse protected params: " + errMsg;
+    if (!parsedProtParms->asMap()) return "Invalid protected params";
+
+    auto& algorithm = parsedProtParms->asMap()->get(ALGORITHM);
+    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != ECDH_ES_HKDF_256) {
+        return "Invalid algorithm";
+    }
+
+    auto& unprotParms = recipient->asArray()->get(1);
+    if (!unprotParms || !unprotParms->asMap()) return "Invalid unprotected params";
+
+    auto& senderCoseKey = unprotParms->asMap()->get(COSE_KEY);
+    if (!senderCoseKey || !senderCoseKey->asMap()) return "Invalid sender COSE_Key";
+
+    auto& keyType = senderCoseKey->asMap()->get(CoseKey::KEY_TYPE);
+    if (!keyType || !keyType->asInt() || keyType->asInt()->value() != OCTET_KEY_PAIR) {
+        return "Invalid key type";
+    }
+
+    auto& curve = senderCoseKey->asMap()->get(CoseKey::CURVE);
+    if (!curve || !curve->asInt() || curve->asInt()->value() != X25519) {
+        return "Unsupported curve";
+    }
+
+    auto& pubkey = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X);
+    if (!pubkey || !pubkey->asBstr() ||
+        pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
+        return "Invalid X25519 public key";
+    }
+
+    auto& key_id = unprotParms->asMap()->get(KEY_ID);
+    if (key_id && key_id->asBstr()) {
+        return std::make_pair(pubkey->asBstr()->value(), key_id->asBstr()->value());
+    }
+
+    // If no key ID, just return an empty vector.
+    return std::make_pair(pubkey->asBstr()->value(), bytevec{});
+}
+
+ErrMsgOr<bytevec> decryptCoseEncrypt(const bytevec& key, const cppbor::Item* coseEncrypt,
+                                     const bytevec& external_aad) {
+    if (!coseEncrypt || !coseEncrypt->asArray() ||
+        coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
+        return "Invalid COSE_Encrypt";
+    }
+
+    auto& protParms = coseEncrypt->asArray()->get(kCoseEncryptProtectedParams);
+    auto& unprotParms = coseEncrypt->asArray()->get(kCoseEncryptUnprotectedParams);
+    auto& ciphertext = coseEncrypt->asArray()->get(kCoseEncryptPayload);
+    auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
+
+    if (!protParms || !protParms->asBstr() || !unprotParms || !ciphertext || !recipients) {
+        return "Invalid COSE_Encrypt";
+    }
+
+    auto [parsedProtParams, _, errMsg] = cppbor::parse(protParms->asBstr()->value());
+    if (!parsedProtParams) {
+        return errMsg + " when parsing protected params.";
+    }
+    if (!parsedProtParams->asMap()) {
+        return "Protected params must be a map";
+    }
+
+    auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
+    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != AES_GCM_256) {
+        return "Unsupported encryption algorithm";
+    }
+
+    if (!unprotParms->asMap() || unprotParms->asMap()->size() != 1) {
+        return "Invalid unprotected params";
+    }
+
+    auto& nonce = unprotParms->asMap()->get(IV);
+    if (!nonce || !nonce->asBstr() || nonce->asBstr()->value().size() != kAesGcmNonceLength) {
+        return "Invalid nonce";
+    }
+
+    if (!ciphertext->asBstr()) return "Invalid ciphertext";
+
+    auto aad = cppbor::Array()                             // Enc strucure as AAD
+                       .add("Encrypt")                     // Context
+                       .add(protParms->asBstr()->value())  // Protected
+                       .add(external_aad)                  // External AAD
+                       .encode();
+
+    return aesGcmDecrypt(key, nonce->asBstr()->value(), aad, ciphertext->asBstr()->value());
+}
+
+ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
+                                        const bytevec& pubKeyB, bool senderIsA) {
+    bytevec rawSharedKey(X25519_SHARED_KEY_LEN);
+    if (!::X25519(rawSharedKey.data(), privKeyA.data(), pubKeyB.data())) {
+        return "ECDH operation failed";
+    }
+
+    bytevec kdfContext = cppbor::Array()
+                                 .add(AES_GCM_256)
+                                 .add(cppbor::Array()  // Sender Info
+                                              .add(cppbor::Bstr("client"))
+                                              .add(bytevec{} /* nonce */)
+                                              .add(senderIsA ? pubKeyA : pubKeyB))
+                                 .add(cppbor::Array()  // Recipient Info
+                                              .add(cppbor::Bstr("server"))
+                                              .add(bytevec{} /* nonce */)
+                                              .add(senderIsA ? pubKeyB : pubKeyA))
+                                 .add(cppbor::Array()           // SuppPubInfo
+                                              .add(128)         // output key length
+                                              .add(bytevec{}))  // protected
+                                 .encode();
+
+    bytevec retval(SHA256_DIGEST_LENGTH);
+    bytevec salt{};
+    if (!HKDF(retval.data(), retval.size(),              //
+              EVP_sha256(),                              //
+              rawSharedKey.data(), rawSharedKey.size(),  //
+              salt.data(), salt.size(),                  //
+              kdfContext.data(), kdfContext.size())) {
+        return "ECDH HKDF failed";
+    }
+
+    return retval;
+}
+
+ErrMsgOr<bytevec> aesGcmEncrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
+                                const bytevec& plaintext) {
+    auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, true /* encrypt */);
+    if (!ctx) return ctx.moveMessage();
+
+    bytevec ciphertext(plaintext.size() + kAesGcmTagSize);
+    int outlen;
+    if (!EVP_CipherUpdate(ctx->get(), ciphertext.data(), &outlen, plaintext.data(),
+                          plaintext.size())) {
+        return "Failed to encrypt plaintext";
+    }
+    assert(plaintext.size() == outlen);
+
+    if (!EVP_CipherFinal_ex(ctx->get(), ciphertext.data() + outlen, &outlen)) {
+        return "Failed to finalize encryption";
+    }
+    assert(outlen == 0);
+
+    if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_GET_TAG, kAesGcmTagSize,
+                             ciphertext.data() + plaintext.size())) {
+        return "Failed to retrieve tag";
+    }
+
+    return ciphertext;
+}
+
+ErrMsgOr<bytevec> aesGcmDecrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
+                                const bytevec& ciphertextWithTag) {
+    auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, false /* encrypt */);
+    if (!ctx) return ctx.moveMessage();
+
+    if (ciphertextWithTag.size() < kAesGcmTagSize) return "Missing tag";
+
+    bytevec plaintext(ciphertextWithTag.size() - kAesGcmTagSize);
+    int outlen;
+    if (!EVP_CipherUpdate(ctx->get(), plaintext.data(), &outlen, ciphertextWithTag.data(),
+                          ciphertextWithTag.size() - kAesGcmTagSize)) {
+        return "Failed to decrypt plaintext";
+    }
+    assert(plaintext.size() == outlen);
+
+    bytevec tag(ciphertextWithTag.end() - kAesGcmTagSize, ciphertextWithTag.end());
+    if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_SET_TAG, kAesGcmTagSize, tag.data())) {
+        return "Failed to set tag: " + std::to_string(ERR_peek_last_error());
+    }
+
+    if (!EVP_CipherFinal_ex(ctx->get(), nullptr, &outlen)) {
+        return "Failed to finalize encryption";
+    }
+    assert(outlen == 0);
+
+    return plaintext;
+}
+
+}  // namespace cppcose
diff --git a/security/keymint/support/include/cppcose/cppcose.h b/security/keymint/support/include/cppcose/cppcose.h
new file mode 100644
index 0000000..a936bfd
--- /dev/null
+++ b/security/keymint/support/include/cppcose/cppcose.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2020 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 <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <openssl/cipher.h>
+#include <openssl/curve25519.h>
+#include <openssl/digest.h>
+#include <openssl/hkdf.h>
+#include <openssl/hmac.h>
+#include <openssl/mem.h>
+#include <openssl/sha.h>
+
+namespace cppcose {
+
+using bytevec = std::vector<uint8_t>;
+
+constexpr int kCoseSign1EntryCount = 4;
+constexpr int kCoseSign1ProtectedParams = 0;
+constexpr int kCoseSign1UnprotectedParams = 1;
+constexpr int kCoseSign1Payload = 2;
+constexpr int kCoseSign1Signature = 3;
+
+constexpr int kCoseMac0EntryCount = 4;
+constexpr int kCoseMac0ProtectedParams = 0;
+constexpr int kCoseMac0UnprotectedParams = 1;
+constexpr int kCoseMac0Payload = 2;
+constexpr int kCoseMac0Tag = 3;
+
+constexpr int kCoseEncryptEntryCount = 4;
+constexpr int kCoseEncryptProtectedParams = 0;
+constexpr int kCoseEncryptUnprotectedParams = 1;
+constexpr int kCoseEncryptPayload = 2;
+constexpr int kCoseEncryptRecipients = 3;
+
+enum Label : int {
+    ALGORITHM = 1,
+    KEY_ID = 4,
+    IV = 5,
+    COSE_KEY = -1,
+};
+
+enum CoseKeyAlgorithm : int {
+    AES_GCM_256 = 3,
+    HMAC_256 = 5,
+    ES256 = -7,  // ECDSA with SHA-256
+    EDDSA = -8,
+    ECDH_ES_HKDF_256 = -25,
+};
+
+enum CoseKeyCurve : int { P256 = 1, X25519 = 4, ED25519 = 6 };
+enum CoseKeyType : int { OCTET_KEY_PAIR = 1, EC2 = 2, SYMMETRIC_KEY = 4 };
+enum CoseKeyOps : int { SIGN = 1, VERIFY = 2, ENCRYPT = 3, DECRYPT = 4 };
+
+constexpr int kAesGcmNonceLength = 12;
+constexpr int kAesGcmTagSize = 16;
+constexpr int kAesGcmKeySize = 32;
+
+template <typename T>
+class ErrMsgOr {
+  public:
+    ErrMsgOr(std::string errMsg) : errMsg_(std::move(errMsg)) {}
+    ErrMsgOr(const char* errMsg) : errMsg_(errMsg) {}
+    ErrMsgOr(T val) : value_(std::move(val)) {}
+
+    operator bool() const { return value_.has_value(); }
+
+    T* operator->() & {
+        assert(value_);
+        return &value_.value();
+    }
+    T& operator*() & {
+        assert(value_);
+        return value_.value();
+    };
+    T&& operator*() && {
+        assert(value_);
+        return std::move(value_).value();
+    };
+
+    const std::string& message() { return errMsg_; }
+    std::string moveMessage() { return std::move(errMsg_); }
+
+    T moveValue() {
+        assert(value_);
+        return std::move(value_).value();
+    }
+
+  private:
+    std::string errMsg_;
+    std::optional<T> value_;
+};
+
+class CoseKey {
+  public:
+    CoseKey() {}
+    CoseKey(const CoseKey&) = delete;
+    CoseKey(CoseKey&&) = default;
+
+    enum Label : int {
+        KEY_TYPE = 1,
+        KEY_ID = 2,
+        ALGORITHM = 3,
+        KEY_OPS = 4,
+        CURVE = -1,
+        PUBKEY_X = -2,
+        PUBKEY_Y = -3,
+        PRIVATE_KEY = -4,
+        TEST_KEY = -70000  // Application-defined
+    };
+
+    static ErrMsgOr<CoseKey> parse(const bytevec& coseKey) {
+        auto [parsedKey, _, errMsg] = cppbor::parse(coseKey);
+        if (!parsedKey) return errMsg + " when parsing key";
+        if (!parsedKey->asMap()) return "CoseKey must be a map";
+        return CoseKey(static_cast<cppbor::Map*>(parsedKey.release()));
+    }
+
+    static ErrMsgOr<CoseKey> parse(const bytevec& coseKey, CoseKeyType expectedKeyType,
+                                   CoseKeyAlgorithm expectedAlgorithm, CoseKeyCurve expectedCurve) {
+        auto key = parse(coseKey);
+        if (!key) return key;
+
+        if (!key->checkIntValue(CoseKey::KEY_TYPE, expectedKeyType) ||
+            !key->checkIntValue(CoseKey::ALGORITHM, expectedAlgorithm) ||
+            !key->checkIntValue(CoseKey::CURVE, expectedCurve)) {
+            return "Unexpected key type:";
+        }
+
+        return key;
+    }
+
+    static ErrMsgOr<CoseKey> parseEd25519(const bytevec& coseKey) {
+        auto key = parse(coseKey, OCTET_KEY_PAIR, EDDSA, ED25519);
+        if (!key) return key;
+
+        auto& pubkey = key->getMap().get(PUBKEY_X);
+        if (!pubkey || !pubkey->asBstr() ||
+            pubkey->asBstr()->value().size() != ED25519_PUBLIC_KEY_LEN) {
+            return "Invalid Ed25519 public key";
+        }
+
+        return key;
+    }
+
+    static ErrMsgOr<CoseKey> parseX25519(const bytevec& coseKey, bool requireKid) {
+        auto key = parse(coseKey, OCTET_KEY_PAIR, ECDH_ES_HKDF_256, X25519);
+        if (!key) return key;
+
+        auto& pubkey = key->getMap().get(PUBKEY_X);
+        if (!pubkey || !pubkey->asBstr() ||
+            pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
+            return "Invalid X25519 public key";
+        }
+
+        auto& kid = key->getMap().get(KEY_ID);
+        if (requireKid && (!kid || !kid->asBstr())) {
+            return "Missing KID";
+        }
+
+        return key;
+    }
+
+    static ErrMsgOr<CoseKey> parseP256(const bytevec& coseKey) {
+        auto key = parse(coseKey, EC2, ES256, P256);
+        if (!key) return key;
+
+        auto& pubkey_x = key->getMap().get(PUBKEY_X);
+        auto& pubkey_y = key->getMap().get(PUBKEY_Y);
+        if (!pubkey_x || !pubkey_y || !pubkey_x->asBstr() || !pubkey_y->asBstr() ||
+            pubkey_x->asBstr()->value().size() != 32 || pubkey_y->asBstr()->value().size() != 32) {
+            return "Invalid P256 public key";
+        }
+
+        return key;
+    }
+
+    std::optional<int> getIntValue(Label label) {
+        const auto& value = key_->get(label);
+        if (!value || !value->asInt()) return {};
+        return value->asInt()->value();
+    }
+
+    std::optional<bytevec> getBstrValue(Label label) {
+        const auto& value = key_->get(label);
+        if (!value || !value->asBstr()) return {};
+        return value->asBstr()->value();
+    }
+
+    const cppbor::Map& getMap() const { return *key_; }
+    cppbor::Map&& moveMap() { return std::move(*key_); }
+
+    bool checkIntValue(Label label, int expectedValue) {
+        const auto& value = key_->get(label);
+        return value && value->asInt() && value->asInt()->value() == expectedValue;
+    }
+
+    void add(Label label, int value) { key_->add(label, value); }
+    void add(Label label, bytevec value) { key_->add(label, std::move(value)); }
+
+    bytevec encode() { return key_->canonicalize().encode(); }
+
+  private:
+    CoseKey(cppbor::Map* parsedKey) : key_(parsedKey) {}
+
+    // This is the full parsed key structure.
+    std::unique_ptr<cppbor::Map> key_;
+};
+
+ErrMsgOr<bytevec> generateCoseMac0Mac(const bytevec& macKey, const bytevec& externalAad,
+                                      const bytevec& payload);
+ErrMsgOr<cppbor::Array> constructCoseMac0(const bytevec& macKey, const bytevec& externalAad,
+                                          const bytevec& payload);
+ErrMsgOr<bytevec /* payload */> parseCoseMac0(const cppbor::Item* macItem);
+ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
+                                                       const bytevec& macKey);
+
+ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
+                                           const bytevec& payload, const bytevec& aad);
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
+                                           const bytevec& aad);
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map extraProtectedFields,
+                                           const bytevec& payload, const bytevec& aad);
+/**
+ * Verify and parse a COSE_Sign1 message, returning the payload.
+ *
+ * @param ignoreSignature indicates whether signature verification should be skipped.  If true, no
+ *        verification of the signature will be done.
+ *
+ * @param coseSign1 is the COSE_Sign1 to verify and parse.
+ *
+ * @param signingCoseKey is a CBOR-encoded COSE_Key to use to verify the signature.  The bytevec may
+ *        be empty, in which case the function assumes that coseSign1's payload is the COSE_Key to
+ *        use, i.e. that coseSign1 is a self-signed "certificate".
+ */
+ErrMsgOr<bytevec /* payload */> verifyAndParseCoseSign1(bool ignoreSignature,
+                                                        const cppbor::Array* coseSign1,
+                                                        const bytevec& signingCoseKey,
+                                                        const bytevec& aad);
+
+ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
+                                              const bytevec& protectedParams, const bytevec& aad);
+ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
+                                             const bytevec& plaintextPayload, const bytevec& aad,
+                                             cppbor::Array recipients);
+ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>> getSenderPubKeyFromCoseEncrypt(
+        const cppbor::Item* encryptItem);
+inline ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>>
+getSenderPubKeyFromCoseEncrypt(const std::unique_ptr<cppbor::Item>& encryptItem) {
+    return getSenderPubKeyFromCoseEncrypt(encryptItem.get());
+}
+
+ErrMsgOr<bytevec /* plaintextPayload */> decryptCoseEncrypt(const bytevec& key,
+                                                            const cppbor::Item* encryptItem,
+                                                            const bytevec& aad);
+
+ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& senderPubKey, const bytevec& senderPrivKey,
+                                        const bytevec& recipientPubKey, bool senderIsA);
+
+ErrMsgOr<bytevec /* ciphertextWithTag */> aesGcmEncrypt(const bytevec& key, const bytevec& nonce,
+                                                        const bytevec& aad,
+                                                        const bytevec& plaintext);
+ErrMsgOr<bytevec /* plaintext */> aesGcmDecrypt(const bytevec& key, const bytevec& nonce,
+                                                const bytevec& aad,
+                                                const bytevec& ciphertextWithTag);
+
+}  // namespace cppcose
diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
new file mode 100644
index 0000000..5e205a2
--- /dev/null
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <cppcose/cppcose.h>
+
+namespace aidl::android::hardware::security::keymint::remote_prov {
+
+using bytevec = std::vector<uint8_t>;
+using namespace cppcose;
+
+extern bytevec kTestMacKey;
+
+/**
+ * Generates random bytes.
+ */
+bytevec randomBytes(size_t numBytes);
+
+struct EekChain {
+    bytevec chain;
+    bytevec last_pubkey;
+    bytevec last_privkey;
+};
+
+/**
+ * Generates an X25518 EEK with the specified eekId and an Ed25519 chain of the
+ * specified length. All keys are generated randomly.
+ */
+ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId);
+
+struct BccEntryData {
+    bytevec pubKey;
+};
+
+/**
+ * Validates the provided CBOR-encoded BCC, returning a vector of BccEntryData
+ * structs containing the BCC entry contents.  If an entry contains no firmware
+ * digest, the corresponding BccEntryData.firmwareDigest will have length zero
+ * (there's no way to distinguish between an empty and missing firmware digest,
+ * which seems fine).
+ */
+ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc);
+
+}  // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
new file mode 100644
index 0000000..111cb30
--- /dev/null
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include <remote_prov/remote_prov_utils.h>
+
+#include <openssl/rand.h>
+
+#include <cppbor.h>
+
+namespace aidl::android::hardware::security::keymint::remote_prov {
+
+bytevec kTestMacKey(32 /* count */, 0 /* byte value */);
+
+bytevec randomBytes(size_t numBytes) {
+    bytevec retval(numBytes);
+    RAND_bytes(retval.data(), numBytes);
+    return retval;
+}
+
+ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId) {
+    auto eekChain = cppbor::Array();
+
+    bytevec prev_priv_key;
+    for (size_t i = 0; i < length - 1; ++i) {
+        bytevec pub_key(ED25519_PUBLIC_KEY_LEN);
+        bytevec priv_key(ED25519_PRIVATE_KEY_LEN);
+
+        ED25519_keypair(pub_key.data(), priv_key.data());
+
+        // The first signing key is self-signed.
+        if (prev_priv_key.empty()) prev_priv_key = priv_key;
+
+        auto coseSign1 = constructCoseSign1(prev_priv_key,
+                                            cppbor::Map() /* payload CoseKey */
+                                                    .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+                                                    .add(CoseKey::ALGORITHM, EDDSA)
+                                                    .add(CoseKey::CURVE, ED25519)
+                                                    .add(CoseKey::PUBKEY_X, pub_key)
+                                                    .canonicalize()
+                                                    .encode(),
+                                            {} /* AAD */);
+        if (!coseSign1) return coseSign1.moveMessage();
+        eekChain.add(coseSign1.moveValue());
+    }
+
+    bytevec pub_key(X25519_PUBLIC_VALUE_LEN);
+    bytevec priv_key(X25519_PRIVATE_KEY_LEN);
+    X25519_keypair(pub_key.data(), priv_key.data());
+
+    auto coseSign1 = constructCoseSign1(prev_priv_key,
+                                        cppbor::Map() /* payload CoseKey */
+                                                .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+                                                .add(CoseKey::KEY_ID, eekId)
+                                                .add(CoseKey::ALGORITHM, ECDH_ES_HKDF_256)
+                                                .add(CoseKey::CURVE, cppcose::X25519)
+                                                .add(CoseKey::PUBKEY_X, pub_key)
+                                                .canonicalize()
+                                                .encode(),
+                                        {} /* AAD */);
+    if (!coseSign1) return coseSign1.moveMessage();
+    eekChain.add(coseSign1.moveValue());
+
+    return EekChain{eekChain.encode(), pub_key, priv_key};
+}
+
+ErrMsgOr<bytevec> verifyAndParseCoseSign1Cwt(bool ignoreSignature, const cppbor::Array* coseSign1,
+                                             const bytevec& signingCoseKey, const bytevec& aad) {
+    if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
+        return "Invalid COSE_Sign1";
+    }
+
+    const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
+    const cppbor::Bstr* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asBstr();
+    const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
+    const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
+
+    if (!protectedParams || !unprotectedParams || !payload || !signature) {
+        return "Invalid COSE_Sign1";
+    }
+
+    auto [parsedProtParams, _, errMsg] = cppbor::parse(protectedParams);
+    if (!parsedProtParams) {
+        return errMsg + " when parsing protected params.";
+    }
+    if (!parsedProtParams->asMap()) {
+        return "Protected params must be a map";
+    }
+
+    auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
+    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
+        return "Unsupported signature algorithm";
+    }
+
+    // TODO(jbires): Handle CWTs as the CoseSign1 payload in a less hacky way. Since the CWT payload
+    //               is extremely remote provisioning specific, probably just make a separate
+    //               function there.
+    auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(payload);
+    if (!parsedPayload) return payloadErrMsg + " when parsing key";
+    if (!parsedPayload->asMap()) return "CWT must be a map";
+    auto serializedKey = parsedPayload->asMap()->get(-4670552)->clone();
+    if (!serializedKey || !serializedKey->asBstr()) return "Could not find key entry";
+
+    if (!ignoreSignature) {
+        bool selfSigned = signingCoseKey.empty();
+        auto key = CoseKey::parseEd25519(selfSigned ? serializedKey->asBstr()->value()
+                                                    : signingCoseKey);
+        if (!key) return "Bad signing key: " + key.moveMessage();
+
+        bytevec signatureInput = cppbor::Array()
+                                         .add("Signature1")
+                                         .add(*protectedParams)
+                                         .add(aad)
+                                         .add(*payload)
+                                         .encode();
+
+        if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
+                            key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
+            return "Signature verification failed";
+        }
+    }
+
+    return serializedKey->asBstr()->value();
+}
+ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc) {
+    if (!bcc || bcc->size() == 0) return "Invalid BCC";
+
+    std::vector<BccEntryData> result;
+
+    bytevec prevKey;
+    // TODO(jbires): Actually process the pubKey at the start of the new bcc entry
+    for (size_t i = 1; i < bcc->size(); ++i) {
+        const cppbor::Array* entry = bcc->get(i)->asArray();
+        if (!entry || entry->size() != kCoseSign1EntryCount) {
+            return "Invalid BCC entry " + std::to_string(i) + ": " + prettyPrint(entry);
+        }
+        auto payload = verifyAndParseCoseSign1Cwt(false /* ignoreSignature */, entry,
+                                                  std::move(prevKey), bytevec{} /* AAD */);
+        if (!payload) {
+            return "Failed to verify entry " + std::to_string(i) + ": " + payload.moveMessage();
+        }
+
+        auto& certProtParms = entry->get(kCoseSign1ProtectedParams);
+        if (!certProtParms || !certProtParms->asBstr()) return "Invalid prot params";
+        auto [parsedProtParms, _, errMsg] = cppbor::parse(certProtParms->asBstr()->value());
+        if (!parsedProtParms || !parsedProtParms->asMap()) return "Invalid prot params";
+
+        result.push_back(BccEntryData{*payload});
+
+        // This entry's public key is the signing key for the next entry.
+        prevKey = payload.moveValue();
+    }
+
+    return result;
+}
+
+}  // namespace aidl::android::hardware::security::keymint::remote_prov