Skip to content

Commit 5f28435

Browse files
authored
feat: add Phase 2 components - keyring, rego, crypto
- OS keyring/keychain key storage provider (feature-gated: keyring-storage) - Rego/OPA policy language support via Regorus (feature-gated: rego) - wsc:crypto WASM component for hardware signing interface - Add .env to gitignore, update lockfile
1 parent e1d5bff commit 5f28435

File tree

11 files changed

+1604
-3
lines changed

11 files changed

+1604
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@ profiles/
3939

4040
# Old binary name
4141
wasmsign2
42+
.env

MODULE.bazel.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/crypto/BUILD.bazel

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""Hardware-backed cryptographic operations provider
2+
3+
This component exports the wsc:crypto/hardware-signing interface,
4+
providing both:
5+
- WASM component for embedding in other components
6+
- Native bindings (crypto_provider_bindings_host) for native builds
7+
8+
The implementation delegates to wsc's platform module for the actual
9+
cryptographic operations.
10+
"""
11+
12+
load("@rules_wasm_component//rust:defs.bzl", "rust_wasm_component_bindgen")
13+
14+
package(default_visibility = ["//visibility:public"])
15+
16+
# Crypto provider component
17+
# This creates:
18+
# crypto_provider - WASM component
19+
# crypto_provider_bindings - WASM bindings library
20+
# crypto_provider_bindings_host - Native bindings library (for native builds!)
21+
rust_wasm_component_bindgen(
22+
name = "crypto_provider",
23+
srcs = ["src/lib.rs"],
24+
crate_features = ["software-keys"], # Enable software key provider
25+
profiles = ["release"],
26+
wit = "//wit:wsc_crypto_wit",
27+
deps = [
28+
"//src/lib:wsc",
29+
"@wsc_deps//:ed25519-compact",
30+
],
31+
)

src/crypto/Cargo.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "wsc-crypto"
3+
version.workspace = true
4+
edition.workspace = true
5+
authors.workspace = true
6+
license.workspace = true
7+
repository.workspace = true
8+
description = "Hardware-backed cryptographic operations provider component"
9+
10+
[lib]
11+
crate-type = ["cdylib"]
12+
13+
[dependencies]
14+
# Core signing library (provides platform module)
15+
wsc = { version = "0.5.0", path = "../lib", features = ["software-keys"] }
16+
17+
# WIT bindings generation
18+
wit-bindgen = { version = "0.47.0", default-features = false, features = ["realloc"] }
19+
20+
# Ed25519 for signature verification
21+
ed25519-compact = "2.1"

src/crypto/examples/BUILD.bazel

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""Native demo using WIT bindings for hardware-signing interface"""
2+
3+
load("@rules_rust//rust:defs.bzl", "rust_binary")
4+
5+
package(default_visibility = ["//visibility:public"])
6+
7+
rust_binary(
8+
name = "native_demo",
9+
srcs = ["native_demo.rs"],
10+
crate_features = [
11+
"software-keys",
12+
"sync",
13+
],
14+
edition = "2024",
15+
deps = [
16+
"//src/crypto:crypto_provider_bindings_host",
17+
"//src/lib:wsc",
18+
"@wsc_deps//:ed25519-compact",
19+
"@wsc_deps//:hex",
20+
],
21+
)

