Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve documentation and doctests #1741

Merged
merged 5 commits into from
Dec 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions openssl/src/derive.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,54 @@
//! Shared secret derivation.
//!
//! # Example
//!
//! The following example implements [ECDH] using `NIST P-384` keys:
//!
//! ```
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # use std::convert::TryInto;
//! use openssl::bn::BigNumContext;
//! use openssl::pkey::PKey;
//! use openssl::derive::Deriver;
//! use openssl::ec::{EcGroup, EcKey, EcPoint, PointConversionForm};
//! use openssl::nid::Nid;
//!
//! let group = EcGroup::from_curve_name(Nid::SECP384R1)?;
//!
//! let first: PKey<_> = EcKey::generate(&group)?.try_into()?;
//!
//! // second party generates an ephemeral key and derives
//! // a shared secret using first party's public key
//! let shared_key = EcKey::generate(&group)?;
//! // shared_public is sent to first party
//! let mut ctx = BigNumContext::new()?;
//! let shared_public = shared_key.public_key().to_bytes(
//! &group,
//! PointConversionForm::COMPRESSED,
//! &mut ctx,
//! )?;
//!
//! let shared_key: PKey<_> = shared_key.try_into()?;
//! let mut deriver = Deriver::new(&shared_key)?;
//! deriver.set_peer(&first)?;
//! // secret can be used e.g. as a symmetric encryption key
//! let secret = deriver.derive_to_vec()?;
//! # drop(deriver);
//!
//! // first party derives the same shared secret using
//! // shared_public
//! let point = EcPoint::from_bytes(&group, &shared_public, &mut ctx)?;
//! let recipient_key: PKey<_> = EcKey::from_public_key(&group, &point)?.try_into()?;
//! let mut deriver = Deriver::new(&first)?;
//! deriver.set_peer(&recipient_key)?;
//! let first_secret = deriver.derive_to_vec()?;
//!
//! assert_eq!(secret, first_secret);
//! # Ok(()) }
//! ```
//!
//! [ECDH]: https://wiki.openssl.org/index.php/Elliptic_Curve_Diffie_Hellman

use foreign_types::ForeignTypeRef;
use std::marker::PhantomData;
use std::ptr;
Expand Down
2 changes: 2 additions & 0 deletions openssl/src/dh.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Diffie-Hellman key agreement.

