From 4bb3c1e0acba091dcde106fd8d7a77217acd2a77 Mon Sep 17 00:00:00 2001 From: Amaury Chamayou Date: Thu, 15 Aug 2024 15:10:24 +0100 Subject: [PATCH 1/8] Address issue with embedded certificates in JWT x5c (#6440) Co-authored-by: Max --- CHANGELOG.md | 8 ++ src/crypto/openssl/openssl_wrappers.h | 27 +++++- src/crypto/openssl/verifier.cpp | 11 +++ src/crypto/pem.cpp | 11 ++- src/crypto/test/crypto.cpp | 134 ++++++++++++++++++++++++++ src/crypto/test/pem.cpp | 41 ++++++-- 6 files changed, 219 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70de64b11571..437388f956f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [5.0.4] + +[5.0.4]: https://github.com/microsoft/CCF/releases/tag/ccf-5.0.4 + +### Bug fix + +- JWT authentication correctly parses certificates that contain other certificates (#6440) + ## [5.0.3] [5.0.3]: https://github.com/microsoft/CCF/releases/tag/ccf-5.0.3 diff --git a/src/crypto/openssl/openssl_wrappers.h b/src/crypto/openssl/openssl_wrappers.h index da54cbde91b8..92a797222a29 100644 --- a/src/crypto/openssl/openssl_wrappers.h +++ b/src/crypto/openssl/openssl_wrappers.h @@ -255,16 +255,35 @@ namespace ccf::crypto {} }; + static const char pem_prefix[] = "-----BEGIN CERTIFICATE-----\n"; + // -1 for the null terminator + static constexpr size_t pem_prefix_len = sizeof(pem_prefix) - 1; + + // Check BIO starts with PEM prefix before attempting to read it as PEM + // because PEM_read_bio_X509 is permissive and will skip over non-PEM data, + // which may for example result in a DER containing nested PEM being read + // as the nested certificate. + inline X509* read_pem(BIO* mem) + { + std::vector buf(pem_prefix_len); + auto read = BIO_read(mem, buf.data(), pem_prefix_len); + BIO_reset(mem); + if ( + read != pem_prefix_len || + std::memcmp(buf.data(), pem_prefix, read) != 0) + { + return nullptr; + } + return PEM_read_bio_X509(mem, NULL, NULL, NULL); + }; + struct Unique_X509 : public Unique_SSL_OBJECT { using Unique_SSL_OBJECT::Unique_SSL_OBJECT; // p == nullptr is OK (e.g. wrong format) Unique_X509(BIO* mem, bool pem, bool check_null = false) : Unique_SSL_OBJECT( - pem ? PEM_read_bio_X509(mem, NULL, NULL, NULL) : - d2i_X509_bio(mem, NULL), - X509_free, - check_null) + pem ? read_pem(mem) : d2i_X509_bio(mem, NULL), X509_free, check_null) {} Unique_X509(X509* cert, bool check_null) : Unique_SSL_OBJECT(cert, X509_free, check_null) diff --git a/src/crypto/openssl/verifier.cpp b/src/crypto/openssl/verifier.cpp index 5ebe4a34547c..cd192854b713 100644 --- a/src/crypto/openssl/verifier.cpp +++ b/src/crypto/openssl/verifier.cpp @@ -116,6 +116,12 @@ namespace ccf::crypto { Unique_BIO tcbio(*pem); Unique_X509 tc(tcbio, true); + if (tc == nullptr) + { + LOG_DEBUG_FMT("Failed to load certificate from PEM: {}", pem->str()); + return false; + } + CHECK1(X509_STORE_add_cert(store, tc)); } @@ -124,6 +130,11 @@ namespace ccf::crypto { Unique_BIO certbio(*pem); Unique_X509 cert(certbio, true); + if (cert == nullptr) + { + LOG_DEBUG_FMT("Failed to load certificate from PEM: {}", pem->str()); + return false; + } CHECK1(sk_X509_push(chain_stack, cert)); CHECK1(X509_up_ref(cert)); diff --git a/src/crypto/pem.cpp b/src/crypto/pem.cpp index 2895c4e0abec..43365bf81177 100644 --- a/src/crypto/pem.cpp +++ b/src/crypto/pem.cpp @@ -42,8 +42,15 @@ namespace ccf::crypto auto next_separator_start = pem.find(separator); while (next_separator_start != std::string_view::npos) { - pems.emplace_back(std::string( - pem.substr(separator_end, next_separator_start + separator.size()))); + // Trim whitespace between certificates + while (separator_end < next_separator_start && + std::isspace(pem[separator_end])) + { + ++separator_end; + } + pems.emplace_back(std::string(pem.substr( + separator_end, + (next_separator_start - separator_end) + separator.size()))); separator_end = next_separator_start + separator.size(); next_separator_start = pem.find(separator, separator_end); } diff --git a/src/crypto/test/crypto.cpp b/src/crypto/test/crypto.cpp index 3c6e7132bd58..35bce3efa4c3 100644 --- a/src/crypto/test/crypto.cpp +++ b/src/crypto/test/crypto.cpp @@ -44,6 +44,127 @@ static const string contents_ = vector contents(contents_.begin(), contents_.end()); +static const string nested_cert = + "MIIV1zCCFL+" + "gAwIBAgIBATANBgkqhkiG9w0BAQsFADAzMTEwLwYDVQQDDChodHRwczovL3NoYXJlZGV1czIuZXV" + "zMi5hdHRlc3QuYXp1cmUubmV0MCIYDzIwMTkwNTAxMDAwMDAwWhgPMjA1MDEyMzEyMzU5NTlaMDM" + "xMTAvBgNVBAMMKGh0dHBzOi8vc2hhcmVkZXVzMi5ldXMyLmF0dGVzdC5henVyZS5uZXQwggEiMA0" + "GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDY0GsRB3BdTNXLan5JnuwGPFtV3iJMY0RAm78638L" + "Q0LNcgNPoMwQB5VktKhZZxbqhdDzWH7JBa3D6MVb9I+" + "AbgUZIvVSdU7xlqTzS2Gi9CTR1tkOj72Wyg6c59d89QvRP0CAe2omlSve0J/" + "JFEt0LQyAXW0DKNlsyPxsd7ZmYn0YtMlPm/0TSLmXdLhZljna8zNlpWl/" + "HD7T+zm1HNyg8aoisw6df/uS/mPuyKypko2rp8/7gwe8tv+1fIcKRboXNfyZSXDJE3ME/" + "dHjFpcG/KTMkxoCIJb9iv9PHJx2ebCxNHuF7VDvyrXYqdiou9RWOD+/f39FYZJsWdo/" + "VhfkfAgMBAAGjghLwMIIS7DAJBgNVHRMEAjAAMB0GA1UdDgQWBBRLSJIoQYE9YTEPZ30bgjdlv/" + "RNDzAfBgNVHSMEGDAWgBRLSJIoQYE9YTEPZ30bgjdlv/" + "RNDzCCEp0GCSsGAQQBgjdpAQSCEo4BAAAAAgAAAH4SAAAAAAAAAwACAAAAAAAKAA8Ak5pyM/" + "ecTKmUCg2zlX8GBz6f+cAQUwPfmJD+H0OHgqMAAAAADg4QD///" + "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAA" + "AMG+d2W08VnHBjXWJzQgwpztMaXmeuK7Kha4P/" + "IN14L3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0ul+" + "6IIVxz5nh9xWOZTagW7ts54B+749ql/" + "ZKevZLgwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnSkA919" + "dcepZaKaCsfznfAwh2Hn98t7XPq5Jdg9cJrQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAyhAAABbJ695qIni/27w8wj0BRxIueJMn4SZTntdR7/" + "e+s5ajJc+jMXwish9akKmwKqeRdyX3cDnkAjPvY0AjYi/" + "39FZtwI3hoTxkyWE3Vpk8IdKJU+oomqS8snlNp+oT+" + "ClCyILcP78X1k0xk5vi2OO44ktNBTyHIVWAKSSdxNj39TBxDg4QD///" + "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQAAAAAAAADnAAAAAAAA" + "AB7AKOTzYYZbiudS8D7kBDlbIscxEdPw8/" + "tDnGuibpX2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMT1d115ZQPpYTf3fGioKaAF" + "asje1wFAsIGwlEkMV7/" + "wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEACgAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvByKZT5Gm6A9i+" + "eXoH22RqqvB4tf80tEosVAMAK0h0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaWdf+" + "dceUZCkBvD8ZTZQDgzklLWu5NJKI+" + "QZb3tC4f7ORUBfklfihcUZXLT3Uc4L8jaXnpDYbMplAIsUMueifCAAAAECAwQFBgcICQoLDA0ODx" + "AREhMUFRYXGBkaGxwdHh8FAGIOAAAtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRTlEQ0" + "NCSm1nQXdJQkFnSVZBTkxaR05BSUVTOVN3QVA4ZGFocnlTN0daamVqTUFvR0NDcUdTTTQ5QkFNQw" + "pNSEF4SWpBZ0JnTlZCQU1NR1VsdWRHVnNJRk5IV0NCUVEwc2dVR3hoZEdadmNtMGdRMEV4R2pBWU" + "JnTlZCQW9NCkVVbHVkR1ZzSUVOdmNuQnZjbUYwYVc5dU1SUXdFZ1lEVlFRSERBdFRZVzUwWVNCRG" + "JHRnlZVEVMTUFrR0ExVUUKQ0F3Q1EwRXhDekFKQmdOVkJBWVRBbFZUTUI0WERUSTBNRFF3TmpFMU" + "5EZzFNVm9YRFRNeE1EUXdOakUxTkRnMQpNVm93Y0RFaU1DQUdBMVVFQXd3WlNXNTBaV3dnVTBkWU" + "lGQkRTeUJEWlhKMGFXWnBZMkYwWlRFYU1CZ0dBMVVFCkNnd1JTVzUwWld3Z1EyOXljRzl5WVhScG" + "IyNHhGREFTQmdOVkJBY01DMU5oYm5SaElFTnNZWEpoTVFzd0NRWUQKVlFRSURBSkRRVEVMTUFrR0" + "ExVUVCaE1DVlZNd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRQQpjR2ZYVWpWME" + "RJUDJMajNUY0pXaHJCMmhTbmlVYkRoWVVOSWozL1pLelRMcGcwUXBzS1NHbkd5amlYRFo5cEg1Cm" + "IzbE1yMndJMFpBbFBRcCsyVVV0bzRJRERqQ0NBd293SHdZRFZSMGpCQmd3Rm9BVWxXOWR6YjBiNG" + "VsQVNjblUKOURQT0FWY0wzbFF3YXdZRFZSMGZCR1F3WWpCZ29GNmdYSVphYUhSMGNITTZMeTloY0" + "drdWRISjFjM1JsWkhObApjblpwWTJWekxtbHVkR1ZzTG1OdmJTOXpaM2d2WTJWeWRHbG1hV05oZE" + "dsdmJpOTJNeTl3WTJ0amNtdy9ZMkU5CmNHeGhkR1p2Y20wbVpXNWpiMlJwYm1jOVpHVnlNQjBHQT" + "FVZERnUVdCQlRlWjU1cXR4OEpVMmI4WkFkaTh4aysKQkhReXlUQU9CZ05WSFE4QkFmOEVCQU1DQn" + "NBd0RBWURWUjBUQVFIL0JBSXdBRENDQWpzR0NTcUdTSWI0VFFFTgpBUVNDQWl3d2dnSW9NQjRHQ2" + "lxR1NJYjRUUUVOQVFFRUVQVndZZHdoWU1HbHB4Z2dOK0xnaDBFd2dnRmxCZ29xCmhraUcrRTBCRF" + "FFQ01JSUJWVEFRQmdzcWhraUcrRTBCRFFFQ0FRSUJEakFRQmdzcWhraUcrRTBCRFFFQ0FnSUIKRG" + "pBUUJnc3Foa2lHK0UwQkRRRUNBd0lCQXpBUUJnc3Foa2lHK0UwQkRRRUNCQUlCQXpBUkJnc3Foa2" + "lHK0UwQgpEUUVDQlFJQ0FQOHdFUVlMS29aSWh2aE5BUTBCQWdZQ0FnRC9NQkFHQ3lxR1NJYjRUUU" + "VOQVFJSEFnRUJNQkFHCkN5cUdTSWI0VFFFTkFRSUlBZ0VBTUJBR0N5cUdTSWI0VFFFTkFRSUpBZ0" + "VBTUJBR0N5cUdTSWI0VFFFTkFRSUsKQWdFQU1CQUdDeXFHU0liNFRRRU5BUUlMQWdFQU1CQUdDeX" + "FHU0liNFRRRU5BUUlNQWdFQU1CQUdDeXFHU0liNApUUUVOQVFJTkFnRUFNQkFHQ3lxR1NJYjRUUU" + "VOQVFJT0FnRUFNQkFHQ3lxR1NJYjRUUUVOQVFJUEFnRUFNQkFHCkN5cUdTSWI0VFFFTkFRSVFBZ0" + "VBTUJBR0N5cUdTSWI0VFFFTkFRSVJBZ0VOTUI4R0N5cUdTSWI0VFFFTkFRSVMKQkJBT0RnTUQvLz" + "hCQUFBQUFBQUFBQUFBTUJBR0NpcUdTSWI0VFFFTkFRTUVBZ0FBTUJRR0NpcUdTSWI0VFFFTgpBUV" + "FFQmdCZ2FnQUFBREFQQmdvcWhraUcrRTBCRFFFRkNnRUJNQjRHQ2lxR1NJYjRUUUVOQVFZRUVDVU" + "JVNGp5CmZ0cnVoMmNvdGVnQXlOSXdSQVlLS29aSWh2aE5BUTBCQnpBMk1CQUdDeXFHU0liNFRRRU" + "5BUWNCQVFIL01CQUcKQ3lxR1NJYjRUUUVOQVFjQ0FRRUFNQkFHQ3lxR1NJYjRUUUVOQVFjREFRRU" + "FNQW9HQ0NxR1NNNDlCQU1DQTBrQQpNRVlDSVFDeW9USFpyR3BoSVBnMHczNWJucjJTR3kyMk16T1" + "ZGODRONUhTR3JPL3B2d0loQVA4WmxOYW9aV2hBCmhibVIyUzNVSHg1SjFSS216bzIwKzZJWmpuM3" + "lScjhaCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS" + "0tCk1JSUNsakNDQWoyZ0F3SUJBZ0lWQUpWdlhjMjlHK0hwUUVuSjFQUXp6Z0ZYQzk1VU1Bb0dDQ3" + "FHU000OUJBTUMKTUdneEdqQVlCZ05WQkFNTUVVbHVkR1ZzSUZOSFdDQlNiMjkwSUVOQk1Sb3dHQV" + "lEVlFRS0RCRkpiblJsYkNCRApiM0p3YjNKaGRHbHZiakVVTUJJR0ExVUVCd3dMVTJGdWRHRWdRMn" + "hoY21FeEN6QUpCZ05WQkFnTUFrTkJNUXN3CkNRWURWUVFHRXdKVlV6QWVGdzB4T0RBMU1qRXhNRF" + "V3TVRCYUZ3MHpNekExTWpFeE1EVXdNVEJhTUhBeElqQWcKQmdOVkJBTU1HVWx1ZEdWc0lGTkhXQ0" + "JRUTBzZ1VHeGhkR1p2Y20wZ1EwRXhHakFZQmdOVkJBb01FVWx1ZEdWcwpJRU52Y25CdmNtRjBhVz" + "l1TVJRd0VnWURWUVFIREF0VFlXNTBZU0JEYkdGeVlURUxNQWtHQTFVRUNBd0NRMEV4CkN6QUpCZ0" + "5WQkFZVEFsVlRNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVOU0IvN3QyMWxYU0" + "8KMkN1enB4dzc0ZUpCNzJFeURHZ1c1clhDdHgydFZUTHE2aEtrNnorVWlSWkNucVI3cHNPdmdxRm" + "VTeGxtVGxKbAplVG1pMldZejNxT0J1ekNCdURBZkJnTlZIU01FR0RBV2dCUWlaUXpXV3AwMGlmT0" + "R0SlZTdjFBYk9TY0dyREJTCkJnTlZIUjhFU3pCSk1FZWdSYUJEaGtGb2RIUndjem92TDJObGNuUn" + "BabWxqWVhSbGN5NTBjblZ6ZEdWa2MyVnkKZG1salpYTXVhVzUwWld3dVkyOXRMMGx1ZEdWc1UwZF" + "lVbTl2ZEVOQkxtUmxjakFkQmdOVkhRNEVGZ1FVbFc5ZAp6YjBiNGVsQVNjblU5RFBPQVZjTDNsUX" + "dEZ1lEVlIwUEFRSC9CQVFEQWdFR01CSUdBMVVkRXdFQi93UUlNQVlCCkFmOENBUUF3Q2dZSUtvWk" + "l6ajBFQXdJRFJ3QXdSQUlnWHNWa2kwdytpNlZZR1czVUYvMjJ1YVhlMFlKRGoxVWUKbkErVGpEMW" + "FpNWNDSUNZYjFTQW1ENXhrZlRWcHZvNFVveWlTWXhyRFdMbVVSNENJOU5LeWZQTisKLS0tLS1FTk" + "QgQ0VSVElGSUNBVEUtLS0tLQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ2p6Q0NBal" + "NnQXdJQkFnSVVJbVVNMWxxZE5JbnpnN1NWVXI5UUd6a25CcXd3Q2dZSUtvWkl6ajBFQXdJdwphRE" + "VhTUJnR0ExVUVBd3dSU1c1MFpXd2dVMGRZSUZKdmIzUWdRMEV4R2pBWUJnTlZCQW9NRVVsdWRHVn" + "NJRU52CmNuQnZjbUYwYVc5dU1SUXdFZ1lEVlFRSERBdFRZVzUwWVNCRGJHRnlZVEVMTUFrR0ExVU" + "VDQXdDUTBFeEN6QUoKQmdOVkJBWVRBbFZUTUI0WERURTRNRFV5TVRFd05EVXhNRm9YRFRRNU1USX" + "pNVEl6TlRrMU9Wb3dhREVhTUJnRwpBMVVFQXd3UlNXNTBaV3dnVTBkWUlGSnZiM1FnUTBFeEdqQV" + "lCZ05WQkFvTUVVbHVkR1ZzSUVOdmNuQnZjbUYwCmFXOXVNUlF3RWdZRFZRUUhEQXRUWVc1MFlTQk" + "RiR0Z5WVRFTE1Ba0dBMVVFQ0F3Q1EwRXhDekFKQmdOVkJBWVQKQWxWVE1Ga3dFd1lIS29aSXpqME" + "NBUVlJS29aSXpqMERBUWNEUWdBRUM2bkV3TURJWVpPai9pUFdzQ3phRUtpNwoxT2lPU0xSRmhXR2" + "pibkJWSmZWbmtZNHUzSWprRFlZTDBNeE80bXFzeVlqbEJhbFRWWXhGUDJzSkJLNXpsS09CCnV6Q0" + "J1REFmQmdOVkhTTUVHREFXZ0JRaVpReldXcDAwaWZPRHRKVlN2MUFiT1NjR3JEQlNCZ05WSFI4RV" + "N6QkoKTUVlZ1JhQkRoa0ZvZEhSd2N6b3ZMMk5sY25ScFptbGpZWFJsY3k1MGNuVnpkR1ZrYzJWeW" + "RtbGpaWE11YVc1MApaV3d1WTI5dEwwbHVkR1ZzVTBkWVVtOXZkRU5CTG1SbGNqQWRCZ05WSFE0RU" + "ZnUVVJbVVNMWxxZE5JbnpnN1NWClVyOVFHemtuQnF3d0RnWURWUjBQQVFIL0JBUURBZ0VHTUJJR0" + "ExVWRFd0VCL3dRSU1BWUJBZjhDQVFFd0NnWUkKS29aSXpqMEVBd0lEU1FBd1JnSWhBT1cvNVFrUi" + "tTOUNpU0RjTm9vd0x1UFJMc1dHZi9ZaTdHU1g5NEJnd1R3ZwpBaUVBNEowbHJIb01zK1hvNW8vc1" + "g2TzlRV3hIUkF2WlVHT2RSUTdjdnFSWGFxST0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoAMA" + "0GCSqGSIb3DQEBCwUAA4IBAQAWPfe1yj4TfaxWipdcjCX+" + "NBJQtQOvhu6TbkzwWczIkvcCQ8O6dzsnMDFkxVkZ2ZlcsufSaB74VS//3BzOh/PLWpSX/" + "TaQHxFKhcK5RxlEq0O/oINnJ7fMhKlrd/hyoD/" + "P2bSLej5zdh63JciGxNGXkanchgQ8qNxXhs9oRUJINYYinFfRsD3OzX6dsHLPVshkdOZFpM9DgP2" + "QozqQJ1GC4tAKwbktxU0Ai3BecoPFzYVIygGLY1BAGd112C6cktj7YZTWE/" + "tCSD+uXWyQieBu5zUN7H/PcxY9VBT/fOkBfaaL+JcpG4/tGrbTTbZUUclzKVQ/5XP6bOa1t6r/" + "zN/W"; + +static const string pem_key_for_nested_cert = + "-----BEGIN PUBLIC " + "KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2NBrEQdwXUzVy2p+" + "SZ7s\nBjxbVd4iTGNEQJu/Ot/C0NCzXIDT6DMEAeVZLSoWWcW6oXQ81h+yQWtw+jFW/" + "SPg\nG4FGSL1UnVO8Zak80thovQk0dbZDo+" + "9lsoOnOfXfPUL0T9AgHtqJpUr3tCfyRRLd\nC0MgF1tAyjZbMj8bHe2ZmJ9GLTJT5v9E0i5l3S4W" + "ZY52vMzZaVpfxw+0/s5tRzco\nPGqIrMOnX/7kv5j7sisqZKNq6fP+4MHvLb/" + "tXyHCkW6FzX8mUlwyRNzBP3R4xaXB\nvykzJMaAiCW/Yr/" + "TxycdnmwsTR7he1Q78q12KnYqLvUVjg/v39/RWGSbFnaP1YX5\nHwIDAQAB\n-----END " + "PUBLIC KEY-----\n"; + template void corrupt(T& buf) { @@ -69,6 +190,19 @@ ccf::crypto::Pem generate_self_signed_cert( kp, name, {}, valid_from, certificate_validity_period_days); } +TEST_CASE("Check verifier handles nested certs for both PEM and DER inputs") +{ + auto cert_der = ccf::crypto::raw_from_b64(nested_cert); + auto cert_pem = fmt::format( + "-----BEGIN CERTIFICATE-----\n{}\n-----END CERTIFICATE-----", nested_cert); + auto der_verifier = make_verifier(cert_der); + auto pem_verifier = make_verifier(cert_pem); + auto pem_key_from_der = der_verifier->public_key_pem(); + auto pem_key_from_pem = pem_verifier->public_key_pem(); + CHECK(pem_key_from_der.str() == pem_key_from_pem.str()); + CHECK(pem_key_from_der.str() == pem_key_for_nested_cert); +} + TEST_CASE("Sign, verify, with KeyPair") { for (const auto curve : supported_curves) diff --git a/src/crypto/test/pem.cpp b/src/crypto/test/pem.cpp index 17b170d1fc74..9f8d1a60453f 100644 --- a/src/crypto/test/pem.cpp +++ b/src/crypto/test/pem.cpp @@ -10,6 +10,36 @@ using namespace std; using namespace ccf::crypto; +void check_bundles( + const std::string& single_cert, + const Pem& cert_pem, + bool lr_before = false, + bool lr_after = false) +{ + for (size_t count : {1, 2, 3, 10}) + { + std::string certs; + for (size_t i = 0; i < count; ++i) + { + if (lr_before) + { + certs += "\n"; + } + certs += single_cert; + if (lr_after) + { + certs += "\n"; + } + } + auto bundle = split_x509_cert_bundle(certs); + REQUIRE(bundle.size() == count); + for (const auto& pem : bundle) + { + REQUIRE(pem == cert_pem); + } + } +} + TEST_CASE("Split x509 cert bundle") { REQUIRE(split_x509_cert_bundle("") == std::vector{}); @@ -31,14 +61,11 @@ TEST_CASE("Split x509 cert bundle") "\n-----END CERTIFICATE-----"; auto bundle = split_x509_cert_bundle(single_cert); const auto cert_pem = Pem(single_cert); - REQUIRE(bundle.size() == 1); - REQUIRE(bundle[0] == cert_pem); - const std::string two_certs = single_cert + single_cert; - bundle = split_x509_cert_bundle(two_certs); - REQUIRE(bundle.size() == 2); - REQUIRE(bundle[0] == cert_pem); - REQUIRE(bundle[1] == cert_pem); + check_bundles(single_cert, cert_pem); + check_bundles(single_cert, cert_pem, true); + check_bundles(single_cert, cert_pem, false, true); + check_bundles(single_cert, cert_pem, true, true); std::string bundle_with_invalid_suffix = single_cert + "ignored suffix"; bundle = split_x509_cert_bundle(bundle_with_invalid_suffix); From 542bba87c7bd258650ca19125774d94bfffe60ae Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 16 Aug 2024 11:43:28 +0100 Subject: [PATCH 2/8] Initial removal of SGX targets (#6426) Co-authored-by: Amaury Chamayou --- .github/workflows/README.md | 2 +- .github/workflows/ci.yml | 13 -- CMakeLists.txt | 203 +++----------------- cmake/ccf_app.cmake | 127 +----------- cmake/ccf_sgx-config.cmake.in | 10 - cmake/ccf_sgx_unsafe-config.cmake.in | 10 - cmake/common.cmake | 10 +- cmake/cpack_settings.cmake | 9 +- cmake/crypto.cmake | 12 +- cmake/nghttp2.cmake | 17 +- cmake/open_enclave.cmake | 46 ----- cmake/preproject.cmake | 9 +- cmake/protobuf.cmake | 10 +- cmake/qcbor.cmake | 14 +- cmake/quickjs.cmake | 21 +- cmake/sss.cmake | 9 +- cmake/t_cose.cmake | 23 +-- cmake/version.cmake | 18 -- edl/ccf.edl | 35 ---- include/ccf/ds/logger.h | 28 +-- samples/apps/basic/CMakeLists.txt | 20 -- samples/apps/basic/oe_sign.conf | 7 - samples/apps/logging/CMakeLists.txt | 20 -- samples/apps/logging/oe_sign.conf | 7 - samples/apps/nobuiltins/CMakeLists.txt | 16 -- samples/apps/nobuiltins/oe_sign.conf | 7 - samples/apps/programmability/CMakeLists.txt | 21 -- samples/apps/programmability/oe_sign.conf | 7 - src/apps/js_generic/oe_sign.conf | 7 - src/apps/tpcc/app/oe_sign.conf | 7 - src/apps/tpcc/tpcc.cmake | 4 - src/ds/test/logger_json_test.cpp | 2 - src/host/enclave.h | 4 - src/node/rpc/gov_logging.h | 9 +- src/node/rpc/node_frontend.h | 4 - 35 files changed, 47 insertions(+), 721 deletions(-) delete mode 100644 cmake/ccf_sgx-config.cmake.in delete mode 100644 cmake/ccf_sgx_unsafe-config.cmake.in delete mode 100644 cmake/open_enclave.cmake delete mode 100644 edl/ccf.edl delete mode 100644 samples/apps/basic/oe_sign.conf delete mode 100644 samples/apps/logging/oe_sign.conf delete mode 100644 samples/apps/nobuiltins/oe_sign.conf delete mode 100644 samples/apps/programmability/oe_sign.conf delete mode 100644 src/apps/js_generic/oe_sign.conf delete mode 100644 src/apps/tpcc/app/oe_sign.conf diff --git a/.github/workflows/README.md b/.github/workflows/README.md index e831e59bb442..77a9f78f03d9 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -30,7 +30,7 @@ File: `ci-containers-ghcr.yml` # CI -Main continuous integration job. Builds CCF for all target platforms, runs unit, end to end and partition tests for SGX and Virtual. Run on every commit, including PRs from forks, gates merging. Also runs once a week, regardless of commits. +Main continuous integration job. Builds CCF for all target platforms, runs unit, end to end and partition tests Virtual. Run on every commit, including PRs from forks, gates merging. Also runs once a week, regardless of commits. File: `ci.yml` 3rd party dependencies: None diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f415bc259d38..e5a28e8fd59c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,10 +42,6 @@ jobs: image: default nodes: [self-hosted, 1ES.Pool=gha-virtual-ccf-sub] options: --user root --publish-all --cap-add NET_ADMIN --cap-add NET_RAW --cap-add SYS_PTRACE -v /lib/modules:/lib/modules:ro - - name: sgx - image: sgx - nodes: [self-hosted, 1ES.Pool=gha-sgx-ccf-sub] - options: --user root --publish-all --cap-add NET_ADMIN --cap-add NET_RAW --device /dev/sgx_enclave:/dev/sgx_enclave --device /dev/sgx_provision:/dev/sgx_provision -v /dev/sgx:/dev/sgx -v /lib/modules:/lib/modules:ro runs-on: ${{ matrix.platform.nodes }} container: image: ghcr.io/microsoft/ccf/ci/${{ matrix.platform.image }}:build-25-07-2024 @@ -65,15 +61,6 @@ jobs: ninja shell: bash - - name: "Platform SGX" - run: | - sudo groupadd -fg $(/usr/bin/stat -Lc '%g' /dev/sgx/provision) sgx_prv - sudo usermod -a -G sgx_prv $(whoami) - samples/scripts/sgxinfo.sh - cat /proc/cpuinfo | grep flags | uniq - shell: bash - if: "${{ matrix.platform.name == 'sgx' }}" - - name: "Platform SNP" run: | samples/scripts/snpinfo.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 3137d23d47c0..75eb5d2fd658 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,10 +2,10 @@ # Licensed under the Apache 2.0 License. cmake_minimum_required(VERSION 3.16) -set(ALLOWED_TARGETS "sgx;snp;virtual") +set(ALLOWED_TARGETS "snp;virtual") set(COMPILE_TARGET - "sgx" + "snp" CACHE STRING "Target compilation platforms, Choose from: ${ALLOWED_TARGETS}" ) @@ -76,7 +76,7 @@ endif() option( VERBOSE_LOGGING - "Enable verbose, potentially unsafe logging of enclave code. Affects logging level passed at run-time to end-to-end-tests, and compile-time max verbosity on SGX." + "Enable verbose, potentially unsafe logging of enclave code. Affects logging level passed at run-time to end-to-end-tests." OFF ) set(TEST_LOGGING_LEVEL "info") @@ -84,17 +84,6 @@ if(VERBOSE_LOGGING) set(TEST_LOGGING_LEVEL "trace") endif() -# NB: Toggling VERBOSE_LOGGING on non-SGX platforms causes no build change, so -# should not cause a rebuild -if(COMPILE_TARGET STREQUAL "sgx" AND NOT VERBOSE_LOGGING) - # Disable verbose, unsafe logging of enclave code. On some platforms it is - # safe to build with this logging enabled, and then it can be disabled at - # run-time. However this run-time control is not possible on SGX, so to ensure - # a given MRENCLAVE cannot leak via debug logging it must be removed at - # build-time, with this option. - add_compile_definitions(CCF_DISABLE_VERBOSE_LOGGING) -endif() - option(USE_NULL_ENCRYPTOR "Turn off encryption of ledger updates - debug only" OFF ) @@ -134,9 +123,6 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/tools.cmake) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/tools.cmake DESTINATION cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/ccf_app.cmake) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/ccf_app.cmake DESTINATION cmake) -install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/open_enclave.cmake - DESTINATION cmake -) if(SAN AND LVI_MITIGATIONS) message( @@ -152,18 +138,6 @@ if(TSAN AND LVI_MITIGATIONS) ) endif() -add_custom_command( - COMMAND - openenclave::oeedger8r ${CCF_DIR}/edl/ccf.edl --search-path ${OE_INCLUDEDIR} - --trusted --trusted-dir ${CCF_GENERATED_DIR} --untrusted --untrusted-dir - ${CCF_GENERATED_DIR} - COMMAND mv ${CCF_GENERATED_DIR}/ccf_t.c ${CCF_GENERATED_DIR}/ccf_t.cpp - COMMAND mv ${CCF_GENERATED_DIR}/ccf_u.c ${CCF_GENERATED_DIR}/ccf_u.cpp - DEPENDS ${CCF_DIR}/edl/ccf.edl - OUTPUT ${CCF_GENERATED_DIR}/ccf_t.cpp ${CCF_GENERATED_DIR}/ccf_u.cpp - COMMENT "Generating code from EDL, and renaming to .cpp" -) - # Copy and install CCF utilities set(CCF_UTILITIES keygenerator.sh submit_recovery_share.sh verify_quote.sh) foreach(UTILITY ${CCF_UTILITIES}) @@ -184,7 +158,6 @@ foreach(UTILITY ${CCF_TEST_UTILITIES}) endforeach() # Install additional utilities -install(PROGRAMS ${CCF_DIR}/samples/scripts/sgxinfo.sh DESTINATION bin) install(PROGRAMS ${CCF_DIR}/samples/scripts/snpinfo.sh DESTINATION bin) install(FILES ${CCF_DIR}/tests/config.jinja DESTINATION bin) @@ -199,15 +172,7 @@ install( USE_SOURCE_PERMISSIONS ) -if(COMPILE_TARGET STREQUAL "sgx") - # While virtual libraries need to be built for sgx for unit tests, these do - # not get installed to minimise installation size - set(INSTALL_VIRTUAL_LIBRARIES OFF) - - if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set(DEFAULT_ENCLAVE_TYPE debug) - endif() -elseif(COMPILE_TARGET STREQUAL "snp") +if(COMPILE_TARGET STREQUAL "snp") set(INSTALL_VIRTUAL_LIBRARIES OFF) else() set(INSTALL_VIRTUAL_LIBRARIES ON) @@ -268,10 +233,6 @@ list(APPEND CCHOST_SOURCES ${CCF_DIR}/src/host/main.cpp ${CCF_DIR}/src/host/env.cpp ) -if(COMPILE_TARGET STREQUAL "sgx") - list(APPEND CCHOST_SOURCES ${CCF_GENERATED_DIR}/ccf_u.cpp) -endif() - add_executable(cchost ${CCHOST_SOURCES}) add_warning_checks(cchost) @@ -282,9 +243,7 @@ target_compile_options( ) target_include_directories(cchost PRIVATE ${CCF_GENERATED_DIR}) -if(COMPILE_TARGET STREQUAL "sgx") - target_compile_definitions(cchost PUBLIC PLATFORM_SGX) -elseif(COMPILE_TARGET STREQUAL "snp") +if(COMPILE_TARGET STREQUAL "snp") target_compile_definitions(cchost PUBLIC PLATFORM_SNP) elseif(COMPILE_TARGET STREQUAL "virtual") target_compile_definitions(cchost PUBLIC PLATFORM_VIRTUAL) @@ -294,21 +253,11 @@ target_link_libraries( cchost PRIVATE uv ${TLS_LIBRARY} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT} ${LINK_LIBCXX} ccfcrypto.host ) -if(COMPILE_TARGET STREQUAL "sgx") - target_link_libraries(cchost PRIVATE openenclave::oehost) -endif() install(TARGETS cchost DESTINATION bin) # HTTP parser -if(COMPILE_TARGET STREQUAL "sgx") - add_enclave_library_c(http_parser.enclave "${HTTP_PARSER_SOURCES}") - install( - TARGETS http_parser.enclave - EXPORT ccf - DESTINATION lib - ) -elseif(COMPILE_TARGET STREQUAL "snp") +if(COMPILE_TARGET STREQUAL "snp") add_library(http_parser.snp "${HTTP_PARSER_SOURCES}") set_property(TARGET http_parser.snp PROPERTY POSITION_INDEPENDENT_CODE ON) install( @@ -353,19 +302,9 @@ set(CCF_JS_SOURCES ${CCF_DIR}/src/js/registry.cpp ) -if(COMPILE_TARGET STREQUAL "sgx") - add_enclave_library(ccf_js.enclave "${CCF_JS_SOURCES}") - target_link_libraries(ccf_js.enclave PUBLIC ccfcrypto.enclave quickjs.enclave) - # JS extension observes jwt_management.h header where this definition is - # required - target_compile_definitions(ccf_js.enclave PUBLIC SGX_ATTESTATION_VERIFICATION) - add_warning_checks(ccf_js.enclave) - install( - TARGETS ccf_js.enclave - EXPORT ccf - DESTINATION lib - ) -elseif(COMPILE_TARGET STREQUAL "snp") +set(OE_BINDIR "") + +if(COMPILE_TARGET STREQUAL "snp") add_host_library(ccf_js.snp "${CCF_JS_SOURCES}") add_san(ccf_js.snp) target_link_libraries(ccf_js.snp PUBLIC ccfcrypto.snp quickjs.snp) @@ -395,15 +334,7 @@ set(CCF_KV_SOURCES ${CCF_DIR}/src/kv/untyped_map_diff.cpp ) -if(COMPILE_TARGET STREQUAL "sgx") - add_enclave_library(ccf_kv.enclave "${CCF_KV_SOURCES}") - add_warning_checks(ccf_kv.enclave) - install( - TARGETS ccf_kv.enclave - EXPORT ccf - DESTINATION lib - ) -elseif(COMPILE_TARGET STREQUAL "snp") +if(COMPILE_TARGET STREQUAL "snp") add_host_library(ccf_kv.snp "${CCF_KV_SOURCES}") add_san(ccf_kv.snp) add_warning_checks(ccf_kv.snp) @@ -426,23 +357,7 @@ if(INSTALL_VIRTUAL_LIBRARIES) endif() # CCF endpoints libs -if(COMPILE_TARGET STREQUAL "sgx") - add_enclave_library(ccf_endpoints.enclave "${CCF_ENDPOINTS_SOURCES}") - target_include_directories( - ccf_endpoints.enclave PRIVATE ${CCF_DIR}/src/endpoints - ) - target_link_libraries( - ccf_endpoints.enclave - PUBLIC qcbor.enclave t_cose.enclave http_parser.enclave ccfcrypto.enclave - ccf_kv.enclave - ) - add_warning_checks(ccf_endpoints.enclave) - install( - TARGETS ccf_endpoints.enclave - EXPORT ccf - DESTINATION lib - ) -elseif(COMPILE_TARGET STREQUAL "snp") +if(COMPILE_TARGET STREQUAL "snp") add_host_library(ccf_endpoints.snp "${CCF_ENDPOINTS_SOURCES}") target_include_directories(ccf_endpoints.snp PRIVATE ${CCF_DIR}/src/endpoints) target_link_libraries( @@ -497,16 +412,7 @@ set(CCF_NETWORK_TEST_ARGS ) set(JS_GENERIC_SOURCES ${CCF_DIR}/src/apps/js_generic/js_generic_base.cpp) -if(COMPILE_TARGET STREQUAL "sgx") - add_enclave_library(js_generic_base.enclave ${JS_GENERIC_SOURCES}) - target_link_libraries(js_generic_base.enclave PUBLIC ccf.enclave) - add_lvi_mitigations(js_generic_base.enclave) - install( - TARGETS js_generic_base.enclave - EXPORT ccf - DESTINATION lib - ) -elseif(COMPILE_TARGET STREQUAL "snp") +if(COMPILE_TARGET STREQUAL "snp") add_library(js_generic_base.snp STATIC ${JS_GENERIC_SOURCES}) add_san(js_generic_base.snp) add_warning_checks(js_generic_base.snp) @@ -545,10 +451,6 @@ add_ccf_app( LINK_LIBS_VIRTUAL js_generic_base.virtual LINK_LIBS_SNP js_generic_base.snp INSTALL_LIBS ON ) -sign_app_library( - js_generic.enclave ${CCF_DIR}/src/apps/js_generic/oe_sign.conf - ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem INSTALL_LIBS ON -) # SNIPPET_END: JS generic application install(DIRECTORY ${CCF_DIR}/samples/apps/logging/js @@ -632,54 +534,8 @@ set(CCF_IMPL_SOURCE ${CCF_DIR}/src/enclave/thread_local.cpp ${CCF_DIR}/src/node/quote.cpp ) -if(COMPILE_TARGET STREQUAL "sgx") - # enclave version - add_enclave_library( - ccf.enclave ${CCF_IMPL_SOURCE} ${CCF_GENERATED_DIR}/ccf_t.cpp - ) - - # PLATFORM_SGX to initialise Open Enclave SGX enclave creation and - # SGX_ATTESTATION_VERIFICATION to verify SGX attestation reports. - target_compile_definitions( - ccf.enclave PUBLIC PLATFORM_SGX SGX_ATTESTATION_VERIFICATION - ) - - add_warning_checks(ccf.enclave) - - target_include_directories( - ccf.enclave SYSTEM - PUBLIC - $ - $ #< This contains the private headers - #< which are currently under src, and - #< should be removed or renamed - $ - $ - ) - - target_link_libraries( - ccf.enclave - PUBLIC http_parser.enclave - sss.enclave - ccf_js.enclave - ccf_endpoints.enclave - ccfcrypto.enclave - ccf_kv.enclave - nghttp2.enclave - ) - - add_lvi_mitigations(ccf.enclave) - - install( - TARGETS ccf.enclave - EXPORT ccf - DESTINATION lib - ) - - add_dependencies(ccf ccf.enclave) - - # Same as virtual for the time being but will diverge soon -elseif(COMPILE_TARGET STREQUAL "snp") +# Same as virtual for the time being but will diverge soon +if(COMPILE_TARGET STREQUAL "snp") # SNP version add_library(ccf.snp STATIC ${CCF_IMPL_SOURCE}) @@ -831,16 +687,6 @@ install(FILES samples/constitutions/default/apply.js DESTINATION bin) install(FILES tests/start_network.py DESTINATION bin) install(FILES tests/requirements.txt DESTINATION bin) -# Generate an ephemeral signing key -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem - COMMAND openssl genrsa -out ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -3 - 3072 -) -add_custom_target( - signing_key ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -) - # Add sample apps add_subdirectory(${CCF_DIR}/samples) @@ -1134,17 +980,14 @@ if(BUILD_TESTS) PROPERTY ENVIRONMENT "ASAN_OPTIONS=alloc_dealloc_mismatch=0" ) - if(NOT UNSAFE_VERSION) - # Unsafe builds do not follow normal version conventions - add_test(NAME versionifier_test - COMMAND ${PYTHON} - ${CMAKE_SOURCE_DIR}/python/src/ccf/_versionifier.py - ) + add_test(NAME versionifier_test + COMMAND ${PYTHON} + ${CMAKE_SOURCE_DIR}/python/src/ccf/_versionifier.py + ) - add_test(NAME github_version_lts_test - COMMAND ${PYTHON} ${CMAKE_SOURCE_DIR}/tests/infra/github.py - ) - endif() + add_test(NAME github_version_lts_test + COMMAND ${PYTHON} ${CMAKE_SOURCE_DIR}/tests/infra/github.py + ) endif() if(NOT TSAN) @@ -1463,9 +1306,7 @@ if(BUILD_TESTS) list(APPEND LTS_TEST_ARGS --check-ledger-compatibility) endif() - if(NOT UNSAFE_VERSION AND NOT SAN) - # Unsafe builds do not follow normal version conventions LTS nodes may - # also require different runtime libraries + if(NOT SAN) add_e2e_test( NAME lts_compatibility PYTHON_SCRIPT ${CMAKE_SOURCE_DIR}/tests/lts_compatibility.py diff --git a/cmake/ccf_app.cmake b/cmake/ccf_app.cmake index fc54a413b946..abd9e5d269d0 100644 --- a/cmake/ccf_app.cmake +++ b/cmake/ccf_app.cmake @@ -1,11 +1,11 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the Apache 2.0 License. -set(ALLOWED_TARGETS "sgx;snp;virtual") +set(ALLOWED_TARGETS "snp;virtual") if(NOT DEFINED COMPILE_TARGET) set(COMPILE_TARGET - "sgx" + "snp" CACHE STRING "Target compilation platforms, Choose from: ${ALLOWED_TARGETS}" ) @@ -19,73 +19,9 @@ if(NOT COMPILE_TARGET IN_LIST ALLOWED_TARGETS) endif() message(STATUS "Compile target platform: ${COMPILE_TARGET}") -include(${CCF_DIR}/cmake/open_enclave.cmake) - list(APPEND COMPILE_LIBCXX -stdlib=libc++) list(APPEND LINK_LIBCXX -lc++ -lc++abi -stdlib=libc++) -# Sign a built enclave library with oesign -function(sign_app_library name app_oe_conf_path enclave_sign_key_path) - cmake_parse_arguments(PARSE_ARGV 1 PARSED_ARGS "" "" "INSTALL_LIBS") - - if(TARGET ${name}) - # Produce a debuggable variant. This doesn't need to be signed, but oesign - # also stamps the other config (heap size etc) which _are_ needed - set(DEBUG_CONF_NAME ${CMAKE_CURRENT_BINARY_DIR}/${name}.debuggable.conf) - - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lib${name}.so.debuggable - # Copy conf file locally - COMMAND cp ${app_oe_conf_path} ${DEBUG_CONF_NAME} - # Remove any existing Debug= lines - COMMAND sed -i "/^Debug=\.*/d" ${DEBUG_CONF_NAME} - # Add Debug=1 line - COMMAND echo "Debug=1" >> ${DEBUG_CONF_NAME} - COMMAND - openenclave::oesign sign -e ${CMAKE_CURRENT_BINARY_DIR}/lib${name}.so -c - ${DEBUG_CONF_NAME} -k ${enclave_sign_key_path} -o - ${CMAKE_CURRENT_BINARY_DIR}/lib${name}.so.debuggable - DEPENDS ${name} ${app_oe_conf_path} ${enclave_sign_key_path} - ) - - add_custom_target( - ${name}_debuggable ALL - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/lib${name}.so.debuggable - ) - - # Produce a releaseable signed variant. This is NOT debuggable - oegdb - # cannot be attached - set(SIGNED_CONF_NAME ${CMAKE_CURRENT_BINARY_DIR}/${name}.signed.conf) - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lib${name}.so.signed - # Copy conf file locally - COMMAND cp ${app_oe_conf_path} ${SIGNED_CONF_NAME} - # Remove any existing Debug= lines - COMMAND sed -i "/^Debug=\.*/d" ${SIGNED_CONF_NAME} - # Add Debug=0 line - COMMAND echo "Debug=0" >> ${SIGNED_CONF_NAME} - COMMAND - openenclave::oesign sign -e ${CMAKE_CURRENT_BINARY_DIR}/lib${name}.so -c - ${SIGNED_CONF_NAME} -k ${enclave_sign_key_path} - DEPENDS ${name} ${app_oe_conf_path} ${enclave_sign_key_path} - ) - - add_custom_target( - ${name}_signed ALL - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/lib${name}.so.signed - ) - - if(${PARSED_ARGS_INSTALL_LIBS}) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib${name}.so.debuggable - DESTINATION lib - ) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib${name}.so.signed - DESTINATION lib - ) - endif() - endif() -endfunction() - # Enclave library wrapper function(add_ccf_app name) @@ -99,34 +35,8 @@ function(add_ccf_app name) ) add_custom_target(${name} ALL) - if(COMPILE_TARGET STREQUAL "sgx") - set(enc_name ${name}.enclave) - - add_library(${enc_name} SHARED ${PARSED_ARGS_SRCS}) - - target_compile_definitions(${enc_name} PUBLIC PLATFORM_SGX) - - target_include_directories(${enc_name} PRIVATE ${PARSED_ARGS_INCLUDE_DIRS}) - target_include_directories( - ${enc_name} SYSTEM PRIVATE ${PARSED_ARGS_SYSTEM_INCLUDE_DIRS} - ) - add_warning_checks(${enc_name}) - target_link_libraries( - ${enc_name} PRIVATE ${PARSED_ARGS_LINK_LIBS_ENCLAVE} - ${OE_TARGET_ENCLAVE_CORE_LIBS} ccf.enclave - ) - - set_property(TARGET ${enc_name} PROPERTY POSITION_INDEPENDENT_CODE ON) - - add_lvi_mitigations(${enc_name}) - - add_dependencies(${name} ${enc_name}) - if(PARSED_ARGS_DEPS) - add_dependencies(${enc_name} ${PARSED_ARGS_DEPS}) - endif() - - elseif(COMPILE_TARGET STREQUAL "snp") - # Build an SNP enclave, loaded as a shared library without OE + if(COMPILE_TARGET STREQUAL "snp") + # Build an SNP enclave, loaded as a shared library set(snp_name ${name}.snp) add_library(${snp_name} SHARED ${PARSED_ARGS_SRCS}) @@ -166,7 +76,7 @@ function(add_ccf_app name) endif() elseif(COMPILE_TARGET STREQUAL "virtual") - # Build a virtual enclave, loaded as a shared library without OE + # Build a virtual enclave, loaded as a shared library set(virt_name ${name}.virtual) add_library(${virt_name} SHARED ${PARSED_ARGS_SRCS}) @@ -207,33 +117,6 @@ function(add_ccf_app name) endif() endfunction() -# Convenience wrapper to build C-libraries that can be linked in enclave, ie. in -# a CCF application. -if(COMPILE_TARGET STREQUAL "sgx") - function(add_enclave_library_c name) - cmake_parse_arguments(PARSE_ARGV 1 PARSED_ARGS "" "" "") - set(files ${PARSED_ARGS_UNPARSED_ARGUMENTS}) - add_library(${name} STATIC ${files}) - target_compile_options(${name} PRIVATE -nostdinc) - target_link_libraries(${name} PRIVATE ${OE_TARGET_LIBC}) - set_property(TARGET ${name} PROPERTY POSITION_INDEPENDENT_CODE ON) - endfunction() - - # Convenience wrapper to build C++-libraries that can be linked in enclave, - # ie. in a CCF application. - function(add_enclave_library name) - cmake_parse_arguments(PARSE_ARGV 1 PARSED_ARGS "" "" "") - set(files ${PARSED_ARGS_UNPARSED_ARGUMENTS}) - add_library(${name} ${files}) - target_compile_options(${name} PUBLIC -nostdinc -nostdinc++) - target_compile_definitions( - ${name} PUBLIC INSIDE_ENCLAVE _LIBCPP_HAS_THREAD_API_PTHREAD - ) - target_link_libraries(${name} PUBLIC ${OE_TARGET_ENCLAVE_AND_STD} -lgcc) - set_property(TARGET ${name} PROPERTY POSITION_INDEPENDENT_CODE ON) - endfunction() -endif() - function(add_host_library name) cmake_parse_arguments(PARSE_ARGV 1 PARSED_ARGS "" "" "") set(files ${PARSED_ARGS_UNPARSED_ARGUMENTS}) diff --git a/cmake/ccf_sgx-config.cmake.in b/cmake/ccf_sgx-config.cmake.in deleted file mode 100644 index 79eef919b49c..000000000000 --- a/cmake/ccf_sgx-config.cmake.in +++ /dev/null @@ -1,10 +0,0 @@ -@PACKAGE_INIT@ - -set(CCF_DIR "@CMAKE_INSTALL_PREFIX@") -set(SAN "@SAN@") - -include("${CCF_DIR}/cmake/ccf-targets.cmake") -include("${CCF_DIR}/cmake/preproject.cmake") -include("${CCF_DIR}/cmake/ccf_app.cmake") -include("${CCF_DIR}/cmake/tools.cmake") -include("${CCF_DIR}/cmake/open_enclave.cmake") diff --git a/cmake/ccf_sgx_unsafe-config.cmake.in b/cmake/ccf_sgx_unsafe-config.cmake.in deleted file mode 100644 index 79eef919b49c..000000000000 --- a/cmake/ccf_sgx_unsafe-config.cmake.in +++ /dev/null @@ -1,10 +0,0 @@ -@PACKAGE_INIT@ - -set(CCF_DIR "@CMAKE_INSTALL_PREFIX@") -set(SAN "@SAN@") - -include("${CCF_DIR}/cmake/ccf-targets.cmake") -include("${CCF_DIR}/cmake/preproject.cmake") -include("${CCF_DIR}/cmake/ccf_app.cmake") -include("${CCF_DIR}/cmake/tools.cmake") -include("${CCF_DIR}/cmake/open_enclave.cmake") diff --git a/cmake/common.cmake b/cmake/common.cmake index f786365d1f0f..fe3bfb6aa60f 100644 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -211,10 +211,7 @@ function(add_perf_test) set(TESTS_SUFFIX "") set(ENCLAVE_TYPE "") set(ENCLAVE_PLATFORM "${COMPILE_TARGET}") - if("sgx" STREQUAL COMPILE_TARGET) - set(TESTS_SUFFIX "${TESTS_SUFFIX}_sgx") - set(ENCLAVE_TYPE "release") - elseif("virtual" STREQUAL COMPILE_TARGET) + if("virtual" STREQUAL COMPILE_TARGET) set(TESTS_SUFFIX "${TESTS_SUFFIX}_virtual") set(ENCLAVE_TYPE "virtual") endif() @@ -284,10 +281,7 @@ function(add_piccolo_test) set(TESTS_SUFFIX "") set(ENCLAVE_TYPE "") set(ENCLAVE_PLATFORM "${COMPILE_TARGET}") - if("sgx" STREQUAL COMPILE_TARGET) - set(TESTS_SUFFIX "${TESTS_SUFFIX}_sgx") - set(ENCLAVE_TYPE "release") - elseif("virtual" STREQUAL COMPILE_TARGET) + if("virtual" STREQUAL COMPILE_TARGET) set(TESTS_SUFFIX "${TESTS_SUFFIX}_virtual") set(ENCLAVE_TYPE "virtual") endif() diff --git a/cmake/cpack_settings.cmake b/cmake/cpack_settings.cmake index 099a608a053c..d3d57e0bd6e9 100644 --- a/cmake/cpack_settings.cmake +++ b/cmake/cpack_settings.cmake @@ -24,14 +24,7 @@ message(STATUS "Debian package version: ${CPACK_DEBIAN_PACKAGE_VERSION}") set(CCF_DEB_BASE_DEPENDENCIES "libuv1 (>= 1.34.2);openssl (>=1.1.1f)") set(CCF_DEB_DEPENDENCIES ${CCF_DEB_BASE_DEPENDENCIES}) -set(OE_VERSION "0.19.7") -if(COMPILE_TARGET STREQUAL "sgx") - list(APPEND CCF_DEB_DEPENDENCIES - "libc++1-11;libc++abi1-11;open-enclave (>=${OE_VERSION})" - ) -else() - list(APPEND CCF_DEB_DEPENDENCIES "libc++1-15;libc++abi1-15") -endif() +list(APPEND CCF_DEB_DEPENDENCIES "libc++1-15;libc++abi1-15") list(JOIN CCF_DEB_DEPENDENCIES ", " CPACK_DEBIAN_PACKAGE_DEPENDS) diff --git a/cmake/crypto.cmake b/cmake/crypto.cmake index 28d512cf8ecd..8dfb7e1b0cdd 100644 --- a/cmake/crypto.cmake +++ b/cmake/crypto.cmake @@ -28,17 +28,7 @@ set(CCFCRYPTO_SRC ${CCF_DIR}/src/crypto/sharing.cpp ) -if(COMPILE_TARGET STREQUAL "sgx") - add_enclave_library(ccfcrypto.enclave ${CCFCRYPTO_SRC}) - target_link_libraries(ccfcrypto.enclave PUBLIC qcbor.enclave) - target_link_libraries(ccfcrypto.enclave PUBLIC t_cose.enclave) - - install( - TARGETS ccfcrypto.enclave - EXPORT ccf - DESTINATION lib - ) -elseif(COMPILE_TARGET STREQUAL "snp") +if(COMPILE_TARGET STREQUAL "snp") add_library(ccfcrypto.snp ${CCFCRYPTO_SRC}) add_san(ccfcrypto.snp) target_compile_options(ccfcrypto.snp PUBLIC ${COMPILE_LIBCXX}) diff --git a/cmake/nghttp2.cmake b/cmake/nghttp2.cmake index f353e4110fce..f69a3d5a50dd 100644 --- a/cmake/nghttp2.cmake +++ b/cmake/nghttp2.cmake @@ -33,22 +33,7 @@ set(NGHTTP2_SRCS ${NGHTTP2_PREFIX}/sfparse.c ) -if(COMPILE_TARGET STREQUAL "sgx") - add_enclave_library_c(nghttp2.enclave ${NGHTTP2_SRCS}) - target_include_directories( - nghttp2.enclave PUBLIC $ - $ - ) - target_compile_definitions( - nghttp2.enclave PUBLIC -DNGHTTP2_STATICLIB -DHAVE_ARPA_INET_H=1 - ) - - install( - TARGETS nghttp2.enclave - EXPORT ccf - DESTINATION lib - ) -elseif(COMPILE_TARGET STREQUAL "snp") +if(COMPILE_TARGET STREQUAL "snp") add_library(nghttp2.snp STATIC ${NGHTTP2_SRCS}) target_include_directories( nghttp2.snp PUBLIC $ diff --git a/cmake/open_enclave.cmake b/cmake/open_enclave.cmake deleted file mode 100644 index 7428e3ec37a1..000000000000 --- a/cmake/open_enclave.cmake +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the Apache 2.0 License. - -if(COMPILE_TARGET STREQUAL "sgx") - # Find OpenEnclave package - find_package(OpenEnclave 0.19.7 CONFIG REQUIRED) - - option(USE_OPENSSL_3 "Use OpenSSL 3.x for Open Enclave builds" ON) - if(USE_OPENSSL_3) - set(OE_OPENSSL_LIBRARY openenclave::oecryptoopenssl_3) - else() - set(OE_OPENSSL_LIBRARY openenclave::oecryptoopenssl) - endif() - # As well as pulling in openenclave:: targets, this sets variables which can - # be used for our edge cases (eg - for virtual libraries). These do not follow - # the standard naming patterns, for example use OE_INCLUDEDIR rather than - # OpenEnclave_INCLUDE_DIRS - if(COMPILE_TARGET STREQUAL "sgx") - set(OE_TARGET_LIBC openenclave::oelibc) - set(OE_TARGET_ENCLAVE_AND_STD openenclave::oeenclave openenclave::oelibcxx - openenclave::oelibc ${OE_OPENSSL_LIBRARY} - ) - - # These oe libraries must be linked in specific order - set(OE_TARGET_ENCLAVE_CORE_LIBS - openenclave::oeenclave openenclave::oesnmalloc openenclave::oecore - openenclave::oesyscall - ) - - option(LVI_MITIGATIONS "Enable LVI mitigations" ON) - if(LVI_MITIGATIONS) - string(APPEND OE_TARGET_LIBC -lvi-cfg) - list(TRANSFORM OE_TARGET_ENCLAVE_AND_STD APPEND -lvi-cfg) - list(TRANSFORM OE_TARGET_ENCLAVE_CORE_LIBS APPEND -lvi-cfg) - endif() - - function(add_lvi_mitigations name) - if(LVI_MITIGATIONS) - # Enable clang-11 built-in LVI mitigation - target_compile_options(${name} PRIVATE -mlvi-cfi) - endif() - endfunction() - - set(OE_HOST_LIBRARY openenclave::oehost) - endif() -endif() diff --git a/cmake/preproject.cmake b/cmake/preproject.cmake index feb37c7aa0dd..e48f76007431 100644 --- a/cmake/preproject.cmake +++ b/cmake/preproject.cmake @@ -11,13 +11,8 @@ if((NOT CMAKE_C_COMPILER) AND "$ENV{CC}" STREQUAL "" AND "$ENV{CXX}" STREQUAL "" ) - if("${COMPILE_TARGET}" STREQUAL "sgx") - find_program(FOUND_CMAKE_C_COMPILER NAMES clang-11) - find_program(FOUND_CMAKE_CXX_COMPILER NAMES clang++-11) - else() - find_program(FOUND_CMAKE_C_COMPILER NAMES clang-15) - find_program(FOUND_CMAKE_CXX_COMPILER NAMES clang++-15) - endif() + find_program(FOUND_CMAKE_C_COMPILER NAMES clang-15) + find_program(FOUND_CMAKE_CXX_COMPILER NAMES clang++-15) if(NOT (FOUND_CMAKE_C_COMPILER AND FOUND_CMAKE_CXX_COMPILER)) message( WARNING diff --git a/cmake/protobuf.cmake b/cmake/protobuf.cmake index 77e9640bb9ee..90616b7941b1 100644 --- a/cmake/protobuf.cmake +++ b/cmake/protobuf.cmake @@ -19,15 +19,7 @@ get_target_property(LIBPROTOBUF_SOURCES libprotobuf SOURCES) set(PROTOBUF_TARGETS "protobuf.virtual") add_host_library(protobuf.virtual ${LIBPROTOBUF_SOURCES}) -if(COMPILE_TARGET STREQUAL "sgx") - add_enclave_library(protobuf.enclave ${LIBPROTOBUF_SOURCES}) - list(APPEND PROTOBUF_TARGETS "protobuf.enclave") - install( - TARGETS protobuf.enclave - EXPORT ccf - DESTINATION lib - ) -elseif(COMPILE_TARGET STREQUAL "snp") +if(COMPILE_TARGET STREQUAL "snp") add_host_library(protobuf.snp ${LIBPROTOBUF_SOURCES}) list(APPEND PROTOBUF_TARGETS "protobuf.snp") install( diff --git a/cmake/qcbor.cmake b/cmake/qcbor.cmake index 32ac9ff6a6c9..6681282472d0 100644 --- a/cmake/qcbor.cmake +++ b/cmake/qcbor.cmake @@ -9,19 +9,7 @@ set(QCBOR_SRCS "${QCBOR_SRC}/qcbor_encode.c" "${QCBOR_SRC}/qcbor_err_to_str.c" "${QCBOR_SRC}/UsefulBuf.c" ) -if(COMPILE_TARGET STREQUAL "sgx") - add_enclave_library_c(qcbor.enclave ${QCBOR_SRCS}) - target_include_directories( - qcbor.enclave PUBLIC $ - $ - ) - - install( - TARGETS qcbor.enclave - EXPORT ccf - DESTINATION lib - ) -elseif(COMPILE_TARGET STREQUAL "snp") +if(COMPILE_TARGET STREQUAL "snp") add_library(qcbor.snp STATIC ${QCBOR_SRCS}) target_include_directories( diff --git a/cmake/quickjs.cmake b/cmake/quickjs.cmake index 2be5dec5a337..4a4f783feb89 100644 --- a/cmake/quickjs.cmake +++ b/cmake/quickjs.cmake @@ -27,26 +27,7 @@ message(STATUS "QuickJS prefix: ${QUICKJS_PREFIX} version: ${QUICKJS_VERSION}") # We need two versions of libquickjs, because it depends on libc -if(COMPILE_TARGET STREQUAL "sgx") - add_enclave_library_c(quickjs.enclave ${QUICKJS_SRC}) - target_compile_options( - quickjs.enclave - PUBLIC -DCONFIG_VERSION="${QUICKJS_VERSION}" -DEMSCRIPTEN - -DCONFIG_STACK_CHECK -DCONFIG_BIGNUM - PRIVATE $<$:-DDUMP_LEAKS> - ) - target_include_directories( - quickjs.enclave - PUBLIC $ - $ - ) - - install( - TARGETS quickjs.enclave - EXPORT ccf - DESTINATION lib - ) -elseif(COMPILE_TARGET STREQUAL "snp") +if(COMPILE_TARGET STREQUAL "snp") add_library(quickjs.snp STATIC ${QUICKJS_SRC}) target_compile_options( quickjs.snp diff --git a/cmake/sss.cmake b/cmake/sss.cmake index 0015d7ef41f8..5ee8cd93b9ce 100644 --- a/cmake/sss.cmake +++ b/cmake/sss.cmake @@ -11,14 +11,7 @@ set(SSS_SRC ${SSS_PREFIX}/sss.c ${SSS_PREFIX}/hazmat.c ${SSS_PREFIX}/tweetnacl.c ) -if(COMPILE_TARGET STREQUAL "sgx") - add_enclave_library_c(sss.enclave ${SSS_SRC}) - install( - TARGETS sss.enclave - EXPORT ccf - DESTINATION lib - ) -elseif(COMPILE_TARGET STREQUAL "snp") +if(COMPILE_TARGET STREQUAL "snp") add_library(sss.snp STATIC ${SSS_SRC}) add_san(sss.snp) set_property(TARGET sss.snp PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/cmake/t_cose.cmake b/cmake/t_cose.cmake index b103164388fb..67a8011dab6a 100644 --- a/cmake/t_cose.cmake +++ b/cmake/t_cose.cmake @@ -12,28 +12,7 @@ set(T_COSE_SRCS "${T_COSE_SRC}/t_cose_util.c" "${T_COSE_DIR}/crypto_adapters/t_cose_openssl_crypto.c" ) -if(COMPILE_TARGET STREQUAL "sgx") - add_enclave_library_c(t_cose.enclave ${T_COSE_SRCS}) - target_compile_definitions(t_cose.enclave PRIVATE ${T_COSE_DEFS}) - target_compile_options(t_cose.enclave INTERFACE ${T_COSE_OPTS_INTERFACE}) - - target_include_directories(t_cose.enclave PRIVATE "${T_COSE_SRC}") - target_include_directories( - t_cose.enclave - PUBLIC $ - $ - ) - - target_link_libraries(t_cose.enclave PUBLIC qcbor.enclave) - # This is needed to get the OpenSSL includes from Open Enclave - target_link_libraries(t_cose.enclave PRIVATE ${OE_OPENSSL_LIBRARY}) - - install( - TARGETS t_cose.enclave - EXPORT ccf - DESTINATION lib - ) -elseif(COMPILE_TARGET STREQUAL "snp") +if(COMPILE_TARGET STREQUAL "snp") find_package(OpenSSL REQUIRED) add_library(t_cose.snp STATIC ${T_COSE_SRCS}) target_compile_definitions(t_cose.snp PRIVATE ${T_COSE_DEFS}) diff --git a/cmake/version.cmake b/cmake/version.cmake index b44770950f94..2c6bb4bae2f4 100644 --- a/cmake/version.cmake +++ b/cmake/version.cmake @@ -5,25 +5,7 @@ unset(CCF_VERSION) unset(CCF_RELEASE_VERSION) unset(CCF_VERSION_SUFFIX) -option( - UNSAFE_VERSION - "Append unsafe suffix to project and targets. Should be used on platforms where log level is determined at build-time, to distinguish builds which are unsafely verbose." - OFF -) - set(CCF_PROJECT "ccf_${COMPILE_TARGET}") -if(UNSAFE_VERSION) - if(NOT ${COMPILE_TARGET} STREQUAL "sgx") - message( - FATAL_ERROR - "UNSAFE_VERSION can only be set for sgx compile target (-DCOMPILE_TARGET=sgx)" - ) - endif() - set(CCF_PROJECT "${CCF_PROJECT}_unsafe") - add_compile_definitions(UNSAFE_VERSION ENABLE_HISTORICAL_VERBOSE_LOGGING) - file(WRITE ${CMAKE_BINARY_DIR}/UNSAFE "UNSAFE") - install(FILES ${CMAKE_BINARY_DIR}/UNSAFE DESTINATION share) -endif() # If possible, deduce project version from git environment if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) diff --git a/edl/ccf.edl b/edl/ccf.edl deleted file mode 100644 index c1d65e04fac0..000000000000 --- a/edl/ccf.edl +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the Apache 2.0 License. - -enclave { - from "openenclave/edl/sgx/platform.edl" import *; - from "openenclave/edl/time.edl" import *; - - include "common/enclave_interface_types.h" - - trusted { - - public CreateNodeStatus enclave_create_node( - [user_check] void* enclave_config, - [user_check] uint8_t* ccf_config, - size_t ccf_config_size, - [user_check] uint8_t* startup_snapshot, - size_t startup_snapshot_size, - [out, count=node_cert_size] uint8_t* node_cert, - size_t node_cert_size, - [out] size_t* node_cert_len, - [out, count=service_cert_size] uint8_t* service_cert, - size_t service_cert_size, - [out] size_t* service_cert_len, - [out, count=enclave_version_size] uint8_t* enclave_version, - size_t enclave_version_size, - [out] size_t* enclave_version_len, - StartType start_type, - LoggerLevel enclave_log_level, - size_t num_worker_thread, - [user_check] void* time_location, - ); - - public bool enclave_run(); - }; -}; diff --git a/include/ccf/ds/logger.h b/include/ccf/ds/logger.h index 262b199d87c5..ce6bd4ed5564 100644 --- a/include/ccf/ds/logger.h +++ b/include/ccf/ds/logger.h @@ -17,13 +17,7 @@ namespace ccf::logger { - static constexpr LoggerLevel MOST_VERBOSE = -#ifdef CCF_DISABLE_VERBOSE_LOGGING - LoggerLevel::INFO -#else - LoggerLevel::TRACE -#endif - ; + static constexpr LoggerLevel MOST_VERBOSE = LoggerLevel::TRACE; static constexpr const char* LevelNames[] = { "trace", "debug", "info", "fail", "fatal"}; @@ -374,23 +368,11 @@ namespace ccf::logger # define CCF_LOGGER_DEPRECATE(MACRO) #endif -#ifndef CCF_DISABLE_VERBOSE_LOGGING -# define LOG_TRACE_FMT \ - CCF_LOGGER_DEPRECATE(LOG_TRACE_FMT) CCF_LOG_FMT(TRACE, "") -# define LOG_DEBUG_FMT \ - CCF_LOGGER_DEPRECATE(LOG_DEBUG_FMT) CCF_LOG_FMT(DEBUG, "") +#define LOG_TRACE_FMT CCF_LOGGER_DEPRECATE(LOG_TRACE_FMT) CCF_LOG_FMT(TRACE, "") +#define LOG_DEBUG_FMT CCF_LOGGER_DEPRECATE(LOG_DEBUG_FMT) CCF_LOG_FMT(DEBUG, "") -# define CCF_APP_TRACE CCF_LOG_FMT(TRACE, "app") -# define CCF_APP_DEBUG CCF_LOG_FMT(DEBUG, "app") -#else -// With verbose logging disabled by compile-time definition, these logging -// macros are compile-time nops (and cannot be enabled by accident or malice) -# define LOG_TRACE_FMT(...) CCF_LOGGER_DEPRECATE(LOG_TRACE_FMT)((void)0) -# define LOG_DEBUG_FMT(...) CCF_LOGGER_DEPRECATE(LOG_DEBUG_FMT)((void)0) - -# define CCF_APP_TRACE(...) ((void)0) -# define CCF_APP_DEBUG(...) ((void)0) -#endif +#define CCF_APP_TRACE CCF_LOG_FMT(TRACE, "app") +#define CCF_APP_DEBUG CCF_LOG_FMT(DEBUG, "app") #define LOG_INFO_FMT CCF_LOGGER_DEPRECATE(LOG_INFO_FMT) CCF_LOG_FMT(INFO, "") #define LOG_FAIL_FMT CCF_LOGGER_DEPRECATE(LOG_FAIL_FMT) CCF_LOG_FMT(FAIL, "") diff --git a/samples/apps/basic/CMakeLists.txt b/samples/apps/basic/CMakeLists.txt index 4094a94e9ea6..c07cac853b07 100644 --- a/samples/apps/basic/CMakeLists.txt +++ b/samples/apps/basic/CMakeLists.txt @@ -5,30 +5,10 @@ cmake_minimum_required(VERSION 3.16) project(basic LANGUAGES C CXX) -option(USE_UNSAFE_VERSION "Use build with unsafe logging levels" OFF) - set(CCF_PROJECT "ccf_${COMPILE_TARGET}") -if(USE_UNSAFE_VERSION) - set(CCF_PROJECT "${CCF_PROJECT}_unsafe") -endif() if(NOT TARGET "ccf") find_package(${CCF_PROJECT} REQUIRED) endif() add_ccf_app(basic SRCS basic.cpp) - -# Generate an ephemeral signing key -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem - COMMAND openssl genrsa -out ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -3 - 3072 -) -add_custom_target( - basic_signing_key ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -) - -sign_app_library( - basic.enclave ${CMAKE_CURRENT_SOURCE_DIR}/oe_sign.conf - ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -) diff --git a/samples/apps/basic/oe_sign.conf b/samples/apps/basic/oe_sign.conf deleted file mode 100644 index 397bde50edeb..000000000000 --- a/samples/apps/basic/oe_sign.conf +++ /dev/null @@ -1,7 +0,0 @@ -# Enclave settings: -NumHeapPages=100000 -NumStackPages=1024 -NumTCS=14 -ProductID=1 -SecurityVersion=1 -# The Debug setting is automatically inserted by sign_app_library in CMake, to build both debuggable and non-debuggable variants diff --git a/samples/apps/logging/CMakeLists.txt b/samples/apps/logging/CMakeLists.txt index 6ca62de95837..0975163501d1 100644 --- a/samples/apps/logging/CMakeLists.txt +++ b/samples/apps/logging/CMakeLists.txt @@ -5,30 +5,10 @@ cmake_minimum_required(VERSION 3.16) project(logging LANGUAGES C CXX) -option(USE_UNSAFE_VERSION "Use build with unsafe logging levels" OFF) - set(CCF_PROJECT "ccf_${COMPILE_TARGET}") -if(USE_UNSAFE_VERSION) - set(CCF_PROJECT "${CCF_PROJECT}_unsafe") -endif() if(NOT TARGET "ccf") find_package(${CCF_PROJECT} REQUIRED) endif() add_ccf_app(logging SRCS logging.cpp create_tx_claims_digest.cpp) - -# Generate an ephemeral signing key -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem - COMMAND openssl genrsa -out ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -3 - 3072 -) -add_custom_target( - logging_signing_key ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -) - -sign_app_library( - logging.enclave ${CMAKE_CURRENT_SOURCE_DIR}/oe_sign.conf - ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -) diff --git a/samples/apps/logging/oe_sign.conf b/samples/apps/logging/oe_sign.conf deleted file mode 100644 index 668529b6da3c..000000000000 --- a/samples/apps/logging/oe_sign.conf +++ /dev/null @@ -1,7 +0,0 @@ -# Enclave settings: -NumHeapPages=50000 -NumStackPages=1024 -NumTCS=8 -ProductID=1 -SecurityVersion=1 -# The Debug setting is automatically inserted by sign_app_library in CMake, to build both debuggable and non-debuggable variants diff --git a/samples/apps/nobuiltins/CMakeLists.txt b/samples/apps/nobuiltins/CMakeLists.txt index da2d8813225b..dd0b324ed8ee 100644 --- a/samples/apps/nobuiltins/CMakeLists.txt +++ b/samples/apps/nobuiltins/CMakeLists.txt @@ -12,19 +12,3 @@ if(NOT TARGET "ccf") endif() add_ccf_app(nobuiltins SRCS nobuiltins.cpp) - -# Generate an ephemeral signing key -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem - COMMAND openssl genrsa -out ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -3 - 3072 -) -add_custom_target( - nobuiltins_signing_key ALL - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -) - -sign_app_library( - nobuiltins.enclave ${CMAKE_CURRENT_SOURCE_DIR}/oe_sign.conf - ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -) diff --git a/samples/apps/nobuiltins/oe_sign.conf b/samples/apps/nobuiltins/oe_sign.conf deleted file mode 100644 index 668529b6da3c..000000000000 --- a/samples/apps/nobuiltins/oe_sign.conf +++ /dev/null @@ -1,7 +0,0 @@ -# Enclave settings: -NumHeapPages=50000 -NumStackPages=1024 -NumTCS=8 -ProductID=1 -SecurityVersion=1 -# The Debug setting is automatically inserted by sign_app_library in CMake, to build both debuggable and non-debuggable variants diff --git a/samples/apps/programmability/CMakeLists.txt b/samples/apps/programmability/CMakeLists.txt index 039e3657d9a4..fd470f86b710 100644 --- a/samples/apps/programmability/CMakeLists.txt +++ b/samples/apps/programmability/CMakeLists.txt @@ -5,31 +5,10 @@ cmake_minimum_required(VERSION 3.16) project(programmability LANGUAGES C CXX) -option(USE_UNSAFE_VERSION "Use build with unsafe logging levels" OFF) - set(CCF_PROJECT "ccf_${COMPILE_TARGET}") -if(USE_UNSAFE_VERSION) - set(CCF_PROJECT "${CCF_PROJECT}_unsafe") -endif() if(NOT TARGET "ccf") find_package(${CCF_PROJECT} REQUIRED) endif() add_ccf_app(programmability SRCS programmability.cpp) - -# Generate an ephemeral signing key -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem - COMMAND openssl genrsa -out ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -3 - 3072 -) -add_custom_target( - programmability_signing_key ALL - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -) - -sign_app_library( - programmability.enclave ${CMAKE_CURRENT_SOURCE_DIR}/oe_sign.conf - ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -) diff --git a/samples/apps/programmability/oe_sign.conf b/samples/apps/programmability/oe_sign.conf deleted file mode 100644 index 397bde50edeb..000000000000 --- a/samples/apps/programmability/oe_sign.conf +++ /dev/null @@ -1,7 +0,0 @@ -# Enclave settings: -NumHeapPages=100000 -NumStackPages=1024 -NumTCS=14 -ProductID=1 -SecurityVersion=1 -# The Debug setting is automatically inserted by sign_app_library in CMake, to build both debuggable and non-debuggable variants diff --git a/src/apps/js_generic/oe_sign.conf b/src/apps/js_generic/oe_sign.conf deleted file mode 100644 index b553df492500..000000000000 --- a/src/apps/js_generic/oe_sign.conf +++ /dev/null @@ -1,7 +0,0 @@ -# Enclave settings: -NumHeapPages=524288 -NumStackPages=1024 -NumTCS=14 -ProductID=1 -SecurityVersion=1 -# The Debug setting is automatically inserted by sign_app_library in CMake, to build both debuggable and non-debuggable variants diff --git a/src/apps/tpcc/app/oe_sign.conf b/src/apps/tpcc/app/oe_sign.conf deleted file mode 100644 index 14b6a005a766..000000000000 --- a/src/apps/tpcc/app/oe_sign.conf +++ /dev/null @@ -1,7 +0,0 @@ -# Enclave settings: -NumHeapPages=327680 -NumStackPages=1024 -NumTCS=8 -ProductID=1 -SecurityVersion=1 -# The Debug setting is automatically inserted by sign_app_library in CMake, to build both debuggable and non-debuggable variants diff --git a/src/apps/tpcc/tpcc.cmake b/src/apps/tpcc/tpcc.cmake index 3eed0b546fd0..e3365f614db3 100644 --- a/src/apps/tpcc/tpcc.cmake +++ b/src/apps/tpcc/tpcc.cmake @@ -19,10 +19,6 @@ add_ccf_app( SRCS ${CMAKE_CURRENT_LIST_DIR}/app/tpcc.cpp SYSTEM_INCLUDE_DIRS ${CCF_DIR}/3rdparty/test ) -sign_app_library( - tpcc.enclave ${CMAKE_CURRENT_LIST_DIR}/app/oe_sign.conf - ${CMAKE_CURRENT_BINARY_DIR}/signing_key.pem -) # tpcc unit tests add_unit_test(tpcc_test ${CMAKE_CURRENT_LIST_DIR}/app/test/tpcc.cpp) diff --git a/src/ds/test/logger_json_test.cpp b/src/ds/test/logger_json_test.cpp index 4f75114fa35f..3cd242cb5a60 100644 --- a/src/ds/test/logger_json_test.cpp +++ b/src/ds/test/logger_json_test.cpp @@ -1,7 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the Apache 2.0 License. -#undef CCF_DISABLE_VERBOSE_LOGGING - #include "ccf/ds/logger.h" #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN diff --git a/src/host/enclave.h b/src/host/enclave.h index 6a243c1745af..5cd23726332c 100644 --- a/src/host/enclave.h +++ b/src/host/enclave.h @@ -128,10 +128,6 @@ namespace host expect_enclave_file_suffix(path, ".enclave.so.signed", type); } -# ifdef CCF_DISABLE_VERBOSE_LOGGING - oe_log_set_callback(nullptr, nop_oe_logger); -# endif - auto err = oe_create_ccf_enclave( path.c_str(), OE_ENCLAVE_TYPE_SGX, diff --git a/src/node/rpc/gov_logging.h b/src/node/rpc/gov_logging.h index 07448d220a12..9111a536eee7 100644 --- a/src/node/rpc/gov_logging.h +++ b/src/node/rpc/gov_logging.h @@ -4,13 +4,8 @@ #include "ccf/ds/logger.h" -#ifndef CCF_DISABLE_VERBOSE_LOGGING -# define GOV_TRACE_FMT CCF_LOG_FMT(TRACE, "gov") -# define GOV_DEBUG_FMT CCF_LOG_FMT(DEBUG, "gov") -#else -# define GOV_TRACE_FMT(...) ((void)0) -# define GOV_DEBUG_FMT(...) ((void)0) -#endif +#define GOV_TRACE_FMT CCF_LOG_FMT(TRACE, "gov") +#define GOV_DEBUG_FMT CCF_LOG_FMT(DEBUG, "gov") #define GOV_INFO_FMT CCF_LOG_FMT(INFO, "gov") #define GOV_FAIL_FMT CCF_LOG_FMT(FAIL, "gov") diff --git a/src/node/rpc/node_frontend.h b/src/node/rpc/node_frontend.h index a36df12217d3..70c5b5a7eacb 100644 --- a/src/node/rpc/node_frontend.h +++ b/src/node/rpc/node_frontend.h @@ -1472,11 +1472,7 @@ namespace ccf GetVersion::Out result; result.ccf_version = ccf::ccf_version; result.quickjs_version = ccf::quickjs_version; -#ifdef UNSAFE_VERSION - result.unsafe = true; -#else result.unsafe = false; -#endif return make_success(result); }; From 56fd6b79f3abedb172131fe566e92eaa81402595 Mon Sep 17 00:00:00 2001 From: Amaury Chamayou Date: Thu, 22 Aug 2024 12:06:49 +0100 Subject: [PATCH 3/8] Remove SGX-specific dependencies from release playbooks (#6447) --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- getting_started/setup_vm/app-dev.yml | 20 ++------------------ getting_started/setup_vm/app-run.yml | 20 ++------------------ 3 files changed, 5 insertions(+), 37 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index bb395bd9ef6e..fe60e8ed98d6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -16,7 +16,7 @@ Steps to reproduce the behavior. A clear and concise description of what you expected to happen. **Environment information** -Version of the code being used, versions of dependencies, relevant environment info where applicable (OS, SGX driver...). +Version of the code being used, versions of dependencies, relevant environment info where applicable (OS, Platform component details...). **Additional context** Add any other context about the problem here. diff --git a/getting_started/setup_vm/app-dev.yml b/getting_started/setup_vm/app-dev.yml index 30819680d29a..daf33c1c52e0 100644 --- a/getting_started/setup_vm/app-dev.yml +++ b/getting_started/setup_vm/app-dev.yml @@ -1,28 +1,12 @@ - hosts: localhost vars: run_only: false - platform: "sgx" - clang_version: "11" + platform: "snp" + clang_version: "15" tasks: - import_role: name: llvm_repo tasks_from: install.yml - when: clang_version == "15" - - import_role: - name: intel - tasks_from: sgx-psw.yml - when: platform == "sgx" - - import_role: - name: intel - tasks_from: sgx-group.yml - when: platform == "sgx" - - import_role: - name: az_dcap - tasks_from: install.yml - - import_role: - name: openenclave - tasks_from: binary_install.yml - when: platform == "sgx" - import_role: name: ccf_build tasks_from: install.yml diff --git a/getting_started/setup_vm/app-run.yml b/getting_started/setup_vm/app-run.yml index d3c395a4c81c..9edd7cf5bc84 100644 --- a/getting_started/setup_vm/app-run.yml +++ b/getting_started/setup_vm/app-run.yml @@ -1,28 +1,12 @@ - hosts: localhost vars: run_only: true - platform: "sgx" - clang_version: "11" + platform: "snp" + clang_version: "15" tasks: - import_role: name: llvm_repo tasks_from: install.yml - when: clang_version == "15" - - import_role: - name: intel - tasks_from: sgx-psw.yml - when: platform == "sgx" - - import_role: - name: intel - tasks_from: sgx-group.yml - when: platform == "sgx" - - import_role: - name: az_dcap - tasks_from: install.yml - - import_role: - name: openenclave - tasks_from: binary_install.yml - when: platform == "sgx" - import_role: name: ccf_install tasks_from: deb_install.yml From 1b30b2472f2eb6ddb2b8c61d5dbd1188479d55b2 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 22 Aug 2024 16:55:29 +0100 Subject: [PATCH 4/8] COSE signing API for raw payload (#6444) Co-authored-by: Amaury Chamayou Co-authored-by: Amaury Chamayou --- cmake/crypto.cmake | 1 + cmake/t_cose.cmake | 2 +- src/crypto/openssl/cose_sign.cpp | 141 +++++++++++++++++++++++++++++ src/crypto/openssl/cose_sign.h | 30 +++++++ src/crypto/test/crypto.cpp | 148 ++++++++++++++++++++++++++++++- 5 files changed, 320 insertions(+), 2 deletions(-) create mode 100644 src/crypto/openssl/cose_sign.cpp create mode 100644 src/crypto/openssl/cose_sign.h diff --git a/cmake/crypto.cmake b/cmake/crypto.cmake index 8dfb7e1b0cdd..c5de9c2fc2d0 100644 --- a/cmake/crypto.cmake +++ b/cmake/crypto.cmake @@ -25,6 +25,7 @@ set(CCFCRYPTO_SRC ${CCF_DIR}/src/crypto/openssl/rsa_key_pair.cpp ${CCF_DIR}/src/crypto/openssl/verifier.cpp ${CCF_DIR}/src/crypto/openssl/cose_verifier.cpp + ${CCF_DIR}/src/crypto/openssl/cose_sign.cpp ${CCF_DIR}/src/crypto/sharing.cpp ) diff --git a/cmake/t_cose.cmake b/cmake/t_cose.cmake index 67a8011dab6a..f1374512f658 100644 --- a/cmake/t_cose.cmake +++ b/cmake/t_cose.cmake @@ -9,7 +9,7 @@ set(T_COSE_DEFS -DT_COSE_USE_OPENSSL_CRYPTO=1 ) set(T_COSE_SRCS "${T_COSE_SRC}/t_cose_parameters.c" "${T_COSE_SRC}/t_cose_sign1_verify.c" - "${T_COSE_SRC}/t_cose_util.c" + "${T_COSE_SRC}/t_cose_sign1_sign.c" "${T_COSE_SRC}/t_cose_util.c" "${T_COSE_DIR}/crypto_adapters/t_cose_openssl_crypto.c" ) if(COMPILE_TARGET STREQUAL "snp") diff --git a/src/crypto/openssl/cose_sign.cpp b/src/crypto/openssl/cose_sign.cpp new file mode 100644 index 000000000000..6ff3d49cfa7e --- /dev/null +++ b/src/crypto/openssl/cose_sign.cpp @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the Apache 2.0 License. + +#include "crypto/openssl/cose_sign.h" + +#include "ccf/ds/logger.h" + +#include +#include + +namespace +{ + constexpr int64_t COSE_HEADER_PARAM_ALG = + 1; // Duplicate of t_cose::COSE_HEADER_PARAM_ALG to keep it compatible. + + size_t estimate_buffer_size( + const ccf::crypto::COSEProtectedHeaders& protected_headers, + std::span payload) + { + size_t result = + 300; // bytes for metadata even everything else is empty. This's the most + // often used value in the t_cose examples, however no recommendation + // is provided which one to use. We will consider this an affordable + // starting point, as soon as we don't expect a shortage of memory on + // the target platforms. + + result = std::accumulate( + protected_headers.begin(), + protected_headers.end(), + result, + [](auto result, const auto& kv) { + return result + sizeof(kv.first) + kv.second.size(); + }); + + return result + payload.size(); + } + + void encode_protected_headers( + t_cose_sign1_sign_ctx* ctx, + QCBOREncodeContext* encode_ctx, + const ccf::crypto::COSEProtectedHeaders& protected_headers) + { + QCBOREncode_BstrWrap(encode_ctx); + QCBOREncode_OpenMap(encode_ctx); + + // This's what the t_cose implementation of `encode_protected_parameters` + // sets unconditionally. + QCBOREncode_AddInt64ToMapN( + encode_ctx, COSE_HEADER_PARAM_ALG, ctx->cose_algorithm_id); + + // Caller-provided headers follow + for (const auto& [label, value] : protected_headers) + { + QCBOREncode_AddSZStringToMapN(encode_ctx, label, value.c_str()); + } + + QCBOREncode_CloseMap(encode_ctx); + QCBOREncode_CloseBstrWrap2(encode_ctx, false, &ctx->protected_parameters); + } + + /* The original `t_cose_sign1_encode_parameters` can't accept a custom set of + parameters to be encoded into headers. This version tags the context as + COSE_SIGN1 and encodes the protected headers in the following order: + - defaults + - algorithm version + - those provided by caller + */ + void encode_parameters_custom( + struct t_cose_sign1_sign_ctx* me, + QCBOREncodeContext* cbor_encode, + const ccf::crypto::COSEProtectedHeaders& protected_headers) + { + QCBOREncode_AddTag(cbor_encode, CBOR_TAG_COSE_SIGN1); + QCBOREncode_OpenArray(cbor_encode); + + encode_protected_headers(me, cbor_encode, protected_headers); + + QCBOREncode_OpenMap(cbor_encode); + // Explicitly leave unprotected headers empty to be an empty map. + QCBOREncode_CloseMap(cbor_encode); + } +} + +namespace ccf::crypto +{ + std::vector cose_sign1( + EVP_PKEY* key, + const COSEProtectedHeaders& protected_headers, + std::span payload) + { + const auto buf_size = estimate_buffer_size(protected_headers, payload); + Q_USEFUL_BUF_MAKE_STACK_UB(signed_cose_buffer, buf_size); + + QCBOREncodeContext cbor_encode; + QCBOREncode_Init(&cbor_encode, signed_cose_buffer); + + t_cose_sign1_sign_ctx sign_ctx; + t_cose_sign1_sign_init(&sign_ctx, 0, T_COSE_ALGORITHM_ES256); + + t_cose_key signing_key; + signing_key.crypto_lib = T_COSE_CRYPTO_LIB_OPENSSL; + signing_key.k.key_ptr = key; + + t_cose_sign1_set_signing_key(&sign_ctx, signing_key, NULL_Q_USEFUL_BUF_C); + + encode_parameters_custom(&sign_ctx, &cbor_encode, protected_headers); + + // Mark empty payload manually. + QCBOREncode_AddNULL(&cbor_encode); + + // If payload is empty - we still want to sign. Putting NULL_Q_USEFUL_BUF_C, + // however, makes t_cose think that the payload is included into the + // context. Luckily, passing empty string instead works, so t_cose works + // emplaces it for TBS (to be signed) as an empty byte sequence. + q_useful_buf_c payload_to_encode = {"", 0}; + if (!payload.empty()) + { + payload_to_encode.ptr = payload.data(); + payload_to_encode.len = payload.size(); + } + auto err = t_cose_sign1_encode_signature_aad_internal( + &sign_ctx, NULL_Q_USEFUL_BUF_C, payload_to_encode, &cbor_encode); + if (err) + { + throw COSESignError( + fmt::format("Can't encode signature with error code {}", err)); + } + + struct q_useful_buf_c signed_cose; + auto qerr = QCBOREncode_Finish(&cbor_encode, &signed_cose); + if (qerr) + { + throw COSESignError( + fmt::format("Can't finish QCBOR encoding with error code {}", err)); + } + + return { + static_cast(signed_cose.ptr), + static_cast(signed_cose.ptr) + signed_cose.len}; + } +} diff --git a/src/crypto/openssl/cose_sign.h b/src/crypto/openssl/cose_sign.h new file mode 100644 index 000000000000..f41dc3388fcd --- /dev/null +++ b/src/crypto/openssl/cose_sign.h @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the Apache 2.0 License. +#pragma once + +#include +#include +#include +#include + +namespace ccf::crypto +{ + struct COSESignError : public std::runtime_error + { + COSESignError(const std::string& msg) : std::runtime_error(msg) {} + }; + + using COSEProtectedHeaders = std::unordered_map; + + /* Sign a cose_sign1 payload with custom protected headers as strings, where + - key: integer label to be assigned in a COSE value + - value: string behind the label. + + Labels have to be unique. For standardised labels list check + https://www.iana.org/assignments/cose/cose.xhtml#header-parameters. + */ + std::vector cose_sign1( + EVP_PKEY* key, + const COSEProtectedHeaders& protected_headers, + std::span payload); +} diff --git a/src/crypto/test/crypto.cpp b/src/crypto/test/crypto.cpp index 35bce3efa4c3..e1f31d5737de 100644 --- a/src/crypto/test/crypto.cpp +++ b/src/crypto/test/crypto.cpp @@ -14,6 +14,8 @@ #include "ccf/crypto/verifier.h" #include "crypto/certs.h" #include "crypto/csr.h" +#include "crypto/openssl/cose_sign.h" +#include "crypto/openssl/cose_verifier.h" #include "crypto/openssl/key_pair.h" #include "crypto/openssl/rsa_key_pair.h" #include "crypto/openssl/symmetric_key.h" @@ -26,7 +28,10 @@ #include #include #include +#include #include +#include +#include using namespace std; using namespace ccf::crypto; @@ -190,6 +195,107 @@ ccf::crypto::Pem generate_self_signed_cert( kp, name, {}, valid_from, certificate_validity_period_days); } +std::string qcbor_buf_to_string(const UsefulBufC& buf) +{ + return std::string(reinterpret_cast(buf.ptr), buf.len); +} + +t_cose_err_t verify_detached( + EVP_PKEY* key, std::span buf, std::span payload) +{ + t_cose_key cose_key; + cose_key.crypto_lib = T_COSE_CRYPTO_LIB_OPENSSL; + cose_key.k.key_ptr = key; + + t_cose_sign1_verify_ctx verify_ctx; + t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_TAG_REQUIRED); + t_cose_sign1_set_verification_key(&verify_ctx, cose_key); + + q_useful_buf_c buf_; + buf_.ptr = buf.data(); + buf_.len = buf.size(); + + q_useful_buf_c payload_; + payload_.ptr = payload.data(); + payload_.len = payload.size(); + + t_cose_err_t error = t_cose_sign1_verify_detached( + &verify_ctx, buf_, NULL_Q_USEFUL_BUF_C, payload_, nullptr); + + return error; +} + +void require_match_headers( + const std::unordered_map& headers, + const std::vector& cose_sign) +{ + UsefulBufC msg{cose_sign.data(), cose_sign.size()}; + + // 0. Init and verify COSE tag + QCBORDecodeContext ctx; + QCBORDecode_Init(&ctx, msg, QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterArray(&ctx, nullptr); + REQUIRE_EQ(QCBORDecode_GetError(&ctx), QCBOR_SUCCESS); + REQUIRE_EQ(QCBORDecode_GetNthTagOfLast(&ctx, 0), CBOR_TAG_COSE_SIGN1); + + // 1. Protected headers + struct q_useful_buf_c protected_parameters; + QCBORDecode_EnterBstrWrapped( + &ctx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &protected_parameters); + QCBORDecode_EnterMap(&ctx, NULL); + + QCBORItem header_items[headers.size() + 2]; + size_t curr_id{0}; + for (const auto& kv : headers) + { + header_items[curr_id].label.int64 = kv.first; + header_items[curr_id].uLabelType = QCBOR_TYPE_INT64; + header_items[curr_id].uDataType = QCBOR_TYPE_TEXT_STRING; + + curr_id++; + } + + // Verify 'alg' is default-encoded. + header_items[curr_id].label.int64 = 1; + header_items[curr_id].uLabelType = QCBOR_TYPE_INT64; + header_items[curr_id].uDataType = QCBOR_TYPE_INT64; + + header_items[++curr_id].uLabelType = QCBOR_TYPE_NONE; + + QCBORDecode_GetItemsInMap(&ctx, header_items); + REQUIRE_EQ(QCBORDecode_GetError(&ctx), QCBOR_SUCCESS); + + curr_id = 0; + for (const auto& kv : headers) + { + REQUIRE_NE(header_items[curr_id].uDataType, QCBOR_TYPE_NONE); + REQUIRE_EQ( + qcbor_buf_to_string(header_items[curr_id].val.string), kv.second); + + curr_id++; + } + + // 'alg' + REQUIRE_NE(header_items[curr_id].uDataType, QCBOR_TYPE_NONE); + + QCBORDecode_ExitMap(&ctx); + QCBORDecode_ExitBstrWrapped(&ctx); + + // 2. Unprotected headers (skip). + QCBORItem item; + QCBORDecode_VGetNextConsume(&ctx, &item); + + // 3. Skip payload (detached); + QCBORDecode_GetNext(&ctx, &item); + + // 4. skip signature (should be verified by cose verifier). + QCBORDecode_GetNext(&ctx, &item); + + // 5. Decode can be completed. + QCBORDecode_ExitArray(&ctx); + REQUIRE_EQ(QCBORDecode_Finish(&ctx), QCBOR_SUCCESS); +} + TEST_CASE("Check verifier handles nested certs for both PEM and DER inputs") { auto cert_der = ccf::crypto::raw_from_b64(nested_cert); @@ -1109,4 +1215,44 @@ TEST_CASE("Sign and verify with RSA key") mdtype, verify_salt_legth)); } -} \ No newline at end of file +} + +TEST_CASE("COSE sign & verify") +{ + std::shared_ptr kp = + std::dynamic_pointer_cast( + ccf::crypto::make_key_pair(CurveID::SECP384R1)); + + std::vector payload{1, 10, 42, 43, 44, 45, 100}; + const std::unordered_map protected_headers = { + {36, "thirsty six"}, {47, "hungry seven"}}; + auto cose_sign = cose_sign1(*kp, protected_headers, payload); + + if constexpr (false) // enable to see the whole cose_sign as byte string + { + std::cout << "Public key: " << kp->public_key_pem().str() << std::endl; + std::cout << "Serialised cose: " << std::hex << std::uppercase + << std::setw(2) << std::setfill('0'); + for (uint8_t x : cose_sign) + std::cout << static_cast(x) << ' '; + std::cout << std::endl; + std::cout << "Raw payload: "; + for (uint8_t x : payload) + std::cout << static_cast(x) << ' '; + std::cout << std::endl; + } + + require_match_headers(protected_headers, cose_sign); + + REQUIRE_EQ(verify_detached(*kp, cose_sign, payload), T_COSE_SUCCESS); + + // Wrong payload, must not pass verification. + REQUIRE_EQ( + verify_detached(*kp, cose_sign, std::vector{1, 2, 3}), + T_COSE_ERR_SIG_VERIFY); + + // Empty headers and payload handled correctly + cose_sign = cose_sign1(*kp, {}, {}); + require_match_headers({}, cose_sign); + REQUIRE_EQ(verify_detached(*kp, cose_sign, {}), T_COSE_SUCCESS); +} From 0d6b1cc351287cef18af3e1d929a8ae18fe7be78 Mon Sep 17 00:00:00 2001 From: Amaury Chamayou Date: Fri, 23 Aug 2024 16:49:36 +0100 Subject: [PATCH 5/8] Remove SGX JWT key filter and policy support (#6450) --- .snpcc_canary | 2 +- CHANGELOG.md | 12 ++ doc/build_apps/auth/jwt.rst | 42 ------- doc/schemas/gov_openapi.json | 22 +--- include/ccf/service/tables/jwt.h | 32 +---- samples/constitutions/default/actions.js | 16 --- src/node/gov/handlers/service_state.h | 6 - src/node/rpc/jwt_management.h | 105 ++--------------- src/node/rpc/member_frontend.h | 2 +- tests/infra/consortium.py | 5 +- tests/jwt_test.py | 144 ----------------------- 11 files changed, 34 insertions(+), 354 deletions(-) diff --git a/.snpcc_canary b/.snpcc_canary index a2af0bef65a3..a90204f06158 100644 --- a/.snpcc_canary +++ b/.snpcc_canary @@ -3,4 +3,4 @@ O \ o | / /-xXx--//-----x=x--/-xXx--/---x---->>>--/ ... -/\/\(-_-) +/\/\d(-_-)b diff --git a/CHANGELOG.md b/CHANGELOG.md index 437388f956f6..01676efe7c59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [6.0.0-dev0] + +[6.0.0-dev0]: https://github.com/microsoft/CCF/releases/tag/6.0.0-dev0 + +### Changed + +- The `set_jwt_issuer` governance action has been updated, and no longer accepts `key_filter` or `key_policy` arguments (#6450). + +### Removed + +- SGX Platform support. + ## [5.0.4] [5.0.4]: https://github.com/microsoft/CCF/releases/tag/ccf-5.0.4 diff --git a/doc/build_apps/auth/jwt.rst b/doc/build_apps/auth/jwt.rst index ffa9c8be491c..5ce24244b050 100644 --- a/doc/build_apps/auth/jwt.rst +++ b/doc/build_apps/auth/jwt.rst @@ -137,48 +137,6 @@ Token signing keys are stored in the ``public:ccf.gov.jwt.public_signing_keys`` If an application uses multiple token issuers, then the ``public:ccf.gov.jwt.public_signing_key_issuer`` kv map which maps key IDs to issuers can be used to determine the issuer that a key belongs to. -Advanced issuer configuration ------------------------------ - -CCF has special support for IdPs that issue tokens within SGX enclaves, for example MAA (`Microsoft Azure Attestation `_). -The goal is to validate that a token has indeed been issued from an SGX enclave that has certain properties. -CCF supports the approach taken by MAA where the token signing key and certificate are generated inside the enclave and the certificate embeds evidence from the enclave platform in an X.509 extension (see Open Enclave's `oe_get_attestation_certificate_with_evidence() `_ for details). -In this model it is sufficient to validate the evidence of the signing certificates when storing them in CCF. -After the signing certificates have been stored, token validation follows the same methods as described in earlier sections. - -CCF validates embedded SGX evidence if a key policy is given in the issuer metadata: - -.. code-block:: json - - { - "actions": [ - { - "name": "set_jwt_issuer", - "args": { - "issuer": "https://shareduks.uks.attest.azure.net", - "key_filter": "sgx", - "key_policy": { - "sgx_claims": { - "signer_id": "5e5410aaf99a32e32df2a97d579e65f8310f274816ec4f34cedeeb1be410a526", - "attributes": "0300000000000000" - } - }, - "auto_refresh": false - } - } - ] - } - -All claims contained in ``key_policy.sgx_claims`` must be identical to the ones embedded in the certificate. -Any attempt to add a certificate with mismatching claims in a ``set_jwt_public_signing_keys`` proposal for that issuer would result in failure. - -.. note:: - - See Open Enclave's `oe_verify_evidence() `_ for a list of available claim names and their meaning. Note that all claim values must be given hex-encoded. - -Some IdPs, like MAA, advertise a mix of SGX and non-SGX signing certificates. -In this case, ``key_filter`` must be set to ``sgx`` such that only those certificates are stored which contain SGX evidence. - Extracting JWT metrics ---------------------- diff --git a/doc/schemas/gov_openapi.json b/doc/schemas/gov_openapi.json index f679b85398b9..fdcc5e6df07d 100644 --- a/doc/schemas/gov_openapi.json +++ b/doc/schemas/gov_openapi.json @@ -305,22 +305,10 @@ }, "JwtIssuerKeyFilter": { "enum": [ - "all", - "sgx" + "all" ], "type": "string" }, - "JwtIssuerKeyPolicy": { - "properties": { - "sgx_claims": { - "$ref": "#/components/schemas/string_to_string" - } - }, - "required": [ - "sgx_claims" - ], - "type": "object" - }, "JwtIssuerMetadata": { "properties": { "auto_refresh": { @@ -331,14 +319,8 @@ }, "key_filter": { "$ref": "#/components/schemas/JwtIssuerKeyFilter" - }, - "key_policy": { - "$ref": "#/components/schemas/JwtIssuerKeyPolicy" } }, - "required": [ - "key_filter" - ], "type": "object" }, "KeyIdInfo": { @@ -1351,7 +1333,7 @@ "info": { "description": "This API is used to submit and query proposals which affect CCF's public governance tables.", "title": "CCF Governance API", - "version": "4.3.0" + "version": "4.4.0" }, "openapi": "3.0.0", "paths": { diff --git a/include/ccf/service/tables/jwt.h b/include/ccf/service/tables/jwt.h index f661b742971e..23ebe5268499 100644 --- a/include/ccf/service/tables/jwt.h +++ b/include/ccf/service/tables/jwt.h @@ -12,37 +12,17 @@ namespace ccf { - struct JwtIssuerKeyPolicy - { - /** OE claim name -> hex-encoded claim value - See openenclave/attestation/verifier.h */ - std::optional> sgx_claims; - - bool operator!=(const JwtIssuerKeyPolicy& rhs) const - { - return rhs.sgx_claims != sgx_claims; - } - }; - - DECLARE_JSON_TYPE(JwtIssuerKeyPolicy); - DECLARE_JSON_REQUIRED_FIELDS(JwtIssuerKeyPolicy, sgx_claims); - enum class JwtIssuerKeyFilter { - All, - SGX + All }; - DECLARE_JSON_ENUM( - JwtIssuerKeyFilter, - {{JwtIssuerKeyFilter::All, "all"}, {JwtIssuerKeyFilter::SGX, "sgx"}}); + DECLARE_JSON_ENUM(JwtIssuerKeyFilter, {{JwtIssuerKeyFilter::All, "all"}}); struct JwtIssuerMetadata { - /// JWT issuer key filter - JwtIssuerKeyFilter key_filter; - /// Optional Key Policy - std::optional key_policy; + /// JWT issuer key filter, kept for compatibility with existing ledgers + JwtIssuerKeyFilter key_filter = JwtIssuerKeyFilter::All; /// Optional CA bundle name used for authentication when auto-refreshing std::optional ca_cert_bundle_name; /// Whether to auto-refresh keys from the issuer @@ -50,9 +30,9 @@ namespace ccf }; DECLARE_JSON_TYPE_WITH_OPTIONAL_FIELDS(JwtIssuerMetadata); - DECLARE_JSON_REQUIRED_FIELDS(JwtIssuerMetadata, key_filter); + DECLARE_JSON_REQUIRED_FIELDS(JwtIssuerMetadata); DECLARE_JSON_OPTIONAL_FIELDS( - JwtIssuerMetadata, key_policy, ca_cert_bundle_name, auto_refresh); + JwtIssuerMetadata, key_filter, ca_cert_bundle_name, auto_refresh); using JwtIssuer = std::string; using JwtKeyId = std::string; diff --git a/samples/constitutions/default/actions.js b/samples/constitutions/default/actions.js index fa380f3c9364..654ecc065326 100644 --- a/samples/constitutions/default/actions.js +++ b/samples/constitutions/default/actions.js @@ -884,22 +884,6 @@ const actions = new Map([ checkType(args.issuer, "string", "issuer"); checkType(args.auto_refresh, "boolean?", "auto_refresh"); checkType(args.ca_cert_bundle_name, "string?", "ca_cert_bundle_name"); - checkEnum(args.key_filter, ["all", "sgx"], "key_filter"); - checkType(args.key_policy, "object?", "key_policy"); - if (args.key_policy) { - checkType( - args.key_policy.sgx_claims, - "object?", - "key_policy.sgx_claims", - ); - if (args.key_policy.sgx_claims) { - for (const [name, value] of Object.entries( - args.key_policy.sgx_claims, - )) { - checkType(value, "string", `key_policy.sgx_claims["${name}"]`); - } - } - } checkType(args.jwks, "object?", "jwks"); if (args.jwks) { checkJwks(args.jwks, "jwks"); diff --git a/src/node/gov/handlers/service_state.h b/src/node/gov/handlers/service_state.h index 1ce0e0c6e287..c941e14f960a 100644 --- a/src/node/gov/handlers/service_state.h +++ b/src/node/gov/handlers/service_state.h @@ -546,14 +546,8 @@ namespace ccf::gov::endpoints const ccf::JwtIssuerMetadata& metadata) { auto jwt_issuer = nlohmann::json::object(); - jwt_issuer["keyFilter"] = metadata.key_filter; jwt_issuer["autoRefresh"] = metadata.auto_refresh; - if (metadata.key_policy.has_value()) - { - jwt_issuer["keyPolicy"] = metadata.key_policy.value(); - } - if (metadata.ca_cert_bundle_name.has_value()) { jwt_issuer["caCertBundleName"] = diff --git a/src/node/rpc/jwt_management.h b/src/node/rpc/jwt_management.h index 1af1cb4c8b52..af7c011ac8ef 100644 --- a/src/node/rpc/jwt_management.h +++ b/src/node/rpc/jwt_management.h @@ -9,17 +9,8 @@ #include "ccf/tx.h" #include "http/http_jwt.h" -#ifdef SGX_ATTESTATION_VERIFICATION -# include -#endif - #include #include -#if defined(INSIDE_ENCLAVE) && !defined(VIRTUAL_ENCLAVE) -# include -#elif defined(SGX_ATTESTATION_VERIFICATION) -# include -#endif namespace ccf { @@ -107,22 +98,6 @@ namespace ccf }); } -#ifdef SGX_ATTESTATION_VERIFICATION - static oe_result_t oe_verify_attestation_certificate_with_evidence_cb( - oe_claim_t* claims, size_t claims_length, void* arg) - { - auto claims_map = (std::map>*)arg; - for (size_t i = 0; i < claims_length; i++) - { - std::string claim_name(claims[i].name); - std::vector claim_value( - claims[i].value, claims[i].value + claims[i].value_size); - claims_map->emplace(std::move(claim_name), std::move(claim_value)); - } - return OE_OK; - } -#endif - static bool set_jwt_public_signing_keys( ccf::kv::Tx& tx, const std::string& log_prefix, @@ -171,83 +146,21 @@ namespace ccf return false; } - std::map> claims; - bool has_key_policy_sgx_claims = issuer_metadata.key_policy.has_value() && - issuer_metadata.key_policy.value().sgx_claims.has_value() && - !issuer_metadata.key_policy.value().sgx_claims.value().empty(); - if ( - issuer_metadata.key_filter == JwtIssuerKeyFilter::SGX || - has_key_policy_sgx_claims) + try { -#ifdef SGX_ATTESTATION_VERIFICATION - oe_verify_attestation_certificate_with_evidence( - der.data(), - der.size(), - oe_verify_attestation_certificate_with_evidence_cb, - &claims); -#else - LOG_FAIL_FMT("{}: SGX claims not supported", log_prefix); - return false; -#endif + ccf::crypto::make_unique_verifier( + (std::vector)der); // throws on error } - - if ( - issuer_metadata.key_filter == JwtIssuerKeyFilter::SGX && claims.empty()) + catch (std::invalid_argument& exc) { - LOG_INFO_FMT( - "{}: Skipping JWT signing key with kid {} (not OE " - "attested)", + LOG_FAIL_FMT( + "{}: JWKS kid {} has an invalid X.509 certificate: {}", log_prefix, - kid); - continue; + kid, + exc.what()); + return false; } - if (has_key_policy_sgx_claims) - { - for (auto& [claim_name, expected_claim_val_hex] : - issuer_metadata.key_policy.value().sgx_claims.value()) - { - if (claims.find(claim_name) == claims.end()) - { - LOG_FAIL_FMT( - "{}: JWKS kid {} is missing the {} SGX claim", - log_prefix, - kid, - claim_name); - return false; - } - auto& actual_claim_val = claims[claim_name]; - auto actual_claim_val_hex = ds::to_hex(actual_claim_val); - if (expected_claim_val_hex != actual_claim_val_hex) - { - LOG_FAIL_FMT( - "{}: JWKS kid {} has a mismatching {} SGX claim: {} != {}", - log_prefix, - kid, - claim_name, - expected_claim_val_hex, - actual_claim_val_hex); - return false; - } - } - } - else - { - try - { - ccf::crypto::make_unique_verifier( - (std::vector)der); // throws on error - } - catch (std::invalid_argument& exc) - { - LOG_FAIL_FMT( - "{}: JWKS kid {} has an invalid X.509 certificate: {}", - log_prefix, - kid, - exc.what()); - return false; - } - } LOG_INFO_FMT("{}: Storing JWT signing key with kid {}", log_prefix, kid); new_keys.emplace(kid, der); diff --git a/src/node/rpc/member_frontend.h b/src/node/rpc/member_frontend.h index fd97f0c36dde..6087e4aff6e1 100644 --- a/src/node/rpc/member_frontend.h +++ b/src/node/rpc/member_frontend.h @@ -599,7 +599,7 @@ namespace ccf openapi_info.description = "This API is used to submit and query proposals which affect CCF's " "public governance tables."; - openapi_info.document_version = "4.3.0"; + openapi_info.document_version = "4.4.0"; } static std::optional get_caller_member_id( diff --git a/tests/infra/consortium.py b/tests/infra/consortium.py index 741c39201ecd..759be70bea64 100644 --- a/tests/infra/consortium.py +++ b/tests/infra/consortium.py @@ -610,9 +610,10 @@ def refresh_js_app_bytecode_cache(self, remote_node): def set_jwt_issuer(self, remote_node, json_path): obj = slurp_json(json_path) args = { + # Key filter is no longer used, but kept for compatibility with + # lts_compatibility tests. + "key_filter": "all", "issuer": obj["issuer"], - "key_filter": obj.get("key_filter", "all"), - "key_policy": obj.get("key_policy"), "ca_cert_bundle_name": obj.get("ca_cert_bundle_name"), "auto_refresh": obj.get("auto_refresh", False), "jwks": obj.get("jwks"), diff --git a/tests/jwt_test.py b/tests/jwt_test.py index 83771dca1904..ef0e861fd3f6 100644 --- a/tests/jwt_test.py +++ b/tests/jwt_test.py @@ -320,147 +320,6 @@ def make_attested_cert(network, args): return pem -@reqs.description("JWT with SGX key policy") -def test_jwt_with_sgx_key_policy(network, args): - primary, _ = network.find_nodes() - oe_cert_path = make_attested_cert(network, args) - - with open(oe_cert_path, encoding="utf-8") as f: - oe_cert_pem = f.read() - - kid = "my_kid_with_policy" - issuer = infra.jwt_issuer.JwtIssuer( - "https://example.issuer_with_policy", oe_cert_pem - ) - - oesign = os.path.join(args.oe_binary, "oesign") - oeutil_enc = os.path.join(args.oe_binary, "oeutil_enc.signed") - sc = infra.proc.ccall( - oesign, - "dump", - "-e", - oeutil_enc, - ) - sc.check_returncode() - lines = sc.stdout.decode().split() - for line in lines: - if line.startswith("mrsigner="): - mrsigner = line.strip().split("=")[1] - break - else: - assert False, f"Could not find mrsigner in {lines}" - - matching_key_policy = { - "sgx_claims": { - "signer_id": mrsigner, - "attributes": "0300000000000000", - } - } - - mismatching_key_policy = { - "sgx_claims": { - "signer_id": "da9ad7331448980aa28890ce73e433638377f179ab4456b2fe237193193a8d0a", - "attributes": "0300000000000000", - } - } - - LOG.info("Add JWT issuer with SGX key policy") - with tempfile.NamedTemporaryFile(prefix="ccf", mode="w+") as metadata_fp: - json.dump( - {"issuer": issuer.name, "key_policy": matching_key_policy}, metadata_fp - ) - metadata_fp.flush() - network.consortium.set_jwt_issuer(primary, metadata_fp.name) - - LOG.info("Try to add a non-OE-attested cert") - non_oe_issuer_name = "non_oe_issuer" - non_oe_issuer = infra.jwt_issuer.JwtIssuer(non_oe_issuer_name) - with tempfile.NamedTemporaryFile(prefix="ccf", mode="w+") as jwks_fp: - json.dump(non_oe_issuer.create_jwks(kid), jwks_fp) - jwks_fp.flush() - try: - network.consortium.set_jwt_public_signing_keys( - primary, non_oe_issuer_name, jwks_fp.name - ) - except infra.proposal.ProposalNotAccepted: - pass - else: - assert False, "Proposal should not have been created" - - LOG.info("Add an OE-attested cert with matching claims") - with tempfile.NamedTemporaryFile(prefix="ccf", mode="w+") as jwks_fp: - json.dump(issuer.create_jwks(kid), jwks_fp) - jwks_fp.flush() - network.consortium.set_jwt_public_signing_keys( - primary, issuer.name, jwks_fp.name - ) - - LOG.info("Update JWT issuer with mismatching SGX key policy") - with tempfile.NamedTemporaryFile(prefix="ccf", mode="w+") as metadata_fp: - json.dump( - { - "issuer": issuer.name, - "key_policy": mismatching_key_policy, - }, - metadata_fp, - ) - metadata_fp.flush() - network.consortium.set_jwt_issuer(primary, metadata_fp.name) - - LOG.info("Try to add an OE-attested cert with mismatching claims") - with tempfile.NamedTemporaryFile(prefix="ccf", mode="w+") as jwks_fp: - json.dump(non_oe_issuer.create_jwks(kid), jwks_fp) - jwks_fp.flush() - try: - network.consortium.set_jwt_public_signing_keys( - primary, non_oe_issuer_name, jwks_fp.name - ) - except infra.proposal.ProposalNotAccepted: - pass - else: - assert False, "Proposal should not have been created" - - return network - - -@reqs.description("JWT with SGX key filter") -def test_jwt_with_sgx_key_filter(network, args): - primary, _ = network.find_nodes() - - oe_cert_path = make_attested_cert(network, args) - with open(oe_cert_path, encoding="utf-8") as f: - oe_cert_pem = f.read() - - oe_issuer = infra.jwt_issuer.JwtIssuer("https://example.oe_issuer", oe_cert_pem) - non_oe_issuer = infra.jwt_issuer.JwtIssuer("https://example.non_oe_issuer") - - oe_kid = "oe_kid" - non_oe_kid = "non_oe_kid" - - LOG.info("Add JWT issuer with SGX key filter") - with tempfile.NamedTemporaryFile(prefix="ccf", mode="w+") as metadata_fp: - json.dump({"issuer": oe_issuer.name, "key_filter": "sgx"}, metadata_fp) - metadata_fp.flush() - network.consortium.set_jwt_issuer(primary, metadata_fp.name) - - LOG.info("Add multiple certs (1 SGX, 1 non-SGX)") - with tempfile.NamedTemporaryFile(prefix="ccf", mode="w+") as jwks_fp: - oe_jwks = oe_issuer.create_jwks(oe_kid) - non_oe_jwks = non_oe_issuer.create_jwks(non_oe_kid) - jwks = {"keys": non_oe_jwks["keys"] + oe_jwks["keys"]} - json.dump(jwks, jwks_fp) - jwks_fp.flush() - network.consortium.set_jwt_public_signing_keys( - primary, oe_issuer.name, jwks_fp.name - ) - - stored_jwt_signing_keys = get_jwt_keys(args, primary) - assert non_oe_kid not in stored_jwt_signing_keys, stored_jwt_signing_keys - assert oe_kid in stored_jwt_signing_keys, stored_jwt_signing_keys - - return network - - def check_kv_jwt_key_matches(args, network, kid, cert_pem): primary, _ = network.find_nodes() latest_jwt_signing_keys = get_jwt_keys(args, primary) @@ -796,9 +655,6 @@ def run_auto(args): test_jwt_issuer_domain_match(network, args) test_jwt_endpoint(network, args) test_jwt_without_key_policy(network, args) - if args.enclave_platform == "sgx": - test_jwt_with_sgx_key_policy(network, args) - test_jwt_with_sgx_key_filter(network, args) test_jwt_key_auto_refresh(network, args) # Check that auto refresh also works on backups From c0178a7a4e83df41de93507dca300df6b7ac828d Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 27 Aug 2024 15:29:56 +0100 Subject: [PATCH 6/8] Fixup verify quote script for load balancer (#6454) --- python/utils/verify_quote.sh | 126 +++++++++++++++++++++-------------- 1 file changed, 75 insertions(+), 51 deletions(-) diff --git a/python/utils/verify_quote.sh b/python/utils/verify_quote.sh index d0d565a6e5a9..b1e51a1982a3 100755 --- a/python/utils/verify_quote.sh +++ b/python/utils/verify_quote.sh @@ -4,13 +4,10 @@ set -e -quote_file_name="quote.bin" -endorsements_file_name="endorsements.bin" open_enclave_path=${OPEN_ENCLAVE_PATH:-"/opt/openenclave"} default_port=443 -function usage() -{ +function usage() { echo "Usage:" echo " $0 https:// [--mrenclave ] [CURL_OPTIONS]" echo "Verify target node's remote attestation quote." @@ -33,20 +30,21 @@ shift # Add default port number if not included (required by openssl s_client) if ! [[ $node_address =~ .*:[0-9]+$ ]]; then - node_address="${node_address}:${default_port}" + node_address="${node_address}:${default_port}" fi while [ "$1" != "" ]; do case $1 in - -h|-\?|--help) - usage - exit 0 - ;; - --mrenclave) - trusted_mrenclaves=("$2") - ;; - *) - break + -h | -\? | --help) + usage + exit 0 + ;; + --mrenclave) + trusted_mrenclaves=("$2") + ;; + *) + break + ;; esac shift shift @@ -65,55 +63,81 @@ fi # Temporary directory for storing retrieved quote tmp_dir=$(mktemp -d) function cleanup() { - rm -rf "${tmp_dir}" + rm -rf "${tmp_dir}" } trap cleanup EXIT -curl_output=$(curl -sS --fail -X GET "${node_address}"/node/quotes/self "${@}") +curl_output=$(curl -sS --fail -X GET "${node_address}"/node/quotes "${@}") + +# Query quotes for ALL nodes to support talking to load-balancer with no session tracking, resulting into talking to different nodes during script execution. +# Save quotes in format +# tmp_dir/node_1_id.endorsements +# tmp_dir/node_1_id.quote +# ... +# tmp_dir/node_N_id.endorsements +# tmp_dir/node_N_id.quote +echo "${curl_output}" | jq -r '.quotes[] | .node_id as $id | .endorsements as $endorsements | .raw as $quote | "\($id).endorsements \($endorsements)\n\($id).quote \($quote)"' | while read -r line; do + filename=$(echo "${line}" | awk '{print $1}') + content=$(echo "${line}" | awk '{for (i=2; i<=NF; i++) printf $i;}') + echo "${content}" | base64 --decode >"${tmp_dir}/${filename}" +done + +echo "${curl_output}" >out.txt -echo "${curl_output}" | jq -r .raw | base64 --decode > "${tmp_dir}/${quote_file_name}" -echo "${curl_output}" | jq -r .endorsements | base64 --decode > "${tmp_dir}/${endorsements_file_name}" +# At least one quote has to be there. +quotes_count=$(find "${tmp_dir}" -maxdepth 1 -type f -name "*.quote" | wc -l) +if [ "$quotes_count" -eq 0 ]; then + echo "Error: No quotes find" + exit 1 +fi -if [ ! -s "${tmp_dir}/${quote_file_name}" ]; then - echo "Error: Node quote is empty. Virtual mode does not support SGX quotes." +# All quotes must be non-empty. +empty_quotes=$(find "${tmp_dir}" -maxdepth 1 -type f -name "*.quote" -empty) +if [ -n "$empty_quotes" ]; then + echo "Error: Empty quote found. Virtual mode does not support SGX quotes." exit 1 fi -echo "Node quote successfully retrieved." +echo "Nodes quotes successfully retrieved." -oeverify_output=$("${open_enclave_path}"/bin/oeverify -r "${tmp_dir}"/"${quote_file_name}" -e "${tmp_dir}"/"${endorsements_file_name}") +nodes=() +for file in "${tmp_dir}"/*.quote; do + base_name=$(basename "$file" .quote) + nodes+=("$base_name") +done + +for node in "${nodes[@]}"; do + quote_file_name="${node}.quote" + endorsements_file_name="${node}.endorsements" -# Extract SGX report data -oeverify_report_data=$(echo "${oeverify_output}" | grep "sgx_report_data" | cut -d ":" -f 2) -# Extract hex sha-256 (64 char) from report data (128 char) -extracted_report_data=$(echo "${oeverify_report_data#*0x}" | head -c 64) + oeverify_output=$("${open_enclave_path}"/bin/oeverify -r "${tmp_dir}"/"${quote_file_name}" -e "${tmp_dir}"/"${endorsements_file_name}") -# Remove protocol and compute hash of target node's public key (DER) -stripped_node_address=${node_address#*//} -node_pubk_hash=$(echo | openssl s_client -showcerts -connect "${stripped_node_address}" 2>/dev/null | openssl x509 -pubkey -noout | openssl ec -pubin -outform der 2>/dev/null | sha256sum | awk '{ print $1 }') + # Extract SGX report data + oeverify_report_data=$(echo "${oeverify_output}" | grep "sgx_report_data" | cut -d ":" -f 2) + # Extract hex sha-256 (64 char) from report data (128 char) + extracted_report_data=$(echo "${oeverify_report_data#*0x}" | head -c 64) -# Extract mrenclave -is_mrenclave_valid=false -oeverify_mrenclave=$(echo "${oeverify_output}" | grep "unique_id" | cut -d ":" -f 2) -extracted_mrenclave="${oeverify_mrenclave#*0x}" -for mrenclave in "${trusted_mrenclaves[@]}"; do - if [ "${mrenclave}" == "${extracted_mrenclave}" ]; then - is_mrenclave_valid=true + # Remove protocol and compute hash of target node's public key (DER) + stripped_node_address=${node_address#*//} + node_pubk_hash=$(echo | openssl s_client -showcerts -connect "${stripped_node_address}" 2>/dev/null | openssl x509 -pubkey -noout | openssl ec -pubin -outform der 2>/dev/null | sha256sum | awk '{ print $1 }') + + # Extract mrenclave + is_mrenclave_valid=false + oeverify_mrenclave=$(echo "${oeverify_output}" | grep "unique_id" | cut -d ":" -f 2) + extracted_mrenclave="${oeverify_mrenclave#*0x}" + for mrenclave in "${trusted_mrenclaves[@]}"; do + if [ "${mrenclave}" == "${extracted_mrenclave}" ]; then + is_mrenclave_valid=true + fi + done + + if [ "${extracted_report_data}" == "${node_pubk_hash}" ] && [ "${is_mrenclave_valid}" == true ]; then + echo "mrenclave: \"${extracted_mrenclave}\"" + echo "Quote verification successful." + exit 0 fi + done -if [ "${extracted_report_data}" != "${node_pubk_hash}" ]; then - echo "Error: quote verification failed." - echo "Reported quote data does not match node certificate public key:" - echo "\"${extracted_report_data}\" != \"${node_pubk_hash}\"" - exit 1 -elif [ "${is_mrenclave_valid}" != true ]; then - echo "Error: quote verification failed." - echo "Reported mrenclave \"${extracted_mrenclave}\" is not trusted. List of trusted mrenclave:" - echo "${trusted_mrenclaves[@]}" - exit 1 -else - echo "mrenclave: \"${extracted_mrenclave}\"" - echo "Quote verification successful." - exit 0 -fi +echo "Error: quote verification failed. No attested node found" +exit 1 From 7540df4282fde8682a88958b59dd404d39f153b3 Mon Sep 17 00:00:00 2001 From: Markus Alexander Kuppe Date: Wed, 28 Aug 2024 00:52:22 -0700 Subject: [PATCH 7/8] Ensure raft traces are always uploaded as workflow artifacts. (#6451) Signed-off-by: Markus Alexander Kuppe --- .github/workflows/tlaplus.yml | 2 +- tests/raft_scenarios_runner.py | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tlaplus.yml b/.github/workflows/tlaplus.yml index 6644bc7204f9..d44297352a48 100644 --- a/.github/workflows/tlaplus.yml +++ b/.github/workflows/tlaplus.yml @@ -250,7 +250,7 @@ jobs: - name: Upload artifacts. uses: actions/upload-artifact@v4 - if: ${{ failure() }} + if: always() with: name: tlc path: | diff --git a/tests/raft_scenarios_runner.py b/tests/raft_scenarios_runner.py index 1761244f0e44..3208024efd20 100644 --- a/tests/raft_scenarios_runner.py +++ b/tests/raft_scenarios_runner.py @@ -169,12 +169,14 @@ def expand_files(files): with block(ostream, "diagram", 3, "mermaid", ["sequenceDiagram"]): ostream.write(mermaid) - with open( - os.path.join(output_dir, f"{os.path.basename(scenario)}.ndjson"), - "w", - encoding="utf-8", - ) as f: - f.write(log) + ## Do not create an empty ndjson file if log is emtpy. + if log: + with open( + os.path.join(output_dir, f"{os.path.basename(scenario)}.ndjson"), + "w", + encoding="utf-8", + ) as f: + f.write(log) write_error_report(err_list) From 4e8bc6281684d30205982eb59971dcfb01d14526 Mon Sep 17 00:00:00 2001 From: Amaury Chamayou Date: Thu, 29 Aug 2024 09:45:09 +0100 Subject: [PATCH 8/8] Update setuptools requirement (#6456) --- python/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pyproject.toml b/python/pyproject.toml index 6662d49b8060..042c2a4ed9c6 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -22,7 +22,7 @@ dependencies = [ "cryptography == 43.*", "string-color >= 1.2.1, == 1.*", "pycose >= 1.0.1, == 1.*", - "setuptools == 72.*", + "setuptools == 73.*", "packaging == 24.*" ]