| /* Copyright (c) 2023, Google Inc. |
| * |
| * Permission to use, copy, modify, and/or distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| //! `Pkey` and `PkeyCtx` classes for holding asymmetric keys. This module is intended for internal |
| //! use within this crate only, to create higher-level abstractions suitable to be exposed |
| //! externally. |
| |
| use crate::{ec::EcKey, CSliceMut, ForeignType}; |
| |
| pub(crate) struct Pkey { |
| ptr: *mut bssl_sys::EVP_PKEY, |
| } |
| |
| // Safety: Implementation ensures `from_ptr(x).as_ptr == x` |
| unsafe impl ForeignType for Pkey { |
| type CType = bssl_sys::EVP_PKEY; |
| |
| unsafe fn from_ptr(ptr: *mut Self::CType) -> Self { |
| Self { ptr } |
| } |
| |
| fn as_ptr(&self) -> *mut Self::CType { |
| self.ptr |
| } |
| } |
| |
| impl From<&EcKey> for Pkey { |
| fn from(eckey: &EcKey) -> Self { |
| // Safety: EVP_PKEY_new does not have any preconditions |
| let pkey = unsafe { bssl_sys::EVP_PKEY_new() }; |
| assert!(!pkey.is_null()); |
| // Safety: |
| // - pkey is just allocated and is null-checked |
| // - EcKey ensures eckey.ptr is valid during its lifetime |
| // - EVP_PKEY_set1_EC_KEY doesn't take ownership |
| let result = |
| unsafe { bssl_sys::EVP_PKEY_set1_EC_KEY(pkey, eckey.as_ptr()) }; |
| assert_eq!(result, 1, "bssl_sys::EVP_PKEY_set1_EC_KEY failed"); |
| Self { ptr: pkey } |
| } |
| } |
| |
| impl Drop for Pkey { |
| fn drop(&mut self) { |
| // Safety: `self.ptr` is owned by this struct |
| unsafe { bssl_sys::EVP_PKEY_free(self.ptr) } |
| } |
| } |
| |
| pub(crate) struct PkeyCtx { |
| ptr: *mut bssl_sys::EVP_PKEY_CTX, |
| } |
| |
| impl PkeyCtx { |
| pub fn new(pkey: &Pkey) -> Self { |
| // Safety: |
| // - `Pkey` ensures `pkey.ptr` is valid, and EVP_PKEY_CTX_new does not take ownership. |
| let pkeyctx = unsafe { bssl_sys::EVP_PKEY_CTX_new(pkey.ptr, core::ptr::null_mut()) }; |
| assert!(!pkeyctx.is_null()); |
| Self { ptr: pkeyctx } |
| } |
| |
| #[allow(clippy::panic)] |
| pub(crate) fn diffie_hellman( |
| self, |
| other_public_key: &Pkey, |
| mut output: CSliceMut, |
| ) -> Result<(), String> { |
| let result = unsafe { bssl_sys::EVP_PKEY_derive_init(self.ptr) }; |
| assert_eq!(result, 1, "bssl_sys::EVP_PKEY_derive_init failed"); |
| |
| let result = unsafe { bssl_sys::EVP_PKEY_derive_set_peer(self.ptr, other_public_key.ptr) }; |
| assert_eq!(result, 1, "bssl_sys::EVP_PKEY_derive_set_peer failed"); |
| |
| let result = |
| unsafe { bssl_sys::EVP_PKEY_derive(self.ptr, output.as_mut_ptr(), &mut output.len()) }; |
| match result { |
| 0 => Err("bssl_sys::EVP_PKEY_derive failed".to_owned()), |
| 1 => Ok(()), |
| _ => panic!("Unexpected result {result:?} from bssl_sys::EVP_PKEY_derive"), |
| } |
| } |
| } |
| |
| impl Drop for PkeyCtx { |
| fn drop(&mut self) { |
| // Safety: self.ptr is owned by this struct |
| unsafe { bssl_sys::EVP_PKEY_CTX_free(self.ptr) } |
| } |
| } |