// Copyright 2026 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Private and public keys
//!
//! The private keys processed here can be paired with certificates to perform further
//! authentication.
//!
//! ```rust
//! # use bssl_x509::certificates::X509Certificate;
//! # use bssl_x509::keys::PrivateKey;
//! # let pem = include_bytes!("tests/BoringSSLTestCA.key");
//! # let crt = include_bytes!("tests/BoringSSLTestCA.crt");
//! # let crt = X509Certificate::parse_one_from_pem(crt).unwrap();
//! let key = PrivateKey::from_pem(
//!     pem, /*password_callback=*/ || b"BoringSSL is awesome!").unwrap();
//! assert!(crt.matches_private_key(&key));
//! ```
//!
//! The public keys can be derived from [`crate::certificates::X509Certificate`] or [`PrivateKey`]s.
//!
//! ```rust
//! # use bssl_x509::certificates::X509Certificate;
//! # use bssl_x509::keys::PrivateKey;
//! # let pem = include_bytes!("tests/BoringSSLTestCA.key");
//! # let crt = include_bytes!("tests/BoringSSLTestCA.crt");
//! # let crt = X509Certificate::parse_one_from_pem(crt).unwrap();
//! # let key = PrivateKey::from_pem(
//! #     pem, /*password_callback=*/ || b"BoringSSL is awesome!").unwrap();
//! assert_eq!(
//!     crt.public_key().unwrap().to_der(),
//!     key.to_public_key().to_der()
//! );
//! ```

use alloc::vec::Vec;
use core::{
    ffi::{c_char, c_int, c_void},
    mem::transmute,
    panic::AssertUnwindSafe,
    ptr::{NonNull, null_mut},
};

use bssl_crypto::{FfiSlice, cbb_to_buffer};
use bssl_macros::bssl_enum;

use crate::ffi::abort_on_panic;
use crate::{errors::PkiError, ffi::Bio};

bssl_enum! {
    /// EVP public key algorithm types.
    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
    #[non_exhaustive]
    pub enum PrivateKeyAlgorithm: i32 {
        /// RSA
        Rsa = bssl_sys::EVP_PKEY_RSA as i32,
        /// RSA-PSS
        RsaPss = bssl_sys::EVP_PKEY_RSA_PSS as i32,
        /// EC
        Ec = bssl_sys::EVP_PKEY_EC as i32,
        /// Ed25519
        Ed25519 = bssl_sys::EVP_PKEY_ED25519 as i32,
        /// X25519
        X25519 = bssl_sys::EVP_PKEY_X25519 as i32,
        /// DSA
        Dsa = bssl_sys::EVP_PKEY_DSA as i32,
        /// DH
        Dh = bssl_sys::EVP_PKEY_DH as i32,
    }
}

/// A private key.
#[repr(transparent)]
pub struct PrivateKey(NonNull<bssl_sys::EVP_PKEY>);
// Safety: `PrivateKey` is locked as immutable at this type state.
unsafe impl Send for PrivateKey {}
unsafe impl Sync for PrivateKey {}

impl PrivateKey {
    /// Parse a [`PrivateKey`] from PEM encoding.
    pub fn from_pem<'a, F: 'a + FnMut() -> &'a [u8]>(
        pem: &[u8],
        mut password_callback: F,
    ) -> Result<Self, PkiError> {
        let mut bio = Bio::from_bytes(pem)?;

        let mut priv_key = null_mut();

        unsafe extern "C" fn write_password<'a, F: 'a + FnMut() -> &'a [u8]>(
            out: *mut c_char,
            size: c_int,
            _rwflag: c_int,
            ctxt: *mut c_void,
        ) -> c_int {
            if size < 0 {
                return -1;
            }
            let password_callback = AssertUnwindSafe(unsafe {
                // Safety: `ctxt` is a valid callback pointer and outlived by `'a`, so it must be
                // valid when invoked.
                &mut *(ctxt as *mut F)
            });
            let get_password = move || {
                let AssertUnwindSafe(pass_callback) = { password_callback };
                let password = pass_callback();
                let Ok(len) = password.len().try_into() else {
                    return -1;
                };
                if len > size {
                    return -1;
                }
                unsafe {
                    // Safety:
                    // - `src` is valid and not larger than `out`.
                    // - `out` is valid per BoringSSL specification.
                    // - `src` and `out` are both 1-aligned.
                    core::ptr::copy(password.as_ffi_void_ptr(), out as _, password.len());
                }
                len
            };
            abort_on_panic(get_password)
        }

        let evp_pkey = unsafe {
            // Safety:
            // - the BIO is still valid.
            // - the `priv_key` pointer is null, so the function will allocate
            //   a new structure.
            bssl_sys::PEM_read_bio_PrivateKey(
                bio.ptr(),
                &raw mut priv_key,
                Some(write_password::<'a, F>),
                &raw mut password_callback as _,
            )
        };
        NonNull::new(evp_pkey)
            .map(Self)
            .ok_or_else(PkiError::extract_lib_err)
    }

    /// Get the algorithm ID of the private key.
    ///
    /// This method returns [`None`] if the key algorithm is unrecognised.
    pub fn algorithm(&self) -> Option<PrivateKeyAlgorithm> {
        let id = unsafe {
            // Safety: self.0 is valid.
            bssl_sys::EVP_PKEY_id(self.ptr())
        };
        let id = i32::try_from(id).ok()?;
        PrivateKeyAlgorithm::try_from(id).ok()
    }

    /// This method releases ownership of the internal key handle.
    ///
    /// # Safety
    /// - This method should only be used for cross-language interoperability,
    ///   so the function that accepts an `EVP_PKEY*` handle must uses exactly the same
    ///   BoringSSL as this crate is linked to.
    pub fn into_raw(self) -> *mut bssl_sys::EVP_PKEY {
        let ptr = self.ptr();
        core::mem::forget(self);
        ptr
    }

    /// This method returns the internal key handle.
    /// # Safety
    /// - This method should only be used for cross-language interoperability,
    ///   so the function that accepts an `EVP_PKEY*` handle must uses exactly the same
    ///   BoringSSL as this crate is linked to.
    /// - The caller must ensure that all future uses of the key handle does not mutate the content.
    /// - All subsequent uses of the returned handle must be outlived by `self`.
    /// - All subsequent uses of the returned handle must not race with uses of `self`.
    ///   unless only refcount is adjusted, one must use locks when necessary.
    pub unsafe fn as_mut_ptr(&mut self) -> *mut bssl_sys::EVP_PKEY {
        self.ptr()
    }

    pub(crate) fn ptr(&self) -> *mut bssl_sys::EVP_PKEY {
        self.0.as_ptr()
    }

    /// Encode the private key to a DER-encoded `PrivateKeyInfo` structure as per [RFC 5208].
    ///
    /// [RFC 5208]: <https://datatracker.ietf.org/doc/html/rfc5208#section-5>
    pub fn private_key_to_der(&self) -> Vec<u8> {
        cbb_to_buffer(0, |cbb| unsafe {
            // Safety: this call does not mutate the private key internals
            // and only allocation happens.
            assert_eq!(1, bssl_sys::EVP_marshal_private_key(cbb, self.ptr()))
        })
        .as_ref()
        .to_vec()
    }

    /// Get the public key.
    pub fn to_public_key(&self) -> &PublicKey {
        unsafe {
            // Safety: `self.0` is still valid.
            debug_assert_eq!(1, bssl_sys::EVP_PKEY_has_public(self.ptr()));
        }
        unsafe {
            // Safety:
            // - the `EVP_PKEY*` in `PrivateKey` always contains a public key.
            // - `PublicKey` is a transparent wrapper of `EVP_PKEY*`
            transmute(self)
        }
    }
}