src/crypto/examples/native_demo.rs

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
//! Native demo using WIT bindings for hardware-signing interface
2+
//!
3+
//! This demonstrates using `crypto_provider_bindings_host` - the native
4+
//! bindings generated from the WIT interface - to build a native application
5+
//! with the same API as the WASM component.
6+
7+
use crypto_provider_bindings::exports::wsc::crypto::hardware_signing::{
8+
Guest, HardwareError, KeyHandle, PublicKeyInfo, SecurityLevel, SigningAlgorithm,
9+
BackendInfo,
10+
};
11+
12+
use std::sync::OnceLock;
13+
use wsc::platform::software::SoftwareProvider;
14+
use wsc::platform::{SecureKeyProvider, SecurityLevel as WscSecurityLevel};
15+
16+
// Global provider instance (same pattern as WASM component)
17+
static PROVIDER: OnceLock<SoftwareProvider> = OnceLock::new();
18+
19+
fn get_provider() -> &'static SoftwareProvider {
20+
PROVIDER.get_or_init(SoftwareProvider::new)
21+
}
22+
23+
fn convert_security_level(level: WscSecurityLevel) -> SecurityLevel {
24+
match level {
25+
WscSecurityLevel::Software => SecurityLevel::Software,
26+
WscSecurityLevel::HardwareBasic => SecurityLevel::HardwareBasic,
27+
WscSecurityLevel::HardwareBacked => SecurityLevel::HardwareBacked,
28+
WscSecurityLevel::HardwareCertified => SecurityLevel::HardwareCertified,
29+
}
30+
}
31+
32+
/// Native implementation of the Guest trait
33+
/// This is the same implementation as the WASM component, but using native bindings
34+
struct NativeCryptoProvider;
35+
36+
impl Guest for NativeCryptoProvider {
37+
fn is_available() -> bool {
38+
true
39+
}
40+
41+
fn get_backend_info() -> Result<BackendInfo, HardwareError> {
42+
let provider = get_provider();
43+
Ok(BackendInfo {
44+
name: provider.name().to_string(),
45+
level: convert_security_level(provider.security_level()),
46+
algorithms: vec![SigningAlgorithm::Ed25519],
47+
manufacturer: None,
48+
firmware_version: None,
49+
})
50+
}
51+
52+
fn get_security_level() -> SecurityLevel {
53+
let provider = get_provider();
54+
convert_security_level(provider.security_level())
55+
}
56+
57+
fn generate_key(
58+
algorithm: SigningAlgorithm,
59+
_usage: u8,
60+
_key_id: Option<String>,
61+
) -> Result<KeyHandle, HardwareError> {
62+
if !matches!(algorithm, SigningAlgorithm::Ed25519) {
63+
return Err(HardwareError::UnsupportedAlgorithm(
64+
"Only Ed25519 is supported".to_string(),
65+
));
66+
}
67+
68+
let provider = get_provider();
69+
let handle = provider.generate_key().map_err(|e| {
70+
HardwareError::GenerationFailed(format!("Key generation failed: {}", e))
71+
})?;
72+
73+
Ok(handle.as_raw())
74+
}
75+
76+
fn sign(handle: KeyHandle, data: Vec<u8>) -> Result<Vec<u8>, HardwareError> {
77+
let provider = get_provider();
78+
let key_handle = wsc::platform::KeyHandle::from_raw(handle);
79+
80+
provider.sign(key_handle, &data).map_err(|e| {
81+
HardwareError::SigningFailed(format!("Signing failed: {}", e))
82+
})
83+
}
84+
85+
fn get_public_key(handle: KeyHandle) -> Result<PublicKeyInfo, HardwareError> {
86+
let provider = get_provider();
87+
let key_handle = wsc::platform::KeyHandle::from_raw(handle);
88+
89+
let public_key = provider.get_public_key(key_handle).map_err(|e| {
90+
HardwareError::KeyNotFound(format!("Failed to get public key: {}", e))
91+
})?;
92+
93+
Ok(PublicKeyInfo {
94+
handle,
95+
algorithm: SigningAlgorithm::Ed25519,
96+
public_key_der: public_key.to_der(),
97+
key_id: public_key.key_id.as_ref().and_then(|id| {
98+
String::from_utf8(id.clone()).ok()
99+
}),
100+
})
101+
}
102+
103+
fn verify(
104+
public_key_der: Vec<u8>,
105+
algorithm: SigningAlgorithm,
106+
data: Vec<u8>,
107+
signature: Vec<u8>,
108+
) -> Result<bool, HardwareError> {
109+
if !matches!(algorithm, SigningAlgorithm::Ed25519) {
110+
return Err(HardwareError::UnsupportedAlgorithm(
111+
"Only Ed25519 is supported".to_string(),
112+
));
113+
}
114+
115+
let public_key = wsc::PublicKey::from_der(&public_key_der).map_err(|e| {
116+
HardwareError::SigningFailed(format!("Invalid public key: {}", e))
117+
})?;
118+
119+
// Use the inner ed25519_compact::PublicKey directly
120+
// Note: public_key.pk is the raw ed25519 key, to_bytes() adds a prefix
121+
use ed25519_compact::Signature;
122+
123+
let sig = Signature::from_slice(&signature).map_err(|e| {
124+
HardwareError::SigningFailed(format!("Invalid signature format: {}", e))
125+
})?;
126+
127+
match public_key.pk.verify(&data, &sig) {
128+
Ok(()) => Ok(true),
129+
Err(_) => Ok(false),
130+
}
131+
}
132+
133+
fn delete_key(handle: KeyHandle) -> Result<(), HardwareError> {
134+
let provider = get_provider();
135+
let key_handle = wsc::platform::KeyHandle::from_raw(handle);
136+
137+
provider.delete_key(key_handle).map_err(|e| {
138+
HardwareError::KeyNotFound(format!("Failed to delete key: {}", e))
139+
})
140+
}
141+
142+
fn list_keys() -> Result<Vec<KeyHandle>, HardwareError> {
143+
let provider = get_provider();
144+
145+
let handles = provider.list_keys().map_err(|e| {
146+
HardwareError::NotAvailable(format!("Failed to list keys: {}", e))
147+
})?;
148+
149+
Ok(handles.into_iter().map(|h| h.as_raw()).collect())
150+
}
151+
}
152+
153+
// Key usage flags
154+
const KEY_USAGE_SIGN: u8 = 0x01;
155+
#[allow(dead_code)]
156+
const KEY_USAGE_VERIFY: u8 = 0x02;
157+
158+
fn main() {
159+
println!("=== Native Crypto Provider Demo ===\n");
160+
161+
// Check availability
162+
println!("Provider available: {}", NativeCryptoProvider::is_available());
163+
164+
// Get backend info
165+
match NativeCryptoProvider::get_backend_info() {
166+
Ok(info) => {
167+
println!("Backend: {}", info.name);
168+
println!("Security level: {:?}", info.level);
169+
println!("Algorithms: {:?}", info.algorithms);
170+
}
171+
Err(e) => println!("Error getting backend info: {:?}", e),
172+
}
173+
174+
println!("\n--- Key Generation ---");
175+
176+
// Generate a key
177+
let handle = match NativeCryptoProvider::generate_key(
178+
SigningAlgorithm::Ed25519,
179+
KEY_USAGE_SIGN,
180+
Some("demo-key".to_string()),
181+
) {
182+
Ok(h) => {
183+
println!("Generated key with handle: {}", h);
184+
h
185+
}
186+
Err(e) => {
187+
println!("Error generating key: {:?}", e);
188+
return;
189+
}
190+
};
191+
192+
// Get public key
193+
match NativeCryptoProvider::get_public_key(handle) {
194+
Ok(info) => {
195+
println!("Public key (DER): {} bytes", info.public_key_der.len());
196+
println!("Algorithm: {:?}", info.algorithm);
197+
}
198+
Err(e) => println!("Error getting public key: {:?}", e),
199+
}
200+
201+
println!("\n--- Signing ---");
202+
203+
let message = b"Hello from native WIT bindings!".to_vec();
204+
println!("Message: {:?}", String::from_utf8_lossy(&message));
205+
206+
let signature = match NativeCryptoProvider::sign(handle, message.clone()) {
207+
Ok(sig) => {
208+
println!("Signature: {} bytes", sig.len());
209+
println!("Signature (hex): {}", hex::encode(&sig));
210+
sig
211+
}
212+
Err(e) => {
213+
println!("Error signing: {:?}", e);
214+
return;
215+
}
216+
};
217+
218+
println!("\n--- Verification ---");
219+
220+
// Get public key for verification
221+
let pub_key_info = NativeCryptoProvider::get_public_key(handle).unwrap();
222+
223+
match NativeCryptoProvider::verify(
224+
pub_key_info.public_key_der,
225+
SigningAlgorithm::Ed25519,
226+
message.clone(),
227+
signature.clone(),
228+
) {
229+
Ok(valid) => println!("Signature valid: {}", valid),
230+
Err(e) => println!("Error verifying: {:?}", e),
231+
}
232+
233+
// Try with wrong message
234+
let wrong_message = b"Wrong message".to_vec();
235+
match NativeCryptoProvider::verify(
236+
NativeCryptoProvider::get_public_key(handle).unwrap().public_key_der,
237+
SigningAlgorithm::Ed25519,
238+
wrong_message,
239+
signature,
240+
) {
241+
Ok(valid) => println!("Wrong message signature valid: {} (expected false)", valid),
242+
Err(e) => println!("Error verifying: {:?}", e),
243+
}
244+
245+
println!("\n--- Cleanup ---");
246+
247+
// List keys
248+
match NativeCryptoProvider::list_keys() {
249+
Ok(keys) => println!("Keys before delete: {:?}", keys),
250+
Err(e) => println!("Error listing keys: {:?}", e),
251+
}
252+
253+
// Delete key
254+
match NativeCryptoProvider::delete_key(handle) {
255+
Ok(()) => println!("Key deleted successfully"),
256+
Err(e) => println!("Error deleting key: {:?}", e),
257+
}
258+
259+
// List keys again
260+
match NativeCryptoProvider::list_keys() {
261+
Ok(keys) => println!("Keys after delete: {:?}", keys),
262+
Err(e) => println!("Error listing keys: {:?}", e),
263+
}
264+
265+
println!("\n=== Demo Complete ===");
266+
}

0 commit comments

Comments
 (0)