1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
use std::ffi::CStr;
use std::marker::PhantomData;
use std::ptr::null;
use std::slice;
use libc::{c_char, size_t};
use rustls::RootCertStore;
use rustls::pki_types::pem::PemObject;
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
use rustls::sign::CertifiedKey;
use crate::crypto_provider::{self, rustls_signing_key};
use crate::error::{map_error, rustls_result};
use crate::ffi::{
Castable, OwnershipArc, OwnershipBox, OwnershipRef, free_arc, free_box, set_arc_mut_ptr,
to_arc_const_ptr, to_boxed_mut_ptr, try_box_from_ptr, try_mut_from_ptr, try_ref_from_ptr,
try_ref_from_ptr_ptr, try_slice, try_take,
};
use crate::panic::ffi_panic_boundary;
use crate::rslice::rustls_slice_bytes;
/// An X.509 certificate, as used in rustls.
/// Corresponds to `CertificateDer` in the Rust pki-types API.
/// <https://docs.rs/rustls-pki-types/latest/rustls_pki_types/struct.CertificateDer.html>
pub struct rustls_certificate<'a> {
_private: [u8; 0],
_marker: PhantomData<&'a ()>,
}
impl<'a> Castable for rustls_certificate<'a> {
type Ownership = OwnershipRef;
type RustType = CertificateDer<'a>;
}
/// Get the DER data of the certificate itself.
/// The data is owned by the certificate and has the same lifetime.
#[no_mangle]
pub extern "C" fn rustls_certificate_get_der(
cert: *const rustls_certificate,
out_der_data: *mut *const u8,
out_der_len: *mut size_t,
) -> rustls_result {
ffi_panic_boundary! {
let cert = try_ref_from_ptr!(cert);
if out_der_data.is_null() || out_der_len.is_null() {
return rustls_result::NullParameter;
}
let der = cert.as_ref();
unsafe {
*out_der_data = der.as_ptr();
*out_der_len = der.len();
}
rustls_result::Ok
}
}
/// The complete chain of certificates to send during a TLS handshake,
/// plus a private key that matches the end-entity (leaf) certificate.
///
/// Corresponds to `CertifiedKey` in the Rust API.
/// <https://docs.rs/rustls/latest/rustls/sign/struct.CertifiedKey.html>
pub struct rustls_certified_key {
_private: [u8; 0],
}
impl Castable for rustls_certified_key {
type Ownership = OwnershipArc;
type RustType = CertifiedKey;
}
impl rustls_certified_key {
/// Build a `rustls_certified_key` from a certificate chain and a private key
/// and the default process-wide crypto provider.
///
/// `cert_chain` must point to a buffer of `cert_chain_len` bytes, containing
/// a series of PEM-encoded certificates, with the end-entity (leaf)
/// certificate first.
///
/// `private_key` must point to a buffer of `private_key_len` bytes, containing
/// a PEM-encoded private key in either PKCS#1, PKCS#8 or SEC#1 format when
/// using `aws-lc-rs` as the crypto provider. Supported formats may vary by
/// provider.
///
/// On success, this writes a pointer to the newly created
/// `rustls_certified_key` in `certified_key_out`. That pointer must later
/// be freed with `rustls_certified_key_free` to avoid memory leaks. Note that
/// internally, this is an atomically reference-counted pointer, so even after
/// the original caller has called `rustls_certified_key_free`, other objects
/// may retain a pointer to the object. The memory will be freed when all
/// references are gone.
///
/// This function does not take ownership of any of its input pointers. It
/// parses the pointed-to data and makes a copy of the result. You may
/// free the cert_chain and private_key pointers after calling it.
///
/// Typically, you will build a `rustls_certified_key`, use it to create a
/// `rustls_server_config` (which increments the reference count), and then
/// immediately call `rustls_certified_key_free`. That leaves the
/// `rustls_server_config` in possession of the sole reference, so the
/// `rustls_certified_key`'s memory will automatically be released when
/// the `rustls_server_config` is freed.
#[no_mangle]
pub extern "C" fn rustls_certified_key_build(
cert_chain: *const u8,
cert_chain_len: size_t,
private_key: *const u8,
private_key_len: size_t,
certified_key_out: *mut *const rustls_certified_key,
) -> rustls_result {
ffi_panic_boundary! {
let default_provider =
match crypto_provider::get_default_or_install_from_crate_features() {
Some(default_provider) => default_provider,
None => return rustls_result::NoDefaultCryptoProvider,
};
let private_key_der =
match PrivateKeyDer::from_pem_slice(try_slice!(private_key, private_key_len)) {
Ok(der) => der,
Err(_) => return rustls_result::PrivateKeyParseError,
};
let private_key = match default_provider
.key_provider
.load_private_key(private_key_der)
{
Ok(key) => key,
Err(e) => return map_error(e),
};
Self::rustls_certified_key_build_with_signing_key(
cert_chain,
cert_chain_len,
to_boxed_mut_ptr(private_key),
certified_key_out,
)
}
}
/// Build a `rustls_certified_key` from a certificate chain and a
/// `rustls_signing_key`.
///
/// `cert_chain` must point to a buffer of `cert_chain_len` bytes, containing
/// a series of PEM-encoded certificates, with the end-entity (leaf)
/// certificate first.
///
/// `signing_key` must point to a `rustls_signing_key` loaded using a
/// `rustls_crypto_provider` and `rustls_crypto_provider_load_key()`.
///
/// On success, this writes a pointer to the newly created
/// `rustls_certified_key` in `certified_key_out`. That pointer must later
/// be freed with `rustls_certified_key_free` to avoid memory leaks. Note that
/// internally, this is an atomically reference-counted pointer, so even after
/// the original caller has called `rustls_certified_key_free`, other objects
/// may retain a pointer to the object. The memory will be freed when all
/// references are gone.
///
/// This function does not take ownership of any of its input pointers. It
/// parses the pointed-to data and makes a copy of the result. You may
/// free the cert_chain and private_key pointers after calling it.
///
/// Typically, you will build a `rustls_certified_key`, use it to create a
/// `rustls_server_config` (which increments the reference count), and then
/// immediately call `rustls_certified_key_free`. That leaves the
/// `rustls_server_config` in possession of the sole reference, so the
/// `rustls_certified_key`'s memory will automatically be released when
/// the `rustls_server_config` is freed.
#[no_mangle]
pub extern "C" fn rustls_certified_key_build_with_signing_key(
cert_chain: *const u8,
cert_chain_len: size_t,
signing_key: *mut rustls_signing_key,
certified_key_out: *mut *const rustls_certified_key,
) -> rustls_result {
ffi_panic_boundary! {
let cert_chain = try_slice!(cert_chain, cert_chain_len);
let signing_key = try_box_from_ptr!(signing_key);
let certified_key_out = try_ref_from_ptr_ptr!(certified_key_out);
let parsed_chain =
match CertificateDer::pem_slice_iter(cert_chain).collect::<Result<Vec<_>, _>>() {
Ok(parsed_chain) => parsed_chain,
Err(_) => return rustls_result::CertificateParseError,
};
set_arc_mut_ptr(
certified_key_out,
CertifiedKey::new(parsed_chain, *signing_key),
);
rustls_result::Ok
}
}
/// Return the i-th rustls_certificate in the rustls_certified_key.
///
/// 0 gives the end-entity certificate. 1 and higher give certificates from the chain.
///
/// Indexes higher than the last available certificate return NULL.
///
/// The returned certificate is valid until the rustls_certified_key is freed.
#[no_mangle]
pub extern "C" fn rustls_certified_key_get_certificate<'a>(
certified_key: *const rustls_certified_key,
i: size_t,
) -> *const rustls_certificate<'a> {
ffi_panic_boundary! {
let certified_key = try_ref_from_ptr!(certified_key);
match certified_key.cert.get(i) {
Some(cert) => cert as *const CertificateDer as *const _,
None => null(),
}
}
}
/// Create a copy of the rustls_certified_key with the given OCSP response data
/// as DER encoded bytes.
///
/// The OCSP response may be given as NULL to clear any possibly present OCSP
/// data from the cloned key.
///
/// The cloned key is independent from its original and needs to be freed
/// by the application.
#[no_mangle]
pub extern "C" fn rustls_certified_key_clone_with_ocsp(
certified_key: *const rustls_certified_key,
ocsp_response: *const rustls_slice_bytes,
cloned_key_out: *mut *const rustls_certified_key,
) -> rustls_result {
ffi_panic_boundary! {
let cloned_key_out = unsafe {
match cloned_key_out.as_mut() {
Some(c) => c,
None => return rustls_result::NullParameter,
}
};
let certified_key = try_ref_from_ptr!(certified_key);
let mut new_key = certified_key.clone();
if !ocsp_response.is_null() {
let ocsp_slice = unsafe { &*ocsp_response };
new_key.ocsp = Some(Vec::from(try_slice!(ocsp_slice.data, ocsp_slice.len)));
} else {
new_key.ocsp = None;
}
*cloned_key_out = to_arc_const_ptr(new_key);
rustls_result::Ok
}
}
/// Verify the consistency of this `rustls_certified_key`'s public and private keys.
///
/// This is done by performing a comparison of subject public key information (SPKI) bytes
/// between the certificate and private key.
///
/// If the private key matches the certificate this function returns `RUSTLS_RESULT_OK`,
/// otherwise an error `rustls_result` is returned.
#[no_mangle]
pub extern "C" fn rustls_certified_key_keys_match(
key: *const rustls_certified_key,
) -> rustls_result {
ffi_panic_boundary! {
match try_ref_from_ptr!(key).keys_match() {
Ok(_) => rustls_result::Ok,
Err(e) => map_error(e),
}
}
}
/// "Free" a certified_key previously returned from `rustls_certified_key_build`.
///
/// Since certified_key is actually an atomically reference-counted pointer,
/// extant certified_key may still hold an internal reference to the Rust object.
///
/// However, C code must consider this pointer unusable after "free"ing it.
///
/// Calling with NULL is fine. Must not be called twice with the same value.
#[no_mangle]
pub extern "C" fn rustls_certified_key_free(key: *const rustls_certified_key) {
ffi_panic_boundary! {
free_arc(key);
}
}
}
/// A `rustls_root_cert_store` being constructed.
///
/// A builder can be modified by adding trust anchor root certificates with
/// `rustls_root_cert_store_builder_add_pem`. Once you're done adding root certificates,
/// call `rustls_root_cert_store_builder_build` to turn it into a `rustls_root_cert_store`.
/// This object is not safe for concurrent mutation.
pub struct rustls_root_cert_store_builder {
_private: [u8; 0],
}
impl Castable for rustls_root_cert_store_builder {
type Ownership = OwnershipBox;
type RustType = Option<RootCertStoreBuilder>;
}
pub(crate) struct RootCertStoreBuilder {
roots: RootCertStore,
}
impl rustls_root_cert_store_builder {
/// Create a `rustls_root_cert_store_builder`.
///
/// Caller owns the memory and may free it with `rustls_root_cert_store_free`, regardless of
/// whether `rustls_root_cert_store_builder_build` was called.
///
/// If you wish to abandon the builder without calling `rustls_root_cert_store_builder_build`,
/// it must be freed with `rustls_root_cert_store_builder_free`.
#[no_mangle]
pub extern "C" fn rustls_root_cert_store_builder_new() -> *mut rustls_root_cert_store_builder {
ffi_panic_boundary! {
let store = RootCertStore::empty();
to_boxed_mut_ptr(Some(RootCertStoreBuilder { roots: store }))
}
}
/// Add one or more certificates to the root cert store builder using PEM
/// encoded data.
///
/// When `strict` is true an error will return a `CertificateParseError`
/// result. So will an attempt to parse data that has zero certificates.
///
/// When `strict` is false, unparseable root certificates will be ignored.
/// This may be useful on systems that have syntactically invalid root
/// certificates.
#[no_mangle]
pub extern "C" fn rustls_root_cert_store_builder_add_pem(
builder: *mut rustls_root_cert_store_builder,
pem: *const u8,
pem_len: size_t,
strict: bool,
) -> rustls_result {
ffi_panic_boundary! {
let certs_pem = try_slice!(pem, pem_len);
let builder = try_mut_from_ptr!(builder);
let builder = match builder {
None => return rustls_result::AlreadyUsed,
Some(b) => b,
};
let certs =
match CertificateDer::pem_slice_iter(certs_pem).collect::<Result<Vec<_>, _>>() {
Ok(certs) => certs,
Err(_) => return rustls_result::CertificateParseError,
};
// We first copy into a temporary root store so we can uphold our
// API guideline that there are no partial failures or partial
// successes.
let mut new_store = RootCertStore::empty();
let (parsed, rejected) = new_store.add_parsable_certificates(certs);
if strict && (rejected > 0 || parsed == 0) {
return rustls_result::CertificateParseError;
}
builder.roots.roots.append(&mut new_store.roots);
rustls_result::Ok
}
}
/// Add one or more certificates to the root cert store builder using PEM
/// encoded data read from the named file.
///
/// When `strict` is true an error will return a `CertificateParseError`
/// result. So will an attempt to parse data that has zero certificates.
///
/// When `strict` is false, unparseable root certificates will be ignored.
/// This may be useful on systems that have syntactically invalid root
/// certificates.
#[no_mangle]
pub extern "C" fn rustls_root_cert_store_builder_load_roots_from_file(
builder: *mut rustls_root_cert_store_builder,
filename: *const c_char,
strict: bool,
) -> rustls_result {
ffi_panic_boundary! {
let builder = try_mut_from_ptr!(builder);
let builder = match builder {
None => return rustls_result::AlreadyUsed,
Some(b) => b,
};
let filename = unsafe {
if filename.is_null() {
return rustls_result::NullParameter;
}
CStr::from_ptr(filename)
};
let filename = filename.to_bytes();
let filename = match std::str::from_utf8(filename) {
Ok(s) => s,
Err(_) => return rustls_result::Io,
};
let certs = match CertificateDer::pem_file_iter(filename) {
Ok(certs) => certs,
Err(_) => return rustls_result::Io,
};
let certs = match certs.collect::<Result<Vec<_>, _>>() {
Ok(certs) => certs,
Err(_) => return rustls_result::CertificateParseError,
};
// We first copy into a temporary root store so we can uphold our
// API guideline that there are no partial failures or partial
// successes.
let mut roots = RootCertStore::empty();
let (parsed, rejected) = roots.add_parsable_certificates(certs);
if strict && (rejected > 0 || parsed == 0) {
return rustls_result::CertificateParseError;
}
builder.roots.roots.append(&mut roots.roots);
rustls_result::Ok
}
}
/// Create a new `rustls_root_cert_store` from the builder.
///
/// The builder is consumed and cannot be used again, but must still be freed.
///
/// The root cert store can be used in several `rustls_web_pki_client_cert_verifier_builder_new`
/// instances and must be freed by the application when no longer needed. See the documentation of
/// `rustls_root_cert_store_free` for details about lifetime.
#[no_mangle]
pub extern "C" fn rustls_root_cert_store_builder_build(
builder: *mut rustls_root_cert_store_builder,
root_cert_store_out: *mut *const rustls_root_cert_store,
) -> rustls_result {
ffi_panic_boundary! {
let builder = try_mut_from_ptr!(builder);
let builder = try_take!(builder);
let root_cert_store_out = try_ref_from_ptr_ptr!(root_cert_store_out);
set_arc_mut_ptr(root_cert_store_out, builder.roots);
rustls_result::Ok
}
}
/// Free a `rustls_root_cert_store_builder` previously returned from
/// `rustls_root_cert_store_builder_new`.
///
/// Calling with NULL is fine. Must not be called twice with the same value.
#[no_mangle]
pub extern "C" fn rustls_root_cert_store_builder_free(
builder: *mut rustls_root_cert_store_builder,
) {
ffi_panic_boundary! {
free_box(builder);
}
}
}
/// A root certificate store.
/// <https://docs.rs/rustls/latest/rustls/struct.RootCertStore.html>
pub struct rustls_root_cert_store {
_private: [u8; 0],
}
impl Castable for rustls_root_cert_store {
type Ownership = OwnershipArc;
type RustType = RootCertStore;
}
impl rustls_root_cert_store {
/// Free a rustls_root_cert_store previously returned from rustls_root_cert_store_builder_build.
///
/// Calling with NULL is fine. Must not be called twice with the same value.
#[no_mangle]
pub extern "C" fn rustls_root_cert_store_free(store: *const rustls_root_cert_store) {
ffi_panic_boundary! {
free_arc(store);
}
}
}