deno.land / x / deno@v1.28.2 / ext / crypto / import_key.rs
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779use crate::key::CryptoNamedCurve;use crate::shared::*;use deno_core::error::AnyError;use deno_core::op;use deno_core::ZeroCopyBuf;use elliptic_curve::pkcs8::PrivateKeyInfo;use p256::pkcs8::EncodePrivateKey;use ring::signature::EcdsaKeyPair;use rsa::pkcs1::UIntRef;use serde::Deserialize;use serde::Serialize;use spki::der::Decode;use spki::der::Encode;
#[derive(Deserialize)]#[serde(rename_all = "camelCase")]pub enum KeyData { Spki(ZeroCopyBuf), Pkcs8(ZeroCopyBuf), Raw(ZeroCopyBuf), JwkSecret { k: String, }, JwkPublicRsa { n: String, e: String, }, JwkPrivateRsa { n: String, e: String, d: String, p: String, q: String, dp: String, dq: String, qi: String, }, JwkPublicEc { x: String, y: String, }, JwkPrivateEc { x: String, y: String, d: String, },}
#[derive(Deserialize)]#[serde(rename_all = "camelCase", tag = "algorithm")]pub enum ImportKeyOptions { #[serde(rename = "RSASSA-PKCS1-v1_5")] RsassaPkcs1v15 {}, #[serde(rename = "RSA-PSS")] RsaPss {}, #[serde(rename = "RSA-OAEP")] RsaOaep {}, #[serde(rename = "ECDSA", rename_all = "camelCase")] Ecdsa { named_curve: EcNamedCurve }, #[serde(rename = "ECDH", rename_all = "camelCase")] Ecdh { named_curve: EcNamedCurve }, #[serde(rename = "AES", rename_all = "camelCase")] Aes {}, #[serde(rename = "HMAC", rename_all = "camelCase")] Hmac {},}
#[derive(Serialize)]#[serde(untagged)]pub enum ImportKeyResult { #[serde(rename_all = "camelCase")] Rsa { raw_data: RawKeyData, modulus_length: usize, public_exponent: ZeroCopyBuf, }, #[serde(rename_all = "camelCase")] Ec { raw_data: RawKeyData }, #[serde(rename_all = "camelCase")] #[allow(dead_code)] Aes { raw_data: RawKeyData }, #[serde(rename_all = "camelCase")] Hmac { raw_data: RawKeyData },}
#[op]pub fn op_crypto_import_key( opts: ImportKeyOptions, key_data: KeyData,) -> Result<ImportKeyResult, AnyError> { match opts { ImportKeyOptions::RsassaPkcs1v15 {} => import_key_rsassa(key_data), ImportKeyOptions::RsaPss {} => import_key_rsapss(key_data), ImportKeyOptions::RsaOaep {} => import_key_rsaoaep(key_data), ImportKeyOptions::Ecdsa { named_curve } | ImportKeyOptions::Ecdh { named_curve } => { import_key_ec(key_data, named_curve) } ImportKeyOptions::Aes {} => import_key_aes(key_data), ImportKeyOptions::Hmac {} => import_key_hmac(key_data), }}
const URL_SAFE_FORGIVING: base64::Config = base64::URL_SAFE_NO_PAD.decode_allow_trailing_bits(true);
macro_rules! jwt_b64_int_or_err { ($name:ident, $b64:expr, $err:expr) => { let bytes = base64::decode_config($b64, URL_SAFE_FORGIVING) .map_err(|_| data_error($err))?; let $name = UIntRef::new(&bytes).map_err(|_| data_error($err))?; };}
fn import_key_rsa_jwk( key_data: KeyData,) -> Result<ImportKeyResult, deno_core::anyhow::Error> { match key_data { KeyData::JwkPublicRsa { n, e } => { jwt_b64_int_or_err!(modulus, &n, "invalid modulus"); jwt_b64_int_or_err!(public_exponent, &e, "invalid public exponent");
let public_key = rsa::pkcs1::RsaPublicKey { modulus, public_exponent, };
let data = public_key .to_vec() .map_err(|_| data_error("invalid rsa public key"))?; let public_exponent = public_key.public_exponent.as_bytes().to_vec().into(); let modulus_length = public_key.modulus.as_bytes().len() * 8;
Ok(ImportKeyResult::Rsa { raw_data: RawKeyData::Public(data.into()), modulus_length, public_exponent, }) } KeyData::JwkPrivateRsa { n, e, d, p, q, dp, dq, qi, } => { jwt_b64_int_or_err!(modulus, &n, "invalid modulus"); jwt_b64_int_or_err!(public_exponent, &e, "invalid public exponent"); jwt_b64_int_or_err!(private_exponent, &d, "invalid private exponent"); jwt_b64_int_or_err!(prime1, &p, "invalid first prime factor"); jwt_b64_int_or_err!(prime2, &q, "invalid second prime factor"); jwt_b64_int_or_err!(exponent1, &dp, "invalid first CRT exponent"); jwt_b64_int_or_err!(exponent2, &dq, "invalid second CRT exponent"); jwt_b64_int_or_err!(coefficient, &qi, "invalid CRT coefficient");
let private_key = rsa::pkcs1::RsaPrivateKey { modulus, public_exponent, private_exponent, prime1, prime2, exponent1, exponent2, coefficient, other_prime_infos: None, };
let data = private_key .to_vec() .map_err(|_| data_error("invalid rsa private key"))?;
let public_exponent = private_key.public_exponent.as_bytes().to_vec().into(); let modulus_length = private_key.modulus.as_bytes().len() * 8;
Ok(ImportKeyResult::Rsa { raw_data: RawKeyData::Private(data.into()), modulus_length, public_exponent, }) } _ => unreachable!(), }}
fn import_key_rsassa( key_data: KeyData,) -> Result<ImportKeyResult, deno_core::anyhow::Error> { match key_data { KeyData::Spki(data) => { // 2-3. let pk_info = spki::SubjectPublicKeyInfo::from_der(&data) .map_err(|e| data_error(e.to_string()))?;
// 4-5. let alg = pk_info.algorithm.oid;
// 6-7. (skipped, only support rsaEncryption for interoperability) if alg != RSA_ENCRYPTION_OID { return Err(data_error("unsupported algorithm")); }
// 8-9. let public_key = rsa::pkcs1::RsaPublicKey::from_der(pk_info.subject_public_key) .map_err(|e| data_error(e.to_string()))?;
let bytes_consumed = public_key .encoded_len() .map_err(|e| data_error(e.to_string()))?;
if bytes_consumed != spki::der::Length::new(pk_info.subject_public_key.len() as u16) { return Err(data_error("public key is invalid (too long)")); }
let data = pk_info.subject_public_key.to_vec().into(); let public_exponent = public_key.public_exponent.as_bytes().to_vec().into(); let modulus_length = public_key.modulus.as_bytes().len() * 8;
Ok(ImportKeyResult::Rsa { raw_data: RawKeyData::Public(data), modulus_length, public_exponent, }) } KeyData::Pkcs8(data) => { // 2-3. let pk_info = PrivateKeyInfo::from_der(&data) .map_err(|e| data_error(e.to_string()))?;
// 4-5. let alg = pk_info.algorithm.oid;
// 6-7. (skipped, only support rsaEncryption for interoperability) if alg != RSA_ENCRYPTION_OID { return Err(data_error("unsupported algorithm")); }
// 8-9. let private_key = rsa::pkcs1::RsaPrivateKey::from_der(pk_info.private_key) .map_err(|e| data_error(e.to_string()))?;
let bytes_consumed = private_key .encoded_len() .map_err(|e| data_error(e.to_string()))?;
if bytes_consumed != spki::der::Length::new(pk_info.private_key.len() as u16) { return Err(data_error("private key is invalid (too long)")); }
let data = pk_info.private_key.to_vec().into(); let public_exponent = private_key.public_exponent.as_bytes().to_vec().into(); let modulus_length = private_key.modulus.as_bytes().len() * 8;
Ok(ImportKeyResult::Rsa { raw_data: RawKeyData::Private(data), modulus_length, public_exponent, }) } KeyData::JwkPublicRsa { .. } | KeyData::JwkPrivateRsa { .. } => { import_key_rsa_jwk(key_data) } _ => Err(unsupported_format()), }}
fn import_key_rsapss( key_data: KeyData,) -> Result<ImportKeyResult, deno_core::anyhow::Error> { match key_data { KeyData::Spki(data) => { // 2-3. let pk_info = spki::SubjectPublicKeyInfo::from_der(&data) .map_err(|e| data_error(e.to_string()))?;
// 4-5. let alg = pk_info.algorithm.oid;
// 6-7. (skipped, only support rsaEncryption for interoperability) if alg != RSA_ENCRYPTION_OID { return Err(data_error("unsupported algorithm")); }
// 8-9. let public_key = rsa::pkcs1::RsaPublicKey::from_der(pk_info.subject_public_key) .map_err(|e| data_error(e.to_string()))?;
let bytes_consumed = public_key .encoded_len() .map_err(|e| data_error(e.to_string()))?;
if bytes_consumed != spki::der::Length::new(pk_info.subject_public_key.len() as u16) { return Err(data_error("public key is invalid (too long)")); }
let data = pk_info.subject_public_key.to_vec().into(); let public_exponent = public_key.public_exponent.as_bytes().to_vec().into(); let modulus_length = public_key.modulus.as_bytes().len() * 8;
Ok(ImportKeyResult::Rsa { raw_data: RawKeyData::Public(data), modulus_length, public_exponent, }) } KeyData::Pkcs8(data) => { // 2-3. let pk_info = PrivateKeyInfo::from_der(&data) .map_err(|e| data_error(e.to_string()))?;
// 4-5. let alg = pk_info.algorithm.oid;
// 6-7. (skipped, only support rsaEncryption for interoperability) if alg != RSA_ENCRYPTION_OID { return Err(data_error("unsupported algorithm")); }
// 8-9. let private_key = rsa::pkcs1::RsaPrivateKey::from_der(pk_info.private_key) .map_err(|e| data_error(e.to_string()))?;
let bytes_consumed = private_key .encoded_len() .map_err(|e| data_error(e.to_string()))?;
if bytes_consumed != spki::der::Length::new(pk_info.private_key.len() as u16) { return Err(data_error("private key is invalid (too long)")); }
let data = pk_info.private_key.to_vec().into(); let public_exponent = private_key.public_exponent.as_bytes().to_vec().into(); let modulus_length = private_key.modulus.as_bytes().len() * 8;
Ok(ImportKeyResult::Rsa { raw_data: RawKeyData::Private(data), modulus_length, public_exponent, }) } KeyData::JwkPublicRsa { .. } | KeyData::JwkPrivateRsa { .. } => { import_key_rsa_jwk(key_data) } _ => Err(unsupported_format()), }}
fn import_key_rsaoaep( key_data: KeyData,) -> Result<ImportKeyResult, deno_core::anyhow::Error> { match key_data { KeyData::Spki(data) => { // 2-3. let pk_info = spki::SubjectPublicKeyInfo::from_der(&data) .map_err(|e| data_error(e.to_string()))?;
// 4-5. let alg = pk_info.algorithm.oid;
// 6-7. (skipped, only support rsaEncryption for interoperability) if alg != RSA_ENCRYPTION_OID { return Err(data_error("unsupported algorithm")); }
// 8-9. let public_key = rsa::pkcs1::RsaPublicKey::from_der(pk_info.subject_public_key) .map_err(|e| data_error(e.to_string()))?;
let bytes_consumed = public_key .encoded_len() .map_err(|e| data_error(e.to_string()))?;
if bytes_consumed != spki::der::Length::new(pk_info.subject_public_key.len() as u16) { return Err(data_error("public key is invalid (too long)")); }
let data = pk_info.subject_public_key.to_vec().into(); let public_exponent = public_key.public_exponent.as_bytes().to_vec().into(); let modulus_length = public_key.modulus.as_bytes().len() * 8;
Ok(ImportKeyResult::Rsa { raw_data: RawKeyData::Public(data), modulus_length, public_exponent, }) } KeyData::Pkcs8(data) => { // 2-3. let pk_info = PrivateKeyInfo::from_der(&data) .map_err(|e| data_error(e.to_string()))?;
// 4-5. let alg = pk_info.algorithm.oid;
// 6-7. (skipped, only support rsaEncryption for interoperability) if alg != RSA_ENCRYPTION_OID { return Err(data_error("unsupported algorithm")); }
// 8-9. let private_key = rsa::pkcs1::RsaPrivateKey::from_der(pk_info.private_key) .map_err(|e| data_error(e.to_string()))?;
let bytes_consumed = private_key .encoded_len() .map_err(|e| data_error(e.to_string()))?;
if bytes_consumed != spki::der::Length::new(pk_info.private_key.len() as u16) { return Err(data_error("private key is invalid (too long)")); }
let data = pk_info.private_key.to_vec().into(); let public_exponent = private_key.public_exponent.as_bytes().to_vec().into(); let modulus_length = private_key.modulus.as_bytes().len() * 8;
Ok(ImportKeyResult::Rsa { raw_data: RawKeyData::Private(data), modulus_length, public_exponent, }) } KeyData::JwkPublicRsa { .. } | KeyData::JwkPrivateRsa { .. } => { import_key_rsa_jwk(key_data) } _ => Err(unsupported_format()), }}
fn decode_b64url_to_field_bytes<C: elliptic_curve::Curve>( b64: &str,) -> Result<elliptic_curve::FieldBytes<C>, deno_core::anyhow::Error> { jwt_b64_int_or_err!(val, b64, "invalid b64 coordinate");
let mut bytes = elliptic_curve::FieldBytes::<C>::default(); let original_bytes = val.as_bytes(); let mut new_bytes: Vec<u8> = vec![]; if original_bytes.len() < bytes.len() { new_bytes = vec![0; bytes.len() - original_bytes.len()]; } new_bytes.extend_from_slice(original_bytes);
let val = new_bytes.as_slice();
if val.len() != bytes.len() { return Err(data_error("invalid b64 coordinate")); } bytes.copy_from_slice(val);
Ok(bytes)}
fn import_key_ec_jwk_to_point( x: String, y: String, named_curve: EcNamedCurve,) -> Result<Vec<u8>, deno_core::anyhow::Error> { let point_bytes = match named_curve { EcNamedCurve::P256 => { let x = decode_b64url_to_field_bytes::<p256::NistP256>(&x)?; let y = decode_b64url_to_field_bytes::<p256::NistP256>(&y)?;
p256::EncodedPoint::from_affine_coordinates(&x, &y, false).to_bytes() } EcNamedCurve::P384 => { let x = decode_b64url_to_field_bytes::<p384::NistP384>(&x)?; let y = decode_b64url_to_field_bytes::<p384::NistP384>(&y)?;
p384::EncodedPoint::from_affine_coordinates(&x, &y, false).to_bytes() } _ => return Err(not_supported_error("Unsupported named curve")), };
Ok(point_bytes.to_vec())}
fn import_key_ec_jwk( key_data: KeyData, named_curve: EcNamedCurve,) -> Result<ImportKeyResult, deno_core::anyhow::Error> { match key_data { KeyData::JwkPublicEc { x, y } => { let point_bytes = import_key_ec_jwk_to_point(x, y, named_curve)?;
Ok(ImportKeyResult::Ec { raw_data: RawKeyData::Public(point_bytes.into()), }) } KeyData::JwkPrivateEc { d, x, y } => { jwt_b64_int_or_err!(private_d, &d, "invalid JWK private key"); let point_bytes = import_key_ec_jwk_to_point(x, y, named_curve)?; let pkcs8_der = match named_curve { EcNamedCurve::P256 => { let d = decode_b64url_to_field_bytes::<p256::NistP256>(&d)?; let pk = p256::SecretKey::from_be_bytes(&d)?;
pk.to_pkcs8_der()? } EcNamedCurve::P384 => { let d = decode_b64url_to_field_bytes::<p384::NistP384>(&d)?; let pk = p384::SecretKey::from_be_bytes(&d)?;
pk.to_pkcs8_der()? } EcNamedCurve::P521 => { return Err(data_error("Unsupported named curve")) } };
// Import using ring, to validate key let key_alg = match named_curve { EcNamedCurve::P256 => CryptoNamedCurve::P256.try_into()?, EcNamedCurve::P384 => CryptoNamedCurve::P256.try_into()?, EcNamedCurve::P521 => { return Err(data_error("Unsupported named curve")) } };
let _key_pair = EcdsaKeyPair::from_private_key_and_public_key( key_alg, private_d.as_bytes(), point_bytes.as_ref(), );
Ok(ImportKeyResult::Ec { raw_data: RawKeyData::Private(pkcs8_der.as_bytes().to_vec().into()), }) } _ => unreachable!(), }}
pub struct ECParametersSpki { pub named_curve_alg: spki::der::asn1::ObjectIdentifier,}
impl<'a> TryFrom<spki::der::asn1::AnyRef<'a>> for ECParametersSpki { type Error = spki::der::Error;
fn try_from( any: spki::der::asn1::AnyRef<'a>, ) -> spki::der::Result<ECParametersSpki> { let x = any.oid()?;
Ok(Self { named_curve_alg: x }) }}
fn import_key_ec( key_data: KeyData, named_curve: EcNamedCurve,) -> Result<ImportKeyResult, AnyError> { match key_data { KeyData::Raw(data) => { // The point is parsed and validated, ultimately the original data is // returned though. match named_curve { EcNamedCurve::P256 => { // 1-2. let point = p256::EncodedPoint::from_bytes(&data) .map_err(|_| data_error("invalid P-256 elliptic curve point"))?; // 3. if point.is_identity() { return Err(data_error("invalid P-256 elliptic curve point")); } } EcNamedCurve::P384 => { // 1-2. let point = p384::EncodedPoint::from_bytes(&data) .map_err(|_| data_error("invalid P-384 elliptic curve point"))?; // 3. if point.is_identity() { return Err(data_error("invalid P-384 elliptic curve point")); } } _ => return Err(not_supported_error("Unsupported named curve")), }; Ok(ImportKeyResult::Ec { raw_data: RawKeyData::Public(data), }) } KeyData::Pkcs8(data) => { // 2-7 // Deserialize PKCS8 - validate structure, extracts named_curve let named_curve_alg = match named_curve { EcNamedCurve::P256 | EcNamedCurve::P384 => { let pk = PrivateKeyInfo::from_der(data.as_ref()) .map_err(|_| data_error("expected valid PKCS#8 data"))?; pk.algorithm .parameters .ok_or_else(|| data_error("malformed parameters"))? .oid() .unwrap() } EcNamedCurve::P521 => { return Err(data_error("Unsupported named curve")) } };
// 8-9. let pk_named_curve = match named_curve_alg { // id-secp256r1 ID_SECP256R1_OID => Some(EcNamedCurve::P256), // id-secp384r1 ID_SECP384R1_OID => Some(EcNamedCurve::P384), // id-secp521r1 ID_SECP521R1_OID => Some(EcNamedCurve::P521), _ => None, };
// 10. if let Some(pk_named_curve) = pk_named_curve { let signing_alg = match pk_named_curve { EcNamedCurve::P256 => CryptoNamedCurve::P256.try_into()?, EcNamedCurve::P384 => CryptoNamedCurve::P384.try_into()?, EcNamedCurve::P521 => { return Err(data_error("Unsupported named curve")) } };
// deserialize pkcs8 using ring crate, to VALIDATE public key let _private_key = EcdsaKeyPair::from_pkcs8(signing_alg, &data)?;
// 11. if named_curve != pk_named_curve { return Err(data_error("curve mismatch")); } } else { return Err(data_error("Unsupported named curve")); }
Ok(ImportKeyResult::Ec { raw_data: RawKeyData::Private(data), }) } KeyData::Spki(data) => { // 2-3. let pk_info = spki::SubjectPublicKeyInfo::from_der(&data) .map_err(|e| data_error(e.to_string()))?;
// 4. let alg = pk_info.algorithm.oid; // id-ecPublicKey if alg != elliptic_curve::ALGORITHM_OID { return Err(data_error("unsupported algorithm")); }
// 5-7. let params = ECParametersSpki::try_from( pk_info .algorithm .parameters .ok_or_else(|| data_error("malformed parameters"))?, ) .map_err(|_| data_error("malformed parameters"))?;
// 8-9. let named_curve_alg = params.named_curve_alg; let pk_named_curve = match named_curve_alg { // id-secp256r1 ID_SECP256R1_OID => Some(EcNamedCurve::P256), // id-secp384r1 ID_SECP384R1_OID => Some(EcNamedCurve::P384), // id-secp521r1 ID_SECP521R1_OID => Some(EcNamedCurve::P521), _ => None, };
// 10. let encoded_key;
if let Some(pk_named_curve) = pk_named_curve { let pk = pk_info.subject_public_key;
encoded_key = pk.to_vec();
let bytes_consumed = match named_curve { EcNamedCurve::P256 => { let point = p256::EncodedPoint::from_bytes(&*encoded_key).map_err(|_| { data_error("invalid P-256 elliptic curve SPKI data") })?; if point.is_identity() { return Err(data_error("invalid P-256 elliptic curve point")); }
point.as_bytes().len() } EcNamedCurve::P384 => { let point = p384::EncodedPoint::from_bytes(&*encoded_key).map_err(|_| { data_error("invalid P-384 elliptic curve SPKI data") })?;
if point.is_identity() { return Err(data_error("invalid P-384 elliptic curve point")); }
point.as_bytes().len() } _ => return Err(not_supported_error("Unsupported named curve")), };
if bytes_consumed != pk_info.subject_public_key.len() { return Err(data_error("public key is invalid (too long)")); }
// 11. if named_curve != pk_named_curve { return Err(data_error("curve mismatch")); } } else { return Err(data_error("Unsupported named curve")); }
Ok(ImportKeyResult::Ec { raw_data: RawKeyData::Public(encoded_key.into()), }) } KeyData::JwkPublicEc { .. } | KeyData::JwkPrivateEc { .. } => { import_key_ec_jwk(key_data, named_curve) } _ => Err(unsupported_format()), }}
fn import_key_aes(key_data: KeyData) -> Result<ImportKeyResult, AnyError> { Ok(match key_data { KeyData::JwkSecret { k } => { let data = base64::decode_config(k, URL_SAFE_FORGIVING) .map_err(|_| data_error("invalid key data"))?; ImportKeyResult::Hmac { raw_data: RawKeyData::Secret(data.into()), } } _ => return Err(unsupported_format()), })}
fn import_key_hmac(key_data: KeyData) -> Result<ImportKeyResult, AnyError> { Ok(match key_data { KeyData::JwkSecret { k } => { let data = base64::decode_config(k, URL_SAFE_FORGIVING) .map_err(|_| data_error("invalid key data"))?; ImportKeyResult::Hmac { raw_data: RawKeyData::Secret(data.into()), } } _ => return Err(unsupported_format()), })}
Version Info