use cfg_if::cfg_if;
use foreign_types::{ForeignType, ForeignTypeRef};
use std::mem;
Expand Down
64 changes: 55 additions & 9 deletions openssl/src/ec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,19 @@ foreign_type_and_impl_send_sync! {

impl EcGroup {
/// Returns the group of a standard named curve.
///
/// # Examples
///
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use openssl::nid::Nid;
/// use openssl::ec::{EcGroup, EcKey};
///
/// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve
/// let group = EcGroup::from_curve_name(nid)?;
/// let key = EcKey::generate(&group)?;
/// # Ok(()) }
/// ```
#[corresponds(EC_GROUP_new_by_curve_name)]
pub fn from_curve_name(nid: Nid) -> Result<EcGroup, ErrorStack> {
unsafe {
Expand Down Expand Up @@ -748,26 +761,32 @@ impl EcKey<Params> {
}

impl EcKey<Public> {
/// Constructs an `EcKey` from the specified group with the associated `EcPoint`, public_key.
/// Constructs an `EcKey` from the specified group with the associated [`EcPoint`]: `public_key`.
///
/// This will only have the associated public_key.
/// This will only have the associated `public_key`.
///
/// # Example
///
/// ```no_run
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use openssl::bn::BigNumContext;
/// use openssl::ec::*;
/// use openssl::nid::Nid;
/// use openssl::pkey::PKey;
///
/// // get bytes from somewhere, i.e. this will not produce a valid key
/// let public_key: Vec<u8> = vec![];
/// let group = EcGroup::from_curve_name(Nid::SECP384R1)?;
/// let mut ctx = BigNumContext::new()?;
///
/// // get bytes from somewhere
/// let public_key = // ...
/// # EcKey::generate(&group)?.public_key().to_bytes(&group,
/// # PointConversionForm::COMPRESSED, &mut ctx)?;
///
/// // create an EcKey from the binary form of a EcPoint
/// let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
/// let mut ctx = BigNumContext::new().unwrap();
/// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx).unwrap();
/// let key = EcKey::from_public_key(&group, &point);
/// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx)?;
/// let key = EcKey::from_public_key(&group, &point)?;
/// key.check_key()?;
/// # Ok(()) }
/// ```
#[corresponds(EC_KEY_set_public_key)]
pub fn from_public_key(
Expand Down Expand Up @@ -835,6 +854,33 @@ impl EcKey<Public> {

impl EcKey<Private> {
/// Generates a new public/private key pair on the specified curve.
///
/// # Examples
///
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use openssl::bn::BigNumContext;
/// use openssl::nid::Nid;
/// use openssl::ec::{EcGroup, EcKey, PointConversionForm};
///
/// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve
/// let group = EcGroup::from_curve_name(nid)?;
/// let key = EcKey::generate(&group)?;
///
/// let mut ctx = BigNumContext::new()?;
///
/// let public_key = &key.public_key().to_bytes(
/// &group,
/// PointConversionForm::COMPRESSED,
/// &mut ctx,
/// )?;
/// assert_eq!(public_key.len(), 33);
/// assert_ne!(public_key[0], 0x04);
///
/// let private_key = key.private_key().to_vec();
/// assert!(private_key.len() >= 31);
/// # Ok(()) }
/// ```
#[corresponds(EC_KEY_generate_key)]
pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> {
unsafe {
Expand Down
103 changes: 69 additions & 34 deletions openssl/src/hash.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,35 @@
//! Message digest (hash) computation support.
//!
//! # Examples
//!
//! Calculate a hash in one go:
//!
//! ```
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use openssl::hash::{hash, MessageDigest};
//!
//! let data = b"\x42\xF4\x97\xE0";
//! let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
//! let res = hash(MessageDigest::md5(), data)?;
//! assert_eq!(&*res, spec);
//! # Ok(()) }
//! ```
//!
//! Supply the input in chunks:
//!
//! ```
//! use openssl::hash::{Hasher, MessageDigest};
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let mut hasher = Hasher::new(MessageDigest::sha256())?;
//! hasher.update(b"test")?;
//! hasher.update(b"this")?;
//! let digest: &[u8] = &hasher.finish()?;
//!
//! let expected = hex::decode("9740e652ab5b4acd997a7cca13d6696702ccb2d441cca59fc6e285127f28cfe6")?;
//! assert_eq!(digest, expected);
//! # Ok(()) }
//! ```
use cfg_if::cfg_if;
use std::ffi::CString;
use std::fmt;
Expand All @@ -18,6 +50,7 @@ cfg_if! {
}
}

/// A message digest algorithm.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct MessageDigest(*const ffi::EVP_MD);

Expand Down Expand Up @@ -174,44 +207,18 @@ use self::State::*;
///
/// # Examples
///
/// Calculate a hash in one go:
///
/// ```
/// use openssl::hash::{hash, MessageDigest};
///
/// let data = b"\x42\xF4\x97\xE0";
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
/// let res = hash(MessageDigest::md5(), data).unwrap();
/// assert_eq!(&*res, spec);
/// ```
///
/// Supply the input in chunks:
///
/// ```
/// use openssl::hash::{Hasher, MessageDigest};
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let data = [b"\x42\xF4", b"\x97\xE0"];
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
/// let mut h = Hasher::new(MessageDigest::md5()).unwrap();
/// h.update(data[0]).unwrap();
/// h.update(data[1]).unwrap();
/// let res = h.finish().unwrap();
/// let mut h = Hasher::new(MessageDigest::md5())?;
/// h.update(data[0])?;
/// h.update(data[1])?;
/// let res = h.finish()?;
/// assert_eq!(&*res, spec);
/// ```
///
/// Use an XOF hasher (OpenSSL 1.1.1+):
///
/// ```
/// #[cfg(ossl111)]
/// {
/// use openssl::hash::{hash_xof, MessageDigest};
///
/// let data = b"\x41\x6c\x6c\x20\x79\x6f\x75\x72\x20\x62\x61\x73\x65\x20\x61\x72\x65\x20\x62\x65\x6c\x6f\x6e\x67\x20\x74\x6f\x20\x75\x73";
/// let spec = b"\x49\xd0\x69\x7f\xf5\x08\x11\x1d\x8b\x84\xf1\x5e\x46\xda\xf1\x35";
/// let mut buf = vec![0; 16];
/// hash_xof(MessageDigest::shake_128(), data, buf.as_mut_slice()).unwrap();
/// assert_eq!(buf, spec);
/// }
/// # Ok(()) }
/// ```
///
/// # Warning
Expand All @@ -220,8 +227,10 @@ use self::State::*;
///
/// Don't ever hash passwords, use the functions in the `pkcs5` module or bcrypt/scrypt instead.
///
/// For extendable output functions (XOFs, i.e. SHAKE128/SHAKE256), you must use finish_xof instead
/// of finish and provide a buf to store the hash. The hash will be as long as the buf.
/// For extendable output functions (XOFs, i.e. SHAKE128/SHAKE256),
/// you must use [`Hasher::finish_xof`] instead of [`Hasher::finish`]
/// and provide a `buf` to store the hash. The hash will be as long as
/// the `buf`.
pub struct Hasher {
ctx: *mut ffi::EVP_MD_CTX,
md: *const ffi::EVP_MD,
Expand Down Expand Up @@ -411,13 +420,39 @@ impl fmt::Debug for DigestBytes {
}

/// Computes the hash of the `data` with the non-XOF hasher `t`.
///
/// # Examples
///
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use openssl::hash::{hash, MessageDigest};
///
/// let data = b"\x42\xF4\x97\xE0";
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
/// let res = hash(MessageDigest::md5(), data)?;
/// assert_eq!(&*res, spec);
/// # Ok(()) }
/// ```
pub fn hash(t: MessageDigest, data: &[u8]) -> Result<DigestBytes, ErrorStack> {
let mut h = Hasher::new(t)?;
h.update(data)?;
h.finish()
}

/// Computes the hash of the `data` with the XOF hasher `t` and stores it in `buf`.
///
/// # Examples
///
/// ```
/// use openssl::hash::{hash_xof, MessageDigest};
///
/// let data = b"\x41\x6c\x6c\x20\x79\x6f\x75\x72\x20\x62\x61\x73\x65\x20\x61\x72\x65\x20\x62\x65\x6c\x6f\x6e\x67\x20\x74\x6f\x20\x75\x73";
/// let spec = b"\x49\xd0\x69\x7f\xf5\x08\x11\x1d\x8b\x84\xf1\x5e\x46\xda\xf1\x35";
/// let mut buf = vec![0; 16];
/// hash_xof(MessageDigest::shake_128(), data, buf.as_mut_slice()).unwrap();
/// assert_eq!(buf, spec);
/// ```
///
#[cfg(ossl111)]
pub fn hash_xof(t: MessageDigest, data: &[u8], buf: &mut [u8]) -> Result<(), ErrorStack> {
let mut h = Hasher::new(t)?;
Expand Down
2 changes: 2 additions & 0 deletions openssl/src/md.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Message digest algorithms.

#[cfg(ossl300)]
use crate::cvt_p;
#[cfg(ossl300)]
Expand Down
6 changes: 4 additions & 2 deletions openssl/src/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@ impl<'a> Write for Signer<'a> {
}
}

/// A type which can be used to verify the integrity and authenticity
/// of data given the signature.
pub struct Verifier<'a> {
md_ctx: *mut ffi::EVP_MD_CTX,
pctx: *mut ffi::EVP_PKEY_CTX,
Expand All @@ -426,7 +428,7 @@ impl<'a> Verifier<'a> {
/// Creates a new `Verifier`.
///
/// This cannot be used with Ed25519 or Ed448 keys. Please refer to
/// `new_without_digest`.
/// [`Verifier::new_without_digest`].
///
/// OpenSSL documentation at [`EVP_DigestVerifyInit`].
///
Expand Down Expand Up @@ -553,7 +555,7 @@ impl<'a> Verifier<'a> {
/// Feeds more data into the `Verifier`.
///
/// Please note that PureEdDSA (Ed25519 and Ed448 keys) do not support streaming.
/// Use `verify_oneshot` instead.
/// Use [`Verifier::verify_oneshot`] instead.
///
/// OpenSSL documentation at [`EVP_DigestUpdate`].
///
Expand Down
2 changes: 2 additions & 0 deletions openssl/src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
// limitations under the License.
//

//! Build and version information.

use cfg_if::cfg_if;
use openssl_macros::corresponds;
use std::ffi::CStr;
Expand Down