2020//! `starts_with(b"-----BEGIN PRIVATE KEY-----")` check before ever parsing the
2121//! key, so it rejects SEC1 outright with `Error::NotPkcs8` even though OpenSSL's
2222//! own PEM parser would happily read it. We re-encode SEC1 -> PKCS8 ourselves via
23- //! the `openssl` crate (already linked in as a `native-tls` dependency) before
24- //! calling `from_pkcs8`.
23+ //! the `openssl` crate (already linked in as a `native-tls` dependency). On
24+ //! Windows, Schannel cannot import this EC identity through `from_pkcs8`, so we
25+ //! package the converted key and certificate as PKCS#12 before handing it to
26+ //! native-tls.
2527
2628use anyhow:: { Context , Result , bail} ;
2729use openssl:: pkey:: PKey ;
@@ -35,8 +37,7 @@ pub fn build_ipc_client_connector(ipc_cert_file: &Path) -> Result<tokio_native_t
3537 let ( cert_pem, key_pem) = split_cert_and_key ( & pem) ?;
3638 let key_pem = to_pkcs8_pem ( & key_pem) ?;
3739
38- let identity = native_tls:: Identity :: from_pkcs8 ( & cert_pem, & key_pem)
39- . context ( "building TLS identity from the IPC cert/key" ) ?;
40+ let identity = identity_from_pkcs8 ( & cert_pem, & key_pem) ?;
4041 let root = native_tls:: Certificate :: from_pem ( & cert_pem)
4142 . context ( "parsing the IPC cert as a trust root" ) ?;
4243
@@ -70,6 +71,33 @@ fn to_pkcs8_pem(key_pem: &[u8]) -> Result<Vec<u8>> {
7071 . context ( "re-encoding the IPC private key as PKCS8" )
7172}
7273
74+ #[ cfg( not( windows) ) ]
75+ fn identity_from_pkcs8 ( cert_pem : & [ u8 ] , key_pem : & [ u8 ] ) -> Result < native_tls:: Identity > {
76+ native_tls:: Identity :: from_pkcs8 ( cert_pem, key_pem)
77+ . context ( "building TLS identity from the IPC cert/key" )
78+ }
79+
80+ #[ cfg( windows) ]
81+ fn identity_from_pkcs8 ( cert_pem : & [ u8 ] , key_pem : & [ u8 ] ) -> Result < native_tls:: Identity > {
82+ // Schannel's PKCS#8 import rejects the Agent's ECDSA identity with
83+ // CRYPT_E_ASN1_BADTAG. PKCS#12 is its native certificate+key interchange
84+ // format and preserves the same key and certificate without changing the
85+ // identity presented on the wire.
86+ let cert = openssl:: x509:: X509 :: from_pem ( cert_pem)
87+ . context ( "parsing the IPC certificate for PKCS12" ) ?;
88+ let key =
89+ PKey :: private_key_from_pem ( key_pem) . context ( "parsing the IPC private key for PKCS12" ) ?;
90+ let mut builder = openssl:: pkcs12:: Pkcs12 :: builder ( ) ;
91+ builder. name ( "Datadog Agent IPC" ) . pkey ( & key) . cert ( & cert) ;
92+ let der = builder
93+ . build2 ( "" )
94+ . and_then ( |pkcs12| pkcs12. to_der ( ) )
95+ . context ( "packaging the IPC identity as PKCS12" ) ?;
96+
97+ native_tls:: Identity :: from_pkcs12 ( & der, "" )
98+ . context ( "building TLS identity from the IPC PKCS12 bundle" )
99+ }
100+
73101/// Split a combined IPC PEM into its CERTIFICATE and private-key blocks.
74102fn split_cert_and_key ( pem : & [ u8 ] ) -> Result < ( Vec < u8 > , Vec < u8 > ) > {
75103 let text = std:: str:: from_utf8 ( pem) . context ( "IPC cert file is not UTF-8" ) ?;
0 commit comments