// 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>();
    }
}
