summaryrefslogtreecommitdiff
path: root/ext/crypto/ec_key.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ext/crypto/ec_key.rs')
-rw-r--r--ext/crypto/ec_key.rs150
1 files changed, 150 insertions, 0 deletions
diff --git a/ext/crypto/ec_key.rs b/ext/crypto/ec_key.rs
new file mode 100644
index 000000000..3509f0aef
--- /dev/null
+++ b/ext/crypto/ec_key.rs
@@ -0,0 +1,150 @@
+use deno_core::error::AnyError;
+
+use elliptic_curve::AlgorithmParameters;
+
+use elliptic_curve::pkcs8;
+use elliptic_curve::pkcs8::der;
+use elliptic_curve::pkcs8::der::asn1::*;
+use elliptic_curve::pkcs8::der::Decodable as Pkcs8Decodable;
+use elliptic_curve::pkcs8::der::Encodable;
+use elliptic_curve::pkcs8::der::TagNumber;
+use elliptic_curve::pkcs8::AlgorithmIdentifier;
+use elliptic_curve::pkcs8::ObjectIdentifier;
+use elliptic_curve::pkcs8::PrivateKeyDocument;
+use elliptic_curve::pkcs8::PrivateKeyInfo;
+use elliptic_curve::zeroize::Zeroizing;
+
+use crate::shared::*;
+
+const VERSION: u8 = 1;
+
+const PUBLIC_KEY_TAG: TagNumber = TagNumber::new(1);
+
+pub struct ECPrivateKey<'a, C: elliptic_curve::Curve> {
+ pub algorithm: AlgorithmIdentifier<'a>,
+
+ pub private_d: elliptic_curve::FieldBytes<C>,
+
+ pub encoded_point: &'a [u8],
+}
+
+#[allow(dead_code)]
+///todo(@sean) - to be removed in #13154
+impl<'a, C> ECPrivateKey<'a, C>
+where
+ C: elliptic_curve::Curve + AlgorithmParameters,
+{
+ /// Create a new ECPrivateKey from a serialized private scalar and encoded public key
+ pub fn from_private_and_public_bytes(
+ private_d: elliptic_curve::FieldBytes<C>,
+ encoded_point: &'a [u8],
+ ) -> Self {
+ Self {
+ private_d,
+ encoded_point,
+ algorithm: C::algorithm_identifier(),
+ }
+ }
+
+ pub fn named_curve_oid(&self) -> Result<ObjectIdentifier, AnyError> {
+ let parameters = self
+ .algorithm
+ .parameters
+ .ok_or_else(|| data_error("malformed parameters"))?;
+
+ Ok(parameters.oid().unwrap())
+ }
+
+ fn internal_to_pkcs8_der(&self) -> der::Result<Vec<u8>> {
+ // Shamelessly copied from pkcs8 crate and modified so as
+ // to not require Arithmetic trait currently missing from p384
+ let secret_key_field = OctetString::new(&self.private_d)?;
+ let public_key_bytes = &self.encoded_point;
+ let public_key_field = ContextSpecific {
+ tag_number: PUBLIC_KEY_TAG,
+ value: BitString::new(public_key_bytes)?.into(),
+ };
+
+ let der_message_fields: &[&dyn Encodable] =
+ &[&VERSION, &secret_key_field, &public_key_field];
+
+ let encoded_len =
+ der::message::encoded_len(der_message_fields)?.try_into()?;
+ let mut der_message = Zeroizing::new(vec![0u8; encoded_len]);
+ let mut encoder = der::Encoder::new(&mut der_message);
+ encoder.message(der_message_fields)?;
+ encoder.finish()?;
+
+ Ok(der_message.to_vec())
+ }
+
+ pub fn to_pkcs8_der(&self) -> Result<PrivateKeyDocument, AnyError> {
+ let pkcs8_der = self
+ .internal_to_pkcs8_der()
+ .map_err(|_| data_error("expected valid PKCS#8 data"))?;
+
+ let pki =
+ pkcs8::PrivateKeyInfo::new(C::algorithm_identifier(), pkcs8_der.as_ref());
+
+ Ok(pki.to_der())
+ }
+}
+
+impl<'a, C: elliptic_curve::Curve> TryFrom<&'a [u8]> for ECPrivateKey<'a, C> {
+ type Error = AnyError;
+
+ fn try_from(bytes: &'a [u8]) -> Result<ECPrivateKey<C>, AnyError> {
+ let pk_info = PrivateKeyInfo::from_der(bytes)
+ .map_err(|_| data_error("expected valid PKCS#8 data"))?;
+
+ Self::try_from(pk_info)
+ }
+}
+
+impl<'a, C: elliptic_curve::Curve> TryFrom<PrivateKeyInfo<'a>>
+ for ECPrivateKey<'a, C>
+{
+ type Error = AnyError;
+
+ fn try_from(
+ pk_info: PrivateKeyInfo<'a>,
+ ) -> Result<ECPrivateKey<'a, C>, AnyError> {
+ let any = der::asn1::Any::from_der(pk_info.private_key).map_err(|_| {
+ data_error("expected valid PrivateKeyInfo private_key der")
+ })?;
+
+ if pk_info.algorithm.oid != elliptic_curve::ALGORITHM_OID {
+ return Err(data_error("unsupported algorithm"));
+ }
+
+ any
+ .sequence(|decoder| {
+ // ver
+ if decoder.uint8()? != VERSION {
+ return Err(der::Tag::Integer.value_error());
+ }
+
+ // private_key
+ let priv_key = decoder.octet_string()?.as_bytes();
+ let mut private_d = elliptic_curve::FieldBytes::<C>::default();
+ if priv_key.len() != private_d.len() {
+ return Err(der::Tag::Sequence.value_error());
+ };
+ private_d.copy_from_slice(priv_key);
+
+ let public_key = decoder
+ .context_specific(PUBLIC_KEY_TAG)?
+ .ok_or_else(|| {
+ der::Tag::ContextSpecific(PUBLIC_KEY_TAG).value_error()
+ })?
+ .bit_string()?;
+
+ Ok(Self {
+ private_d,
+ encoded_point: public_key.as_bytes(),
+ algorithm: pk_info.algorithm,
+ })
+ })
+ .map_err(|_| data_error("expected valid PrivateKeyInfo private_key der"))
+ }
+}