Skip to content

Commit 0fa787c

Browse files
committed
Key cache
1 parent ce6a9fc commit 0fa787c

6 files changed

Lines changed: 196 additions & 103 deletions

File tree

src/cose/cose_rs/Cargo.lock

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

src/cose/cose_rs/src/lib.rs

Lines changed: 78 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -93,44 +93,43 @@ fn build_endorsement_phdr(
9393
])
9494
}
9595

96-
/// Sign a ledger signature.
96+
/// Sign an identity endorsement using a pre-created key handle.
9797
///
98-
/// On success, writes the output pointer and length into `out_ptr`/`out_len`
99-
/// and returns 0. On failure returns non-zero. Caller frees with `cose_free`.
98+
/// `epoch_end_ptr`/`epoch_end_len` and `prev_root_ptr`/`prev_root_len` may be
99+
/// null/0 if not applicable.
100100
///
101101
/// # Safety
102+
/// `key` must be a valid pointer from `cose_key_from_der_private`.
102103
/// All pointer+length pairs must be valid.
103104
#[unsafe(no_mangle)]
104-
pub unsafe extern "C" fn cose_sign_ledger(
105-
key_der_ptr: *const u8,
106-
key_der_len: usize,
107-
kid_ptr: *const u8,
108-
kid_len: usize,
105+
pub unsafe extern "C" fn cose_sign_endorsement(
106+
key: *const EvpKey,
109107
iat: i64,
110-
issuer_ptr: *const u8,
111-
issuer_len: usize,
112-
subject_ptr: *const u8,
113-
subject_len: usize,
114-
txid_ptr: *const u8,
115-
txid_len: usize,
108+
epoch_begin_ptr: *const u8,
109+
epoch_begin_len: usize,
110+
epoch_end_ptr: *const u8,
111+
epoch_end_len: usize,
112+
prev_root_ptr: *const u8,
113+
prev_root_len: usize,
116114
payload_ptr: *const u8,
117115
payload_len: usize,
118116
out_ptr: *mut *mut u8,
119117
out_len: *mut usize,
120118
) -> i32 {
119+
if key.is_null() {
120+
return -1;
121+
}
121122
let result = std::panic::catch_unwind(|| unsafe {
122-
let key_der = slice_from_raw(key_der_ptr, key_der_len);
123-
let kid = slice_from_raw(kid_ptr, kid_len);
124-
let issuer = str_from_raw(issuer_ptr, issuer_len);
125-
let subject = str_from_raw(subject_ptr, subject_len);
126-
let txid = str_from_raw(txid_ptr, txid_len);
123+
let key = &*key;
124+
let epoch_begin = str_from_raw(epoch_begin_ptr, epoch_begin_len);
125+
let epoch_end = str_from_raw(epoch_end_ptr, epoch_end_len);
126+
let prev_root = slice_from_raw(prev_root_ptr, prev_root_len);
127127
let payload = slice_from_raw(payload_ptr, payload_len);
128128

129-
let key = EvpKey::from_der_private(key_der)?;
130-
let phdr = build_ledger_phdr(kid, iat, issuer, subject, txid);
129+
let phdr = build_endorsement_phdr(iat, epoch_begin, epoch_end, prev_root);
131130
let uhdr = CborValue::Map(vec![]);
132131

133-
cose_openssl::cose_sign1(&key, phdr, uhdr, payload, true)
132+
cose_openssl::cose_sign1(key, phdr, uhdr, payload, false)
134133
});
135134

136135
match result {
@@ -145,41 +144,79 @@ pub unsafe extern "C" fn cose_sign_ledger(
145144
}
146145
}
147146

148-
/// Sign an identity endorsement.
149-
///
150-
/// `epoch_end_ptr`/`epoch_end_len` and `prev_root_ptr`/`prev_root_len` may be
151-
/// null/0 if not applicable.
147+
/// Create an opaque signing key from a DER-encoded private key.
148+
/// Returns a pointer to the key, or null on failure.
149+
/// The caller must free the key with `cose_key_free`.
152150
///
153151
/// # Safety
154-
/// All pointer+length pairs must be valid.
152+
/// `key_der_ptr` must point to `key_der_len` valid bytes.
155153
#[unsafe(no_mangle)]
156-
pub unsafe extern "C" fn cose_sign_endorsement(
154+
pub unsafe extern "C" fn cose_key_from_der_private(
157155
key_der_ptr: *const u8,
158156
key_der_len: usize,
157+
) -> *mut EvpKey {
158+
let result = std::panic::catch_unwind(|| unsafe {
159+
let key_der = slice_from_raw(key_der_ptr, key_der_len);
160+
EvpKey::from_der_private(key_der)
161+
});
162+
163+
match result {
164+
Ok(Ok(key)) => Box::into_raw(Box::new(key)),
165+
_ => std::ptr::null_mut(),
166+
}
167+
}
168+
169+
/// Free a key previously created by `cose_key_from_der_private`.
170+
///
171+
/// # Safety
172+
/// `key` must be a pointer returned by `cose_key_from_der_private`,
173+
/// or null (which is a no-op).
174+
#[unsafe(no_mangle)]
175+
pub unsafe extern "C" fn cose_key_free(key: *mut EvpKey) {
176+
if !key.is_null() {
177+
unsafe {
178+
drop(Box::from_raw(key));
179+
}
180+
}
181+
}
182+
183+
/// Sign a ledger signature using a pre-created key handle.
184+
///
185+
/// # Safety
186+
/// `key` must be a valid pointer from `cose_key_from_der_private`.
187+
/// All pointer+length pairs must be valid.
188+
#[unsafe(no_mangle)]
189+
pub unsafe extern "C" fn cose_sign_ledger(
190+
key: *const EvpKey,
191+
kid_ptr: *const u8,
192+
kid_len: usize,
159193
iat: i64,
160-
epoch_begin_ptr: *const u8,
161-
epoch_begin_len: usize,
162-
epoch_end_ptr: *const u8,
163-
epoch_end_len: usize,
164-
prev_root_ptr: *const u8,
165-
prev_root_len: usize,
194+
issuer_ptr: *const u8,
195+
issuer_len: usize,
196+
subject_ptr: *const u8,
197+
subject_len: usize,
198+
txid_ptr: *const u8,
199+
txid_len: usize,
166200
payload_ptr: *const u8,
167201
payload_len: usize,
168202
out_ptr: *mut *mut u8,
169203
out_len: *mut usize,
170204
) -> i32 {
205+
if key.is_null() {
206+
return -1;
207+
}
171208
let result = std::panic::catch_unwind(|| unsafe {
172-
let key_der = slice_from_raw(key_der_ptr, key_der_len);
173-
let epoch_begin = str_from_raw(epoch_begin_ptr, epoch_begin_len);
174-
let epoch_end = str_from_raw(epoch_end_ptr, epoch_end_len);
175-
let prev_root = slice_from_raw(prev_root_ptr, prev_root_len);
209+
let key = &*key;
210+
let kid = slice_from_raw(kid_ptr, kid_len);
211+
let issuer = str_from_raw(issuer_ptr, issuer_len);
212+
let subject = str_from_raw(subject_ptr, subject_len);
213+
let txid = str_from_raw(txid_ptr, txid_len);
176214
let payload = slice_from_raw(payload_ptr, payload_len);
177215

178-
let key = EvpKey::from_der_private(key_der)?;
179-
let phdr = build_endorsement_phdr(iat, epoch_begin, epoch_end, prev_root);
216+
let phdr = build_ledger_phdr(kid, iat, issuer, subject, txid);
180217
let uhdr = CborValue::Map(vec![]);
181218

182-
cose_openssl::cose_sign1(&key, phdr, uhdr, payload, false)
219+
cose_openssl::cose_sign1(key, phdr, uhdr, payload, true)
183220
});
184221

185222
match result {

src/cose/cose_rs_ffi.h

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,22 @@ extern "C"
1111
{
1212
#endif
1313

14-
/// Sign a CCF ledger signature (COSE_Sign1, detached payload).
14+
/// Opaque handle to a Rust-managed signing key.
15+
typedef struct CoseEvpKey CoseEvpKey;
16+
17+
/// Create a signing key from DER-encoded private key bytes.
18+
/// Returns an opaque pointer, or NULL on failure.
19+
/// The caller must free the key with cose_key_free.
20+
CoseEvpKey* cose_key_from_der_private(
21+
const uint8_t* key_der_ptr, size_t key_der_len);
22+
23+
/// Free a key created by cose_key_from_der_private.
24+
void cose_key_free(CoseEvpKey* key);
25+
26+
/// Sign a CCF ledger signature using a pre-created key handle.
1527
/// Returns 0 on success, non-zero on failure.
1628
int cose_sign_ledger(
17-
const uint8_t* key_der_ptr,
18-
size_t key_der_len,
29+
const CoseEvpKey* key,
1930
const uint8_t* kid_ptr,
2031
size_t kid_len,
2132
int64_t iat,
@@ -34,8 +45,7 @@ extern "C"
3445
/// epoch_end and prev_root may be NULL/0 if not applicable.
3546
/// Returns 0 on success, non-zero on failure.
3647
int cose_sign_endorsement(
37-
const uint8_t* key_der_ptr,
38-
size_t key_der_len,
48+
const CoseEvpKey* key,
3949
int64_t iat,
4050
const uint8_t* epoch_begin_ptr,
4151
size_t epoch_begin_len,
@@ -141,9 +151,65 @@ class CoseBuffer
141151
}
142152
};
143153

154+
/// RAII wrapper for a Rust-managed signing key.
155+
/// Automatically calls cose_key_free on destruction.
156+
class CoseKey
157+
{
158+
CoseEvpKey* key = nullptr;
159+
160+
public:
161+
CoseKey() = default;
162+
163+
CoseKey(const uint8_t* der_ptr, size_t der_len) :
164+
key(cose_key_from_der_private(der_ptr, der_len))
165+
{}
166+
167+
CoseKey(const CoseKey&) = delete;
168+
CoseKey& operator=(const CoseKey&) = delete;
169+
170+
CoseKey(CoseKey&& other) noexcept : key(other.key)
171+
{
172+
other.key = nullptr;
173+
}
174+
175+
CoseKey& operator=(CoseKey&& other) noexcept
176+
{
177+
if (this != &other)
178+
{
179+
reset();
180+
key = other.key;
181+
other.key = nullptr;
182+
}
183+
return *this;
184+
}
185+
186+
~CoseKey()
187+
{
188+
reset();
189+
}
190+
191+
void reset()
192+
{
193+
if (key != nullptr)
194+
{
195+
cose_key_free(key);
196+
key = nullptr;
197+
}
198+
}
199+
200+
[[nodiscard]] const CoseEvpKey* get() const
201+
{
202+
return key;
203+
}
204+
205+
[[nodiscard]] bool ok() const
206+
{
207+
return key != nullptr;
208+
}
209+
};
210+
144211
inline int cose_sign_ledger(
145-
const uint8_t* key_der_ptr,
146-
size_t key_der_len,
212+
const CoseKey& key,
147213
const uint8_t* kid_ptr,
148214
size_t kid_len,
149215
int64_t iat,
@@ -158,8 +224,7 @@ inline int cose_sign_ledger(
158224
CoseBuffer& out)
159225
{
160226
return ::cose_sign_ledger(
161-
key_der_ptr,
162-
key_der_len,
227+
key.get(),
163228
kid_ptr,
164229
kid_len,
165230
iat,
@@ -176,8 +241,7 @@ inline int cose_sign_ledger(
176241
}
177242

178243
inline int cose_sign_endorsement(
179-
const uint8_t* key_der_ptr,
180-
size_t key_der_len,
244+
const CoseKey& key,
181245
int64_t iat,
182246
const uint8_t* epoch_begin_ptr,
183247
size_t epoch_begin_len,
@@ -190,8 +254,7 @@ inline int cose_sign_endorsement(
190254
CoseBuffer& out)
191255
{
192256
return ::cose_sign_endorsement(
193-
key_der_ptr,
194-
key_der_len,
257+
key.get(),
195258
iat,
196259
epoch_begin_ptr,
197260
epoch_begin_len,

0 commit comments

Comments
 (0)