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);