diff --git a/.ci/certs/ca_certificate.pem b/.ci/certs/ca_certificate.pem
index f1ae0b232e..99dbe6ccd4 100644
--- a/.ci/certs/ca_certificate.pem
+++ b/.ci/certs/ca_certificate.pem
@@ -1,21 +1,21 @@
-----BEGIN CERTIFICATE-----
-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
+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
-----END CERTIFICATE-----
diff --git a/.ci/certs/ca_key.pem b/.ci/certs/ca_key.pem
index 75349f7475..0bfd2fd992 100644
--- a/.ci/certs/ca_key.pem
+++ b/.ci/certs/ca_key.pem
@@ -1,30 +1,30 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
-MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIm6kLjkvzznECAggA
-MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECGjVddOBQ1QOBIIEyOAafHUtExxT
-tY2ONQkUkXZG4/fIDvuNwt8IIkNUIGVp9WEDd4Mh5Ofa52uUKmlhj+FyRZ6u2mGT
-VHU65e4kBYB10n0oybRPvRU1tFxgr8qI0T7Fqnx7WJAP3m0Bo/tWfqE0GHRrspZV
-gABLVTOFvHE8oOsEh/ndMe+Y2qGaLsl+MF3jkfYAxSK2QwEK9HDa16Xsit7hqVbz
-JUyvBmQVfTZzanIall+EpUntv/vlILKIlAFOZUXIZ/iL8LTQCmpycfGLknr4/9KP
-gCYZmWFS18X9KVAwgV2kSdUebWH9phDosSw6fZh843l1SQvjG65PgrnWYb6Fw7B4
-s3Nk6bXjHYtvLT19EUrQOdeOegynaQQBs5WIcp9LbKT3LJVQpaVGV9thi+LPz1Bu
-Lep583ayXTecA7Dbfa6S9R97TgRoMdDWaz1kTBReQTUhrL5736A38gpwJeBZDqel
-39sRULCKARz2ZX0YpeZCmfVhVVSguO5gCfACsqHoOiTxYOA97GR128BcpEVJ1lst
-sZZNwT3m6xIcXbS37EImhUMGiQ5fyGZ+8FIozTL9xNopIR97b3ceA9CoLc7EVcFC
-RxHvh1HwtpyBDyopJp2wYu31nqcSDsJh+lmjo5R7bqvDDmflfkfu1G45JkXKr3Vz
-M89S/y6Uo8W/EYT2MPYTsqcobtjx6oM1RYkVuYTR6cyUgQkHGtptkzGKxYE8dYwQ
-4EIm87czYvCW0Mrp6yy0NGKzqBb+19Kuqc0HO+YezEQ8RjOVb8+D+cuCp2ZSItJ/
-S9m7BDTOzTS2lBotrFVkSbzaQafAmxQiaSP7gd0M9dnC0AOB2ILbyRAyIDQ0Y2dm
-kMbiewQwNFiY9moRtgzHuHRfFZu4w996Q20cYZyMbxDfY17QoZQzfKWQH1BD7nq5
-G4RFpInt6q4q0F94nQWCif195VZF64+8ETMteJqtBFhUSQbq7PzKdpuf8NFxczLt
-MDEWg2l6qNLP+zswulcVbFcC/HxAu4UtYf2m5MAtaurXZZ/+xPW5c/0caWMycQ7g
-fbkYvC4j0OT7aqqMd1SYzEx7l75Vqn1sr2BsXZFoaqK2c/1LIb6U1kAhyhDQ46rV
-0v6q4GUk4fdnE4N+9MXWBvlKSnqEVYlE54IuSUrYRuuBhO4LQpPMOAafQPR6QCTI
-ikqWVmLAj50n7uba0Ao9lRKR7bFpdOQob/nYMTKT6YQaohYhbCv4zIK9fDgWWiXE
-a2ecIP3KiZzw7oLMKXLcDt1RkkzE1FQxLfOeZ5EP4RwBGPDvR88ELO+lGQQt3VnS
-FIZoXBUFUf7bEUzTwM4240zkjDYQPxD1j769Zq/JZfKyOEXXOJT8xHiwMg3ARWuE
-hGlNKApbJGMn9myC61KaGMyCKRvMVxI25w3LfI4OAWt+67BB5OuAG11nmn9Kja73
-bhMFDIMZ8kE0p9IWfpiUJlDB9odGEc4z3Jl5CqBVDkMCDxq9BQDM0hSDk+ov8FO9
-g03PqMxvsxd2c56vkMtNY4hSGkYfN0RsM3vTXXLtPwRwRZURCmKK76BmsT4oBd+W
-orqH4SABIAbYTwNOb7k/wOc4EfucawBqMG4g+29qewD67+EXjB0GadqOXRoQyhRq
-hd74uUK5gzJOqStqiowQ0A==
+MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQInKuSvrFErBsCAggA
+MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECGntAWF0aGBPBIIEyERsOoQOptO1
+0C4KOtGgTlYCdOldaGrxQL6aUD0utzdswl5iIixBZkdwyc+4KbHWnKBDI4kj4/z8
+NFywpb4mzOmGtKZbAvz9Xjf/KUQ5TdbTr8ZKV8tm2K/CQLrWmnlXI7sqa/zxQvde
+hEDrnx/TIKotm3ZrAJZwSXQSO6p+uMyPzzpIsy0dLjxMwtjiRzIzpxvHeKANIxZ2
+yRdsWZohImyni8zX5NDp4iYcvPC0/+0LPpE8K2/YotegwIm1HN0w/kFcZF97gQ+P
+42frJLTnbDkmCqJSBMhSdfEChO6jbDcYe0K0HXlmS2oJK4HQsO+011gFRb6aXoMs
+9vMWdjtXyOON4SYHJnYi5TkWFj9zzNEbVtIKEgIYQl+p/UPT711i8LdkfV9w/tic
+gb4FwamLAwXwPViM88maRt0AwVWTVKgzFOR4B3uGdIqFH6HQVCAfmdRc9iPM9BK1
+98P5aWwiy69iuK826HMqGyvvE0wzRHcXoKwXOFqn5hZeYc53J3bN3Q5wihhoLyGd
+E7STEXnLmJkJtNCd5sYrevh8lMxWFr/LdWdkF6SQFllEDBQsGTNQxoRqKu9DWXI3
+hJUmPlkJUGKo5BxOQ4KuqBaT+h7Td2CkRx8GXSyHwks1QNCqlvvTVCaVXIFT/fPu
+A30wb7zlszeg0lt2anTXswVbt3vDNcNxXy4rl1ys4bTSp0OGX7MtJL3Du0X4+tmS
+/x1HKSbZ8ppF4h1TYBid3N31ABUtPVzY6icVpjW4/F2Nyc/k30aRmOotectn7alR
+XdHaFO08bdYD2j4Wk1oo9YGNYWtVrJ2zgwj8qy04BzlnnR/D+NtW4Y1XtPPbTa+G
+z86y2EffTQEHEc8BvVx8FOGUkttsR9FVNEhgXiRl8XR1HzfnQMqhHbhZp8jyTn+X
+wm9vx7jlsQgOfxMmUOvmKlSQsJnNmnIfBSTXEFKYoGhiIdXc8gx4ye8houcoel+r
+TEgwmhzG6nqJV3QNn/ahJqEjyGDr4hsmADtZHXX2Ws+6TQCh/IRa6tBwmk62Dscf
+aduchD3BV9Tt0oCIUrdy68RQmtV0bCj03cVzfCwL6pfEUx1QYwty0heXnUfBhMpU
+IcHxCsUXU0MEj5feyrvNOLPBfj59hJUAdZTgmkeMkcNCU15sadoqVy0At6oI+18V
+XNkGwxA/qcaPVDGAm22uPNm6abD+L2i1hlCxzbG+onfcMTCeAwYLH1aaFkdRGLfC
+lTmCJTC88mtojzAWoMU9BAzaKZsFFqnAUiIsTrC2+ANJEdb2UCmJsLg7emsOBgDi
+OjVTw6mdULoyysVIFZ6YKgOfXQGHp4wt8lWsxonh7+f1p56q6/rqW4Pu6pzWEOOB
+ZPHERrpKKoQh42UJtYHG+dkfKslKtNCWiKWlKqsQNIDzZJka3DPCqiVm8cjUs0n0
+BpDhyqt7g7wmOrCvMnQQJF7FOm/UNC3DMqbMwykuCn/7VGZeItHdxzKcfdMFZKuK
+4TQG+GfGPcyj80sE0iNciZNnRnOLMJReAtqDpHxzt6r6g4V3e1RGDFN5E1z+CH+w
+zk+mPd5FargbA/2MjcU1SZ3NbLFE14fmsV4WO2wGyzNCwIFoh9sm0Jos/iTyzrdc
+qTx0cg/7JEvaV0jy9ytKBQ==
-----END ENCRYPTED PRIVATE KEY-----
diff --git a/.ci/certs/chained_ca_certificate.pem b/.ci/certs/chained_ca_certificate.pem
new file mode 100644
index 0000000000..558e26f0f5
--- /dev/null
+++ b/.ci/certs/chained_ca_certificate.pem
@@ -0,0 +1,41 @@
+-----BEGIN CERTIFICATE-----
+MIIDWTCCAkGgAwIBAgIBATANBgkqhkiG9w0BAQsFADBLMTowOAYDVQQDDDFUTFNH
+ZW5TZWxmU2lnbmVkUm9vdENBIDIwMjUtMTEtMDVUMTE6NTA6MjUuNzEzNTY2MQ0w
+CwYDVQQHDAQkJCQkMB4XDTI1MTEwNTE5NTAyOFoXDTM1MTEwMzE5NTAyOFowMDES
+MBAGA1UEAwwJbG9jYWxob3N0MRowGAYDVQQKDBFJbnRlcm1lZGlhdGUgQ0EgMTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANKXfTftwYjSbFTLVfEPdPHS
+jMHAoHG11NlHoC2lAzKSi39MZpw5kJL3F+QhaArXHoqliCApr2YsdbQAov0LBHEc
+HqLgwuuOS5z7XZJowy7ZGZRQ/wW7PI4RGzgDBTsY8UE5ffw6OET2yS68L3b4rgcj
+BiVZQnUjeXsIYlh1f0CDqMm3qtUl/3y6ML5+CIrtItAhIom26euQ2CvwZWR3mk65
+zgNIZ3EqXMLr3FzQ+aJnz0TBDQAx/KduP8ZpYYOZ1Kw1OU/sIkcol0zfrFUYIgx0
++7LoCoV5QwKm0rSrMjUaudpBCsZjP5sQbvGj9JmekhHwiKI95TmtA6mPuQL2zDkC
+AwEAAaNjMGEwEgYDVR0TAQH/BAgwBgEB/wIBADALBgNVHQ8EBAMCAQYwHQYDVR0O
+BBYEFI2/L45C3RmYVeg6NP26Xny18yPWMB8GA1UdIwQYMBaAFJLwQcD9+OGZt/Ti
+vAdtLTmQJVCCMA0GCSqGSIb3DQEBCwUAA4IBAQC+Poi7gOzAdSwJ8n7YBwqPwpA+
+Tz44B6jIXw0M8XXDSwGeGKEWa5DWeNIJD2uV05KR+2Ph63VBKcRgl2Zf/QzZ59I6
+z51w4+sJ+kJHtxMPzOqDdiNZuZAJQk+rFGsIgHZjb+rJlDQGjy1I+5rMVIsOuJoN
+JRBZ6qJunU4AF7+Al4qeXj9182NHJ67fexE3YCjNf81Hnd1fnS0rsEzDQaA4lRO+
+uTYrfpwILaq1ghy0uarvwVMDEp5s7Nodi+ALwWlmIa6VTC4ML8kxl6YbRruprVoU
+XS9e7q6qXCSQzzt2DEorySnlmaiUKtyHfqt6qGFI5PVRyshSQq/IknTY0iMw
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDhDCCAmygAwIBAgIUftOapTprbnKyfBM1Hd7DVVWY3bEwDQYJKoZIhvcNAQEL
+BQAwSzE6MDgGA1UEAwwxVExTR2VuU2VsZlNpZ25lZFJvb3RDQSAyMDI1LTExLTA1
+VDExOjUwOjI1LjcxMzU2NjENMAsGA1UEBwwEJCQkJDAeFw0yNTExMDUxOTUwMjZa
+Fw0zNTExMDMxOTUwMjZaMEsxOjA4BgNVBAMMMVRMU0dlblNlbGZTaWduZWRSb290
+Q0EgMjAyNS0xMS0wNVQxMTo1MDoyNS43MTM1NjYxDTALBgNVBAcMBCQkJCQwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDdXHuxDyvLjbmiWQJgh5Flnmd7
+dB9eKzgnpwGXW7pF68LSCd8aJDaQV+7BVUw5PyviNqr6saHVB2XRs0fiTUp9OkjA
+Oo4MYWLfdHCJVlTTpghusbewf6j+Zi6cAeKXyUmRqf9V9lk6H/IixRAloF1vsHeA
+sI8bPq9PwogMnkz5bTMnCiLOLc0IYOoYATdMl4VxgzK6Osc4g/XMOsvTEKd2OX/Q
+7QKkwGQDSuZWSc//Vtv0OpdrC74CDvLdkb/q7h1Kg3O6M/b3in4sjtyKAcVXKeUA
+0bS4U79I31aN8FWUSBxvLNUaDzEmRLnW2FDb37X05x4ZK8jte1eNmqqq6143AgMB
+AAGjYDBeMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBSS
+8EHA/fjhmbf04rwHbS05kCVQgjAfBgNVHSMEGDAWgBSS8EHA/fjhmbf04rwHbS05
+kCVQgjANBgkqhkiG9w0BAQsFAAOCAQEADvKmzBN7TiKL8I2PIwO5QfB6RSZcLrcB
+bo75Cj2MUx+UTwsNrl8mYAMqma+COh56rN2p/qj+nj1w5cyrV/vRRFfw35GLx08f
+0eNH15bZARJdHtYSC3Qr1N5lmvx3maOvsGaxtJI1+UYdLK8Z2lDnGk33QHoyf+7/
+MEtnQyd0LG9IjjWeqUu33aTapvKavJQuTJVe5jnHJXPvuS5T0en8nJO5AjXRk64s
+XUL5S63fZss9OtKgYm5RW/8HWGEsuxQ5kBMzgeWdJereGtI7MnRcazXunf5fOaBM
+Brq07sL6VOu+rPAcYuVcPvktF3pIZbwuGtQ+VHpFv6qBKAjCtXM49w==
+-----END CERTIFICATE-----
diff --git a/.ci/certs/client.p12 b/.ci/certs/client.p12
new file mode 100644
index 0000000000..13eb43b8c7
Binary files /dev/null and b/.ci/certs/client.p12 differ
diff --git a/.ci/certs/client_certificate.pem b/.ci/certs/client_certificate.pem
new file mode 100644
index 0000000000..7958efcfe7
--- /dev/null
+++ b/.ci/certs/client_certificate.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDczCCAlugAwIBAgIBAzANBgkqhkiG9w0BAQsFADAwMRIwEAYDVQQDDAlsb2Nh
+bGhvc3QxGjAYBgNVBAoMEUludGVybWVkaWF0ZSBDQSAxMB4XDTI1MTEwNTE5NTAy
+OVoXDTM1MTEwMzE5NTAyOVowJTESMBAGA1UEAwwJbG9jYWxob3N0MQ8wDQYDVQQK
+DAZjbGllbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDbNWqHe+Re
+oD8FqrWV4bl9aFbje45hrMpy0W4dzHHNP8MjEw6sCqX9por22oZ89cTrf//Sp+RT
+x9NFCO7l3VTgjRjRkfVSVydhDYzMscUvTuzxobzWxDx6MEYrv7emWKaM3+Ph/nZh
+o0cCFEvZ5mHFeAqaYDTQkTt2Yscpo6f84SwY5JcJAfCykCcgZCTqoWoEvidHCk6q
+ZV98MQbbMsSWtmUuhYIMxERIfx46/mbWFGIOOv3mW/6TKadlf0NmkI5kC1QlZbdh
+bL0I0syzXxwLxA2zQL5nM05pmZ4RxStioEOcZoZBxwA8aaMuE7ZJp8c1Stq2lVoI
+9RnfAWazTQNnAgMBAAGjgaIwgZ8wCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwEwYD
+VR0lBAwwCgYIKwYBBQUHAwIwMAYDVR0RBCkwJ4IJbG9jYWxob3N0gg9TRUEtM0xH
+NUhWSlVXSkuCCWxvY2FsaG9zdDAdBgNVHQ4EFgQUBeolqURKViMO2PIB2c4sfwUn
+bXMwHwYDVR0jBBgwFoAUjb8vjkLdGZhV6Do0/bpefLXzI9YwDQYJKoZIhvcNAQEL
+BQADggEBAGD6seY0AQjuA4BC4daOFn7gUPiuy85yZcu2gSRup4imZPEx6Ig8nyFL
+aG6ztpaaTORpMTwoiQYM304vPvfFSpGcy4+bGV776jjYCkCc1Mg32m2z8ftA3+0s
+Z+reafKGA4F53aBHz1Cz+yU0uja5MM6DDDzRRnM8XTR4aRAmH4VMxc8/140Q/3OT
+SoUFEJ7MMBb8Jq34x/cuXNEMg0PtfG4kTsHVCmmrLKdrKqQYFdHI3DAnE5jslhxs
+11TFUdAgfh5P4w9e5fJBatyog0HmQHnz6w/eZWTUVRcKU0WeGSQDV0vCKWrWpF/s
+Mz1GaCK+9EI2eVzAvejQ/jReUtNguOY=
+-----END CERTIFICATE-----
diff --git a/.ci/certs/client_direct.p12 b/.ci/certs/client_direct.p12
new file mode 100644
index 0000000000..b139e3df8b
Binary files /dev/null and b/.ci/certs/client_direct.p12 differ
diff --git a/.ci/certs/client_direct_certificate.pem b/.ci/certs/client_direct_certificate.pem
new file mode 100644
index 0000000000..71f5a3ea3a
--- /dev/null
+++ b/.ci/certs/client_direct_certificate.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDlTCCAn2gAwIBAgIBBTANBgkqhkiG9w0BAQsFADBLMTowOAYDVQQDDDFUTFNH
+ZW5TZWxmU2lnbmVkUm9vdENBIDIwMjUtMTEtMDVUMTE6NTA6MjUuNzEzNTY2MQ0w
+CwYDVQQHDAQkJCQkMB4XDTI1MTEwNTE5NTAzMVoXDTM1MTEwMzE5NTAzMVowLDES
+MBAGA1UEAwwJbG9jYWxob3N0MRYwFAYDVQQKDA1jbGllbnRfZGlyZWN0MIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy7UbxnPne7KE4nue8IrUSYdROfio
+yreIuGs0vx0ueDwUAWpKdoD7ntri907Sk6iUNOiXrt6S3w4rFEbcSuJWZcH4hKCH
+FwEZyov5xpjQpcFy+7nLzNRvFfUlppQRFqY4zykbWeZ4IBiS5e5Uk0di+QeDXC59
+bGj06QC/h2+rnLQMGJYlpaWjDwFb5KIxfSQ4pd2/JIG9fJZ+MEvYJum0ssho5MPd
+TuQ/aRnlR1mJdwr22MNN1IVb8qneYhhTzBfoxnKNSc5/AnwrtGE3KCVeFYKWoWfJ
+MjxLwR1euW/sRqCWzM5HbHgmO/wvXaVpnFSUgwODTEb8HUlo3lqKWQtCNQIDAQAB
+o4GiMIGfMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUF
+BwMCMDAGA1UdEQQpMCeCCWxvY2FsaG9zdIIPU0VBLTNMRzVIVkpVV0pLgglsb2Nh
+bGhvc3QwHQYDVR0OBBYEFAmI+G1mB4F1yFumiIHEHfGZf2RmMB8GA1UdIwQYMBaA
+FJLwQcD9+OGZt/TivAdtLTmQJVCCMA0GCSqGSIb3DQEBCwUAA4IBAQAiiSdP77h2
+ipSEOxHH9KbOptSsoZy6l/LhCLRY8sMgdd7bn+gyKG7f/6SQ5UcdX87iu26ax5zv
+xKizrNbxT1pLCZif4Kzs1ItqcZYWidhdrMIXJF70RVKdOFzGOr9zwSoMw1Yuy1sR
+z8Uj9/G+yMvfOVDJ7K1VKbl4YcMx+bWT774GVt27ZjEnICb1NvhP6/Pf2vdQRKol
+czJ/83bkckJ4rKgY8mGV7k4t+xfvyHEp/+qTpy+xfxDXgf0n4qIb8MABmnRAzwAy
+XMA01jBma/WnUDlvQhWlD6s7TEyR646jaykl/LXJ7N0S4I4oY/kHH60wDEjwntK3
+surniMqJ6Xss
+-----END CERTIFICATE-----
diff --git a/.ci/certs/client_direct_key.pem b/.ci/certs/client_direct_key.pem
new file mode 100644
index 0000000000..a419f1bc9e
--- /dev/null
+++ b/.ci/certs/client_direct_key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIv8ZrCBQ0Zx4CAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBCds9Bwm3XTrNb4LvM5doWuBIIE
+0H9lVAJt07/VYjVuABP/H9oI7QC/xqOSrPpdA+mdWkg6SrAxosSDC1UJckla23I0
+Z/mZbok7wOdHYPEfqsyyxQ++4/N+XPLMm7azl6BlaZll1yTLMAhoM9zY2JDy6oH0
+F0UZBZ3hdzWfUp0A2cz4ArpQ3jvzhLMhJ2glb5zh3uQ/3GEuwnmkIxzJIxZoUfjB
+2Jihf7fKSvIpS8gSA5dX2YMtGptwBQiK8sTbN1ihznOcpqkp4aSKx2h8kuDCMTmK
+eI0SWVbzBXGI0455NXqRxuDwv4Met+s6urdXMhEf+qXmA6G35Hgu7dp/IMHlDCXE
+0X9lCM90R+KxJASjqtgnFRY1qIue4qNr+GiFE6llLJRcUIO6BHEHXbn3Oc+mLWiu
+bBVUdNuo5hiu7TNmCwZQe8tdxoLxmHz31tdGyIKLL6erw01uDarHaT0AO0lUqCqn
+f2dCPmwzR6uc4VgB4aLJUlVknkoh4s7SBfN2BsdMBT4d7FnrwL1SEsLQGyKkd9Zb
+wAi7zwX4GeSiW0J84NjPWLsY4wV++/8oOJa+siUi5dltyIHsaHb0u6mkJksX0lkZ
+hvEydhQi3aDwk4kEbqqr4e9EfdCTCJY8gtbZmw3ytiEQHiaSKmJUDNPfXOhQmeMb
+SGSkYHIDxrEUiBsEWfbbAlaoeRTmKdvc3I5QdDAs+58/KTPXMvgC9PfasCjjLBel
+ABEEGMH2sbrJ73drgzH8iIKJTJtoIf0q829pfiEZlovoxmN+RLSChdyk/T1vkc67
+evYA39Z4vfMSgKkDvMIsx/akHwKAb7/6ggvapRC2JWNabcFPF+Jtboglyo89hr92
+8uDVqCFeWmcJ/l/Ss2I2Dw4E3P+ID3cn0IXtQ4VMuw/vwfKB59MCYUQCnQWGa5pJ
+8iaHKDr3mf8AtlA8rBXNqOyXfKC78YNzw9pcSHK4UEz602IWID4fq+hGDFgcQJPC
+oirYHzwFLF9KlN2QE16Ocw1JRzYlvVRsg03Kj8IqezGfQtIPFFDgW3LQ+oCTf0TK
+gmyBIqM0Qeqx5ahr+PC+8BKKLRI6F0JHzieVnVr5oJPE2hpEQ59EF3RAamqnWnvz
+q4nI24hqppLpK304vc7u336Ug3L7/xAKwoQNjxO7UcZJhyQil0DtLtFJDtPqp8tV
+FNtb2PU6PIXoRYk6VDdWK/dXWpQeRXzXZEFmC8p9mDhEIWtT6Udj5NkZV7rgWq0o
+1d8u/yf6A6K59gLcLpv1O5AaQRv8S/DylhDNjPXr0TiMmloFUDL4A2dZrZBUZ9LR
+R6oF7pgt9MLW1453vCkuDvmX+QOf1cIxP9m0xVMJxeFJK5Xdv3Ae+6zb/aYysJMb
+OGzGru8YM80yzjrXnERoL7P9duoaBUEKEzdZn2CjYAmlfTliitGITomPyKk1UKmF
+Wo45NLPtD7X3NXyuKC+//dDmWBNHnd8d8CDmcR5erVy8UEkrdPDfQdsW8d0YAPUP
+yRlMkCkbqnFpZ507youYrXHzbNflVma3my0oLucsxAqjSKpw58wl8mdw3fFqtoyc
+76r2BUzRmoS4rki/hsZZHo3QWRmRIR96MBdwS84ZtncgvkR8ulqAMjm9wt/fEbuP
+zWHex8Q7UHba5vhSCIsCScVwntb8p/5gK+SdM7tRXMQJ
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/.ci/certs/client_key.pem b/.ci/certs/client_key.pem
new file mode 100644
index 0000000000..9409b060c1
--- /dev/null
+++ b/.ci/certs/client_key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIjlBujt2JEpsCAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBBFCV+cvg6jLi8qqpzrQ/86BIIE
+0OPCwGM+z1gtdTN7GhuMdz0FeDDOtwWk2wHLzT1b8p1L07V+OJhcdkJycNJeLvwr
+awZSusV6VircXcb/MTUq2XZ8N9uMarVEECRmc4nxY8cXu5A5HWA6UAMfaYe0lI1z
+K+bVDa6CVYQjwiOk1ZloyHshtg6dCuSkkGta0oHa76OgSYpNY03pWPn+nKmv4P8h
+gc2x+nel/GdmzRWMZF2S0ZcC3VNPz48v4ZoAQgJBsXbH07PZjQqoxdzQZMhV0PH9
+8FLQpCMA53bI7u/JW58IRVOTz5+NsEtPtNU1nBBQGTQZKO6ZCodo83A+ygfc0U2C
+LQ9+N52KPKI6G2ZdwDYRbiCLAFQXSb8z/s+3Em32rXfZ6Y1A0BHQe1nlilEArVyI
+OaiBr7TbwhfLLk5fIFL8WQhgA3VRlDZkiCDIbun64fFKpyVwOu52e8Ku5rDqFILJ
+eHFWRdvCzr4AJ9/RczQh2JFXL04d8UR5BwuMwl/LkMrekwWLfNwIPZmOoUl6Zt5X
++3k0Q0dKv4hFdFOI2XlVsgUbIdv915TCrSnyVjbAlijhHLq+pYFA/DJ/s1xvPz7O
+VX6gKV97YmTsEWqx5TWGusNuXhf0bj1DpakJhwGRhV09GEj2VAhF6rfb1tp6m1R8
+fi5OiLPlN2T7BTGcesZyJI++40qthjeL2w1er1WfVq1Y3ECNyDD+Lr9YcUbYd86l
+kkRXg/O0O9MlwEBEMS7DqkUf1KEu81StmL3mckNG/kzBzAUypOoern1zuWEM+G1W
+8HPMlGqi24XG7GQRAiqbMGGErht9W983oq5r5DR/c9OVq7btnN+YrzAqezaFhwcC
+x4gd6M4z/9LFwwsxkIccgBhwfpJLWNzwieFKCjh/s5lhSad3IF+BkuoDtZPqmJLk
+TxQwLg0rzT4iN8/0sOL+v3fU76dp7bdg9pRyz8cvd+SlUcr5WCe2YvXtfa3V9qfZ
+eTSUARt6erYLnM5IKH4OFnwtabGEirOaepfJl09TbDiboubRY/95JF+7pnA3U8Su
+CtrjOSDuHJCPgZ9mcPot4GlVc4nBozmmE6Mv23Y/Qz9UKCNhTDXgKP6ndh0duYOt
+2j+rLRJVeOQ8fMmfNDtwqkLK7cAdruhxd1+0skm0tZ8TXbdWA6XG66eaDWuzMpH9
+bI+XRU2zZB3TwMBh+IUXgFW7k8wT8qrygxJj50tGUnVHgguxWk+fqTB4tq0+X+Jz
+ZBmqChtQF6pZQXN+BAjjzbGnX5Z06zMDzFSvbXH5gK+uSTZu/YmcbcSXo1M/F2B5
+9KGhWval+wexOLAELjQIk701Wo2c2LIOyygeetOEt8tiAhXyD79/GaQrVhQcB6jh
+/hCrlhrlVBN2TGrZtbBXcziZnVRVv7tVty6y4xeV8/7rchmsHUvDmXzJTdlv+pBM
+iCYoMg0a093207VQP8zhwoRA5tRsaQgM1Rtf6RgtNZaAlnyx0rwaM8iaOPAUmF3r
+DsYbYcrtazPJstxUQszAFXF4UgJAUZZ6L718gxUEzT/IYwbS6zQepmruehuR4zPl
+ejtBl6H6HGF85OjN/9d87lUkRpdrz7m7ehIF7yFw1FELu6xXUxEDtO+kLF8MACOD
+T2lyyUvc+/1QEkhXqstDZC0Kcc4RzZ4BiIqNZ9tnTCXS
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/.ci/certs/client_localhost.p12 b/.ci/certs/client_localhost.p12
deleted file mode 100644
index 1d688c585d..0000000000
Binary files a/.ci/certs/client_localhost.p12 and /dev/null differ
diff --git a/.ci/certs/client_localhost_certificate.pem b/.ci/certs/client_localhost_certificate.pem
deleted file mode 100644
index 1af5a9f163..0000000000
--- a/.ci/certs/client_localhost_certificate.pem
+++ /dev/null
@@ -1,22 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDvDCCAqSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBMMTswOQYDVQQDDDJUTFNH
-ZW5TZWxmU2lnbmVkdFJvb3RDQSAyMDIzLTEwLTA4VDA4OjE2OjAzLjU5MDQ1NDEN
-MAsGA1UEBwwEJCQkJDAeFw0yMzEwMDgxNTE2MDNaFw0zMzEwMDUxNTE2MDNaMCUx
-EjAQBgNVBAMMCWxvY2FsaG9zdDEPMA0GA1UECgwGY2xpZW50MIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxoOGcKsURRZG0D89J8rGcolZVqX56rDgA0Ma
-cn4AosMQTZ86XAq+Ygn6QVcFV3NjuHxb29vsZfjSYbBpgQNLfpXN9EfeswVvaJND
-wblKdRo10RTPslFewI4Aac88GXva+3DBMCwv3viI2S69apcuZgGw0+EKDh+JmbcM
-sdH81hZhYjmrS529qSOIji8vJYFTCQPMbGN17elnA7pZaHEmPKj5mzm0veSBvCwU
-OZORr4eFE7Nct5RmhLm8DWT0EBRUWT8D6/b6+0ln32Yv30YNpKrua5wkn+kxsvKJ
-tQRRKYRyfegSj6mo6L4za1ZvwV/JMN5mDLQUajvtOCsD4NpKcQIDAQABo4HPMIHM
-MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMCoG
-A1UdEQQjMCGCCWxvY2FsaG9zdIIJUFJPS09GSUVWgglsb2NhbGhvc3QwMQYDVR0f
-BCowKDAmoCSgIoYgaHR0cDovL2NybC1zZXJ2ZXI6ODAwMC9iYXNpYy5jcmwwHQYD
-VR0OBBYEFLPquWS+kT4+JE+cssrriRkL9UADMB8GA1UdIwQYMBaAFNSsn21DVr1X
-hhqmU+wMnLWFZc55MA0GCSqGSIb3DQEBCwUAA4IBAQC1Pz8SahCsQyiyuu6dz391
-KENabMpCwb/2wxljN5lfkOvvUrVmupld8/5nIdN2drL9jCrfbBz5ZRz+9Ryb8yrc
-sioH8Y9RNU5Gc3UJo7aAoMx4sIib6uJ+UO4fVlVvD4cN2h2sLHxtkI173Oo7lnMf
-4c+75iyZYdkEDXaOk+UbR8dncCj84y1Sbt0FYfCMT688O4HYkIGA3xGmqyX7PYV/
-CP8CNKwJEuZpQRaGdClkmAmoEPyuFW9ec+A9gOrgCpuFJBI4MRcicC5Q+qmx+LTM
-pZ2louMnnlTRoj3tL4aDgfdwV0YGxyIjIzuYLy6QCF8MZ/TLwPK0C3oXXuYmCLBO
------END CERTIFICATE-----
diff --git a/.ci/certs/client_localhost_key.pem b/.ci/certs/client_localhost_key.pem
deleted file mode 100644
index 241f86f2ad..0000000000
--- a/.ci/certs/client_localhost_key.pem
+++ /dev/null
@@ -1,30 +0,0 @@
------BEGIN ENCRYPTED PRIVATE KEY-----
-MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIqKZZASlLYRICAggA
-MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBCQpWBZXmYQn0c6PZ4CnLrQBIIE
-0HwXxx0lDzPbw53k/ak73G4CwBilSpaIM5x7jNwwD7UhiR4Qo9JiYLRy2zn0RQZJ
-wK/Hhta3SKecTHqgMwPHk8s4Bu6EhSIm3/x2OhAtk2lLeubZkjgEKCfQbu4tVpeH
-jOw66Pxz52fhdJ7GzaTnWjjTYmEPxNpkRiUAe0v+lOD09OQvQIFVEDyqSATzRUjd
-GTvQs8H5N/XJR7xTuPRQekauY5gIcneE4oynGF5a9L870XfLh/H62f+pD19rvESh
-qqdCxklxwAfHGHni2p1UKgNPxJHzSMH9dGCAGT1fxLg0RtXfBMdl3gzPnwbZ1PmB
-tjVxCqtw7XAirdlBX79+dhZ58HCN+j7pkL9LWwRap1klN7Y+Iwf0XhK6imSY7Ex4
-4odxin7kF1yW65PTYKyS7cRuFip+k2YShXApN5PrF5SqNEFVt0A9RG7h+GF7EXSD
-QS0ecqwhnzuHGHSpBjvsEw9z3FWBL1tFC1i2cF7m3yTHDLVQoevkUY43Fmh8S/CZ
-gthQ9P58A3dIDSJM0vcGhHqJBLbxOF7rSqwIuihZJhBfqclw1V4fKk9VuRzp4MHf
-NrZEuCr8CTrcYnl2n6Z/MaJ33XRg8uwwy+O5RGF1I1GAmH2KdKORUtrYHlOdTd4K
-2NXEgy2mgDQYPbl/1tk8bH6hroIY9Qofpzi7MTZ++32AY3ggf4GnqAk4eAP5R3Ey
-PUYFtWaGftaOQCR5Ovocdn41YitUJxAPh6hE5HqVicO2rEfx13uzug9usdg6256i
-GgKSTg4jqBiEw0oJhb9TVYNY44koh9yMRM/sfidqarNKWU7bWDVKhl3hGaNhj+oX
-v6ZC8rH6m/zHRtbn7tAw/q+EtTHmLo2AaUf13V4Ii6VrEXMRSlv/AyipYmOIwgV2
-EZriwyhsT2RaVesAgKExHbnP6dzX2P2IGTMNISZDNlATMT01BfWG/loPe+6DbxzW
-aHv6Y0FknGeHGLDwiZMv/hyn8a4KOvIl35YZBJqZ8UxTirs9mLRd4Us5CdXAHQlL
-5skAzf5FSrVbQvUbvKIrO+ULGB5mDATHR/tgOWVaP656tiRMrtFW8XGNxaPjyDPt
-xhA3fVOc68f1UzTqoGpsZtUUMQxkndW3Tg50V4ssw4F9D4Grce9XXgfBdEFz/Gfc
-gSR4SYKelS5udrMvqKxUs+zobx8TH2CqzwDDcC0kxqC9VCMnHqaD3wSMbN/RBoYT
-lkD4DRmDFTwlsQd80i2j6K0eDFo7uvROWM72gAOb/wmssZBaSF3g0E5CrNSxApkz
-+VhgqfGBYDrFZijMHiCw+XB8kFFBrlXlcBOUHu1trIi7nwcmN1JvnXL0dVOgfSGE
-VNAmVz/sHdeAJacf05tehkAFTubdiZ24M/mM+VbKiJ2dajYRSoePPc8P65urlv6E
-rszIC9NhfwBy0TDgXNC/GV3y8mC7rp6kzbyzEb2H2M5ltyEKOIyjvRvtks2/opSX
-5T42x6xJtS6qTRttwrpRE5KjBHgcq0m8LSQu6chKwWinFUfOAdcZODvVVqLA2e6K
-plfcGb027WE4DHqTzW73nbnK+NwkP3lLORbro7KWDFdNKP3v/Rx0Uq7CPGVN994G
-tH7wyGheZNTMtKDFGrAdOqse9/sKcTF3thaqYqXgDDZY
------END ENCRYPTED PRIVATE KEY-----
diff --git a/.ci/certs/intermediate_ca_certificate.pem b/.ci/certs/intermediate_ca_certificate.pem
new file mode 100644
index 0000000000..c8157ccedb
--- /dev/null
+++ b/.ci/certs/intermediate_ca_certificate.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDWTCCAkGgAwIBAgIBATANBgkqhkiG9w0BAQsFADBLMTowOAYDVQQDDDFUTFNH
+ZW5TZWxmU2lnbmVkUm9vdENBIDIwMjUtMTEtMDVUMTE6NTA6MjUuNzEzNTY2MQ0w
+CwYDVQQHDAQkJCQkMB4XDTI1MTEwNTE5NTAyOFoXDTM1MTEwMzE5NTAyOFowMDES
+MBAGA1UEAwwJbG9jYWxob3N0MRowGAYDVQQKDBFJbnRlcm1lZGlhdGUgQ0EgMTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANKXfTftwYjSbFTLVfEPdPHS
+jMHAoHG11NlHoC2lAzKSi39MZpw5kJL3F+QhaArXHoqliCApr2YsdbQAov0LBHEc
+HqLgwuuOS5z7XZJowy7ZGZRQ/wW7PI4RGzgDBTsY8UE5ffw6OET2yS68L3b4rgcj
+BiVZQnUjeXsIYlh1f0CDqMm3qtUl/3y6ML5+CIrtItAhIom26euQ2CvwZWR3mk65
+zgNIZ3EqXMLr3FzQ+aJnz0TBDQAx/KduP8ZpYYOZ1Kw1OU/sIkcol0zfrFUYIgx0
++7LoCoV5QwKm0rSrMjUaudpBCsZjP5sQbvGj9JmekhHwiKI95TmtA6mPuQL2zDkC
+AwEAAaNjMGEwEgYDVR0TAQH/BAgwBgEB/wIBADALBgNVHQ8EBAMCAQYwHQYDVR0O
+BBYEFI2/L45C3RmYVeg6NP26Xny18yPWMB8GA1UdIwQYMBaAFJLwQcD9+OGZt/Ti
+vAdtLTmQJVCCMA0GCSqGSIb3DQEBCwUAA4IBAQC+Poi7gOzAdSwJ8n7YBwqPwpA+
+Tz44B6jIXw0M8XXDSwGeGKEWa5DWeNIJD2uV05KR+2Ph63VBKcRgl2Zf/QzZ59I6
+z51w4+sJ+kJHtxMPzOqDdiNZuZAJQk+rFGsIgHZjb+rJlDQGjy1I+5rMVIsOuJoN
+JRBZ6qJunU4AF7+Al4qeXj9182NHJ67fexE3YCjNf81Hnd1fnS0rsEzDQaA4lRO+
+uTYrfpwILaq1ghy0uarvwVMDEp5s7Nodi+ALwWlmIa6VTC4ML8kxl6YbRruprVoU
+XS9e7q6qXCSQzzt2DEorySnlmaiUKtyHfqt6qGFI5PVRyshSQq/IknTY0iMw
+-----END CERTIFICATE-----
diff --git a/.ci/certs/server.p12 b/.ci/certs/server.p12
new file mode 100644
index 0000000000..9f7feb6a1b
Binary files /dev/null and b/.ci/certs/server.p12 differ
diff --git a/.ci/certs/server_certificate.pem b/.ci/certs/server_certificate.pem
new file mode 100644
index 0000000000..a257485ec8
--- /dev/null
+++ b/.ci/certs/server_certificate.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDczCCAlugAwIBAgIBAjANBgkqhkiG9w0BAQsFADAwMRIwEAYDVQQDDAlsb2Nh
+bGhvc3QxGjAYBgNVBAoMEUludGVybWVkaWF0ZSBDQSAxMB4XDTI1MTEwNTE5NTAy
+OFoXDTM1MTEwMzE5NTAyOFowJTESMBAGA1UEAwwJbG9jYWxob3N0MQ8wDQYDVQQK
+DAZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC11X4GprXk
+Loe/H9WGTS8gLEI0iFYS/Fh3YKjwBSrLvcT6ygnTQvXekBQ147OJK5mc8ujDCOY6
+aW3e/eCPey1MKUlIGgHzO8SwxXEL1zhZaetOpqZoJEJ0tuteKHqwZW0CGF0AwqRe
+7tE5I5dX50MBBmI4owXAEjF73QTw1mkw05s2eGqDRqfU+6k+0RvK5BNtJLeenSnd
+PNk6ifD07Qkg+g+I71RvZEEqKKnx2Vts4tTPr5K4IfWUxZOLkVndjqk2NFd28HG4
+1Wuls5QgDjjKU/ZIXTK51KJMOR8j8K0LxK8gwWuWmj/Q7ZQ3LaBwGNXDy5o4tWcP
+Xg+saJDBcOHRAgMBAAGjgaIwgZ8wCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwEwYD
+VR0lBAwwCgYIKwYBBQUHAwEwMAYDVR0RBCkwJ4IJbG9jYWxob3N0gg9TRUEtM0xH
+NUhWSlVXSkuCCWxvY2FsaG9zdDAdBgNVHQ4EFgQUSq8OVzwzxJpP79VK1O03EyUz
+hMEwHwYDVR0jBBgwFoAUjb8vjkLdGZhV6Do0/bpefLXzI9YwDQYJKoZIhvcNAQEL
+BQADggEBALV+DsNfB5ktXuwZenTmkyAtfub8h5/bW+civWaz67S5bPEGwGhQ3EKS
+/JwMCa+Kr/mohjatKNgOjiB0/uxTyUCQ5ZFE5ISBVQYK7D1jsHAhUxHjcJ8tWKrw
+wZojiV/Jqrx5G+8leRn3floGDXHSccFv0WL8Iu7EZ41zdbe9daxuVC7KLygtuoSe
+R5xR2yvHnQy+byDc9CC3CmF0Pim0tWoH8SEujnuTPeU6N7557PjDNk8IGEQmJLNP
+Rm0pzOZBUgJraEnxIa2VwvbQ3KxgHzwf9kiRuULGd3ectd+EmK9ijTUnRnsVIlwB
+foT6fy80TgCMmXe2xy/0Tyix3kIFdkI=
+-----END CERTIFICATE-----
diff --git a/.ci/certs/server_direct.p12 b/.ci/certs/server_direct.p12
new file mode 100644
index 0000000000..45f410e87b
Binary files /dev/null and b/.ci/certs/server_direct.p12 differ
diff --git a/.ci/certs/server_direct_certificate.pem b/.ci/certs/server_direct_certificate.pem
new file mode 100644
index 0000000000..811e1785f8
--- /dev/null
+++ b/.ci/certs/server_direct_certificate.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDlTCCAn2gAwIBAgIBBDANBgkqhkiG9w0BAQsFADBLMTowOAYDVQQDDDFUTFNH
+ZW5TZWxmU2lnbmVkUm9vdENBIDIwMjUtMTEtMDVUMTE6NTA6MjUuNzEzNTY2MQ0w
+CwYDVQQHDAQkJCQkMB4XDTI1MTEwNTE5NTAyOVoXDTM1MTEwMzE5NTAyOVowLDES
+MBAGA1UEAwwJbG9jYWxob3N0MRYwFAYDVQQKDA1zZXJ2ZXJfZGlyZWN0MIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1qOgJMROFlhP13vEjL42YOzzoyXd
+D/UbEZ9u2Ikin78H79Er9/t2Zwh4YMdU0YU4K6AqKc8I7Pk8LDqFJefGhtb0yq2y
+sZ6ZptPtFE/VcGoUPkmxtTZoEDWs/UcstpLWzFO+oqS0lh5CA1AaTS3YkA61q7So
+j5KbbPRcg4IhRzlqYfRGiW8wqtIwls9z0Cdj/hQL2SmQrklk5qLfca1eshDYLJtw
+9stCxFGJsLrXcNjiN7bD5hJScIdSDXlsz3rxzHXY6FOw2eLX86JCh/BZk7i2HmL5
+ADsBhYGRFtou5cWd9XK2WIOArMvwdY1wyhQjonS9mM1aLIUo+PzFHFIp+QIDAQAB
+o4GiMIGfMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUF
+BwMBMDAGA1UdEQQpMCeCCWxvY2FsaG9zdIIPU0VBLTNMRzVIVkpVV0pLgglsb2Nh
+bGhvc3QwHQYDVR0OBBYEFO7LhQd4H1Bjur3wuF4BV9MgPuRIMB8GA1UdIwQYMBaA
+FJLwQcD9+OGZt/TivAdtLTmQJVCCMA0GCSqGSIb3DQEBCwUAA4IBAQCntkp723Bx
+EuF4lRy4h1zPnGr5DkC2aW4kAFFqbvebaeH5WFpsQoYK5XQsb8NE+6o7hUBkcsc7
+dVCY/MUmpZkqj5AVCMunAFDRCuAV7Ucy989pxjaYlvFk/QG5anLeDfp5dSDj8lMI
+jfee2r34+wujcTXp+QyCijmAdbOH/ianragpvf4mNxKQ9SIj1nQh1l9pKySHX7DR
+ncLzSVscyIl7rFuWYJWwJXVpEAFZQ+68/nltFCA0rbawoPafh88fF/KB7FjCFkfU
+ayj6LMLnmPCKgE6+iCyOt8S3xMLjG7naCYN1SDRFttDg7OvBOpioW+xSvnqCb3cz
+gvpm/RMrDIeX
+-----END CERTIFICATE-----
diff --git a/.ci/certs/server_direct_key.pem b/.ci/certs/server_direct_key.pem
new file mode 100644
index 0000000000..d5ca61091e
--- /dev/null
+++ b/.ci/certs/server_direct_key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIF7MM6KKkuIACAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBAEICVrLTKyRgmEwfmoSoJ6BIIE
+0IPVShlBo1RqlWGzIlo/Q8hnn/IzlAOQ/FpQx/ye788MbpJhuCuNl7EtX+CJYNA/
+wWI1XKj4C6f4wHKFCQJcj7UsiFDLam8EIU2woVW8YhXdMmG+5a9p9RDbfMVTng0/
+CktsO9ccmleF/ueWChhI7Ji4weHwd7YrE7TfXiB91tr83AnDcg6aqsNRiCufh77l
+F2b73Rid0OGftIKh/GJSszhKNah5mvcUVkJ66ng5Zyoz6aLlStxTj2cMtxthD+Dy
+2wTnlCKjvjLqJrnxP03YKlj//BvGQnZ12sypKBWhnci1ZzcBptpYZUVqFWBJ2QdB
+J6g6Kvl0NdKpFnRPgwQfN4k+N1othBeuytT+QPwMKdQp8/s8R5ncmmriVIrIA+NO
+2CiZQRv5rhmuESwehbXQqUuNoIpTzn+1UG2FXR/Iqaysw/TARhpcTCqH9Pddm02T
+00v+1EE+lS1mC3HAF4usvQ2pzXl16HJ0cWODNg+0Z2+IvtPbtunvQ2nXRJTU5KNN
+58f5vDgIyQJaDkOTMOUiF6M5ymTQVTqtWwOUzFlSmJzdEUio3J6Ji538vJM8moA0
+X5yeOE8EXu8znT8Jh+7fDjdLiDL3KWCkHYvSNOrTa5eI7E3jR2l7WbN10dLjXxZn
+KWrbp49kL+/2cU7nj+whasKdpxYySvkkQUgmDqwA9sTP0maV2hmlgGauj7jfThvi
+yk3NVWsGmTzCrjw6UQbkQXBO4btr6lTjmqDaPltxyWhqZU/0Y6hQf70S9Ef8Xwmu
+HOqwVBwGsrLV/9GU42+Gnd26E7tzZNNDA4Z9FUyp7Rc4Bi3G3Ds48qGCX8xW0ayG
+MjUTw5fK4Ma14F0tHnhsBNhWyb+OEB7oiGgUwvzzuJbLDNOS+Dgzfq/1+wRO8l4J
+DtAD8gzs1m88N675iKSg8XFgVre7sHSRmhZLs/SSrDndfYUVALHpVpj7IGBlAQnr
+0j7sq+sxFx2VTZCB00HGrPySt2Lwcx0z1G6o2FtmhKyoy6y9JNtyclqh6Lx7m+1h
+/K7M0BvGscnnXMsAb85JPIffX+k6nlSXCtkx414U69yH0bmNoN7VmyFOhEq2LyK1
+YZtBWWs07KwDWRCb9SxPMP3EtO416CNw/BOhcCbjHTmFTJUY06l5jR4A7Ng+YMoj
+5gq3HxolqOcsC0SDUFskwpkI3Kx50kiy6+dK3wfr9U82KzUf+MhN9ii8clYgoUh2
+rUaF39SUNqR9nOUgIv21EVTyHGgFP3vPIlsudfV9pU+zCS1OY4kGdSErV7KIejJq
+Ex+T1nuZDYgQFRa/z4IwDunH7XA0e0G5fuxIGeyU57ikKPVWdN935MkHoT/q0LUC
++bw6QFMWaazfdC0s5No3v+KgBYSQihCA5pOEj63K6jSzbouAyoJD9ALsYdc4qcut
+hZOy5ogf984hVA/JrQ4+1GJvWS+mujZuXF46hA2O4ntk874aVE2VDJxzNIKuuBAD
+NbAixVgyanLUXqkmNSQnGZ48ADL59oYPgSIl8C6SZaK0McdX7l/c2a4K7HAp6eOM
+3SifZWiwPK5s23m2M9hjAi3zTs/wK9ao7XoRymNfqMUgudxm800CA2hyDkAkFeEk
+awQ+0an2dM2hIpy8hmKrSnHkJbdrb/yfzRRsfHsLga/X
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/.ci/certs/server_key.pem b/.ci/certs/server_key.pem
new file mode 100644
index 0000000000..bcaf2c9175
--- /dev/null
+++ b/.ci/certs/server_key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIMCiIkGoNeoECAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBCAg7HN/OMTzIDYKEVuBbRBBIIE
+0ANnpnpkdFkpEymfRgAhyXL2cFN6UDFKsIP1Kpcnor7/pCki05x4jejcVanChk5r
+C4HMr3KB/fEWnohHcr888CWHxMD8lshqamBoqVkLR/+lOeigCJDcJcpo6ehoiUu+
+z1kKVEaARShA1RjyECn4n43JLbaBbUdT+LCL2yAssdX40VdydD4P3oVv/LphS6zr
+YHBrkOCtQFnKjiHM2UpPOMG+6GJOVBEoVIztIP15G4RXYy4NjvzA0pfJysUDjk11
+earGitMODSqxc832mZBeOP+CSZiLX2DTvmzoqH/AYQ1PFGlC/i3AMx/pMrrsjkK6
+Dp+lRx/CtESys1xgDW3WF5yV334F9wFROHd91GT5AGV06hcZ4UnCfpLyKmsIB2av
+6hqOI2bW2o+iUBrD/teE/Ft6a/OiUmczFu+0tZO2rDNBR6cnQrVr9UlWCD5ES//5
+UDt8U0/JeDEslxtGQwxhycraUibF2ZBDiuRtCzR958ESEpbCthmrfOmx03ZpL+UD
+3inwSoWGlesui86eydDs6gDbSYvjIl+Zg0Er2eKBV1AZUgOBbamjsYU2/Nnb7uV+
+mGYBH24tx60ZLBc0j/D8WVN/XvS8QWiEJXpp4Ef1+muhkJfBZ2NElf+DDSI4NQAz
+BIcmGOhjxnpqJMaCAL0KPb+7rwMLLEqEPuBl0EHlevM2NdycEE7dA0XiAdlEBdnq
+s8MlFB47+hpIe0w3e3Ycd8QyS2ajlNtc5BtTcRibnKJ81e/gCHqrPXlOZ5hnds5M
+yiOy5jd6lK/YOmVcsLru7fByGVYoJL9ip7FXJplRMipXeM7GjiUxgFAzIVzoO7AD
+lq2zL8c1ezsxbP4Lk9tfcNrXGVhQevDANzqIFwLpiUXHdlspuSBRIkpMI1qTbnPp
+fwdYzfFRodLH3hECOQMGaFcWEfSk0ILy1QHgGMMbbHiABKgs9ZDO10xXMvgkD28t
+8bFaohGbENF26Tp1pksh+RdNWZ1ouaZ9hD+laPX/I8uuDRJKy5OUfN4okCqhtA9O
+zskcGgE1k5fYxEXJqGc3W7r2uU7d2Omc/Ap8G78p2HmWMLh8+Bduj1vVpMCpCQiC
+EurNEc2Y8ow5zBryN61gcyZjf5rFrzf9p0p4ctjNI/bhIwqW2b4I4TM6lMcX/HNb
+blYqnPItjLdUgVMoSkZVoLwCBJLRved611rEJX3j76znt4Q0lSvMkty6i21IhJPs
+4wfo8TVxRF4Zn1/K6PNBLrPQNeU6xDptPqgH7MO8ammbOb6z6jkhvq9riDDNYMOk
+rKX/zRgpJLQyI6/OMZukHr+R+bL8WR204AvK6NN9oBSu4gEwr4FzyMv/8GXWXoYF
+3BRrzUuTIZJnZvIov88CUoASWexxrxlFMK85IuDP7vmSbRQ4NglXATVajbvzCYjx
+CiAPoQUOnO9OWS2JSGHCoYZIB5bk9MYGsRhW7pcbXLDvpmMwt6NnfeY3zSEQkHXE
+rXMQzSo7xG0AN+05ftppJeGe0alaFUl9bsVZ1gEBQWgZKFbikz81Y6dIElRTEtZz
+bVtFjFc20QYSFO9OQXvdisaxOVdO1PA3mCoIDL4dqnr7wzwqud4y7aCHkRMJ2w40
+c9576h6cNNXoqk4fi6hDHHvHY3rdKzp8NWdNi6Nh2MY/
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/.ci/certs/server_localhost.p12 b/.ci/certs/server_localhost.p12
deleted file mode 100644
index d77b7dca63..0000000000
Binary files a/.ci/certs/server_localhost.p12 and /dev/null differ
diff --git a/.ci/certs/server_localhost_certificate.pem b/.ci/certs/server_localhost_certificate.pem
deleted file mode 100644
index a67718d63b..0000000000
--- a/.ci/certs/server_localhost_certificate.pem
+++ /dev/null
@@ -1,22 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDvDCCAqSgAwIBAgIBATANBgkqhkiG9w0BAQsFADBMMTswOQYDVQQDDDJUTFNH
-ZW5TZWxmU2lnbmVkdFJvb3RDQSAyMDIzLTEwLTA4VDA4OjE2OjAzLjU5MDQ1NDEN
-MAsGA1UEBwwEJCQkJDAeFw0yMzEwMDgxNTE2MDNaFw0zMzEwMDUxNTE2MDNaMCUx
-EjAQBgNVBAMMCWxvY2FsaG9zdDEPMA0GA1UECgwGc2VydmVyMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2dxp0wR++oE89W/mhEL7/XfJfo8iDbKKciUP
-PyIgBvggv625HifmEJG+epl77KinbCuZdc0DX/2FKH6HPM/tC6VcWB2cZRSHpBSM
-aieRV4yiaUFTqlOgQalJyRczRtv35QPdaIcDOX4lOw887sn6sJuZY5FtAyDr3opA
-gZWLR+6fqi0YWqp5wqaz3hMzTGEEuu/ZKSqMWURRvp+Voz13auiShvhRb9hsdRp0
-zf12Y9wGhWjOg7G6v1r/BP6/Nr1gWrgNUhuomSFC1FCRdCr1VrLpUfG3VNloVEOG
-mbWYfo+cDN6fV+PDlVB5UQp9YciFfpGXBzSXgNcsk8fEXpg8IQIDAQABo4HPMIHM
-MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMCoG
-A1UdEQQjMCGCCWxvY2FsaG9zdIIJUFJPS09GSUVWgglsb2NhbGhvc3QwHQYDVR0O
-BBYEFPezEEGf7j3HedbaRCh4/FHT2VXrMB8GA1UdIwQYMBaAFNSsn21DVr1Xhhqm
-U+wMnLWFZc55MDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwtc2VydmVyOjgw
-MDAvYmFzaWMuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQBLeagmroj4FFOXgUqDQo7i
-kGCBZuCmn6GnCYdwEHtMoysGZ3vNFsB1BCug4fTuL7OU1l+Xw8iVnIvnGBpKypmt
-b7h9dN6urty0ewCS4WO8BTZUIdc1RJMo9N+nEMTja+5cqXHtO/VQnO2eqeALWJUU
-IDPycb6HcTkHGFX0QDwxsPuMFL3p5HGr6U0llLF0J5FedxUA/YLLVCStofrWvBGT
-PKngh7S6ntaIUnTvwyzY2kPJ+byqRDNrL5jdavw1U8cGh1vi3k9mf1Uloi0mnAMT
-kqOPzbQmHIQjxIOwqp2xkObXgqz1b0KNDfRDTwp90wzVxOCF5JJBCAIjPyLuncDv
------END CERTIFICATE-----
diff --git a/.ci/certs/server_localhost_key.pem b/.ci/certs/server_localhost_key.pem
deleted file mode 100644
index a49d186760..0000000000
--- a/.ci/certs/server_localhost_key.pem
+++ /dev/null
@@ -1,30 +0,0 @@
------BEGIN ENCRYPTED PRIVATE KEY-----
-MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQILovSnFfKBhECAggA
-MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBBmLCdyyKqcbbjoi1/8A+rxBIIE
-0Mmi72DP32seewlELsG4gVkOH6Gwvs5iAqHYap1yOps3mfI1TtuMhDEZDH2Sj+MB
-J1E35WEzJGGxTVhvK/J+R/1fUfd44Acgl1Ks1IINJyre4+vYfDUyWB5O2lS+9mr7
-L6q7kfAbBB2OuAEuGL5GMlTRetyASXbspWbi0M+vA9R+NemYbRzFpozP/fedFpQY
-6r/QnogSwuRcE1VMghUjZwzZWyG2HFMFp5emiAHRVi+SxLpIIv6wwV8SB4jDMO46
-CsyxLjkjhd2GmkMRpmIxXw7eXbWa/bnf/KhJG7gSDBgmGuoBJ4cDnQc2jFN8UqXW
-IG3+K6PIeGTT/t4aC6YSq+kb8R3rTfVbPdq51Uo55uMatpJg8AatsysL900nNfuz
-MejikInTz4+m6jY5kzEm+fToRNHXhcmnQeD6SYc8PNi/4QfxiMcHcI91GRNQ2nFI
-Xd5a1CG4f78WGUmK9PylxBdh+1nx9yQyrZKWcShuLkOQk4UAL0w31B70/l9jVoiN
-gcN4w18TUfYLIg8Ab6lL6wXipBrr1AjB/Dn2oCpMTiMolyWcsPAHDtxvrsgbsXRr
-vxd/vNo+RpSsvjq2wnXhxe+qC/uHBzJeyfx0m+rs6vBKPZvS7uTBfYGG+RhVJvb5
-W2RRfprvTzgBbbKBCTJ5ry4SMZX7ci008f7oVqKLAlsApA58dDgZ+ORF4TxtdSkJ
-u3r2htUBvC+mzYMYU4D+sYQ7S9qqVhKe7hvNzLW5UhkEhH57SQ1dIcstTsTYUDC7
-1o/zOkpVxByudKEGwgEtyYM+DD/YoGLGB/4qPULnHFOBwxWdK6Ov9I0ezuhe/nOA
-ERe3ixLklwHRI5sM/gt57A7MiMPhFHDpqt/xO/m/uCX2VRDW/IAKXpIfxuuxDcIz
-MLLxJhYCrGRHMStmBAPy3zmmhpn+wHTkwVbEVRMsh+o8M2vPelrysUtUlarRBQI+
-l5tY/UCgX0bGUvHKIp5z8GuRu/CTpjtpsyuNwtpq2TrgnmyiznyfFl4oknvEcfmF
-BLUd23ZrTyn1ha8cnKXY9JSHgS2cxdU0QnkPT1BEypptf30nQ1lLqiUg9GLR+xC5
-EeHn/80gL/MrpVnWdEznJdWMzau39kqf3ajNQlUb/SX5YQaeUKYrWoLHI+UNhUG2
-5fr2vcBgk0gt7k5ZDpWejhEu0BDTf3xrE9dU2jj6hOw6E+Q5bI59QvnLYqCvqBmE
-asDMBafo+/Px8xnXazFr5b5FyNqeXzBRPgRw5wFmK5YdFXU0fIpuF9IJb1TwLITp
-Hk+Hn760AsT3ALzHgRzC2e6bUUO6F/iw/6s6awwRbEPpLYTHwb9Mv7efeVsGTYiM
-Fi0OHapnzzbb4ErVL+92mkOT8flDoLhbKHJCRbOvu4C9awRs5aVbkEsygV67tLwu
-SIgUMpdxOMYYquyCJ+WUbyv5VSyvhnUIj7u2kdH+zyAendAi4Rgx/5e4PcD62c+X
-tNKp4KrlpF3jGIaPODXZVE2aIrhI0njVlUjIQRs6OOMXleO6+xWQI/1fx/xn/oKm
-TBUOtW3Y7AzyojbPiScvjmT+aoVwAZ3juHnUuxEuyUcI3WokkWPpllcaGd95sCUG
-7iR90VPBJ/meYyQMYY1BGq4ngi5DvLGy6K/pS5CHPi0U
------END ENCRYPTED PRIVATE KEY-----
diff --git a/.ci/ubuntu/gha-setup.sh b/.ci/ubuntu/gha-setup.sh
index a2e4668962..9bc789bb09 100755
--- a/.ci/ubuntu/gha-setup.sh
+++ b/.ci/ubuntu/gha-setup.sh
@@ -144,8 +144,19 @@ function install_ca_certificate
openssl s_client -connect localhost:5671 \
-CAfile "$GITHUB_WORKSPACE/.ci/certs/ca_certificate.pem" \
- -cert "$GITHUB_WORKSPACE/.ci/certs/client_localhost_certificate.pem" \
- -key "$GITHUB_WORKSPACE/.ci/certs/client_localhost_key.pem" \
+ -cert "$GITHUB_WORKSPACE/.ci/certs/client_direct_certificate.pem" \
+ -key "$GITHUB_WORKSPACE/.ci/certs/client_direct_key.pem" \
+ -pass pass:grapefruit < /dev/null
+
+ # rabbitmq/rabbitmq-dotnet-client#1864
+ # https://docs.openssl.org/master/man1/openssl-s_client/#options
+ # This tests the case where the client certificate is signed by an
+ # intermediate certificate
+ openssl s_client -connect localhost:5671 \
+ -CAfile "$GITHUB_WORKSPACE/.ci/certs/ca_certificate.pem" \
+ -chainCAfile "$GITHUB_WORKSPACE/.ci/certs/chained_ca_certificate.pem" \
+ -cert "$GITHUB_WORKSPACE/.ci/certs/client_certificate.pem" \
+ -key "$GITHUB_WORKSPACE/.ci/certs/client_key.pem" \
-pass pass:grapefruit < /dev/null
}
diff --git a/.ci/ubuntu/rabbitmq.conf b/.ci/ubuntu/rabbitmq.conf
index d03fa510cd..afe273a1f0 100644
--- a/.ci/ubuntu/rabbitmq.conf
+++ b/.ci/ubuntu/rabbitmq.conf
@@ -9,8 +9,8 @@ listeners.ssl.default = 5671
reverse_dns_lookups = false
loopback_users.guest = true
ssl_options.verify = verify_peer
-ssl_options.fail_if_no_peer_cert = false
+ssl_options.fail_if_no_peer_cert = true
ssl_options.cacertfile = /etc/rabbitmq/certs/ca_certificate.pem
-ssl_options.certfile = /etc/rabbitmq/certs/server_localhost_certificate.pem
-ssl_options.keyfile = /etc/rabbitmq/certs/server_localhost_key.pem
+ssl_options.certfile = /etc/rabbitmq/certs/server_direct_certificate.pem
+ssl_options.keyfile = /etc/rabbitmq/certs/server_direct_key.pem
ssl_options.password = grapefruit
diff --git a/.ci/windows/gha-setup.ps1 b/.ci/windows/gha-setup.ps1
index 16ead59d24..4f9fe1efaa 100644
--- a/.ci/windows/gha-setup.ps1
+++ b/.ci/windows/gha-setup.ps1
@@ -240,7 +240,11 @@ $ErrorActionPreference = 'Continue'
Write-Host '[INFO] Enabling plugins...'
& $rabbitmq_plugins_path enable rabbitmq_management rabbitmq_stream rabbitmq_stream_management rabbitmq_amqp1_0
-echo Q | openssl s_client -connect localhost:5671 -CAfile "$certs_dir/ca_certificate.pem" -cert "$certs_dir/client_localhost_certificate.pem" -key "$certs_dir/client_localhost_key.pem" -pass pass:grapefruit
+echo Q | openssl s_client -connect localhost:5671 `
+ -CAfile "$certs_dir/ca_certificate.pem" `
+ -cert "$certs_dir/client_direct_certificate.pem" `
+ -key "$certs_dir/client_direct_key.pem" `
+ -pass pass:grapefruit
if ($LASTEXITCODE -ne 0)
{
throw "[ERROR] 'openssl s_client' returned error: $LASTEXITCODE"
diff --git a/.ci/windows/rabbitmq.conf.in b/.ci/windows/rabbitmq.conf.in
index dfcb44c51e..3daf4925e1 100644
--- a/.ci/windows/rabbitmq.conf.in
+++ b/.ci/windows/rabbitmq.conf.in
@@ -8,8 +8,8 @@ listeners.ssl.default = 5671
reverse_dns_lookups = false
loopback_users.guest = true
ssl_options.verify = verify_peer
-ssl_options.fail_if_no_peer_cert = false
+ssl_options.fail_if_no_peer_cert = true
ssl_options.cacertfile = @@CERTS_DIR@@/ca_certificate.pem
-ssl_options.certfile = @@CERTS_DIR@@/server_localhost_certificate.pem
-ssl_options.keyfile = @@CERTS_DIR@@/server_localhost_key.pem
+ssl_options.certfile = @@CERTS_DIR@@/server_direct_certificate.pem
+ssl_options.keyfile = @@CERTS_DIR@@/server_direct_key.pem
ssl_options.password = grapefruit
diff --git a/projects/RabbitMQ.Client/Impl/SslHelper.cs b/projects/RabbitMQ.Client/Impl/SslHelper.cs
index ebe309d037..efbbd0a45b 100644
--- a/projects/RabbitMQ.Client/Impl/SslHelper.cs
+++ b/projects/RabbitMQ.Client/Impl/SslHelper.cs
@@ -75,14 +75,20 @@ Task TryAuthenticating(SslOption opts)
certificateRevocationCheckMode = X509RevocationMode.Online;
}
- var o = new SslClientAuthenticationOptions
+ var sslClientAuthenticationOptions = new SslClientAuthenticationOptions
{
CertificateRevocationCheckMode = certificateRevocationCheckMode,
ClientCertificates = opts.Certs,
EnabledSslProtocols = opts.Version,
TargetHost = opts.ServerName,
};
- return sslStream.AuthenticateAsClientAsync(o, cancellationToken);
+
+ if (opts.ClientCertificateContext != null)
+ {
+ sslClientAuthenticationOptions.ClientCertificateContext = opts.ClientCertificateContext;
+ }
+
+ return sslStream.AuthenticateAsClientAsync(sslClientAuthenticationOptions, cancellationToken);
#else
return sslStream.AuthenticateAsClientAsync(opts.ServerName, opts.Certs, opts.Version, opts.CheckCertificateRevocation);
#endif
diff --git a/projects/RabbitMQ.Client/PublicAPI/PublicAPI.Unshipped.net8.0.txt b/projects/RabbitMQ.Client/PublicAPI/PublicAPI.Unshipped.net8.0.txt
new file mode 100644
index 0000000000..0ad2bc143b
--- /dev/null
+++ b/projects/RabbitMQ.Client/PublicAPI/PublicAPI.Unshipped.net8.0.txt
@@ -0,0 +1,18 @@
+RabbitMQ.Client.Exceptions.PublishException.PublishException(ulong publishSequenceNumber, bool isReturn, string! message) -> void
+RabbitMQ.Client.Exceptions.PublishReturnException
+RabbitMQ.Client.Exceptions.PublishReturnException.Exchange.get -> string!
+RabbitMQ.Client.Exceptions.PublishReturnException.PublishReturnException(ulong publishSequenceNumber, string! message, string? exchange = null, string? routingKey = null, ushort? replyCode = null, string? replyText = null) -> void
+RabbitMQ.Client.Exceptions.PublishReturnException.ReplyCode.get -> ushort
+RabbitMQ.Client.Exceptions.PublishReturnException.ReplyText.get -> string!
+RabbitMQ.Client.Exceptions.PublishReturnException.RoutingKey.get -> string!
+RabbitMQ.Client.RabbitMQTracingOptions
+RabbitMQ.Client.RabbitMQTracingOptions.RabbitMQTracingOptions() -> void
+RabbitMQ.Client.RabbitMQTracingOptions.UsePublisherAsParent.get -> bool
+RabbitMQ.Client.RabbitMQTracingOptions.UsePublisherAsParent.set -> void
+RabbitMQ.Client.RabbitMQTracingOptions.UseRoutingKeyAsOperationName.get -> bool
+RabbitMQ.Client.RabbitMQTracingOptions.UseRoutingKeyAsOperationName.set -> void
+static RabbitMQ.Client.RabbitMQActivitySource.TracingOptions.get -> RabbitMQ.Client.RabbitMQTracingOptions!
+static RabbitMQ.Client.RabbitMQActivitySource.TracingOptions.set -> void
+RabbitMQ.Client.SslOption.ClientCertificateContext.get -> System.Net.Security.SslStreamCertificateContext
+RabbitMQ.Client.SslOption.ClientCertificateContext.set -> void
+
diff --git a/projects/RabbitMQ.Client/PublicAPI.Unshipped.txt b/projects/RabbitMQ.Client/PublicAPI/PublicAPI.Unshipped.netstandard2.0.txt
similarity index 100%
rename from projects/RabbitMQ.Client/PublicAPI.Unshipped.txt
rename to projects/RabbitMQ.Client/PublicAPI/PublicAPI.Unshipped.netstandard2.0.txt
diff --git a/projects/RabbitMQ.Client/RabbitMQ.Client.csproj b/projects/RabbitMQ.Client/RabbitMQ.Client.csproj
index d552e63244..acdc9e9635 100644
--- a/projects/RabbitMQ.Client/RabbitMQ.Client.csproj
+++ b/projects/RabbitMQ.Client/RabbitMQ.Client.csproj
@@ -81,4 +81,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/projects/RabbitMQ.Client/SslOption.cs b/projects/RabbitMQ.Client/SslOption.cs
index cb067cccb4..00b332d8e6 100644
--- a/projects/RabbitMQ.Client/SslOption.cs
+++ b/projects/RabbitMQ.Client/SslOption.cs
@@ -166,5 +166,13 @@ internal SslProtocols UseFallbackTlsVersions()
Version = SslProtocols.Tls12;
return Version;
}
+
+#if NET
+ ///
+ /// Retrieve or set the to supply
+ /// a set of certificates used for building a certificate chain.
+ ///
+ public SslStreamCertificateContext? ClientCertificateContext { get; set; }
+#endif
}
}
diff --git a/projects/Test/Common/SslEnv.cs b/projects/Test/Common/SslEnv.cs
index a855cf0e26..7e8deb842f 100644
--- a/projects/Test/Common/SslEnv.cs
+++ b/projects/Test/Common/SslEnv.cs
@@ -37,7 +37,9 @@ namespace Test
public class SslEnv
{
private readonly string _certPassphrase;
- private readonly string _certPath;
+ private readonly string _certDirectPath;
+ private readonly string _certIntermediatePath;
+ private readonly string _certIntermediateCaPath;
private const string _hostname = "localhost";
private readonly string _sslDir;
private readonly bool _isSslConfigured;
@@ -52,13 +54,25 @@ public SslEnv()
if (_isSslConfigured)
{
- _certPath = Path.Combine(_sslDir, $"client_{_hostname}.p12");
+ _certDirectPath = Path.Combine(_sslDir, $"client_direct.p12");
+ _certIntermediatePath = Path.Combine(_sslDir, $"client.p12");
+ _certIntermediateCaPath = Path.Combine(_sslDir, $"intermediate_ca_certificate.pem");
}
}
- public string CertPath
+ public string CertDirectPath
{
- get { return _certPath; }
+ get { return _certDirectPath; }
+ }
+
+ public string CertIntermediatePath
+ {
+ get { return _certIntermediatePath; }
+ }
+
+ public string CertIntermediateCaPath
+ {
+ get { return _certIntermediateCaPath; }
}
public string CertPassphrase
diff --git a/projects/Test/Integration/TestSsl.cs b/projects/Test/Integration/TestSsl.cs
index 0a06ecc4be..a0d1b6c3e3 100644
--- a/projects/Test/Integration/TestSsl.cs
+++ b/projects/Test/Integration/TestSsl.cs
@@ -32,6 +32,7 @@
using System.IO;
using System.Net.Security;
using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using RabbitMQ.Client;
using Xunit;
@@ -46,6 +47,7 @@ public class TestSsl : IntegrationFixture
public TestSsl(ITestOutputHelper output) : base(output)
{
_sslEnv = new SslEnv();
+ Assert.True(File.Exists(_sslEnv.CertDirectPath));
}
public override Task InitializeAsync()
@@ -64,6 +66,8 @@ public async Task TestServerVerifiedIgnoringNameMismatch()
ConnectionFactory cf = CreateConnectionFactory();
cf.Port = 5671;
cf.Ssl.ServerName = "*";
+ cf.Ssl.CertPath = _sslEnv.CertDirectPath;
+ cf.Ssl.CertPassphrase = _sslEnv.CertPassphrase;
cf.Ssl.AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNameMismatch;
cf.Ssl.Enabled = true;
@@ -78,6 +82,8 @@ public async Task TestServerVerified()
ConnectionFactory cf = CreateConnectionFactory();
cf.Port = 5671;
cf.Ssl.ServerName = _sslEnv.Hostname;
+ cf.Ssl.CertPath = _sslEnv.CertDirectPath;
+ cf.Ssl.CertPassphrase = _sslEnv.CertPassphrase;
cf.Ssl.Enabled = true;
await SendReceiveAsync(cf);
@@ -88,22 +94,18 @@ public async Task TestClientAndServerVerified()
{
Skip.IfNot(_sslEnv.IsSslConfigured, "SSL_CERTS_DIR and/or PASSWORD are not configured, skipping test");
- string certPath = _sslEnv.CertPath;
- Assert.True(File.Exists(certPath));
-
ConnectionFactory cf = CreateConnectionFactory();
cf.Port = 5671;
cf.Ssl.ServerName = _sslEnv.Hostname;
- cf.Ssl.CertPath = certPath;
+ cf.Ssl.CertPath = _sslEnv.CertDirectPath;
cf.Ssl.CertPassphrase = _sslEnv.CertPassphrase;
cf.Ssl.Enabled = true;
await SendReceiveAsync(cf);
}
- // rabbitmq/rabbitmq-dotnet-client#46, also #44 and #45
[SkippableFact]
- public async Task TestNoClientCertificate()
+ public async Task TestWithClientCertificate()
{
Skip.IfNot(_sslEnv.IsSslConfigured, "SSL_CERTS_DIR and/or PASSWORD are not configured, skipping test");
@@ -111,7 +113,8 @@ public async Task TestNoClientCertificate()
cf.Port = 5671;
cf.Ssl = new SslOption()
{
- CertPath = null,
+ CertPath = _sslEnv.CertDirectPath,
+ CertPassphrase = _sslEnv.CertPassphrase,
Enabled = true,
ServerName = _sslEnv.Hostname,
Version = SslProtocols.None,
@@ -123,6 +126,31 @@ public async Task TestNoClientCertificate()
await SendReceiveAsync(cf);
}
+#if NET
+ [SkippableFact]
+ public async Task TestWithClientCertificateSignedByIntermediate()
+ {
+ Skip.IfNot(_sslEnv.IsSslConfigured, "SSL_CERTS_DIR and/or PASSWORD are not configured, skipping test");
+
+ Assert.True(File.Exists(_sslEnv.CertIntermediatePath));
+
+ X509Certificate2 clientCertificate = new(_sslEnv.CertIntermediatePath, _sslEnv.CertPassphrase);
+ X509Certificate2 intermediateCaCertificate = new(_sslEnv.CertIntermediateCaPath);
+ X509Certificate2Collection intermediateCertificates = new(intermediateCaCertificate);
+
+ ConnectionFactory cf = CreateConnectionFactory();
+ cf.Port = 5671;
+ cf.Ssl.Enabled = true;
+ cf.Ssl.ClientCertificateContext = SslStreamCertificateContext.Create(clientCertificate, intermediateCertificates);
+ cf.Ssl.ServerName = _sslEnv.Hostname;
+ cf.Ssl.AcceptablePolicyErrors =
+ SslPolicyErrors.RemoteCertificateNotAvailable |
+ SslPolicyErrors.RemoteCertificateNameMismatch;
+
+ await SendReceiveAsync(cf);
+ }
+#endif
+
private async Task SendReceiveAsync(ConnectionFactory connectionFactory)
{
await using IConnection conn = await CreateConnectionAsyncWithRetries(connectionFactory);
diff --git a/projects/Test/SequentialIntegration/TestHeartbeats.cs b/projects/Test/SequentialIntegration/TestHeartbeats.cs
index 520cdbfbcf..8709a35462 100644
--- a/projects/Test/SequentialIntegration/TestHeartbeats.cs
+++ b/projects/Test/SequentialIntegration/TestHeartbeats.cs
@@ -85,7 +85,7 @@ public async Task TestThatHeartbeatWriterWithTLSEnabledAsync()
cf.AutomaticRecoveryEnabled = false;
cf.Ssl.ServerName = sslEnv.Hostname;
- cf.Ssl.CertPath = sslEnv.CertPath;
+ cf.Ssl.CertPath = sslEnv.CertDirectPath;
cf.Ssl.CertPassphrase = sslEnv.CertPassphrase;
cf.Ssl.Enabled = true;