blob: 3b8f12007ade2b8a305210d4a956ad3a2f6e1ea4 [file] [log] [blame]
// Copyright 2018 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
//! Elliptic Curve-based cryptographic algorithms over NIST P curves.
//!
//! This module only supports elliptic curve cryptography over NIST's P curves,
//! defined in FIPS 186-3. These are the P-256, P-384, and P-521 curves (P-224
//! is considered insecure, and thus is not supported). The ECDSA and ECDH
//! algorithms are both defined over P curves, and so are exposed in this
//! module.
//!
//! Other elliptic curve algorithms on non-P curves live in other modules (e.g.,
//! operations on the Edwards 25519 curve live in the [`ed25519`] module).
//!
//! [`ed25519`]: ::public::ed25519
mod curve;
pub use public::ec::curve::{PCurve, P256, P384, P521};
use std::fmt::{self, Debug, Formatter};
use boringssl::{CHeapWrapper, CStackWrapper};
use public::ec::curve::CurveKind;
use public::ec::inner::EcKey;
use public::{inner::DerKey, DerPrivateKey, DerPublicKey, PrivateKey, PublicKey};
use util::Sealed;
use Error;
mod inner {
use std::marker::PhantomData;
use boringssl::{self, BoringError, CHeapWrapper, CStackWrapper};
use public::ec::curve::PCurve;
use public::inner::BoringDerKey;
use Error;
// A convenience wrapper around boringssl::EC_KEY.
//
// EcKey maintains the following invariants:
// - The key is valid.
// - The key is on the curve C.
//
// This is marked pub and put in this (non-public) module so that using it in impls of
// the Key trait don't result in public-in-private errors.
#[derive(Clone)]
pub struct EcKey<C: PCurve> {
pub key: CHeapWrapper<boringssl::EC_KEY>,
_marker: PhantomData<C>,
}
impl<C: PCurve> EcKey<C> {
pub fn generate() -> Result<EcKey<C>, BoringError> {
let mut key = CHeapWrapper::default();
// EC_KEY_set_group only errors if there's already a group set
key.ec_key_set_group(&C::group()).unwrap();
key.ec_key_generate_key()?;
Ok(EcKey { key, _marker: PhantomData })
}
/// Creates an `EcKey` from a BoringSSL `EC_KEY`.
///
/// `from_EC_KEY` validates that `key`'s curve is `C`.
///
/// # Panics
///
/// `from_EC_KEY` panics if `key`'s group is not set.
#[allow(non_snake_case)]
pub fn from_EC_KEY(key: CHeapWrapper<boringssl::EC_KEY>) -> Result<EcKey<C>, Error> {
// ec_key_get0_group returns the EC_KEY's internal group pointer,
// which is guaranteed to be set by the caller.
C::validate_group(key.ec_key_get0_group().unwrap())?;
Ok(EcKey { key, _marker: PhantomData })
}
}
impl<C: PCurve> BoringDerKey for EcKey<C> {
fn pkey_assign(&self, pkey: &mut CHeapWrapper<boringssl::EVP_PKEY>) {
pkey.evp_pkey_assign_ec_key(self.key.clone())
}
// NOTE: panics if the key is an EC key and doesn't have a group set
// (due to EcKey::from_EC_KEY)
fn pkey_get(pkey: &mut CHeapWrapper<boringssl::EVP_PKEY>) -> Result<Self, Error> {
let key = pkey.evp_pkey_get1_ec_key()?;
EcKey::from_EC_KEY(key)
}
fn parse_private_key(cbs: &mut CStackWrapper<boringssl::CBS>) -> Result<EcKey<C>, Error> {
// The last argument is a group. If it's not None, then it is either
// used as the group or, if the DER encoding also contains a group,
// the encoded group is validated against the group passed as an
// argument. Note that this validation is mostly redundant - similar
// validation is performed in EcKey::from_EC_KEY - however, it's not
// fully redundant, since it allows keys to be parsed which have no
// group.
let key = CHeapWrapper::ec_key_parse_private_key(cbs, Some(C::group()))?;
EcKey::from_EC_KEY(key)
}
fn marshal_private_key(
&self,
cbb: &mut CStackWrapper<boringssl::CBB>,
) -> Result<(), Error> {
self.key.ec_key_marshal_private_key(cbb).map_err(From::from)
}
}
#[cfg(test)]
mod tests {
use std::mem;
use super::*;
use public::ec::{P256, P384, P521};
#[test]
fn test_refcount() {
fn test<C: PCurve>() {
let key = EcKey::<C>::generate().unwrap();
for i in 0..8 {
// make i clones and then free them all
let mut keys = Vec::new();
for _ in 0..i {
keys.push(key.clone());
}
mem::drop(keys);
}
mem::drop(key);
}
test::<P256>();
test::<P384>();
test::<P521>();
}
}
}
/// An elliptic curve public key over a P curve.
///
/// `EcPubKey` is a public key over the curve `C`.
pub struct EcPubKey<C: PCurve> {
inner: EcKey<C>,
}
impl<C: PCurve> Sealed for EcPubKey<C> {}
impl<C: PCurve> DerPublicKey for EcPubKey<C> {}
impl<C: PCurve> DerKey for EcPubKey<C> {
type Boring = EcKey<C>;
fn boring(&self) -> &EcKey<C> {
&self.inner
}
fn from_boring(inner: EcKey<C>) -> EcPubKey<C> {
EcPubKey { inner }
}
}
impl<C: PCurve> PublicKey for EcPubKey<C> {
type Private = EcPrivKey<C>;
}
impl<C: PCurve> Debug for EcPubKey<C> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(f, "EcPubKey")
}
}
/// An elliptic curve private key over a P curve.
///
/// `EcPrivKey` is a private key over the curve `C`.
pub struct EcPrivKey<C: PCurve> {
inner: EcKey<C>,
}
impl<C: PCurve> EcPrivKey<C> {
/// Generates a new private key.
#[must_use]
pub fn generate() -> Result<EcPrivKey<C>, Error> {
Ok(EcPrivKey { inner: EcKey::generate()? })
}
}
impl<C: PCurve> Sealed for EcPrivKey<C> {}
impl<C: PCurve> DerPrivateKey for EcPrivKey<C> {}
impl<C: PCurve> DerKey for EcPrivKey<C> {
type Boring = EcKey<C>;
fn boring(&self) -> &EcKey<C> {
&self.inner
}
fn from_boring(inner: EcKey<C>) -> EcPrivKey<C> {
EcPrivKey { inner }
}
}
impl<C: PCurve> PrivateKey for EcPrivKey<C> {
type Public = EcPubKey<C>;
fn public(&self) -> EcPubKey<C> {
EcPubKey { inner: self.inner.clone() }
}
}
impl<C: PCurve> Debug for EcPrivKey<C> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(f, "EcPrivKey")
}
}
/// An elliptic curve public key whose curve is unknown at compile time.
///
/// An `EcPubKeyAnyCurve` is an enum of [`EcPubKey`]s over the three supported
/// curves.
#[allow(missing_docs)]
#[derive(Debug)]
pub enum EcPubKeyAnyCurve {
P256(EcPubKey<P256>),
P384(EcPubKey<P384>),
P521(EcPubKey<P521>),
}
impl EcPubKeyAnyCurve {
/// Parses a public key in DER format with any curve.
///
/// `parse_from_der` is like [`DerPublicKey::parse_from_der`], but it
/// accepts any [`PCurve`] rather than a particular, static curve.
///
/// Since [`EcPubKey`] requires a static [`PCurve`] type parameter, the
/// `parse_from_der` function on `EcPubKey`'s `DerPublicKey` implementation
/// can only be called when the curve is known ahead of time. This function,
/// on the other hand, accepts any curve.
///
/// Because the curve is not known statically, one must be specified in the DER
/// input.
///
/// [`DerPublicKey::parse_from_der`]: ::public::DerPublicKey::parse_from_der
/// [`PublicKey`]: ::public::PublicKey
#[must_use]
pub fn parse_from_der(bytes: &[u8]) -> Result<EcPubKeyAnyCurve, Error> {
CStackWrapper::cbs_with_temp_buffer(bytes, |cbs| {
let mut evp_pkey = CHeapWrapper::evp_parse_public_key(cbs)?;
let key = evp_pkey.evp_pkey_get1_ec_key()?;
if cbs.cbs_len() > 0 {
return Err(Error::new("excess data provided after valid DER input".to_string()));
}
// EVP_parse_public_key guarantees that the returned key has its group
// set, so this unwrap is safe.
let group = key.ec_key_get0_group().unwrap();
Ok(match CurveKind::from_nid(group.ec_group_get_curve_name())? {
CurveKind::P256 => {
EcPubKeyAnyCurve::P256(EcPubKey { inner: EcKey::from_EC_KEY(key.clone())? })
}
CurveKind::P384 => {
EcPubKeyAnyCurve::P384(EcPubKey { inner: EcKey::from_EC_KEY(key.clone())? })
}
CurveKind::P521 => {
EcPubKeyAnyCurve::P521(EcPubKey { inner: EcKey::from_EC_KEY(key.clone())? })
}
})
})
}
}
/// An elliptic curve private key whose curve is unknown at compile time.
///
/// An `EcPrivKeyAnyCurve` is an enum of [`EcPrivKey`]s over the three supported
/// curves.
#[allow(missing_docs)]
#[derive(Debug)]
pub enum EcPrivKeyAnyCurve {
P256(EcPrivKey<P256>),
P384(EcPrivKey<P384>),
P521(EcPrivKey<P521>),
}
impl EcPrivKeyAnyCurve {
/// Gets the public key corresponding to this private key.
#[must_use]
pub fn public(&self) -> EcPubKeyAnyCurve {
match self {
EcPrivKeyAnyCurve::P256(key) => EcPubKeyAnyCurve::P256(key.public()),
EcPrivKeyAnyCurve::P384(key) => EcPubKeyAnyCurve::P384(key.public()),
EcPrivKeyAnyCurve::P521(key) => EcPubKeyAnyCurve::P521(key.public()),
}
}
/// Parses a private key in DER format with any curve.
///
/// `parse_from_der` is like [`DerPrivateKey::parse_from_der`], but it
/// accepts any [`PCurve`] rather than a particular, static curve.
///
/// Since [`EcPrivKey`] requires a static [`PCurve`] type parameter, the
/// `parse_from_der` function on `EcPrivKey`'s `DerPrivateKey`
/// implementation can only be called when the curve is known ahead of time.
/// This function, on the other hand, accepts any curve.
///
/// Because the curve is not known statically, one must be specified in the DER
/// input.
///
/// [`DerPrivateKey::parse_from_der`]: ::public::DerPrivateKey::parse_from_der
/// [`PrivateKey`]: ::public::PrivateKey
#[must_use]
pub fn parse_from_der(bytes: &[u8]) -> Result<EcPrivKeyAnyCurve, Error> {
CStackWrapper::cbs_with_temp_buffer(bytes, |cbs| {
// The last argument is a group. Since it's None,
// EC_KEY_parse_private_key will require the DER to name the group.
let key = CHeapWrapper::ec_key_parse_private_key(cbs, None)?;
if cbs.cbs_len() > 0 {
return Err(Error::new("excess data provided after valid DER input".to_string()));
}
// TODO(joshlf): Add documentation to EC_KEY_parse_private_key
// guaranteeing that the internal group pointer is set.
let group = key.ec_key_get0_group().unwrap();
Ok(match CurveKind::from_nid(group.ec_group_get_curve_name())? {
CurveKind::P256 => {
EcPrivKeyAnyCurve::P256(EcPrivKey { inner: EcKey::from_EC_KEY(key.clone())? })
}
CurveKind::P384 => {
EcPrivKeyAnyCurve::P384(EcPrivKey { inner: EcKey::from_EC_KEY(key.clone())? })
}
CurveKind::P521 => {
EcPrivKeyAnyCurve::P521(EcPrivKey { inner: EcKey::from_EC_KEY(key.clone())? })
}
})
})
}
}
/// The Elliptic Curve Digital Signature Algorithm.
pub mod ecdsa {
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use boringssl;
#[cfg(feature = "experimental-sha512-ec")]
use hash::Sha512;
use hash::{inner::Digest, Hasher, Sha256, Sha384};
use public::{
ec::{EcPrivKey, EcPubKey, PCurve, P256, P384, P521},
Signature,
};
use util::Sealed;
use Error;
/// A hash function which is compatible with ECDSA signatures over the curve
/// `C`.
///
/// An ECDSA signature is constructed by hashing the message and then
/// signing the resulting digest. However, EC keys over certain curves may
/// not be compatible with all hashes. In particular, some digests may be
/// too long (in number of bytes) and thus not correspond to a point on the
/// curve. `EcdsaHash<C>` is implemented by all hash functions whose digests
/// are compatible with ECDSA signatures over the curve `C`.
pub trait EcdsaHash<C: PCurve>: Sealed {}
impl EcdsaHash<P256> for Sha256 {}
impl EcdsaHash<P384> for Sha256 {}
impl EcdsaHash<P384> for Sha384 {}
impl EcdsaHash<P521> for Sha256 {}
impl EcdsaHash<P521> for Sha384 {}
#[cfg(feature = "experimental-sha512-ec")]
impl EcdsaHash<P384> for Sha512 {}
#[cfg(feature = "experimental-sha512-ec")]
impl EcdsaHash<P521> for Sha512 {}
// The maximum length of an ECDSA signature over P-521. Since this isn't
// exposed in the API, we can increase later if we add support for curves
// with larger signatures.
//
// This was calculated with the following equation, which is thanks to
// agl@google.com:
//
// r = s = (521 + 7)/8 # Bytes to store the integers r and s
// = 66
// DER encoded bytes = (1 # type byte 0x02
// + 1 # length byte
// + 1 # possible 0 padding
// + 66) * 2 # one for each of r and s
// + 1 # ASN.1 SEQUENCE type byte
// + 2 # outer length
// = 141
const MAX_SIGNATURE_LEN: usize = 141;
/// A DER-encoded ECDSA signature.
#[must_use]
pub struct EcdsaSignature<C: PCurve, H: Hasher + EcdsaHash<C>> {
bytes: [u8; MAX_SIGNATURE_LEN],
// Invariant: len is in [0; MAX_SIGNATURE_LEN). If len is 0, it
// indicates an invalid signature. Invalid signatures can be produced
// when a caller invokes from_bytes with a byte slice longer than
// MAX_SIGNATURE_LEN. Such signatures cannot possibly have been
// generated by an ECDSA signature over any of the curves we support,
// and so it could not possibly be valid. In other words, it would never
// be correct for Signature::is_valid to return true when invoked on such a
// signature.
//
// However, if we were to simply truncate the byte slice and store a
// subset of it, then we might open ourselves up to attacks in which an
// attacker induces a mismatch between the signature that the caller
// /thinks/ is being verified and the signature that is /actually/ being
// verified. Thus, it's important that we always reject such signatures.
//
// Finally, it's OK for us to use 0 as the sentinal value to mean
// "invalid signature" because ECDSA can never produce a 0-byte
// signature. Thus, we will never produce a 0-byte signature from
// ecdsa_sign, and similarly, if the caller constructs a 0-byte
// signature using from_bytes, it's correct for us to treat it as
// invalid.
len: usize,
_marker: PhantomData<(C, H)>,
}
impl<C: PCurve, H: Hasher + EcdsaHash<C>> EcdsaSignature<C, H> {
/// Constructs an `EcdsaSignature` from raw bytes.
#[must_use]
pub fn from_bytes(bytes: &[u8]) -> EcdsaSignature<C, H> {
if bytes.len() > MAX_SIGNATURE_LEN {
// see comment on the len field for why we do this
return Self::empty();
}
let mut ret = Self::empty();
(&mut ret.bytes[..bytes.len()]).copy_from_slice(bytes);
ret.len = bytes.len();
ret
}
// TODO(joshlf): Once we have const generics, have this return a
// fixed-length array.
/// Gets the raw bytes of this `EcdsaSignature`.
#[must_use]
pub fn bytes(&self) -> &[u8] {
&self.bytes[..self.len]
}
fn is_valid_format(&self) -> bool {
self.len != 0
}
fn empty() -> EcdsaSignature<C, H> {
EcdsaSignature { bytes: [0u8; MAX_SIGNATURE_LEN], len: 0, _marker: PhantomData }
}
}
impl<C: PCurve, H: Hasher + EcdsaHash<C>> Sealed for EcdsaSignature<C, H> {}
impl<C: PCurve, H: Hasher + EcdsaHash<C>> Signature for EcdsaSignature<C, H> {
type PrivateKey = EcPrivKey<C>;
fn sign(key: &EcPrivKey<C>, message: &[u8]) -> Result<EcdsaSignature<C, H>, Error> {
let digest = H::hash(message);
let mut sig = EcdsaSignature::empty();
sig.len = boringssl::ecdsa_sign(digest.as_ref(), &mut sig.bytes[..], &key.inner.key)?;
Ok(sig)
}
fn is_valid(&self, key: &EcPubKey<C>, message: &[u8]) -> bool {
if !self.is_valid_format() {
// see comment on EcdsaSignature::len for why we do this
return false;
}
let digest = H::hash(message);
boringssl::ecdsa_verify(digest.as_ref(), self.bytes(), &key.inner.key)
}
}
impl<C: PCurve, H: Hasher + EcdsaHash<C>> Debug for EcdsaSignature<C, H> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(f, "EcdsaSignature")
}
}
#[cfg(test)]
mod tests {
use super::{super::*, *};
use public::testutil::test_signature_smoke;
#[test]
fn test_smoke() {
let p256 = EcPrivKey::<P256>::generate().unwrap();
let p384 = EcPrivKey::<P384>::generate().unwrap();
let p521 = EcPrivKey::<P521>::generate().unwrap();
test_signature_smoke(
&p256,
EcdsaSignature::<_, Sha256>::from_bytes,
EcdsaSignature::bytes,
);
test_signature_smoke(
&p384,
EcdsaSignature::<_, Sha256>::from_bytes,
EcdsaSignature::bytes,
);
test_signature_smoke(
&p384,
EcdsaSignature::<_, Sha384>::from_bytes,
EcdsaSignature::bytes,
);
test_signature_smoke(
&p521,
EcdsaSignature::<_, Sha256>::from_bytes,
EcdsaSignature::bytes,
);
test_signature_smoke(
&p521,
EcdsaSignature::<_, Sha384>::from_bytes,
EcdsaSignature::bytes,
);
#[cfg(feature = "experimental-sha512-ec")]
{
test_signature_smoke(
&p384,
EcdsaSignature::<_, Sha512>::from_bytes,
EcdsaSignature::bytes,
);
test_signature_smoke(
&p521,
EcdsaSignature::<_, Sha512>::from_bytes,
EcdsaSignature::bytes,
);
}
}
#[test]
fn test_invalid_signature() {
fn test_is_invalid(sig: &EcdsaSignature<P256, Sha256>) {
assert_eq!(sig.len, 0);
assert!(!sig.is_valid_format());
assert!(!sig.is_valid(&EcPrivKey::<P256>::generate().unwrap().public(), &[],));
}
test_is_invalid(&EcdsaSignature::from_bytes(&[0; MAX_SIGNATURE_LEN + 1]));
test_is_invalid(&EcdsaSignature::from_bytes(&[]));
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use hash::Sha256;
use public::ec::ecdsa::*;
use public::Signature;
use util::should_fail;
#[test]
fn test_generate() {
EcPrivKey::<P256>::generate().unwrap();
EcPrivKey::<P384>::generate().unwrap();
EcPrivKey::<P521>::generate().unwrap();
}
#[test]
fn test_marshal_parse() {
// Test various combinations of parsing and serializing keys.
//
// Since we need to test dynamic parsing (the
// parse_private_key_der_any_curve and parse_public_key_der_any_curve
// functions), we need a way of unwrapping their return values into a
// static key type. Unfortunately, there's no way (on stable Rust) to do
// that generically, so the caller must pass a function which will do
// it.
fn test<
C: PCurve,
F: Fn(EcPrivKeyAnyCurve) -> EcPrivKey<C>,
G: Fn(EcPubKeyAnyCurve) -> EcPubKey<C>,
>(
unwrap_priv_any: F,
unwrap_pub_any: G,
) where
Sha256: EcdsaHash<C>,
{
const MESSAGE: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7];
let key = EcPrivKey::<C>::generate().unwrap();
let parsed_key = EcPrivKey::<C>::parse_from_der(&key.marshal_to_der()).unwrap();
let parsed_key_any_curve =
unwrap_priv_any(EcPrivKeyAnyCurve::parse_from_der(&key.marshal_to_der()).unwrap());
let pubkey = key.public();
let parsed_pubkey = EcPubKey::<C>::parse_from_der(&pubkey.marshal_to_der()).unwrap();
let parsed_pubkey_any_curve =
unwrap_pub_any(EcPubKeyAnyCurve::parse_from_der(&pubkey.marshal_to_der()).unwrap());
fn sign_and_verify<C: PCurve>(privkey: &EcPrivKey<C>, pubkey: &EcPubKey<C>)
where
Sha256: EcdsaHash<C>,
{
let sig = EcdsaSignature::<C, Sha256>::sign(&privkey, MESSAGE).unwrap();
assert!(
EcdsaSignature::<C, Sha256>::from_bytes(sig.bytes()).is_valid(&pubkey, MESSAGE)
)
}
// Sign and verify with every pair of keys to make sure we parsed
// the same key we marshaled.
sign_and_verify(&key, &pubkey);
sign_and_verify(&key, &parsed_pubkey);
sign_and_verify(&key, &parsed_pubkey_any_curve);
sign_and_verify(&parsed_key, &pubkey);
sign_and_verify(&parsed_key, &parsed_pubkey);
sign_and_verify(&parsed_key, &parsed_pubkey_any_curve);
sign_and_verify(&parsed_key_any_curve, &pubkey);
sign_and_verify(&parsed_key_any_curve, &parsed_pubkey);
sign_and_verify(&parsed_key_any_curve, &parsed_pubkey_any_curve);
let _ = EcPubKey::<C>::marshal_to_der;
let _ = EcPubKey::<C>::parse_from_der;
}
macro_rules! unwrap_any_curve {
($name:ident, $any_type:ty, $key_type:ty, $curve_variant:path) => {
fn $name(key: $any_type) -> $key_type {
match key {
$curve_variant(key) => key,
_ => panic!("unexpected curve"),
}
}
};
}
unwrap_any_curve!(
unwrap_priv_key_any_p256,
EcPrivKeyAnyCurve,
EcPrivKey<P256>,
EcPrivKeyAnyCurve::P256
);
unwrap_any_curve!(
unwrap_priv_key_any_p384,
EcPrivKeyAnyCurve,
EcPrivKey<P384>,
EcPrivKeyAnyCurve::P384
);
unwrap_any_curve!(
unwrap_priv_key_any_p521,
EcPrivKeyAnyCurve,
EcPrivKey<P521>,
EcPrivKeyAnyCurve::P521
);
unwrap_any_curve!(
unwrap_pub_key_any_p256,
EcPubKeyAnyCurve,
EcPubKey<P256>,
EcPubKeyAnyCurve::P256
);
unwrap_any_curve!(
unwrap_pub_key_any_p384,
EcPubKeyAnyCurve,
EcPubKey<P384>,
EcPubKeyAnyCurve::P384
);
unwrap_any_curve!(
unwrap_pub_key_any_p521,
EcPubKeyAnyCurve,
EcPubKey<P521>,
EcPubKeyAnyCurve::P521
);
test::<P256, _, _>(unwrap_priv_key_any_p256, unwrap_pub_key_any_p256);
test::<P384, _, _>(unwrap_priv_key_any_p384, unwrap_pub_key_any_p384);
test::<P521, _, _>(unwrap_priv_key_any_p521, unwrap_pub_key_any_p521);
}
#[test]
fn test_parse_fail() {
// Test that invalid input is rejected.
fn test_parse_invalid<C: PCurve>() {
should_fail(
EcPrivKey::<C>::parse_from_der(&[]),
"EcPrivKey::parse_from_der",
"elliptic curve routines:OPENSSL_internal:DECODE_ERROR",
);
should_fail(
EcPubKey::<C>::parse_from_der(&[]),
"EcPubKey::parse_from_der",
"public key routines:OPENSSL_internal:DECODE_ERROR",
);
should_fail(
EcPrivKeyAnyCurve::parse_from_der(&[]),
"EcPrivKeyAnyCurve::parse_from_der",
"elliptic curve routines:OPENSSL_internal:DECODE_ERROR",
);
should_fail(
EcPubKeyAnyCurve::parse_from_der(&[]),
"EcPubKeyAnyCurve::parse_from_der",
"public key routines:OPENSSL_internal:DECODE_ERROR",
);
}
test_parse_invalid::<P256>();
test_parse_invalid::<P384>();
test_parse_invalid::<P521>();
// Test that, when a particular curve is expected, other curves are
// rejected.
fn test_parse_wrong_curve<C1: PCurve, C2: PCurve>() {
let privkey = EcPrivKey::<C1>::generate().unwrap();
let key_der = privkey.marshal_to_der();
should_fail(
EcPrivKey::<C2>::parse_from_der(&key_der),
"EcPrivKey::parse_from_der",
"elliptic curve routines:OPENSSL_internal:GROUP_MISMATCH",
);
let key_der = privkey.public().marshal_to_der();
should_fail(
EcPubKey::<C2>::parse_from_der(&key_der),
"EcPubKey::parse_from_der",
"unexpected curve:",
);
}
// All pairs of curves, (X, Y), such that X != Y.
test_parse_wrong_curve::<P256, P384>();
test_parse_wrong_curve::<P256, P521>();
test_parse_wrong_curve::<P384, P256>();
test_parse_wrong_curve::<P384, P521>();
test_parse_wrong_curve::<P521, P256>();
test_parse_wrong_curve::<P521, P384>();
}
}