impl Clone for PrivateKey {
    fn clone(&self) -> Self {
        unsafe {
            // Safety: `self.0` is still valid at cloning.
            bssl_sys::EVP_PKEY_up_ref(self.ptr());
        }
        Self(self.0)
    }
}

impl Drop for PrivateKey {
    fn drop(&mut self) {
        unsafe {
            // Safety: `self.0` is still valid at dropping.
            bssl_sys::EVP_PKEY_free(self.ptr());
        }
    }
}

/// A public key.
#[repr(transparent)]
pub struct PublicKey(pub(crate) NonNull<bssl_sys::EVP_PKEY>);
// Safety: `PublicKey` is locked as immutable at this type state.
unsafe impl Send for PublicKey {}
unsafe impl Sync for PublicKey {}

impl PublicKey {
    /// Parse a [`PublicKey`] from PEM encoding.
    pub fn from_pem(pem: &[u8]) -> Result<Self, PkiError> {
        let mut bio = Bio::from_bytes(pem)?;

        let mut pub_key = null_mut();
        let evp_pkey = unsafe {
            // Safety:
            // - the BIO is still valid.
            // - the `pub_key` pointer is null, so the function will allocate
            //   a new structure.
            bssl_sys::PEM_read_bio_PUBKEY(bio.ptr(), &raw mut pub_key, None, null_mut())
        };
        NonNull::new(evp_pkey)
            .map(Self)
            .ok_or_else(PkiError::extract_lib_err)
    }

    /// Serialize the public key into a DER-encoded `SubjectPublicKeyInfo` structure.
    pub fn to_der(&self) -> Vec<u8> {
        cbb_to_buffer(0, |cbb| unsafe {
            // Safety: this call does not mutate the private key internals
            // and only allocation happens.
            assert_eq!(1, bssl_sys::EVP_marshal_public_key(cbb, self.ptr()))
        })
        .as_ref()
        .to_vec()
    }

    pub(crate) fn ptr(&self) -> *mut bssl_sys::EVP_PKEY {
        self.0.as_ptr()
    }

    /// This method returns the internal key handle.
    /// # Safety
    /// - This method should only be used for cross-language interoperability,
    ///   so the function that accepts an `EVP_PKEY*` handle must uses exactly the same
    ///   BoringSSL as this crate is linked to.
    /// - The caller must ensure that all future uses of the key handle does not mutate the content.
    /// - All subsequent uses of the returned handle must be outlived by `self`.
    /// - All subsequent uses of the returned handle must not race with uses of `self`.
    ///   unless only refcount is adjusted, one must use locks when necessary.
    pub unsafe fn as_mut_ptr(&mut self) -> *mut bssl_sys::EVP_PKEY {
        self.ptr()
    }
}

impl Clone for PublicKey {
    fn clone(&self) -> Self {
        unsafe {
            // Safety: `self.0` is still valid at cloning.
            bssl_sys::EVP_PKEY_up_ref(self.ptr());
        }
        Self(self.0)
    }
}

impl Drop for PublicKey {
    fn drop(&mut self) {
        unsafe {
            // Safety: `self.0` is still valid at dropping.
            bssl_sys::EVP_PKEY_free(self.ptr());
        }
    }
}
