From e7420dfd0441bf279c1d48409e4598630ed802c4 Mon Sep 17 00:00:00 2001 From: Ahson Khan Date: Mon, 16 Sep 2024 12:10:39 -0700 Subject: [PATCH] Accept base64 (PEM) encoded certificate as std::string instead of vector (#5991) * Accept base64 (PEM) encoded certificate as std::string instead of vector * Fix unix implementation and remove use of privacy enhance mail in comments, in favor of PEM --- .../client_certificate_credential.hpp | 24 ++-- .../src/client_certificate_credential.cpp | 39 +++---- .../ut/client_certificate_credential_test.cpp | 106 +++++------------- 3 files changed, 54 insertions(+), 115 deletions(-) diff --git a/sdk/identity/azure-identity/inc/azure/identity/client_certificate_credential.hpp b/sdk/identity/azure-identity/inc/azure/identity/client_certificate_credential.hpp index e7ac78027..4cc6e253c 100644 --- a/sdk/identity/azure-identity/inc/azure/identity/client_certificate_credential.hpp +++ b/sdk/identity/azure-identity/inc/azure/identity/client_certificate_credential.hpp @@ -99,8 +99,8 @@ namespace Azure { namespace Identity { explicit ClientCertificateCredential( std::string tenantId, std::string const& clientId, - std::vector clientCertificate, - std::vector privateKey, + std::string clientCertificate, + std::string privateKey, std::string const& authorityHost, std::vector additionallyAllowedTenants, bool sendCertificateChain, @@ -112,8 +112,8 @@ namespace Azure { namespace Identity { * * @param tenantId Tenant ID. * @param clientId Client ID. - * @param clientCertificatePath The path to a Privacy Enhanced Mail (PEM) file containing - * exactly one certificate which is used for signing along with its corresponding private key. + * @param clientCertificatePath The path to a PEM file containing exactly one certificate which + * is used for signing along with its corresponding private key. * @param options Options for token retrieval. */ explicit ClientCertificateCredential( @@ -128,17 +128,17 @@ namespace Azure { namespace Identity { * * @param tenantId Tenant ID. * @param clientId Client ID. - * @param clientCertificate The x509 certificate which is used for signing, in base64 string - * format, including the begin and end headers. - * @param privateKey The binary representation of the corresponding RSA private key of the - * certificate. + * @param clientCertificate The PEM encoded x509 certificate which is used for signing, in + * base64 string format, including the begin and end headers. + * @param privateKey The PEM encoded representation of the corresponding + * RSA private key of the certificate. * @param options Options for token retrieval. */ explicit ClientCertificateCredential( std::string tenantId, std::string const& clientId, - std::vector clientCertificate, - std::vector privateKey, + std::string clientCertificate, + std::string privateKey, ClientCertificateCredentialOptions const& options = {}); /** @@ -146,8 +146,8 @@ namespace Azure { namespace Identity { * * @param tenantId Tenant ID. * @param clientId Client ID. - * @param clientCertificatePath The path to a Privacy Enhanced Mail (PEM) file containing - * exactly one certificate which is used for signing along with its corresponding private key. + * @param clientCertificatePath The path to a PEM file containing exactly one certificate which + * is used for signing along with its corresponding private key. * @param options Options for token retrieval. */ explicit ClientCertificateCredential( diff --git a/sdk/identity/azure-identity/src/client_certificate_credential.cpp b/sdk/identity/azure-identity/src/client_certificate_credential.cpp index 985c3fdc4..e566ca6c0 100644 --- a/sdk/identity/azure-identity/src/client_certificate_credential.cpp +++ b/sdk/identity/azure-identity/src/client_certificate_credential.cpp @@ -77,21 +77,15 @@ template std::vector ToUInt8Vector(T const& in) return outVec; } -std::string FindPemCertificateContent( - std::string const& path, - std::vector clientCertificate) +std::string FindPemCertificateContent(std::string const& path, std::string clientCertificate) { - std::string pem{}; + std::string pem = clientCertificate; if (clientCertificate.empty()) { auto pemContent{FileBodyStream(path).ReadToEnd()}; pem = std::string{pemContent.begin(), pemContent.end()}; pemContent = {}; } - else - { - pem = std::string{clientCertificate.begin(), clientCertificate.end()}; - } const std::string beginHeader = std::string("-----BEGIN CERTIFICATE-----"); auto headerStart = pem.find(beginHeader); @@ -127,7 +121,7 @@ std::string GetJwtToken( CertificateThumbprint mdVec, bool sendCertificateChain, std::string const& clientCertificatePath, - std::vector clientCertificate = {}) + std::string clientCertificate = {}) { std::string thumbprintHexStr; std::string thumbprintBase64Str; @@ -328,15 +322,13 @@ UniquePrivateKey ImportPemPrivateKey(std::string const& pem) } std::tuple ReadPemCertificate( - std::vector clientCertificate, - std::vector privateKey) + std::string clientCertificate, + std::string privateKey) { auto certContext = ImportPemCertificate(clientCertificate); // We only support the RSA private key type. - return std::make_tuple( - GetThumbprint(certContext.get()), - ImportRsaPrivateKey(privateKey.data(), static_cast(privateKey.size()))); + return std::make_tuple(GetThumbprint(certContext.get()), ImportPemPrivateKey(privateKey)); } std::tuple ReadPemCertificate(std::string const& path) @@ -430,20 +422,21 @@ std::tuple GetThumbprintAndKey( } std::tuple ReadPemCertificate( - std::vector clientCertificate, - std::vector privateKey) + std::string clientCertificate, + std::string privateKey) { // Create a BIO from the private key vector data in memory. UniqueHandle bioKey(BIO_new_mem_buf(privateKey.data(), static_cast(privateKey.size()))); if (!bioKey) { - throw AuthenticationException("Failed to create BIO for the binary private key."); + throw AuthenticationException("Failed to create BIO for the PEM encoded private key."); } - UniquePrivateKey pkey{d2i_PrivateKey_bio(bioKey.get(), nullptr)}; + UniquePrivateKey pkey{PEM_read_bio_PrivateKey(bioKey.get(), nullptr, nullptr, nullptr)}; if (!pkey) { - throw AuthenticationException("Failed to read the binary private key for the certificate."); + throw AuthenticationException( + "Failed to read the PEM encoded private key for the certificate."); } // Create a BIO from the client certificate vector data in memory. @@ -592,8 +585,8 @@ ClientCertificateCredential::ClientCertificateCredential( ClientCertificateCredential::ClientCertificateCredential( std::string tenantId, std::string const& clientId, - std::vector clientCertificate, - std::vector privateKey, + std::string clientCertificate, + std::string privateKey, std::string const& authorityHost, std::vector additionallyAllowedTenants, bool sendCertificateChain, @@ -662,8 +655,8 @@ ClientCertificateCredential::ClientCertificateCredential( ClientCertificateCredential::ClientCertificateCredential( std::string tenantId, std::string const& clientId, - std::vector clientCertificate, - std::vector privateKey, + std::string clientCertificate, + std::string privateKey, ClientCertificateCredentialOptions const& options) : ClientCertificateCredential( tenantId, diff --git a/sdk/identity/azure-identity/test/ut/client_certificate_credential_test.cpp b/sdk/identity/azure-identity/test/ut/client_certificate_credential_test.cpp index ac79b7241..9a500a033 100644 --- a/sdk/identity/azure-identity/test/ut/client_certificate_credential_test.cpp +++ b/sdk/identity/azure-identity/test/ut/client_certificate_credential_test.cpp @@ -95,71 +95,6 @@ std::string ExampleValidPrivateKeyString "qxxMaq+sv5e9c56EJtctxNnAK27JsoadD+b+NjysZgMeKUdBIzSrHQ==\n" "-----END RSA PRIVATE KEY-----\n"; // cspell:enable - -std::vector ExampleValidPrivateKey{ - 48, 130, 4, 164, 2, 1, 0, 2, 130, 1, 1, 0, 207, 118, 110, 41, 186, 67, 187, - 186, 1, 49, 243, 5, 235, 154, 142, 21, 32, 74, 34, 114, 158, 240, 221, 11, 4, 36, - 96, 54, 108, 204, 125, 156, 115, 47, 194, 232, 6, 231, 139, 117, 225, 10, 95, 168, 20, - 24, 65, 98, 222, 47, 81, 230, 165, 192, 222, 138, 245, 67, 251, 94, 89, 93, 225, 139, - 8, 245, 89, 4, 120, 104, 99, 198, 86, 26, 38, 223, 132, 0, 51, 169, 13, 15, 244, - 38, 181, 147, 39, 99, 188, 30, 46, 37, 193, 39, 23, 244, 88, 181, 11, 250, 159, 163, - 176, 153, 211, 181, 192, 157, 182, 36, 215, 17, 148, 203, 89, 170, 105, 219, 253, 13, 8, - 159, 103, 227, 92, 70, 221, 151, 206, 127, 25, 153, 88, 204, 196, 17, 119, 39, 200, 211, - 42, 226, 73, 16, 92, 97, 93, 164, 131, 76, 222, 92, 44, 95, 152, 43, 193, 222, 182, - 250, 35, 82, 169, 161, 65, 71, 150, 71, 135, 182, 71, 131, 194, 109, 21, 29, 65, 45, - 224, 124, 252, 130, 23, 1, 211, 75, 72, 229, 228, 182, 124, 125, 171, 62, 66, 13, 64, - 167, 58, 251, 68, 20, 11, 98, 136, 9, 0, 190, 27, 50, 108, 96, 54, 240, 64, 230, - 168, 229, 88, 100, 243, 65, 249, 45, 27, 140, 244, 215, 115, 191, 231, 212, 222, 82, 231, - 146, 214, 2, 129, 120, 11, 244, 5, 248, 47, 244, 125, 103, 131, 243, 182, 230, 168, 254, - 166, 209, 2, 3, 1, 0, 1, 2, 130, 1, 1, 0, 196, 25, 34, 186, 40, 137, 59, - 153, 238, 229, 66, 220, 150, 189, 233, 141, 72, 143, 42, 142, 131, 116, 18, 204, 5, 231, - 72, 86, 73, 114, 229, 76, 139, 136, 90, 200, 45, 54, 146, 25, 35, 85, 69, 227, 190, - 210, 202, 131, 100, 150, 255, 232, 111, 70, 166, 84, 92, 207, 28, 124, 43, 38, 213, 57, - 49, 135, 143, 211, 236, 232, 103, 95, 35, 37, 231, 22, 161, 83, 251, 128, 208, 139, 2, - 241, 207, 241, 191, 106, 195, 119, 23, 145, 178, 72, 124, 153, 7, 124, 98, 77, 76, 182, - 82, 8, 165, 24, 8, 112, 74, 169, 249, 236, 113, 99, 225, 102, 118, 87, 109, 146, 243, - 82, 145, 197, 84, 4, 220, 16, 157, 120, 190, 161, 99, 225, 19, 104, 46, 163, 104, 53, - 4, 249, 54, 129, 177, 116, 251, 113, 111, 74, 180, 60, 67, 1, 135, 131, 235, 144, 39, - 10, 208, 164, 159, 146, 7, 212, 242, 185, 1, 90, 184, 100, 121, 255, 4, 170, 31, 221, - 220, 20, 126, 88, 11, 255, 175, 228, 142, 234, 91, 166, 80, 123, 71, 251, 172, 66, 144, - 15, 38, 198, 87, 57, 1, 148, 162, 114, 24, 37, 88, 152, 249, 251, 93, 175, 240, 38, - 184, 176, 179, 225, 89, 33, 241, 243, 127, 121, 180, 144, 152, 160, 196, 151, 127, 31, 4, - 235, 156, 164, 160, 248, 127, 40, 6, 9, 224, 238, 86, 75, 116, 22, 22, 28, 193, 137, - 132, 13, 2, 129, 129, 0, 227, 201, 168, 91, 187, 51, 122, 11, 223, 46, 229, 5, 107, - 75, 7, 127, 34, 174, 55, 43, 206, 191, 181, 174, 119, 139, 26, 210, 92, 29, 40, 241, - 210, 249, 171, 112, 47, 164, 205, 81, 96, 128, 26, 74, 38, 96, 0, 196, 123, 122, 162, - 98, 3, 23, 13, 127, 84, 222, 25, 86, 235, 57, 45, 96, 88, 244, 222, 217, 209, 131, - 136, 129, 142, 159, 39, 114, 18, 193, 84, 183, 247, 89, 222, 83, 61, 28, 53, 84, 171, - 184, 101, 110, 55, 203, 192, 81, 133, 133, 149, 251, 118, 120, 179, 89, 242, 48, 64, 192, - 52, 86, 202, 70, 98, 251, 44, 48, 116, 230, 133, 135, 116, 147, 35, 20, 175, 203, 233, - 135, 2, 129, 129, 0, 233, 40, 85, 226, 253, 145, 66, 37, 243, 145, 110, 134, 29, 32, - 89, 12, 133, 71, 9, 229, 176, 188, 137, 93, 58, 81, 31, 27, 188, 51, 101, 110, 30, - 243, 3, 67, 133, 244, 140, 181, 124, 137, 175, 55, 219, 19, 37, 193, 181, 82, 168, 17, - 39, 79, 232, 217, 230, 245, 110, 223, 181, 204, 167, 91, 222, 185, 75, 222, 19, 30, 236, - 187, 250, 135, 239, 30, 142, 137, 2, 111, 32, 255, 75, 151, 239, 76, 25, 219, 162, 212, - 242, 168, 100, 36, 196, 214, 154, 195, 141, 4, 210, 139, 193, 76, 228, 21, 62, 213, 26, - 199, 90, 6, 88, 154, 155, 84, 75, 190, 55, 147, 81, 23, 80, 130, 119, 237, 34, 231, - 2, 129, 129, 0, 224, 86, 26, 153, 61, 36, 213, 110, 27, 191, 243, 142, 2, 189, 66, - 4, 212, 3, 0, 19, 4, 235, 137, 226, 233, 152, 246, 49, 118, 198, 193, 44, 104, 187, - 187, 60, 33, 176, 13, 5, 184, 36, 113, 191, 213, 75, 119, 118, 10, 166, 28, 134, 170, - 196, 105, 102, 158, 14, 158, 166, 27, 195, 148, 12, 239, 143, 58, 107, 11, 12, 159, 195, - 248, 210, 133, 230, 178, 209, 244, 189, 185, 189, 168, 88, 18, 55, 85, 206, 173, 208, 77, - 20, 223, 158, 171, 41, 158, 118, 145, 223, 182, 45, 233, 117, 12, 48, 185, 148, 145, 247, - 103, 255, 42, 60, 116, 168, 196, 120, 195, 201, 67, 230, 37, 6, 154, 156, 24, 193, 2, - 129, 128, 89, 174, 98, 26, 197, 93, 178, 11, 214, 252, 1, 127, 36, 132, 228, 187, 164, - 40, 6, 238, 138, 100, 122, 145, 153, 116, 202, 122, 104, 145, 124, 90, 55, 29, 82, 12, - 14, 226, 89, 157, 21, 34, 0, 123, 131, 144, 129, 221, 88, 89, 74, 188, 14, 90, 246, - 61, 154, 80, 157, 44, 255, 72, 144, 183, 13, 156, 72, 74, 75, 32, 129, 254, 108, 7, - 13, 58, 187, 168, 135, 127, 39, 58, 11, 97, 141, 113, 192, 32, 115, 41, 101, 140, 207, - 184, 52, 222, 54, 249, 48, 172, 194, 47, 111, 82, 156, 8, 111, 250, 152, 42, 69, 190, - 91, 38, 92, 200, 183, 185, 154, 182, 215, 98, 24, 93, 150, 179, 103, 209, 2, 129, 128, - 55, 188, 105, 17, 190, 48, 228, 148, 77, 53, 227, 1, 91, 44, 108, 54, 52, 82, 207, - 120, 220, 83, 125, 214, 160, 102, 106, 3, 106, 15, 42, 51, 40, 0, 42, 14, 130, 175, - 117, 28, 76, 208, 137, 72, 14, 115, 169, 182, 62, 0, 125, 186, 73, 212, 148, 225, 52, - 226, 67, 96, 26, 84, 248, 12, 232, 241, 74, 30, 116, 3, 96, 157, 219, 89, 218, 125, - 117, 69, 40, 230, 149, 14, 147, 19, 245, 134, 150, 200, 171, 28, 76, 106, 175, 172, 191, - 151, 189, 115, 158, 132, 38, 215, 45, 196, 217, 192, 43, 110, 201, 178, 134, 157, 15, 230, - 254, 54, 60, 172, 102, 3, 30, 41, 71, 65, 35, 52, 171, 29, 171}; } // namespace class GetCredentialName : public ::testing::TestWithParam { @@ -504,6 +439,7 @@ TEST(ClientCertificateCredential, InvalidContentInFile) TEST(ClientCertificateCredential, InvalidContentInMemory) { + // Empty string parameters. EXPECT_THROW( ClientCertificateCredential const cred( "01234567-89ab-cdef-fedc-ba8976543210", @@ -513,13 +449,29 @@ TEST(ClientCertificateCredential, InvalidContentInMemory) {}), Azure::Core::Credentials::AuthenticationException); + EXPECT_THROW( + ClientCertificateCredential const cred( + "01234567-89ab-cdef-fedc-ba8976543210", + "fedcba98-7654-3210-0123-456789abcdef", + ExampleValidCertString, + {}, + {}), + Azure::Core::Credentials::AuthenticationException); + + EXPECT_THROW( + ClientCertificateCredential const cred( + "01234567-89ab-cdef-fedc-ba8976543210", + "fedcba98-7654-3210-0123-456789abcdef", + {}, + ExampleValidPrivateKeyString), + Azure::Core::Credentials::AuthenticationException); + // cspell:disable std::string invalidContents[] = {"a", "-----BEGIN CERTIFICATE-----\na", "-----BEGIN RSA PRIVATE KEY-----\na", "-----BEGIN RSA PRIVATE KEY-----\na-----BEGIN CERTIFICATE-----\na", - ExampleValidPrivateKeyString, "-----BEGIN RSA PRIVATE " "KEY-----\nqxxMaq+sv5e9c56EJtctxNnAK27JsoadD+b+NjysZgMeKUdBIzSrHQ==\n-----END RSA " "PRIVATE KEY-----\n-----BEGIN " @@ -527,18 +479,14 @@ TEST(ClientCertificateCredential, InvalidContentInMemory) "-END CERTIFICATE-----"}; // cspell:enable - std::vector validCert(ExampleValidCertString.begin(), ExampleValidCertString.end()); - for (std::string invalidContent : invalidContents) { - std::vector invalid(invalidContent.begin(), invalidContent.end()); - EXPECT_THROW( ClientCertificateCredential const cred( "01234567-89ab-cdef-fedc-ba8976543210", "fedcba98-7654-3210-0123-456789abcdef", - validCert, - invalid, + ExampleValidCertString, + invalidContent, {}), Azure::Core::Credentials::AuthenticationException); @@ -546,8 +494,8 @@ TEST(ClientCertificateCredential, InvalidContentInMemory) ClientCertificateCredential const cred( "01234567-89ab-cdef-fedc-ba8976543210", "fedcba98-7654-3210-0123-456789abcdef", - invalid, - ExampleValidPrivateKey, + invalidContent, + ExampleValidPrivateKeyString, {}), Azure::Core::Credentials::AuthenticationException); @@ -555,8 +503,8 @@ TEST(ClientCertificateCredential, InvalidContentInMemory) ClientCertificateCredential const cred( "01234567-89ab-cdef-fedc-ba8976543210", "fedcba98-7654-3210-0123-456789abcdef", - invalid, - invalid, + invalidContent, + invalidContent, {}), Azure::Core::Credentials::AuthenticationException); } @@ -590,13 +538,11 @@ TEST_P(GetTokenFromCertInMemory, ) options.Transport.Transport = transport; options.SendCertificateChain = GetSendCertChain(); - std::vector cert(ExampleValidCertString.begin(), ExampleValidCertString.end()); - return std::make_unique( "01234567-89ab-cdef-fedc-ba8976543210", "fedcba98-7654-3210-0123-456789abcdef", - cert, - ExampleValidPrivateKey, + ExampleValidCertString, + ExampleValidPrivateKeyString, options); }, {{{"https://azure.com/.default"}}, {{}}},