summaryrefslogtreecommitdiff
path: root/security/keymint/support/cppcose.cpp
diff options
context:
space:
mode:
authorMax Bires <jbires@google.com>2021-04-07 11:12:01 -0700
committerMax Bires <jbires@google.com>2021-04-17 18:19:28 -0700
commit9704ff6b85b97ba8ee4ac5056efa1878024d8e2c (patch)
treeb4dd64d3bb61c50b372837e8c5b6c369ecc5ecb7 /security/keymint/support/cppcose.cpp
parent6594b5f1b4a65fb22e12c1c42dad235feb6ae69d (diff)
Porting IRPC functionality.
This is the change that removes the functionality that has been shifted over to appropriate classes and contexts in system/keymaster. Test: atest VtsHalRemotelyProvisionedComponentTargetTest Change-Id: I491f4ef823868322ea6a804d88ca09662c099a44
Diffstat (limited to 'security/keymint/support/cppcose.cpp')
-rw-r--r--security/keymint/support/cppcose.cpp467
1 files changed, 0 insertions, 467 deletions
diff --git a/security/keymint/support/cppcose.cpp b/security/keymint/support/cppcose.cpp
deleted file mode 100644
index bafb2b6bc9..0000000000
--- a/security/keymint/support/cppcose.cpp
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * 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::Map() /* 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)->asMap();
- 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)->asMap();
- 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(cppbor::Map() /* 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::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
- 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