swift_secure_enclave_tool_rs/
lib.rs1use base64::engine::general_purpose::STANDARD;
2use base64::Engine;
3use rust_util::{debugging, opt_result, simple_error, XResult};
4use std::process::{Command, Output};
5
6const SWIFT_SECURE_ENCLAVE_TOOL_CMD: &str = "swift-secure-enclave-tool";
7
8#[derive(Debug, Clone, Copy)]
9pub enum KeyPurpose {
10 Signing,
11 KeyAgreement,
12}
13
14#[derive(Debug)]
15pub struct KeyMaterial {
16 pub public_key_point: Vec<u8>,
17 pub public_key_der: Vec<u8>,
18 pub private_key_representation: Vec<u8>,
19}
20
21pub fn is_secure_enclave_supported() -> XResult<bool> {
22 let mut cmd = Command::new(SWIFT_SECURE_ENCLAVE_TOOL_CMD);
23 cmd.arg("is_support_secure_enclave");
24
25 let cmd_stdout = run_command_stdout(cmd)?;
26 if cmd_stdout.starts_with("ok:") {
27 let result = cmd_stdout.chars().skip(3).collect::<String>();
28 Ok(result == "true")
29 } else {
30 simple_error!("Invalid is_secure_enclave_supported result: {}", cmd_stdout)
31 }
32}
33
34pub fn generate_ecdsa_keypair(key_purpose: KeyPurpose, require_bio: bool) -> XResult<KeyMaterial> {
35 let mut cmd = Command::new(SWIFT_SECURE_ENCLAVE_TOOL_CMD);
36 cmd.arg(match key_purpose {
37 KeyPurpose::Signing => "generate_p256_ecsign_keypair",
38 KeyPurpose::KeyAgreement => "generate_p256_ecdh_keypair",
39 });
40 cmd.arg(&format!("{}", require_bio));
41
42 let cmd_stdout = run_command_stdout(cmd)?;
43 parse_keypair_result(&cmd_stdout)
44}
45
46pub fn recover_ecdsa_keypair(
47 key_purpose: KeyPurpose,
48 private_key_representation: &[u8],
49) -> XResult<KeyMaterial> {
50 let mut cmd = Command::new(SWIFT_SECURE_ENCLAVE_TOOL_CMD);
51 cmd.arg(match key_purpose {
52 KeyPurpose::Signing => "recover_p256_ecsign_public_key",
53 KeyPurpose::KeyAgreement => "recover_p256_ecdh_public_key",
54 });
55 cmd.arg(&STANDARD.encode(private_key_representation));
56
57 let cmd_stdout = run_command_stdout(cmd)?;
58 parse_keypair_result(&cmd_stdout)
59}
60
61pub fn private_key_ecdsa_sign(
62 private_key_representation: &[u8],
63 content: &[u8],
64) -> XResult<Vec<u8>> {
65 let mut cmd = Command::new(SWIFT_SECURE_ENCLAVE_TOOL_CMD);
66 cmd.arg("compute_p256_ecsign");
67 cmd.arg(&STANDARD.encode(private_key_representation));
68 cmd.arg(&STANDARD.encode(content));
69
70 let cmd_stdout = run_command_stdout(cmd)?;
71 if cmd_stdout.starts_with("ok:") {
72 let result = cmd_stdout.chars().skip(3).collect::<String>();
73 Ok(STANDARD.decode(result)?)
74 } else {
75 simple_error!("Invalid private_key_ecdsa_sign result: {}", cmd_stdout)
76 }
77}
78
79pub fn private_key_ecdh(
81 private_key_representation: &[u8],
82 ephemera_public_key: &[u8],
83) -> XResult<Vec<u8>> {
84 let mut cmd = Command::new(SWIFT_SECURE_ENCLAVE_TOOL_CMD);
85 cmd.arg("compute_p256_ecdh");
86 cmd.arg(&STANDARD.encode(private_key_representation));
87 cmd.arg(&STANDARD.encode(ephemera_public_key));
88
89 let cmd_stdout = run_command_stdout(cmd)?;
90 if cmd_stdout.starts_with("ok:SharedSecret:") {
91 let result = cmd_stdout.chars().skip(16).collect::<String>();
92 Ok(hex::decode(result.trim())?)
93 } else {
94 simple_error!("Invalid compute_p256_ecdh result: {}", cmd_stdout)
95 }
96}
97
98fn run_command_stdout(cmd: Command) -> XResult<String> {
99 let output = run_command(cmd)?;
100 let stdout_text = opt_result!(String::from_utf8(output.stdout), "Parse stdout failed:{}");
101 Ok(stdout_text.trim().to_string())
102}
103
104fn run_command(mut cmd: Command) -> XResult<Output> {
105 debugging!("Run command: {:?}", cmd);
106 let output = cmd.output();
107 match output {
108 Err(e) => simple_error!("Run command failed: {:?}", e),
109 Ok(output) => {
110 debugging!("Output: {:?}", output);
111 if !output.status.success() {
112 simple_error!("Run command not success: {:?}", output.status.code())
113 } else {
114 Ok(output)
115 }
116 }
117 }
118}
119
120fn parse_keypair_result(cmd_stdout: &str) -> XResult<KeyMaterial> {
121 if cmd_stdout.starts_with("ok:") {
122 let result = cmd_stdout.chars().skip(3).collect::<String>();
123 let parts = result.split(",").collect::<Vec<_>>();
124 let public_key_point = STANDARD.decode(&parts[0])?;
125 let public_key_der = STANDARD.decode(&parts[1])?;
126 let private_key_representation = STANDARD.decode(&parts[2])?;
127 Ok(KeyMaterial {
128 public_key_point,
129 public_key_der,
130 private_key_representation,
131 })
132 } else {
133 simple_error!("Invalid result: {}", cmd_stdout)
134 }
135}