blob: f7ee2bbfde5b07dbb466141ce365e3e56e1bb82a [file] [log] [blame]
// Copyright 2015-2017 Brian Smith.
//
// 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 AUTHORS DISCLAIM ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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.
//! Public key signatures: signing and verification.
//!
//! Use the `verify` function to verify signatures, passing a reference to the
//! algorithm that identifies the algorithm. See the documentation for `verify`
//! for examples.
//!
//! For signature verification, this API treats each combination of parameters
//! as a separate algorithm. For example, instead of having a single "RSA"
//! algorithm with a verification function that takes a bunch of parameters,
//! there are `RSA_PKCS1_2048_8192_SHA256`, `RSA_PKCS1_2048_8192_SHA384`, etc.,
//! which encode sets of parameter choices into objects. This is designed to
//! reduce the risks of algorithm agility and to provide consistency with ECDSA
//! and EdDSA.
//!
//! Currently this module does not support digesting the message to be signed
//! separately from the public key operation, as it is currently being
//! optimized for Ed25519 and for the implementation of protocols that do not
//! requiring signing large messages. An interface for efficiently supporting
//! larger messages may be added later.
//!
//!
//! # Algorithm Details
//!
//! ## `ECDSA_*_ASN1` Details: ASN.1-encoded ECDSA Signatures
//!
//! The signature is a ASN.1 DER-encoded `Ecdsa-Sig-Value` as described in
//! [RFC 3279 Section 2.2.3]. This is the form of ECDSA signature used in
//! X.509-related structures and in TLS's `ServerKeyExchange` messages.
//!
//! The public key is encoding in uncompressed form using the
//! Octet-String-to-Elliptic-Curve-Point algorithm in
//! [SEC 1: Elliptic Curve Cryptography, Version 2.0].
//!
//! During verification, the public key is validated using the ECC Partial
//! Public-Key Validation Routine from Section 5.6.2.3.3 of
//! [NIST Special Publication 800-56A, revision 2] and Appendix A.3 of the
//! NSA's [Suite B implementer's guide to FIPS 186-3]. Note that, as explained
//! in the NSA guide, ECC Partial Public-Key Validation is equivalent to ECC
//! Full Public-Key Validation for prime-order curves like this one.
//!
//! ## `ECDSA_*_FIXED` Details: Fixed-length (PKCS#11-style) ECDSA Signatures
//!
//! The signature is *r*||*s*, where || denotes concatenation, and where both
//! *r* and *s* are both big-endian-encoded values that are left-padded to the
//! maximum length. A P-256 signature will be 64 bytes long (two 32-byte
//! components) and a P-384 signature will be 96 bytes long (two 48-byte
//! components). This is the form of ECDSA signature used PKCS#11 and DNSSEC.
//!
//! The public key is encoding in uncompressed form using the
//! Octet-String-to-Elliptic-Curve-Point algorithm in
//! [SEC 1: Elliptic Curve Cryptography, Version 2.0].
//!
//! During verification, the public key is validated using the ECC Partial
//! Public-Key Validation Routine from Section 5.6.2.3.3 of
//! [NIST Special Publication 800-56A, revision 2] and Appendix A.3 of the
//! NSA's [Suite B implementer's guide to FIPS 186-3]. Note that, as explained
//! in the NSA guide, ECC Partial Public-Key Validation is equivalent to ECC
//! Full Public-Key Validation for prime-order curves like this one.
//!
//! ## `RSA_PKCS1_*` Details: RSA PKCS#1 1.5 Signatures
//!
//! The signature is an RSASSA-PKCS1-v1_5 signature as described in
//! [RFC 3447 Section 8.2].
//!
//! The public key is encoded as an ASN.1 `RSAPublicKey` as described in
//! [RFC 3447 Appendix-A.1.1]. The public key modulus length, rounded *up* to
//! the nearest (larger) multiple of 8 bits, must be in the range given in the
//! name of the algorithm. The public exponent must be an odd integer of 2-33
//! bits, inclusive.
//!
//!
//! ## `RSA_PSS_*` Details: RSA PSS Signatures
//!
//! The signature is an RSASSA-PSS signature as described in
//! [RFC 3447 Section 8.1].
//!
//! The public key is encoded as an ASN.1 `RSAPublicKey` as described in
//! [RFC 3447 Appendix-A.1.1]. The public key modulus length, rounded *up* to
//! the nearest (larger) multiple of 8 bits, must be in the range given in the
//! name of the algorithm. The public exponent must be an odd integer of 2-33
//! bits, inclusive.
//!
//! During verification, signatures will only be accepted if the MGF1 digest
//! algorithm is the same as the message digest algorithm and if the salt
//! length is the same length as the message digest. This matches the
//! requirements in TLS 1.3 and other recent specifications.
//!
//! During signing, the message digest algorithm will be used as the MGF1
//! digest algorithm. The salt will be the same length as the message digest.
//! This matches the requirements in TLS 1.3 and other recent specifications.
//! Additionally, the entire salt is randomly generated separately for each
//! signature using the secure random number generator passed to `sign()`.
//!
//!
//! [SEC 1: Elliptic Curve Cryptography, Version 2.0]:
//! http://www.secg.org/sec1-v2.pdf
//! [NIST Special Publication 800-56A, revision 2]:
//! http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf
//! [Suite B implementer's guide to FIPS 186-3]:
//! https://github.com/briansmith/ring/blob/master/doc/ecdsa.pdf
//! [RFC 3279 Section 2.2.3]:
//! https://tools.ietf.org/html/rfc3279#section-2.2.3
//! [RFC 3447 Section 8.2]:
//! https://tools.ietf.org/html/rfc3447#section-7.2
//! [RFC 3447 Section 8.1]:
//! https://tools.ietf.org/html/rfc3447#section-8.1
//! [RFC 3447 Appendix-A.1.1]:
//! https://tools.ietf.org/html/rfc3447#appendix-A.1.1
//!
//!
//! # Examples
//!
//! ## Signing and verifying with Ed25519
//!
//! ```
//! extern crate ring;
//! extern crate untrusted;
//!
//! use ring::{rand, signature};
//!
//! # fn sign_and_verify_ed25519() -> Result<(), ring::error::Unspecified> {
//! // Generate a key pair in PKCS#8 (v2) format.
//! let rng = rand::SystemRandom::new();
//! let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng)?;
//!
//! // Normally the application would store the PKCS#8 file persistently. Later
//! // it would read the PKCS#8 file from persistent storage to use it.
//!
//! let key_pair = signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes))?;
//!
//! // Sign the message "hello, world".
//! const MESSAGE: &[u8] = b"hello, world";
//! let sig = key_pair.sign(MESSAGE);
//!
//! // Normally an application would extract the bytes of the signature and
//! // send them in a protocol message to the peer(s). Here we just get the
//! // public key key directly from the key pair.
//! let peer_public_key_bytes = key_pair.public_key_bytes();
//! let sig_bytes = sig.as_ref();
//!
//! // Verify the signature of the message using the public key. Normally the
//! // verifier of the message would parse the inputs to `signature::verify`
//! // out of the protocol message(s) sent by the signer.
//! let peer_public_key = untrusted::Input::from(peer_public_key_bytes);
//! let msg = untrusted::Input::from(MESSAGE);
//! let sig = untrusted::Input::from(sig_bytes);
//!
//! signature::verify(&signature::ED25519, peer_public_key, msg, sig)?;
//!
//! # Ok(())
//! # }
//!
//! # fn main() { sign_and_verify_ed25519().unwrap() }
//! ```
//!
//! ## Signing and verifying with RSA (PKCS#1 1.5 padding)
//!
//! RSA signing (but not verification) requires the `rsa_signing` feature to
//! be enabled.
//!
//! By default OpenSSL writes RSA public keys in SubjectPublicKeyInfo format,
//! not RSAPublicKey format, and Base64-encodes them (“PEM” format).
//!
//! To convert the PEM SubjectPublicKeyInfo format (“BEGIN PUBLIC KEY”) to the
//! binary RSAPublicKey format needed by `verify()`, use:
//!
//! ```sh
//! openssl rsa -pubin \
//! -in public_key.pem \
//! -inform PEM \
//! -RSAPublicKey_out \
//! -outform DER \
//! -out public_key.der
//! ```
//!
//! To extract the RSAPublicKey-formatted public key from an ASN.1 (binary)
//! DER-encoded RSAPrivateKey format private key file, use:
//!
//! ```sh
//! openssl rsa -in private_key.der \
//! -inform DER \
//! -RSAPublicKey_out \
//! -outform DER \
//! -out public_key.der
//! ```
//!
//! ```
//! extern crate ring;
//! extern crate untrusted;
//!
//! use ring::{rand, signature};
//!
//! # #[cfg(all(feature = "rsa_signing", feature = "use_heap"))]
//! fn sign_and_verify_rsa(private_key_path: &std::path::Path,
//! public_key_path: &std::path::Path)
//! -> Result<(), MyError> {
//! // Create an `RSAKeyPair` from the DER-encoded bytes. This example uses
//! // a 2048-bit key, but larger keys are also supported.
//! let private_key_der = read_file(private_key_path)?;
//! let private_key_der = untrusted::Input::from(&private_key_der);
//! let key_pair = signature::RSAKeyPair::from_der(private_key_der)
//! .map_err(|ring::error::Unspecified| MyError::BadPrivateKey)?;
//!
//! // Create a signing state.
//! let key_pair = std::sync::Arc::new(key_pair);
//! let mut signing_state = signature::RSASigningState::new(key_pair)
//! .map_err(|ring::error::Unspecified| MyError::OOM)?;
//!
//! // Sign the message "hello, world", using PKCS#1 v1.5 padding and the
//! // SHA256 digest algorithm.
//! const MESSAGE: &'static [u8] = b"hello, world";
//! let rng = rand::SystemRandom::new();
//! let mut signature = vec![0; signing_state.key_pair().public_modulus_len()];
//! signing_state.sign(&signature::RSA_PKCS1_SHA256, &rng, MESSAGE,
//! &mut signature)
//! .map_err(|ring::error::Unspecified| MyError::OOM)?;
//!
//! // Verify the signature.
//! let public_key_der = read_file(public_key_path)?;
//! let public_key_der = untrusted::Input::from(&public_key_der);
//! let message = untrusted::Input::from(MESSAGE);
//! let signature = untrusted::Input::from(&signature);
//! signature::verify(&signature::RSA_PKCS1_2048_8192_SHA256,
//! public_key_der, message, signature)
//! .map_err(|ring::error::Unspecified| MyError::BadSignature)?;
//!
//! Ok(())
//! }
//!
//! #[derive(Debug)]
//! enum MyError {
//! # #[cfg(all(feature = "rsa_signing", feature = "use_heap"))]
//! IO(std::io::Error),
//! BadPrivateKey,
//! OOM,
//! BadSignature,
//! }
//!
//! # #[cfg(all(feature = "rsa_signing", feature = "use_heap"))]
//! fn read_file(path: &std::path::Path) -> Result<Vec<u8>, MyError> {
//! use std::io::Read;
//!
//! let mut file = std::fs::File::open(path).map_err(|e| MyError::IO(e))?;
//! let mut contents: Vec<u8> = Vec::new();
//! file.read_to_end(&mut contents).map_err(|e| MyError::IO(e))?;
//! Ok(contents)
//! }
//! #
//! # #[cfg(not(all(feature = "rsa_signing", feature = "use_heap")))]
//! # fn sign_and_verify_rsa(_private_key_path: &std::path::Path,
//! # _public_key_path: &std::path::Path)
//! # -> Result<(), ()> {
//! # Ok(())
//! # }
//! #
//! # fn main() {
//! # let private_key_path =
//! # std::path::Path::new("src/rsa/signature_rsa_example_private_key.der");
//! # let public_key_path =
//! # std::path::Path::new("src/rsa/signature_rsa_example_public_key.der");
//! # sign_and_verify_rsa(&private_key_path, &public_key_path).unwrap()
//! # }
//! ```
use core;
#[cfg(feature = "use_heap")]
use crate::rand;
use crate::{error, init, private};
use untrusted;
#[cfg(feature = "use_heap")]
use std;
pub use ec::suite_b::ecdsa::{
signing::{
Key as ECDSAKeyPair, ECDSA_P256_SHA256_ASN1_SIGNING, ECDSA_P256_SHA256_FIXED_SIGNING,
ECDSA_P384_SHA384_ASN1_SIGNING, ECDSA_P384_SHA384_FIXED_SIGNING,
},
verification::{
Algorithm as ECDSAVerification, ECDSA_P256_SHA256_ASN1, ECDSA_P256_SHA256_FIXED,
ECDSA_P256_SHA384_ASN1, ECDSA_P384_SHA256_ASN1, ECDSA_P384_SHA384_ASN1,
ECDSA_P384_SHA384_FIXED,
},
};
pub use ec::curve25519::ed25519::PUBLIC_KEY_LEN as ED25519_PUBLIC_KEY_LEN;
pub use ec::curve25519::ed25519::verification::{EdDSAParameters, ED25519};
pub use ec::curve25519::ed25519::signing::{
KeyPair as Ed25519KeyPair, PKCS8_V2_LEN as ED25519_PKCS8_V2_LEN,
};
#[cfg(all(feature = "rsa_signing", feature = "use_heap"))]
pub use rsa::signing::{KeyPair as RSAKeyPair, SigningState as RSASigningState};
#[cfg(all(feature = "rsa_signing", feature = "use_heap"))]
pub use rsa::{
RSAEncoding,
// `RSA_PKCS1_SHA1` is intentionally not exposed. At a minimum, we'd need
// to create test vectors for signing with it, which we don't currently
// have. But, it's a bad idea to use SHA-1 anyway, so perhaps we just won't
// ever expose it.
RSA_PKCS1_SHA256,
RSA_PKCS1_SHA384,
RSA_PKCS1_SHA512,
RSA_PSS_SHA256,
RSA_PSS_SHA384,
RSA_PSS_SHA512,
};
#[cfg(feature = "use_heap")]
pub use rsa::RSAParameters;
#[cfg(feature = "use_heap")]
pub use rsa::verification::{
RSA_PKCS1_2048_8192_SHA1, RSA_PKCS1_2048_8192_SHA256, RSA_PKCS1_2048_8192_SHA384,
RSA_PKCS1_2048_8192_SHA512, RSA_PKCS1_3072_8192_SHA384, RSA_PSS_2048_8192_SHA256,
RSA_PSS_2048_8192_SHA384, RSA_PSS_2048_8192_SHA512,
};
pub use signature_impl::Signature;
/// Lower-level verification primitives. Usage of `ring::signature::verify()`
/// is preferred when the public key and signature are encoded in standard
/// formats, as it also handles the parsing.
#[cfg(feature = "use_heap")]
pub mod primitive {
pub use rsa::verification::verify_rsa;
}
/// A key pair for signing.
#[derive(Debug)]
#[cfg(feature = "use_heap")]
pub struct KeyPair {
inner: std::boxed::Box<KeyPairImpl + Send + Sync>,
}
#[cfg(feature = "use_heap")]
impl KeyPair {
pub(crate) fn new<I: KeyPairImpl + Sync>(inner: I) -> Self {
Self {
inner: std::boxed::Box::new(inner),
}
}
}
#[cfg(feature = "use_heap")]
pub(crate) trait KeyPairImpl: core::fmt::Debug + Send + 'static {
fn sign(
&self, rng: &rand::SecureRandom, msg: untrusted::Input,
) -> Result<Signature, error::Unspecified>;
}
/// An algorithm for signing.
#[cfg(feature = "use_heap")]
pub trait SigningAlgorithm: core::fmt::Debug + Sync + 'static + private::Sealed {
/// Parses the key out of the given PKCS#8 document, verifying that it is
/// valid for the algorithm.
fn from_pkcs8(&'static self, input: untrusted::Input) -> Result<KeyPair, error::Unspecified>;
}
/// Returns a key for signing that is parsed from a PKCS#8 document.
///
/// The key is checked to ensure it is valid for the given algorithm.
#[cfg(feature = "use_heap")]
#[inline]
pub fn key_pair_from_pkcs8(
alg: &'static SigningAlgorithm, input: untrusted::Input,
) -> Result<KeyPair, error::Unspecified> {
alg.from_pkcs8(input)
}
/// Returns a signature of the given data using the given key. The signing may
/// or may not use `rng`, depending on the `key_pair's algorithm.
#[cfg(feature = "use_heap")]
#[inline]
pub fn sign(
key_pair: &KeyPair, rng: &rand::SecureRandom, msg: untrusted::Input,
) -> Result<Signature, error::Unspecified> {
key_pair.inner.sign(rng, msg)
}
/// A signature verification algorithm.
pub trait VerificationAlgorithm: core::fmt::Debug + Sync + private::Sealed {
/// Verify the signature `signature` of message `msg` with the public key
/// `public_key`.
fn verify(
&self, public_key: untrusted::Input, msg: untrusted::Input, signature: untrusted::Input,
) -> Result<(), error::Unspecified>;
}
/// Verify the signature `signature` of message `msg` with the public key
/// `public_key` using the algorithm `alg`.
///
/// # Examples
///
/// ## Verify a RSA PKCS#1 signature that uses the SHA-256 digest
///
/// ```
/// extern crate ring;
/// extern crate untrusted;
///
/// use ring::signature;
///
/// enum Error {
/// InvalidSignature,
/// }
///
/// # #[cfg(feature = "use_heap")]
/// fn verify_rsa_pkcs1_sha256(
/// public_key: untrusted::Input, msg: untrusted::Input, sig: untrusted::Input,
/// ) -> Result<(), Error> {
/// signature::verify(&signature::RSA_PKCS1_2048_8192_SHA256, public_key, msg, sig)
/// .map_err(|_| Error::InvalidSignature)
/// }
/// # fn main() { }
/// ```
pub fn verify(
alg: &VerificationAlgorithm, public_key: untrusted::Input, msg: untrusted::Input,
signature: untrusted::Input,
) -> Result<(), error::Unspecified> {
init::init_once();
alg.verify(public_key, msg, signature)
}