Skip to content

Commit

Permalink
Merge pull request #1074 from marmijo/marmijo-allow-empty-ca
Browse files Browse the repository at this point in the history
  • Loading branch information
jlebon committed Jun 21, 2024
2 parents 547c950 + 622b0d0 commit 4dfc444
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 25 deletions.
1 change: 1 addition & 0 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Major changes:
Minor changes:

- Hetzner: fix duplicate attribute prefix
- Fix Azure SSH key fetching when no key provisioned

Packaging changes:

Expand Down
18 changes: 7 additions & 11 deletions src/providers/microsoft/azure/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ impl Azure {
}

// put it all together
fn get_ssh_pubkey(&self, certs_endpoint: String) -> Result<PublicKey> {
fn get_ssh_pubkey(&self, certs_endpoint: String) -> Result<Option<PublicKey>> {
// we have to generate the rsa public/private keypair and the x509 cert
// that we use to make the request. this is equivalent to
// `openssl req -x509 -nodes -subj /CN=LinuxTransport -days 365 -newkey rsa:2048 -keyout private.pem -out cert.pem`
Expand All @@ -271,10 +271,7 @@ impl Azure {
.context("failed to decrypt cms blob")?;

// convert that to the OpenSSH public key format
let ssh_pubkey = crypto::p12_to_ssh_pubkey(&p12)
.context("failed to convert pkcs12 blob to ssh pubkey")?;

Ok(ssh_pubkey)
crypto::p12_to_ssh_pubkey(&p12).context("failed to convert pkcs12 blob to ssh pubkey")
}

#[cfg(test)]
Expand Down Expand Up @@ -402,18 +399,17 @@ impl MetadataProvider for Azure {
let goalstate = self.fetch_goalstate()?;
let certs_endpoint = match goalstate.certs_endpoint() {
Some(ep) => ep,
None => {
warn!("SSH pubkeys requested, but not provisioned for this instance");
return Ok(vec![]);
}
None => return Ok(vec![]),
};

if certs_endpoint.is_empty() {
bail!("unexpected empty certificates endpoint");
}

let key = self.get_ssh_pubkey(certs_endpoint)?;
Ok(vec![key])
let maybe_key = self.get_ssh_pubkey(certs_endpoint)?;
let key: Vec<PublicKey> = maybe_key.into_iter().collect();

Ok(key)
}

fn boot_checkin(&self) -> Result<()> {
Expand Down
18 changes: 7 additions & 11 deletions src/providers/microsoft/azurestack/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ impl AzureStack {
}

// put it all together
fn get_ssh_pubkey(&self, certs_endpoint: String) -> Result<PublicKey> {
fn get_ssh_pubkey(&self, certs_endpoint: String) -> Result<Option<PublicKey>> {
// we have to generate the rsa public/private keypair and the x509 cert
// that we use to make the request. this is equivalent to
// `openssl req -x509 -nodes -subj /CN=LinuxTransport -days 365 -newkey rsa:2048 -keyout private.pem -out cert.pem`
Expand All @@ -287,10 +287,7 @@ impl AzureStack {
.context("failed to decrypt cms blob")?;

// convert that to the OpenSSH public key format
let ssh_pubkey = crypto::p12_to_ssh_pubkey(&p12)
.context("failed to convert pkcs12 blob to ssh pubkey")?;

Ok(ssh_pubkey)
crypto::p12_to_ssh_pubkey(&p12).context("failed to convert pkcs12 blob to ssh pubkey")
}

fn fetch_hostname(&self) -> Result<Option<String>> {
Expand Down Expand Up @@ -326,18 +323,17 @@ impl MetadataProvider for AzureStack {
let goalstate = self.fetch_goalstate()?;
let certs_endpoint = match goalstate.certs_endpoint() {
Some(ep) => ep,
None => {
warn!("SSH pubkeys requested, but not provisioned for this instance");
return Ok(vec![]);
}
None => return Ok(vec![]),
};

if certs_endpoint.is_empty() {
bail!("unexpected empty certificates endpoint");
}

let key = self.get_ssh_pubkey(certs_endpoint)?;
Ok(vec![key])
let maybe_key = self.get_ssh_pubkey(certs_endpoint)?;
let key: Vec<PublicKey> = maybe_key.into_iter().collect();

Ok(key)
}

fn boot_checkin(&self) -> Result<()> {
Expand Down
13 changes: 10 additions & 3 deletions src/providers/microsoft/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub fn decrypt_cms(smime: &[u8], pkey: &PKey<Private>, x509: &X509) -> Result<Ve
Ok(p12_der)
}

pub fn p12_to_ssh_pubkey(p12_der: &[u8]) -> Result<PublicKey> {
pub fn p12_to_ssh_pubkey(p12_der: &[u8]) -> Result<Option<PublicKey>> {
// the contents of that encrypted cms blob we got are actually a different
// cryptographic structure. we read that in from the contents and parse it.
// PKCS12 has the ability to have a password, but we don't have one, hence
Expand All @@ -65,7 +65,14 @@ pub fn p12_to_ssh_pubkey(p12_der: &[u8]) -> Result<PublicKey> {
// ParsedPKCS12_2 has three parts: a pkey, a main x509 cert, and a list of other
// x509 certs. The list of other x509 certs are called the `certificate chain`
// currently denoted as `ca`; there is only one cert in this `certificate chain`,
// which is the ssh public key.
// which is the ssh public key. The certs endpoint may still be populated even if
// an SSH public key hasn't been provided, which would lead to this code being
// executed. The certificate chain will be empty in this case, so just return
// None and handle it further up the stack.
if p12.ca.is_none() {
return Ok(None);
}

let ca = p12
.ca
.ok_or_else(|| anyhow!("failed to get chain from pkcs12"))?;
Expand All @@ -86,5 +93,5 @@ pub fn p12_to_ssh_pubkey(p12_der: &[u8]) -> Result<PublicKey> {
let n = ssh_pubkey_rsa.n().to_vec();
let ssh_pubkey = PublicKey::from_rsa(e, n);

Ok(ssh_pubkey)
Ok(Some(ssh_pubkey))
}

0 comments on commit 4dfc444

Please sign in to comment.