1 /* Copyright (c) 2023, Google Inc. 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 */ 15 16 //! `Pkey` and `PkeyCtx` classes for holding asymmetric keys. This module is intended for internal 17 //! use within this crate only, to create higher-level abstractions suitable to be exposed 18 //! externally. 19 20 use crate::{ec::EcKey, CSliceMut, ForeignType}; 21 use alloc::borrow::ToOwned; 22 use alloc::string::String; 23 24 pub(crate) struct Pkey { 25 ptr: *mut bssl_sys::EVP_PKEY, 26 } 27 28 // Safety: Implementation ensures `from_ptr(x).as_ptr == x` 29 unsafe impl ForeignType for Pkey { 30 type CType = bssl_sys::EVP_PKEY; 31 from_ptr(ptr: *mut Self::CType) -> Self32 unsafe fn from_ptr(ptr: *mut Self::CType) -> Self { 33 Self { ptr } 34 } 35 as_ptr(&self) -> *mut Self::CType36 fn as_ptr(&self) -> *mut Self::CType { 37 self.ptr 38 } 39 } 40 41 impl From<&EcKey> for Pkey { from(eckey: &EcKey) -> Self42 fn from(eckey: &EcKey) -> Self { 43 // Safety: EVP_PKEY_new does not have any preconditions 44 let pkey = unsafe { bssl_sys::EVP_PKEY_new() }; 45 assert!(!pkey.is_null()); 46 // Safety: 47 // - pkey is just allocated and is null-checked 48 // - EcKey ensures eckey.ptr is valid during its lifetime 49 // - EVP_PKEY_set1_EC_KEY doesn't take ownership 50 let result = unsafe { bssl_sys::EVP_PKEY_set1_EC_KEY(pkey, eckey.as_ptr()) }; 51 assert_eq!(result, 1, "bssl_sys::EVP_PKEY_set1_EC_KEY failed"); 52 Self { ptr: pkey } 53 } 54 } 55 56 impl Drop for Pkey { drop(&mut self)57 fn drop(&mut self) { 58 // Safety: `self.ptr` is owned by this struct 59 unsafe { bssl_sys::EVP_PKEY_free(self.ptr) } 60 } 61 } 62 63 pub(crate) struct PkeyCtx { 64 ptr: *mut bssl_sys::EVP_PKEY_CTX, 65 } 66 67 impl PkeyCtx { new(pkey: &Pkey) -> Self68 pub fn new(pkey: &Pkey) -> Self { 69 // Safety: 70 // - `Pkey` ensures `pkey.ptr` is valid, and EVP_PKEY_CTX_new does not take ownership. 71 let pkeyctx = unsafe { bssl_sys::EVP_PKEY_CTX_new(pkey.ptr, core::ptr::null_mut()) }; 72 assert!(!pkeyctx.is_null()); 73 Self { ptr: pkeyctx } 74 } 75 76 #[allow(clippy::panic)] diffie_hellman( self, other_public_key: &Pkey, mut output: CSliceMut, ) -> Result<(), String>77 pub(crate) fn diffie_hellman( 78 self, 79 other_public_key: &Pkey, 80 mut output: CSliceMut, 81 ) -> Result<(), String> { 82 let result = unsafe { bssl_sys::EVP_PKEY_derive_init(self.ptr) }; 83 assert_eq!(result, 1, "bssl_sys::EVP_PKEY_derive_init failed"); 84 85 let result = unsafe { bssl_sys::EVP_PKEY_derive_set_peer(self.ptr, other_public_key.ptr) }; 86 assert_eq!(result, 1, "bssl_sys::EVP_PKEY_derive_set_peer failed"); 87 88 let result = 89 unsafe { bssl_sys::EVP_PKEY_derive(self.ptr, output.as_mut_ptr(), &mut output.len()) }; 90 match result { 91 0 => Err("bssl_sys::EVP_PKEY_derive failed".to_owned()), 92 1 => Ok(()), 93 _ => panic!("Unexpected result {result:?} from bssl_sys::EVP_PKEY_derive"), 94 } 95 } 96 } 97 98 impl Drop for PkeyCtx { drop(&mut self)99 fn drop(&mut self) { 100 // Safety: self.ptr is owned by this struct 101 unsafe { bssl_sys::EVP_PKEY_CTX_free(self.ptr) } 102 } 103 } 104