mundane/boringssl/
raw.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Almost-raw bindings to the BoringSSL API.
6//!
7//! The `raw` module provides bindings to the BoringSSL API which add a little
8//! bit of safety beyond the safety provided by completely raw bindings by
9//! ensuring that all return values are checked for errors, and converting these
10//! C-style return values into Rust `Result`s.
11//!
12//! This module also directly re-exports any raw bindings which are infallible
13//! (e.g., `void` functions).
14
15pub use bssl_sys::{
16    CBB_len, CBS_init, CBS_len, CRYPTO_memcmp, EC_GROUP_get_curve_name, ED25519_keypair,
17    ED25519_keypair_from_seed, ERR_print_errors_cb, HMAC_CTX_init, HMAC_size, RC4_set_key,
18    RSA_bits, RC4,
19};
20
21use std::convert::TryInto;
22use std::num::NonZeroUsize;
23use std::os::raw::{c_char, c_int, c_uint, c_void};
24use std::ptr::{self, NonNull};
25
26use bssl_sys::{
27    self as ffi, BIGNUM, BN_GENCB, CBB, CBS, EC_GROUP, EC_KEY, EVP_MD, EVP_PKEY, HMAC_CTX, RSA,
28    SHA512_CTX,
29};
30
31use boringssl::abort::UnwrapAbort;
32use boringssl::wrapper::CInit;
33use boringssl::BoringError;
34
35macro_rules! impl_hash_context {
36    ($ctx:ident, $update:ident, $final:ident) => {
37        #[allow(non_snake_case)]
38        pub unsafe fn $update(ctx: *mut ffi::$ctx, data: *const c_void, len: usize) {
39            // All XXX_Update functions promise to return 1.
40            assert_abort_eq!(ffi::$update(ctx, data, len), 1);
41        }
42        #[allow(non_snake_case)]
43        pub unsafe fn $final(md: *mut u8, ctx: *mut ffi::$ctx) -> Result<(), BoringError> {
44            one_or_err(stringify!($final), ffi::$final(md, ctx))
45        }
46    };
47}
48
49// bn.h
50
51// BIGNUMs can be either heap- or stack-allocated, and they keep track of which
52// they are internally so that BN_free does the right thing - freeing the object
53// itself if heap-allocated, and only freeing its internal state otherwise.
54impl_traits!(BIGNUM, CInit => BN_init, CDestruct => BN_free);
55
56#[allow(non_snake_case)]
57#[must_use]
58pub unsafe fn BN_set_u64(bn: *mut BIGNUM, value: u64) -> Result<(), BoringError> {
59    one_or_err("BN_set_u64", ffi::BN_set_u64(bn, value))
60}
61
62// bytestring.h
63
64impl_traits!(CBB, CDestruct => CBB_cleanup);
65impl_traits!(CBS, CDestruct => _);
66
67#[allow(non_snake_case)]
68#[must_use]
69pub unsafe fn CBB_init(cbb: *mut CBB, initial_capacity: usize) -> Result<(), BoringError> {
70    one_or_err("CBB_init", ffi::CBB_init(cbb, initial_capacity))
71}
72
73#[allow(non_snake_case)]
74#[must_use]
75pub unsafe fn CBB_data(cbb: *const CBB) -> Result<NonNull<u8>, BoringError> {
76    ptr_or_err("CBB_init", ffi::CBB_data(cbb) as *mut _)
77}
78
79// curve25519.h
80
81#[allow(non_snake_case)]
82#[must_use]
83pub unsafe fn ED25519_sign(
84    out: *mut [u8; 64],
85    message: *const u8,
86    message_len: usize,
87    private_key: *const [u8; 64],
88) -> Result<(), BoringError> {
89    one_or_err(
90        "ED25519_sign",
91        ffi::ED25519_sign(out as *mut u8, message, message_len, private_key as *const u8),
92    )
93}
94
95#[allow(non_snake_case)]
96#[must_use]
97pub unsafe fn ED25519_verify(
98    message: *const u8,
99    message_len: usize,
100    signature: *const [u8; 64],
101    public_key: *const [u8; 32],
102) -> bool {
103    match ffi::ED25519_verify(message, message_len, signature as *const u8, public_key as *const u8)
104    {
105        0 => false,
106        1 => true,
107        // ED25519_verify promises to only return 0 or 1
108        _ => unreachable_abort!(),
109    }
110}
111
112// digest.h
113
114macro_rules! evp_digest {
115    ($name:ident) => {
116        #[allow(non_snake_case)]
117        #[must_use]
118        pub unsafe fn $name() -> NonNull<EVP_MD> {
119            // These return pointers to statically-allocated objects, so should
120            // never fail.
121            use boringssl::abort::UnwrapAbort;
122            ptr_or_err(stringify!($name), ffi::$name() as *mut _).unwrap_abort()
123        }
124    };
125}
126
127evp_digest!(EVP_md5);
128evp_digest!(EVP_sha1);
129evp_digest!(EVP_sha256);
130evp_digest!(EVP_sha384);
131evp_digest!(EVP_sha512);
132
133// ec.h
134
135#[allow(non_snake_case)]
136#[must_use]
137pub unsafe fn EC_GROUP_new_by_curve_name(nid: c_int) -> Result<NonNull<EC_GROUP>, BoringError> {
138    ptr_or_err("EC_GROUP_new_by_curve_name", ffi::EC_GROUP_new_by_curve_name(nid))
139}
140
141// ec_key.h
142
143impl_traits!(EC_KEY, CNew => EC_KEY_new, CUpRef => EC_KEY_up_ref, CFree => EC_KEY_free);
144impl_traits!(EVP_PKEY, CNew => EVP_PKEY_new, CUpRef => EVP_PKEY_up_ref, CFree => EVP_PKEY_free);
145
146#[allow(non_snake_case)]
147#[must_use]
148pub unsafe fn EC_curve_nid2nist(nid: c_int) -> Result<NonNull<c_char>, BoringError> {
149    ptr_or_err("EC_curve_nid2nist", ffi::EC_curve_nid2nist(nid) as *mut _)
150}
151
152#[allow(non_snake_case)]
153#[must_use]
154pub unsafe fn EC_KEY_generate_key(key: *mut EC_KEY) -> Result<(), BoringError> {
155    one_or_err("EC_KEY_generate_key", ffi::EC_KEY_generate_key(key))
156}
157
158#[allow(non_snake_case)]
159#[must_use]
160pub unsafe fn EC_KEY_get0_group(key: *const EC_KEY) -> Result<NonNull<EC_GROUP>, BoringError> {
161    ptr_or_err("EC_KEY_get0_group", ffi::EC_KEY_get0_group(key) as *mut _)
162}
163
164#[allow(non_snake_case)]
165#[must_use]
166pub unsafe fn EC_KEY_marshal_private_key(
167    cbb: *mut CBB,
168    key: *const EC_KEY,
169    enc_flags: c_uint,
170) -> Result<(), BoringError> {
171    one_or_err("EC_KEY_marshal_private_key", ffi::EC_KEY_marshal_private_key(cbb, key, enc_flags))
172}
173
174#[allow(non_snake_case)]
175#[must_use]
176pub unsafe fn EC_KEY_parse_private_key(
177    cbs: *mut CBS,
178    group: *const EC_GROUP,
179) -> Result<NonNull<EC_KEY>, BoringError> {
180    ptr_or_err("EC_KEY_parse_private_key", ffi::EC_KEY_parse_private_key(cbs, group))
181}
182
183#[allow(non_snake_case)]
184#[must_use]
185pub unsafe fn EC_KEY_set_group(
186    key: *mut EC_KEY,
187    group: *const EC_GROUP,
188) -> Result<(), BoringError> {
189    one_or_err("EC_KEY_set_group", ffi::EC_KEY_set_group(key, group))
190}
191
192// ecdsa.h
193
194#[allow(non_snake_case)]
195#[must_use]
196pub unsafe fn ECDSA_sign(
197    type_: c_int,
198    digest: *const u8,
199    digest_len: usize,
200    sig: *mut u8,
201    sig_len: *mut c_uint,
202    key: *const EC_KEY,
203) -> Result<(), BoringError> {
204    one_or_err("ECDSA_sign", ffi::ECDSA_sign(type_, digest, digest_len, sig, sig_len, key))
205}
206
207#[allow(non_snake_case)]
208#[must_use]
209pub unsafe fn ECDSA_size(key: *const EC_KEY) -> Result<NonZeroUsize, BoringError> {
210    NonZeroUsize::new(ffi::ECDSA_size(key)).ok_or_else(|| BoringError::consume_stack("ECDSA_size"))
211}
212
213#[allow(non_snake_case)]
214#[must_use]
215pub unsafe fn ECDSA_verify(
216    type_: c_int,
217    digest: *const u8,
218    digest_len: usize,
219    sig: *const u8,
220    sig_len: usize,
221    key: *const EC_KEY,
222) -> bool {
223    match ffi::ECDSA_verify(type_, digest, digest_len, sig, sig_len, key) {
224        1 => true,
225        0 => false,
226        // ECDSA_verify promises to only return 0 or 1
227        _ => unreachable_abort!(),
228    }
229}
230
231// evp.h
232
233#[allow(non_snake_case)]
234#[must_use]
235pub unsafe fn EVP_marshal_public_key(
236    cbb: *mut CBB,
237    key: *const EVP_PKEY,
238) -> Result<(), BoringError> {
239    one_or_err("EVP_marshal_public_key", ffi::EVP_marshal_public_key(cbb, key))
240}
241
242#[allow(non_snake_case)]
243#[must_use]
244pub unsafe fn EVP_parse_public_key(cbs: *mut CBS) -> Result<NonNull<EVP_PKEY>, BoringError> {
245    ptr_or_err("EVP_parse_public_key", ffi::EVP_parse_public_key(cbs))
246}
247
248#[allow(non_snake_case)]
249#[must_use]
250pub unsafe fn EVP_PKEY_assign_EC_KEY(
251    pkey: *mut EVP_PKEY,
252    key: *mut EC_KEY,
253) -> Result<(), BoringError> {
254    one_or_err("EVP_PKEY_assign_EC_KEY", ffi::EVP_PKEY_assign_EC_KEY(pkey, key))
255}
256
257#[allow(non_snake_case)]
258#[must_use]
259pub unsafe fn EVP_PKEY_assign_RSA(pkey: *mut EVP_PKEY, key: *mut RSA) -> Result<(), BoringError> {
260    one_or_err("EVP_PKEY_assign_RSA", ffi::EVP_PKEY_assign_RSA(pkey, key))
261}
262
263#[allow(non_snake_case)]
264#[must_use]
265pub unsafe fn EVP_PKEY_get1_EC_KEY(pkey: *mut EVP_PKEY) -> Result<NonNull<EC_KEY>, BoringError> {
266    ptr_or_err("EVP_PKEY_get1_EC_KEY", ffi::EVP_PKEY_get1_EC_KEY(pkey))
267}
268
269#[allow(non_snake_case)]
270#[must_use]
271pub unsafe fn EVP_PKEY_get1_RSA(pkey: *mut EVP_PKEY) -> Result<NonNull<RSA>, BoringError> {
272    ptr_or_err("EVP_PKEY_get1_RSA", ffi::EVP_PKEY_get1_RSA(pkey))
273}
274
275#[allow(non_snake_case)]
276#[allow(clippy::too_many_arguments)]
277#[must_use]
278pub unsafe fn EVP_PBE_scrypt(
279    password: *const c_char,
280    password_len: usize,
281    salt: *const u8,
282    salt_len: usize,
283    N: u64,
284    r: u64,
285    p: u64,
286    max_mem: usize,
287    out_key: *mut u8,
288    key_len: usize,
289) -> Result<(), BoringError> {
290    one_or_err(
291        "EVP_PBE_scrypt",
292        ffi::EVP_PBE_scrypt(
293            password,
294            password_len,
295            salt,
296            salt_len,
297            N,
298            r,
299            p,
300            max_mem,
301            out_key,
302            key_len,
303        ),
304    )
305}
306
307#[cfg(feature = "kdf")]
308#[allow(non_snake_case)]
309#[allow(clippy::too_many_arguments)]
310#[must_use]
311pub unsafe fn PKCS5_PBKDF2_HMAC(
312    password: *const c_char,
313    password_len: usize,
314    salt: *const u8,
315    salt_len: usize,
316    iterations: c_uint,
317    digest: *const EVP_MD,
318    key_len: usize,
319    out_key: *mut u8,
320) -> Result<(), BoringError> {
321    one_or_err(
322        "PKCS5_PBKDF2_HMAC",
323        ffi::PKCS5_PBKDF2_HMAC(
324            password,
325            password_len,
326            salt,
327            salt_len,
328            iterations,
329            digest,
330            key_len,
331            out_key,
332        ),
333    )
334}
335
336// hmac.h
337
338// NOTE: We don't implement CInit because some functions that take an HMAC_CTX
339// pointer have extra invariants beyond simply having called HMAC_CTX_init. If
340// we implemented CInit, then safe code would be able to construct a
341// CStackWrapper<HMAC_CTX> using Default::default, and then pass a pointer to
342// that object to functions that require extra initialization, leading to
343// usoundness.
344impl_traits!(HMAC_CTX, CDestruct => HMAC_CTX_cleanup);
345
346#[allow(non_snake_case)]
347#[must_use]
348pub unsafe fn HMAC_Init_ex(
349    ctx: *mut HMAC_CTX,
350    key: *const c_void,
351    key_len: usize,
352    md: *const EVP_MD,
353) -> Result<(), BoringError> {
354    one_or_err("HMAC_Init_ex", ffi::HMAC_Init_ex(ctx, key, key_len, md, ptr::null_mut()))
355}
356
357#[allow(non_snake_case)]
358pub unsafe fn HMAC_Update(ctx: *mut HMAC_CTX, data: *const u8, data_len: usize) {
359    // HMAC_Update promises to return 1.
360    assert_abort_eq!(ffi::HMAC_Update(ctx, data, data_len), 1);
361}
362
363#[allow(non_snake_case)]
364#[must_use]
365pub unsafe fn HMAC_Final(
366    ctx: *mut HMAC_CTX,
367    out: *mut u8,
368    out_len: *mut c_uint,
369) -> Result<(), BoringError> {
370    one_or_err("HMAC_Final", ffi::HMAC_Final(ctx, out, out_len))
371}
372
373#[allow(non_snake_case)]
374pub unsafe fn HMAC_CTX_copy(dest: *mut HMAC_CTX, src: *const HMAC_CTX) -> Result<(), BoringError> {
375    one_or_err("HMAC_CTX_copy", ffi::HMAC_CTX_copy(dest, src))
376}
377
378// rand.h
379
380#[allow(non_snake_case)]
381pub unsafe fn RAND_bytes(buf: *mut u8, len: usize) {
382    // RAND_bytes promises to return 1.
383    assert_abort_eq!(ffi::RAND_bytes(buf, len), 1);
384}
385
386// rsa.h
387
388impl_traits!(RSA, CNew => RSA_new, CUpRef => RSA_up_ref, CFree => RSA_free);
389
390#[allow(non_snake_case)]
391#[must_use]
392pub unsafe fn RSA_generate_key_ex(
393    rsa: *mut RSA,
394    bits: c_int,
395    e: *const BIGNUM,
396    cb: *mut BN_GENCB,
397) -> Result<(), BoringError> {
398    one_or_err("RSA_generate_key_ex", ffi::RSA_generate_key_ex(rsa, bits, e, cb))
399}
400
401#[allow(non_snake_case)]
402#[must_use]
403pub unsafe fn RSA_marshal_private_key(cbb: *mut CBB, rsa: *const RSA) -> Result<(), BoringError> {
404    one_or_err("RSA_marshal_private_key", ffi::RSA_marshal_private_key(cbb, rsa))
405}
406
407#[allow(non_snake_case)]
408#[must_use]
409pub unsafe fn RSA_parse_private_key(cbs: *mut CBS) -> Result<NonNull<RSA>, BoringError> {
410    ptr_or_err("RSA_parse_private_key", ffi::RSA_parse_private_key(cbs))
411}
412
413#[cfg(feature = "rsa-pkcs1v15")]
414#[allow(non_snake_case)]
415#[must_use]
416pub unsafe fn RSA_sign(
417    hash_nid: c_int,
418    in_: *const u8,
419    in_len: usize,
420    out: *mut u8,
421    out_len: *mut c_uint,
422    key: *mut RSA,
423) -> Result<(), BoringError> {
424    one_or_err("RSA_sign", ffi::RSA_sign(hash_nid, in_, in_len, out, out_len, key))
425}
426
427#[allow(non_snake_case)]
428#[must_use]
429pub unsafe fn RSA_sign_pss_mgf1(
430    rsa: *mut RSA,
431    out_len: *mut usize,
432    out: *mut u8,
433    max_out: usize,
434    in_: *const u8,
435    in_len: usize,
436    md: *const EVP_MD,
437    mgf1_md: *const EVP_MD,
438    salt_len: c_int,
439) -> Result<(), BoringError> {
440    one_or_err(
441        "RSA_sign_pss_mgf1",
442        ffi::RSA_sign_pss_mgf1(rsa, out_len, out, max_out, in_, in_len, md, mgf1_md, salt_len),
443    )
444}
445
446#[allow(non_snake_case)]
447#[must_use]
448pub unsafe fn RSA_size(key: *const RSA) -> Result<NonZeroUsize, BoringError> {
449    NonZeroUsize::new(ffi::RSA_size(key).try_into().unwrap_abort())
450        .ok_or_else(|| BoringError::consume_stack("RSA_size"))
451}
452
453#[cfg(feature = "rsa-pkcs1v15")]
454#[allow(non_snake_case)]
455#[must_use]
456pub unsafe fn RSA_verify(
457    hash_nid: c_int,
458    msg: *const u8,
459    msg_len: usize,
460    sig: *const u8,
461    sig_len: usize,
462    rsa: *mut RSA,
463) -> bool {
464    match ffi::RSA_verify(hash_nid, msg, msg_len, sig, sig_len, rsa) {
465        0 => false,
466        1 => true,
467        // RSA_verify promises to only return 0 or 1
468        _ => unreachable_abort!(),
469    }
470}
471
472#[allow(non_snake_case)]
473#[must_use]
474pub unsafe fn RSA_verify_pss_mgf1(
475    rsa: *mut RSA,
476    msg: *const u8,
477    msg_len: usize,
478    md: *const EVP_MD,
479    mgf1_md: *const EVP_MD,
480    salt_len: c_int,
481    sig: *const u8,
482    sig_len: usize,
483) -> bool {
484    match ffi::RSA_verify_pss_mgf1(rsa, msg, msg_len, md, mgf1_md, salt_len, sig, sig_len) {
485        0 => false,
486        1 => true,
487        // RSA_verify_pss_mgf1 promises to only return 0 or 1
488        _ => unreachable_abort!(),
489    }
490}
491
492// rc4.h
493
494impl_traits!(RC4_KEY, CDestruct => _);
495
496// md5.h and sha.h
497
498unsafe impl CInit for ffi::MD5_CTX {
499    unsafe fn init(ctx: *mut Self) {
500        // MD5_Init promises to return 1.
501        assert_abort_eq!(ffi::MD5_Init(ctx), 1);
502    }
503}
504
505#[allow(non_snake_case)]
506pub unsafe fn SHA384_Init(ctx: *mut SHA512_CTX) {
507    // SHA384_Init promises to return 1.
508    assert_abort_eq!(ffi::SHA384_Init(ctx), 1);
509}
510
511// Implemented manually (rather than via impl_traits! or c_init!) so that we can
512// assert_abort_eq! that the return value is 1.
513unsafe impl CInit for ffi::SHA_CTX {
514    unsafe fn init(ctx: *mut Self) {
515        // SHA1_Init promises to return 1.
516        assert_abort_eq!(ffi::SHA1_Init(ctx), 1);
517    }
518}
519unsafe impl CInit for ffi::SHA256_CTX {
520    unsafe fn init(ctx: *mut Self) {
521        // SHA256_Init promises to return 1.
522        assert_abort_eq!(ffi::SHA256_Init(ctx), 1);
523    }
524}
525unsafe impl CInit for ffi::SHA512_CTX {
526    unsafe fn init(ctx: *mut Self) {
527        // SHA512_Init promises to return 1.
528        assert_abort_eq!(ffi::SHA512_Init(ctx), 1);
529    }
530}
531
532// implement no-op destructors
533impl_traits!(MD5_CTX, CDestruct => _);
534impl_traits!(SHA_CTX, CDestruct => _);
535impl_traits!(SHA256_CTX, CDestruct => _);
536impl_traits!(SHA512_CTX, CDestruct => _);
537
538impl_hash_context!(MD5_CTX, MD5_Update, MD5_Final);
539impl_hash_context!(SHA_CTX, SHA1_Update, SHA1_Final);
540impl_hash_context!(SHA256_CTX, SHA256_Update, SHA256_Final);
541impl_hash_context!(SHA512_CTX, SHA384_Update, SHA384_Final);
542impl_hash_context!(SHA512_CTX, SHA512_Update, SHA512_Final);
543
544// utility functions
545
546// If code is 1, returns Ok, otherwise returns Err. f should be the name of the
547// function that returned this value.
548#[must_use]
549pub fn one_or_err<S: TryInto<usize>>(f: &str, code: S) -> Result<(), BoringError> {
550    // If the conversion failed, then the value is definitely not 1 since 1 is
551    // representable in `usize`. Thus, in that case, we assume there was an
552    // error.
553    if code.try_into().map(|code| code == 1).unwrap_or(false) {
554        Ok(())
555    } else {
556        Err(BoringError::consume_stack(f))
557    }
558}
559
560// If ptr is non-NULL, returns Ok, otherwise returns Err. f should be the name
561// of the function that returned this value.
562fn ptr_or_err<T>(f: &str, ptr: *mut T) -> Result<NonNull<T>, BoringError> {
563    NonNull::new(ptr).ok_or_else(|| BoringError::consume_stack(f))
564}