Skip to content

Commit 77c3a91

Browse files
authored
Merge pull request #51 from Dstack-TEE/cert-sign
certgen: Add subcommand to sign a single cert
2 parents e7c45a2 + 32091d5 commit 77c3a91

File tree

2 files changed

+84
-11
lines changed

2 files changed

+84
-11
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ certs: ${TO}
99

1010
${TO}:
1111
mkdir -p ${TO}
12-
cargo run --bin certgen -- --domain ${DOMAIN} --output-dir ${TO}
12+
cargo run --bin certgen -- generate --domain ${DOMAIN} --output-dir ${TO}
1313

1414
run:
1515
$(MAKE) -C mkguest run

certgen/src/main.rs

Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,74 @@
11
use clap::Parser;
22
use fs_err as fs;
33
use ra_tls::{
4-
cert::CertRequest,
4+
cert::{CaCert, CertRequest},
55
rcgen::{KeyPair, PKCS_ECDSA_P256_SHA256},
66
};
77

88
#[derive(Parser)]
99
#[command(author, version, about)]
1010
struct Args {
11-
/// Domain name for the generated certificates
12-
#[arg(short, long, default_value = "local")]
13-
domain: String,
11+
#[command(subcommand)]
12+
command: Commands,
13+
}
14+
15+
#[derive(clap::Subcommand)]
16+
enum Commands {
17+
/// Generate certificates for the KMS system
18+
Generate {
19+
/// Domain name for the generated certificates
20+
#[arg(short, long)]
21+
domain: String,
22+
23+
/// Output directory for the generated certificates
24+
#[arg(short, long, default_value = "certs")]
25+
output_dir: String,
26+
},
27+
/// Sign a certificate using an existing CA
28+
Sign {
29+
/// Domain name for the generated certificate
30+
#[arg(short, long)]
31+
domain: String,
32+
33+
/// CA key file
34+
#[arg(short, long)]
35+
ca_key: String,
1436

15-
/// Output directory for the generated certificates
16-
#[arg(short, long, default_value = "certs")]
17-
output_dir: String,
37+
/// CA cert file
38+
#[arg(short, long)]
39+
ca_cert: String,
40+
41+
/// Output cert file
42+
#[arg(short, long)]
43+
cert: String,
44+
45+
/// Output key file
46+
#[arg(short, long)]
47+
key: String,
48+
},
1849
}
1950

2051
fn main() -> anyhow::Result<()> {
2152
let args = Args::parse();
2253

54+
match args.command {
55+
Commands::Generate { domain, output_dir } => {
56+
generate_and_store_certificates(&domain, &output_dir)?;
57+
}
58+
Commands::Sign {
59+
domain,
60+
ca_key,
61+
ca_cert,
62+
cert,
63+
key,
64+
} => {
65+
sign_certificate(&domain, &ca_key, &ca_cert, &cert, &key)?;
66+
}
67+
}
68+
Ok(())
69+
}
70+
71+
fn generate_and_store_certificates(domain: &str, output_dir: &str) -> anyhow::Result<()> {
2372
let tmp_ca_key = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256)?;
2473
let ca_key = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256)?;
2574
let kms_rpc_key = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256)?;
@@ -42,7 +91,7 @@ fn main() -> anyhow::Result<()> {
4291
.build()
4392
.self_signed()?;
4493

45-
let kms_domain = format!("kms.{}", args.domain);
94+
let kms_domain = format!("kms.{domain}");
4695
// Sign WWW server cert with KMS cert
4796
let kms_rpc_cert = CertRequest::builder()
4897
.subject(&kms_domain)
@@ -51,15 +100,14 @@ fn main() -> anyhow::Result<()> {
51100
.build()
52101
.signed_by(&ca_cert, &ca_key)?;
53102

54-
let tproxy_domain = format!("tproxy.{}", args.domain);
103+
let tproxy_domain = format!("tproxy.{domain}");
55104
let tproxy_rpc_cert = CertRequest::builder()
56105
.subject(&tproxy_domain)
57106
.alt_names(&[tproxy_domain.clone()])
58107
.key(&tproxy_rpc_key)
59108
.build()
60109
.signed_by(&ca_cert, &ca_key)?;
61110

62-
let output_dir = &args.output_dir;
63111
store_cert(
64112
output_dir,
65113
"tmp-ca",
@@ -84,6 +132,7 @@ fn main() -> anyhow::Result<()> {
84132
&tproxy_rpc_cert.pem(),
85133
&tproxy_rpc_key.serialize_pem(),
86134
)?;
135+
87136
Ok(())
88137
}
89138

@@ -94,3 +143,27 @@ fn store_cert(path: &str, name: &str, cert: &str, key: &str) -> anyhow::Result<(
94143
fs::write(key_path, key)?;
95144
Ok(())
96145
}
146+
147+
fn sign_certificate(
148+
domain: &str,
149+
ca_key_path: &str,
150+
ca_cert_path: &str,
151+
cert_path: &str,
152+
key_path: &str,
153+
) -> anyhow::Result<()> {
154+
let ca_key = fs::read_to_string(ca_key_path)?;
155+
let ca_cert = fs::read_to_string(ca_cert_path)?;
156+
let ca = CaCert::new(ca_cert, ca_key)?;
157+
let key = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256)?;
158+
159+
let cert = CertRequest::builder()
160+
.subject(domain)
161+
.alt_names(&[domain.to_string()])
162+
.key(&key)
163+
.build()
164+
.signed_by(&ca.cert, &ca.key)?;
165+
166+
fs::write(cert_path, cert.pem())?;
167+
fs::write(key_path, key.serialize_pem())?;
168+
Ok(())
169+
}

0 commit comments

Comments
 (0)