diff --git a/TeepUnitTest/ProtocolTests.cpp b/TeepUnitTest/ProtocolTests.cpp index 303f678..0ff4453 100644 --- a/TeepUnitTest/ProtocolTests.cpp +++ b/TeepUnitTest/ProtocolTests.cpp @@ -62,10 +62,10 @@ static void TestConfigureKeys(teep_signature_kind_t signatureKind) char agent_public_key_filename[256]; REQUIRE(StartAgentBroker(TEEP_AGENT_DATA_DIRECTORY, TRUE, signatureKind, agent_public_key_filename) == 0); - // Copy Agent keys to TAM + // Copy Agent keys to TAM. CopyFile(agent_public_key_filename, TAM_DATA_DIRECTORY "/trusted"); - // Copy TAM keys to Agent + // Copy TAM keys to Agent. char tam_public_key_filename[256]; TamGetPublicKey(signatureKind, tam_public_key_filename); CopyFile(tam_public_key_filename, TEEP_AGENT_DATA_DIRECTORY "/trusted"); diff --git a/protocol/TeepAgentLib/AgentKeys.cpp b/protocol/TeepAgentLib/AgentKeys.cpp index d88c1a3..374ffe2 100644 --- a/protocol/TeepAgentLib/AgentKeys.cpp +++ b/protocol/TeepAgentLib/AgentKeys.cpp @@ -26,7 +26,7 @@ void TeepAgentGetSigningKeyPair(_Out_ struct t_cose_key* keyPair, _Out_ teep_sig *kind = g_teep_agent_signing_key_kind; } -vector g_tam_key_pairs; +map g_tam_key_pairs; /* TODO: This is just a placeholder for a real implementation. * Currently we provide untrusted keys into the TAM. @@ -64,14 +64,15 @@ teep_error_code_t TeepAgentConfigureTamKeys(_In_z_ const char* directory_name) if (result != TEEP_ERR_SUCCESS) { break; } - g_tam_key_pairs.emplace_back(key_pair); + teep_signature_kind_t kind = (strstr(filename, "es256") != nullptr) ? TEEP_SIGNATURE_ES256 : TEEP_SIGNATURE_EDDSA; + g_tam_key_pairs[kind] = key_pair; } closedir(dir); return result; } /* Get the TEEP Agents' public keys to verify an incoming message against. */ -vector TeepAgentGetTamKeys() +map TeepAgentGetTamKeys() { return g_tam_key_pairs; } diff --git a/protocol/TeepAgentLib/AgentKeys.h b/protocol/TeepAgentLib/AgentKeys.h index 9727a23..15a4cd7 100644 --- a/protocol/TeepAgentLib/AgentKeys.h +++ b/protocol/TeepAgentLib/AgentKeys.h @@ -1,10 +1,10 @@ // Copyright (c) TEEP contributors // SPDX-License-Identifier: MIT #pragma once -#include +#include teep_error_code_t TeepAgentConfigureTamKeys(_In_z_ const char* directory_name); -std::vector TeepAgentGetTamKeys(); +std::map TeepAgentGetTamKeys(); void TeepAgentGetSigningKeyPair(_Out_ struct t_cose_key* keyPair, _Out_ teep_signature_kind_t* kind); \ No newline at end of file diff --git a/protocol/TeepAgentLib/TeepAgent.cpp b/protocol/TeepAgentLib/TeepAgent.cpp index 9ce6575..6dc3ad7 100644 --- a/protocol/TeepAgentLib/TeepAgent.cpp +++ b/protocol/TeepAgentLib/TeepAgent.cpp @@ -754,8 +754,8 @@ static teep_error_code_t TeepAgentVerifyMessageSignature( UsefulBufC signed_cose; signed_cose.ptr = message; signed_cose.len = messageLength; - for (auto key_pair : TeepAgentGetTamKeys()) { - teep_error_code_t teeperr = teep_verify_cbor_message(&key_pair, &signed_cose, pencoded); + for (auto [kind, key_pair] : TeepAgentGetTamKeys()) { + teep_error_code_t teeperr = teep_verify_cbor_message(kind, &key_pair, &signed_cose, pencoded); if (teeperr == TEEP_ERR_SUCCESS) { // TODO(#114): save key_pair in session return TEEP_ERR_SUCCESS; diff --git a/protocol/TeepCommonLib/TeepCommonLib.vcxproj b/protocol/TeepCommonLib/TeepCommonLib.vcxproj index 466df56..84384eb 100644 --- a/protocol/TeepCommonLib/TeepCommonLib.vcxproj +++ b/protocol/TeepCommonLib/TeepCommonLib.vcxproj @@ -82,6 +82,7 @@ Level3 $(ProgramW6432)\openssl\include;$(SolutionDir)external\openssl\include;$(SolutionDir)external\openssl\_build\include;$(SolutionDir)external/t_cose/inc;$(SolutionDir)external/qcbor/inc MultiThreadedDebug + stdcpp17 $(OutDir);%(AdditionalLibraryDirectories) diff --git a/protocol/TeepCommonLib/common.cpp b/protocol/TeepCommonLib/common.cpp index 17848f4..2fbbab2 100644 --- a/protocol/TeepCommonLib/common.cpp +++ b/protocol/TeepCommonLib/common.cpp @@ -223,6 +223,34 @@ teep_error_code_t TeepInitialize(_In_z_ const char* signing_private_key_pair_fil return teep_load_signing_key_pair(&key_pair, signing_private_key_pair_filename, signing_public_key_filename, signature_kind); } +teep_error_code_t +teep_compute_key_id(teep_signature_kind_t signature_kind, _In_ const struct t_cose_key* key_pair, _Out_ UsefulBuf* key_id) +{ +#if 1 + // TODO: this is not correct or secure, switch to the other code path once we + // can get the public key from a t_cose_key key pair. + *(teep_signature_kind_t*)key_id->ptr = signature_kind; + key_id->len = sizeof(signature_kind); + return TEEP_ERR_SUCCESS; +#else + // Get the public key. + if (signature_kind == TEEP_SIGNATURE_ES256) { + } + else { + } + + // Compute SHA-256 hash. + unsigned char hash[SHA256_DIGEST_LENGTH]; + SHA256_CTX sha256; + SHA256_Init(&sha256); + SHA256_Update(&sha256, public_key.key.buffer.ptr, public_key.key.buffer.len); + SHA256_Final(hash, &sha256); + + *key_id = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(hash); + return TEEP_ERR_PERMANENT_ERROR; +#endif +} + teep_error_code_t teep_sign1_cbor_message( _In_ const struct t_cose_key* key_pair, @@ -234,7 +262,12 @@ teep_sign1_cbor_message( // Initialize for signing. struct t_cose_sign1_sign_ctx sign_ctx; t_cose_sign1_sign_init(&sign_ctx, 0, get_cose_algorithm(signature_kind)); - t_cose_sign1_set_signing_key(&sign_ctx, *key_pair, NULL_Q_USEFUL_BUF_C); + UsefulBuf_MAKE_STACK_UB(key_id, SHA256_DIGEST_LENGTH); + teep_error_code_t result = teep_compute_key_id(signature_kind, key_pair, &key_id); + if (result != TEEP_ERR_SUCCESS) { + return result; + } + t_cose_sign1_set_signing_key(&sign_ctx, *key_pair, UsefulBuf_Const(key_id)); // Compute the size of the output and auxiliary buffers. struct q_useful_buf null_buff { NULL, SIZE_MAX }; @@ -292,19 +325,90 @@ teep_sign_cbor_message( teep_signature_kind_t signature_kind, _Out_ UsefulBufC* signed_message) { - // TODO(#104): t_cose 2.0 should support Sign. - // Switch to it once it's ready and supports EdDSA. - // In the meantime, we just use Sign1 ES256. + // Initialize for signing. + struct t_cose_sign_sign_ctx sign_ctx; + t_cose_sign_sign_init(&sign_ctx, T_COSE_OPT_MESSAGE_TYPE_SIGN); + + struct t_cose_signature_sign_eddsa eddsa_signer; + struct t_cose_signature_sign_main es256_signer; + UsefulBuf_MAKE_STACK_UB(eddsa_key_id, SHA256_DIGEST_LENGTH); + UsefulBuf_MAKE_STACK_UB(es256_key_id, SHA256_DIGEST_LENGTH); + for (const auto& [kind, key_pair] : key_pairs) { + int32_t algorithm_id = (kind == TEEP_SIGNATURE_ES256) ? T_COSE_ALGORITHM_ES256 : T_COSE_ALGORITHM_EDDSA; + if (kind == TEEP_SIGNATURE_ES256) { + t_cose_signature_sign_main_init(&es256_signer, algorithm_id); + teep_error_code_t result = teep_compute_key_id(kind, &key_pair, &es256_key_id); + if (result != TEEP_ERR_SUCCESS) { + return result; + } + t_cose_signature_sign_main_set_signing_key(&es256_signer, key_pair, UsefulBuf_Const(es256_key_id)); + t_cose_sign_add_signer(&sign_ctx, t_cose_signature_sign_from_main(&es256_signer)); + } else { + t_cose_signature_sign_eddsa_init(&eddsa_signer); + teep_error_code_t result = teep_compute_key_id(kind, &key_pair, &eddsa_key_id); + if (result != TEEP_ERR_SUCCESS) { + return result; + } + t_cose_signature_sign_eddsa_set_signing_key(&eddsa_signer, key_pair, UsefulBuf_Const(eddsa_key_id)); + t_cose_sign_add_signer(&sign_ctx, t_cose_signature_sign_from_eddsa(&eddsa_signer)); + + // Compute the size of the output and auxiliary buffers. + struct q_useful_buf null_buff { NULL, SIZE_MAX }; + struct q_useful_buf_c signed_cose; + enum t_cose_err_t return_value = t_cose_sign_sign(&sign_ctx, + NULL_Q_USEFUL_BUF_C, // No externally supplied AAD. + *unsigned_message, + null_buff, + &signed_cose); + + // Allocate buffers of the right size. + if (signed_cose.len > signed_message_buffer.len) { + return TEEP_ERR_TEMPORARY_ERROR; + } + struct q_useful_buf auxiliary_buffer = {}; + auxiliary_buffer.len = t_cose_signature_sign_eddsa_auxiliary_buffer_size(&eddsa_signer); + if (auxiliary_buffer.len > 0) { + // TODO: remove workaround for https://github.com/laurencelundblade/t_cose/issues/251 + // once it is fixed. + auxiliary_buffer.len += 50; + + auxiliary_buffer.ptr = malloc(auxiliary_buffer.len); + if (auxiliary_buffer.ptr == NULL) { + return TEEP_ERR_TEMPORARY_ERROR; + } + } + + t_cose_signature_sign_eddsa_set_auxiliary_buffer(&eddsa_signer, auxiliary_buffer); + } + } - return teep_sign1_cbor_message(&key_pairs[TEEP_SIGNATURE_ES256], - unsigned_message, + // Sign. + enum t_cose_err_t return_value = t_cose_sign_sign(&sign_ctx, + NULL_Q_USEFUL_BUF_C, // No externally supplied AAD. + *unsigned_message, + /* Non-const pointer and length of the + * buffer where the completed output is + * written to. The length here is that + * of the whole buffer. + */ signed_message_buffer, - TEEP_SIGNATURE_ES256, + /* Const pointer and actual length of + * the completed, signed and encoded + * COSE_Sign1 message. This points + * into the output buffer and has the + * lifetime of the output buffer. + */ signed_message); + if (return_value != T_COSE_SUCCESS) { + TeepLogMessage("COSE Sign failed with error %d\n", return_value); + return TEEP_ERR_PERMANENT_ERROR; + } + + return TEEP_ERR_SUCCESS; } teep_error_code_t -teep_verify_cbor_message( +teep_verify_cbor_message_sign1( _In_ const struct t_cose_key* key_pair, _In_ const UsefulBufC* signed_cose, _Out_ UsefulBufC* encoded) @@ -313,7 +417,7 @@ teep_verify_cbor_message( t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_DECODE_ONLY); UsefulBufC payload = {}; - int return_value = t_cose_sign1_verify(&verify_ctx, *signed_cose, &payload, nullptr); + t_cose_err_t return_value = t_cose_sign1_verify(&verify_ctx, *signed_cose, &payload, nullptr); if (return_value != T_COSE_SUCCESS) { TeepLogMessage("First t_cose_sign1_verify failed with error %d\n", return_value); return TEEP_ERR_PERMANENT_ERROR; @@ -338,7 +442,7 @@ teep_verify_cbor_message( return_value = t_cose_sign1_verify(&verify_ctx, *signed_cose, /* COSE to verify */ encoded, /* Payload from signed_cose */ - NULL); /* Don't return parameters */ + nullptr); /* Don't return parameters */ free(auxiliary_buffer.ptr); if (return_value != T_COSE_SUCCESS) { TeepLogMessage("Second t_cose_sign1_verify failed with error %d\n", return_value); @@ -348,6 +452,90 @@ teep_verify_cbor_message( return TEEP_ERR_SUCCESS; } +teep_error_code_t +teep_verify_cbor_message_sign( + teep_signature_kind_t signature_kind, + _In_ const struct t_cose_key* key_pair, + _In_ const UsefulBufC* signed_cose, + _Out_ UsefulBufC* encoded) +{ + struct t_cose_sign_verify_ctx verify_ctx; + + UsefulBuf_MAKE_STACK_UB(key_id, SHA256_DIGEST_LENGTH); + teep_error_code_t result = teep_compute_key_id(signature_kind, key_pair, &key_id); + if (result != TEEP_ERR_SUCCESS) { + return result; + } + + // Initialize verifiers. + t_cose_sign_verify_init(&verify_ctx, T_COSE_OPT_DECODE_ONLY); + struct t_cose_signature_verify_main es256_verifier; + struct t_cose_signature_verify_eddsa eddsa_verifier; + if (signature_kind == TEEP_SIGNATURE_ES256) { + // ES256 verifier. + t_cose_signature_verify_main_init(&es256_verifier); + t_cose_signature_verify_main_set_key(&es256_verifier, *key_pair, UsefulBuf_Const(key_id)); + t_cose_sign_add_verifier(&verify_ctx, t_cose_signature_verify_from_main(&es256_verifier)); + } else { + // EdDSA verifier. + t_cose_signature_verify_eddsa_init(&eddsa_verifier, 0); + t_cose_signature_verify_eddsa_set_key(&eddsa_verifier, *key_pair, UsefulBuf_Const(key_id)); + t_cose_sign_add_verifier(&verify_ctx, t_cose_signature_verify_from_eddsa(&eddsa_verifier)); + } + + // Compute the auxiliary buffer size needed. + // TODO: this code path is blocked on https://github.com/laurencelundblade/t_cose/issues/252 + // which causes t_cose_sign_verify to fail when it shouldn't. + UsefulBufC payload = {}; + t_cose_err_t return_value = t_cose_sign_verify(&verify_ctx, *signed_cose, NULL_Q_USEFUL_BUF_C, &payload, nullptr); + if (return_value != T_COSE_SUCCESS) { + TeepLogMessage("First t_cose_sign1_verify failed with error %d\n", return_value); + return TEEP_ERR_PERMANENT_ERROR; + } + + // Allocate an auxiliary buffer of the right size. + struct q_useful_buf auxiliary_buffer = {}; + auxiliary_buffer.len = t_cose_signature_verify_eddsa_auxiliary_buffer_size(&eddsa_verifier); + if (auxiliary_buffer.len > 0) { + auxiliary_buffer.ptr = malloc(auxiliary_buffer.len); + if (auxiliary_buffer.ptr == NULL) { + TeepLogMessage("teep_verify_cbor_message could not allocate %d bytes\n", auxiliary_buffer.len); + return TEEP_ERR_TEMPORARY_ERROR; + } + } + t_cose_signature_verify_eddsa_set_auxiliary_buffer(&eddsa_verifier, auxiliary_buffer); + + // Do the actual verification. + t_cose_sign_verify_init(&verify_ctx, 0); + return_value = t_cose_sign_verify(&verify_ctx, + *signed_cose, /* COSE to verify */ + NULL_Q_USEFUL_BUF_C, /* No AAD */ + encoded, /* Payload from signed_cose */ + nullptr); /* Don't return parameters */ + if (return_value != T_COSE_SUCCESS) { + TeepLogMessage("Second t_cose_sign_verify failed with error %d\n", return_value); + return TEEP_ERR_PERMANENT_ERROR; + } + + return TEEP_ERR_SUCCESS; +} + +teep_error_code_t +teep_verify_cbor_message( + teep_signature_kind_t signature_kind, + _In_ const struct t_cose_key* key_pair, + _In_ const UsefulBufC* signed_cose, + _Out_ UsefulBufC* encoded) +{ +#if 0 + teep_error_code_t result = teep_verify_cbor_message_sign1(key_pair, signed_cose, encoded); + if (result == TEEP_ERR_SUCCESS) { + return TEEP_ERR_SUCCESS; + } +#endif + return teep_verify_cbor_message_sign(signature_kind, key_pair, signed_cose, encoded); +} + #ifdef TEEP_USE_CERTIFICATES // Currently unused. _Ret_writes_bytes_maybenull_(*pCertificateSize) const unsigned char* GetDerCertificate( diff --git a/protocol/TeepCommonLib/common.h b/protocol/TeepCommonLib/common.h index 73a17a2..6596709 100644 --- a/protocol/TeepCommonLib/common.h +++ b/protocol/TeepCommonLib/common.h @@ -85,6 +85,7 @@ teep_sign_cbor_message( teep_error_code_t teep_verify_cbor_message( + teep_signature_kind_t signature_kind, _In_ const struct t_cose_key* key_pair, _In_ const UsefulBufC* signed_cose, _Out_ UsefulBufC* encoded); diff --git a/protocol/TeepTamLib/TamKeys.cpp b/protocol/TeepTamLib/TamKeys.cpp index 6a4919b..0bb1326 100644 --- a/protocol/TeepTamLib/TamKeys.cpp +++ b/protocol/TeepTamLib/TamKeys.cpp @@ -25,7 +25,7 @@ teep_error_code_t TamGetSigningKeyPairs(_Out_ std::map g_agent_key_pairs; +map g_agent_key_pairs; /* TODO: This is just a placeholder for a real implementation. * Currently we provide untrusted keys into the TAM. @@ -63,7 +63,8 @@ teep_error_code_t TamConfigureAgentKeys(_In_z_ const char* directory_name) if (result != TEEP_ERR_SUCCESS) { break; } - g_agent_key_pairs.emplace_back(key_pair); + teep_signature_kind_t kind = (strstr(filename, "es256") != nullptr) ? TEEP_SIGNATURE_ES256 : TEEP_SIGNATURE_EDDSA; + g_agent_key_pairs[kind] = key_pair; TeepLogMessage("TAM loaded TEEP agent key from %s\n", keyfile.c_str()); } @@ -72,7 +73,7 @@ teep_error_code_t TamConfigureAgentKeys(_In_z_ const char* directory_name) } /* Get the TEEP Agents' public keys to verify an incoming message against. */ -vector TamGetTeepAgentKeys() +map TamGetTeepAgentKeys() { return g_agent_key_pairs; } diff --git a/protocol/TeepTamLib/TamKeys.h b/protocol/TeepTamLib/TamKeys.h index 7b7df2c..acb5e87 100644 --- a/protocol/TeepTamLib/TamKeys.h +++ b/protocol/TeepTamLib/TamKeys.h @@ -2,11 +2,10 @@ // SPDX-License-Identifier: MIT #pragma once #include -#include teep_error_code_t TamConfigureAgentKeys(_In_z_ const char* directory_name); -std::vector TamGetTeepAgentKeys(); +std::map TamGetTeepAgentKeys(); teep_error_code_t TamGetSigningKeyPairs(_Out_ std::map& key_pairs); diff --git a/protocol/TeepTamLib/TeepTamMessageHandler.cpp b/protocol/TeepTamLib/TeepTamMessageHandler.cpp index a1dd896..de74980 100644 --- a/protocol/TeepTamLib/TeepTamMessageHandler.cpp +++ b/protocol/TeepTamLib/TeepTamMessageHandler.cpp @@ -396,7 +396,7 @@ static teep_error_code_t TamSendErrorUpdateMessage(_In_ void* sessionHandle, tee TeepLogMessage("Sending Update message...\n"); - err = TamSendMessage(sessionHandle, TEEP_CBOR_MEDIA_TYPE, &update, TEEP_SIGNATURE_ES256); + err = TamSendMessage(sessionHandle, TEEP_CBOR_MEDIA_TYPE, &update, TEEP_SIGNATURE_ES256); // XXX free((void*)update.ptr); if (err != TEEP_ERR_SUCCESS) { return err; @@ -672,7 +672,7 @@ static teep_error_code_t TamHandleQueryResponse( TeepLogMessage("Sending Update message...\n"); - err = TamSendMessage(sessionHandle, TEEP_CBOR_MEDIA_TYPE, &update, TEEP_SIGNATURE_ES256); + err = TamSendMessage(sessionHandle, TEEP_CBOR_MEDIA_TYPE, &update, TEEP_SIGNATURE_ES256); // XXX free((void*)update.ptr); if (err != TEEP_ERR_SUCCESS) { return err; @@ -771,8 +771,8 @@ static teep_error_code_t TamVerifyMessageSignature( UsefulBufC signed_cose; signed_cose.ptr = message; signed_cose.len = messageLength; - for (auto key_pair : TamGetTeepAgentKeys()) { - teep_error_code_t teeperr = teep_verify_cbor_message(&key_pair, &signed_cose, pencoded); + for (auto [kind, key_pair] : TamGetTeepAgentKeys()) { + teep_error_code_t teeperr = teep_verify_cbor_message(kind, &key_pair, &signed_cose, pencoded); if (teeperr == TEEP_ERR_SUCCESS) { // TODO(#114): save key_pair in session return TEEP_ERR_SUCCESS;