Skip to content

Commit 2ec2d6f

Browse files
committed
[ACTP] import par-control IPC identity via PKCS12 on Windows
1 parent d306782 commit 2ec2d6f

1 file changed

Lines changed: 32 additions & 4 deletions

File tree

  • pkg/privateactionrunner/par-control/src

pkg/privateactionrunner/par-control/src/tls.rs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
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
2628
use anyhow::{Context, Result, bail};
2729
use 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.
74102
fn 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

Comments
 (0)