mirror of
https://github.com/denoland/deno.git
synced 2024-11-28 16:20:57 -05:00
refactor(ext/crypto): clean up exportKey rust code (#13052)
This commit is contained in:
parent
cd03de3c7b
commit
5afb2cca65
4 changed files with 156 additions and 212 deletions
|
@ -852,6 +852,7 @@
|
||||||
* @param {CryptoKey} key
|
* @param {CryptoKey} key
|
||||||
* @returns {Promise<any>}
|
* @returns {Promise<any>}
|
||||||
*/
|
*/
|
||||||
|
// deno-lint-ignore require-await
|
||||||
async exportKey(format, key) {
|
async exportKey(format, key) {
|
||||||
webidl.assertBranded(this, SubtleCrypto);
|
webidl.assertBranded(this, SubtleCrypto);
|
||||||
const prefix = "Failed to execute 'exportKey' on 'SubtleCrypto'";
|
const prefix = "Failed to execute 'exportKey' on 'SubtleCrypto'";
|
||||||
|
@ -878,7 +879,7 @@
|
||||||
case "RSASSA-PKCS1-v1_5":
|
case "RSASSA-PKCS1-v1_5":
|
||||||
case "RSA-PSS":
|
case "RSA-PSS":
|
||||||
case "RSA-OAEP": {
|
case "RSA-OAEP": {
|
||||||
return await exportKeyRSA(format, key, innerKey);
|
return exportKeyRSA(format, key, innerKey);
|
||||||
}
|
}
|
||||||
case "AES-CTR":
|
case "AES-CTR":
|
||||||
case "AES-CBC":
|
case "AES-CBC":
|
||||||
|
@ -2532,7 +2533,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function exportKeyRSA(format, key, innerKey) {
|
function exportKeyRSA(format, key, innerKey) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case "pkcs8": {
|
case "pkcs8": {
|
||||||
// 1.
|
// 1.
|
||||||
|
@ -2544,12 +2545,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.
|
// 2.
|
||||||
const data = await core.opAsync("op_crypto_export_key", {
|
const data = core.opSync("op_crypto_export_key", {
|
||||||
key: innerKey,
|
|
||||||
format: "pkcs8",
|
|
||||||
algorithm: key[_algorithm].name,
|
algorithm: key[_algorithm].name,
|
||||||
hash: key[_algorithm].hash.name,
|
format: "pkcs8",
|
||||||
});
|
}, innerKey);
|
||||||
|
|
||||||
// 3.
|
// 3.
|
||||||
return data.buffer;
|
return data.buffer;
|
||||||
|
@ -2564,12 +2563,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.
|
// 2.
|
||||||
const data = await core.opAsync("op_crypto_export_key", {
|
const data = core.opSync("op_crypto_export_key", {
|
||||||
key: innerKey,
|
|
||||||
format: "spki",
|
|
||||||
algorithm: key[_algorithm].name,
|
algorithm: key[_algorithm].name,
|
||||||
hash: key[_algorithm].hash.name,
|
format: "spki",
|
||||||
});
|
}, innerKey);
|
||||||
|
|
||||||
// 3.
|
// 3.
|
||||||
return data.buffer;
|
return data.buffer;
|
||||||
|
|
113
ext/crypto/export_key.rs
Normal file
113
ext/crypto/export_key.rs
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
use deno_core::error::AnyError;
|
||||||
|
use deno_core::OpState;
|
||||||
|
use deno_core::ZeroCopyBuf;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
|
use spki::der::asn1;
|
||||||
|
use spki::der::Encodable;
|
||||||
|
|
||||||
|
use crate::shared::*;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ExportKeyOptions {
|
||||||
|
format: ExportKeyFormat,
|
||||||
|
#[serde(flatten)]
|
||||||
|
algorithm: ExportKeyAlgorithm,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum ExportKeyFormat {
|
||||||
|
Pkcs8,
|
||||||
|
Spki,
|
||||||
|
Jwk,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase", tag = "algorithm")]
|
||||||
|
pub enum ExportKeyAlgorithm {
|
||||||
|
#[serde(rename = "RSASSA-PKCS1-v1_5")]
|
||||||
|
RsassaPkcs1v15 {},
|
||||||
|
#[serde(rename = "RSA-PSS")]
|
||||||
|
RsaPss {},
|
||||||
|
#[serde(rename = "RSA-OAEP")]
|
||||||
|
RsaOaep {},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum ExportKeyResult {
|
||||||
|
Pkcs8(ZeroCopyBuf),
|
||||||
|
Spki(ZeroCopyBuf),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn op_crypto_export_key(
|
||||||
|
_state: &mut OpState,
|
||||||
|
opts: ExportKeyOptions,
|
||||||
|
key_data: RawKeyData,
|
||||||
|
) -> Result<ExportKeyResult, AnyError> {
|
||||||
|
match opts.algorithm {
|
||||||
|
ExportKeyAlgorithm::RsassaPkcs1v15 {}
|
||||||
|
| ExportKeyAlgorithm::RsaPss {}
|
||||||
|
| ExportKeyAlgorithm::RsaOaep {} => export_key_rsa(opts.format, key_data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn export_key_rsa(
|
||||||
|
format: ExportKeyFormat,
|
||||||
|
key_data: RawKeyData,
|
||||||
|
) -> Result<ExportKeyResult, deno_core::anyhow::Error> {
|
||||||
|
match format {
|
||||||
|
ExportKeyFormat::Spki => {
|
||||||
|
let subject_public_key = &key_data.as_rsa_public_key()?;
|
||||||
|
|
||||||
|
// the SPKI structure
|
||||||
|
let key_info = spki::SubjectPublicKeyInfo {
|
||||||
|
algorithm: spki::AlgorithmIdentifier {
|
||||||
|
// rsaEncryption(1)
|
||||||
|
oid: spki::ObjectIdentifier::new("1.2.840.113549.1.1.1"),
|
||||||
|
// parameters field should not be ommited (None).
|
||||||
|
// It MUST have ASN.1 type NULL.
|
||||||
|
parameters: Some(asn1::Any::from(asn1::Null)),
|
||||||
|
},
|
||||||
|
subject_public_key,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Infallible because we know the public key is valid.
|
||||||
|
let spki_der = key_info.to_vec().unwrap();
|
||||||
|
Ok(ExportKeyResult::Spki(spki_der.into()))
|
||||||
|
}
|
||||||
|
ExportKeyFormat::Pkcs8 => {
|
||||||
|
let private_key = key_data.as_rsa_private_key()?;
|
||||||
|
|
||||||
|
// the PKCS#8 v1 structure
|
||||||
|
// PrivateKeyInfo ::= SEQUENCE {
|
||||||
|
// version Version,
|
||||||
|
// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
|
||||||
|
// privateKey PrivateKey,
|
||||||
|
// attributes [0] IMPLICIT Attributes OPTIONAL }
|
||||||
|
|
||||||
|
// version is 0 when publickey is None
|
||||||
|
|
||||||
|
let pk_info = rsa::pkcs8::PrivateKeyInfo {
|
||||||
|
attributes: None,
|
||||||
|
public_key: None,
|
||||||
|
algorithm: rsa::pkcs8::AlgorithmIdentifier {
|
||||||
|
// rsaEncryption(1)
|
||||||
|
oid: rsa::pkcs8::ObjectIdentifier::new("1.2.840.113549.1.1.1"),
|
||||||
|
// parameters field should not be ommited (None).
|
||||||
|
// It MUST have ASN.1 type NULL as per defined in RFC 3279 Section 2.3.1
|
||||||
|
parameters: Some(asn1::Any::from(asn1::Null)),
|
||||||
|
},
|
||||||
|
private_key,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Infallible because we know the private key is valid.
|
||||||
|
let pkcs8_der = pk_info.to_vec().unwrap();
|
||||||
|
|
||||||
|
Ok(ExportKeyResult::Pkcs8(pkcs8_der.into()))
|
||||||
|
}
|
||||||
|
_ => Err(unsupported_format()),
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ use deno_core::op_sync;
|
||||||
use deno_core::Extension;
|
use deno_core::Extension;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_core::ZeroCopyBuf;
|
use deno_core::ZeroCopyBuf;
|
||||||
|
use export_key::op_crypto_export_key;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
@ -56,6 +57,7 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
pub use rand; // Re-export rand
|
pub use rand; // Re-export rand
|
||||||
|
|
||||||
|
mod export_key;
|
||||||
mod import_key;
|
mod import_key;
|
||||||
mod key;
|
mod key;
|
||||||
mod shared;
|
mod shared;
|
||||||
|
@ -93,7 +95,7 @@ pub fn init(maybe_seed: Option<u64>) -> Extension {
|
||||||
("op_crypto_verify_key", op_async(op_crypto_verify_key)),
|
("op_crypto_verify_key", op_async(op_crypto_verify_key)),
|
||||||
("op_crypto_derive_bits", op_async(op_crypto_derive_bits)),
|
("op_crypto_derive_bits", op_async(op_crypto_derive_bits)),
|
||||||
("op_crypto_import_key", op_sync(op_crypto_import_key)),
|
("op_crypto_import_key", op_sync(op_crypto_import_key)),
|
||||||
("op_crypto_export_key", op_async(op_crypto_export_key)),
|
("op_crypto_export_key", op_sync(op_crypto_export_key)),
|
||||||
("op_crypto_encrypt_key", op_async(op_crypto_encrypt_key)),
|
("op_crypto_encrypt_key", op_async(op_crypto_encrypt_key)),
|
||||||
("op_crypto_decrypt_key", op_async(op_crypto_decrypt_key)),
|
("op_crypto_decrypt_key", op_async(op_crypto_decrypt_key)),
|
||||||
("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)),
|
("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)),
|
||||||
|
@ -569,205 +571,6 @@ pub async fn op_crypto_verify_key(
|
||||||
Ok(verification)
|
Ok(verification)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct ExportKeyArg {
|
|
||||||
key: KeyData,
|
|
||||||
algorithm: Algorithm,
|
|
||||||
format: KeyFormat,
|
|
||||||
// RSA-PSS
|
|
||||||
hash: Option<CryptoHash>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn op_crypto_export_key(
|
|
||||||
_state: Rc<RefCell<OpState>>,
|
|
||||||
args: ExportKeyArg,
|
|
||||||
_: (),
|
|
||||||
) -> Result<ZeroCopyBuf, AnyError> {
|
|
||||||
let algorithm = args.algorithm;
|
|
||||||
match algorithm {
|
|
||||||
Algorithm::RsassaPkcs1v15 => {
|
|
||||||
match args.format {
|
|
||||||
KeyFormat::Pkcs8 => {
|
|
||||||
// private_key is a PKCS#1 DER-encoded private key
|
|
||||||
|
|
||||||
let private_key = &args.key.data;
|
|
||||||
|
|
||||||
// the PKCS#8 v1 structure
|
|
||||||
// PrivateKeyInfo ::= SEQUENCE {
|
|
||||||
// version Version,
|
|
||||||
// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
|
|
||||||
// privateKey PrivateKey,
|
|
||||||
// attributes [0] IMPLICIT Attributes OPTIONAL }
|
|
||||||
|
|
||||||
// version is 0 when publickey is None
|
|
||||||
|
|
||||||
let pk_info = rsa::pkcs8::PrivateKeyInfo {
|
|
||||||
attributes: None,
|
|
||||||
public_key: None,
|
|
||||||
algorithm: rsa::pkcs8::AlgorithmIdentifier {
|
|
||||||
// rsaEncryption(1)
|
|
||||||
oid: rsa::pkcs8::ObjectIdentifier::new("1.2.840.113549.1.1.1"),
|
|
||||||
// parameters field should not be ommited (None).
|
|
||||||
// It MUST have ASN.1 type NULL as per defined in RFC 3279 Section 2.3.1
|
|
||||||
parameters: Some(asn1::Any::from(asn1::Null)),
|
|
||||||
},
|
|
||||||
private_key,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(pk_info.to_der().as_ref().to_vec().into())
|
|
||||||
}
|
|
||||||
KeyFormat::Spki => {
|
|
||||||
// public_key is a PKCS#1 DER-encoded public key
|
|
||||||
|
|
||||||
let subject_public_key = &args.key.data;
|
|
||||||
|
|
||||||
// the SPKI structure
|
|
||||||
let key_info = spki::SubjectPublicKeyInfo {
|
|
||||||
algorithm: spki::AlgorithmIdentifier {
|
|
||||||
// rsaEncryption(1)
|
|
||||||
oid: spki::ObjectIdentifier::new("1.2.840.113549.1.1.1"),
|
|
||||||
// parameters field should not be ommited (None).
|
|
||||||
// It MUST have ASN.1 type NULL.
|
|
||||||
parameters: Some(asn1::Any::from(asn1::Null)),
|
|
||||||
},
|
|
||||||
subject_public_key,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Infallible based on spec because of the way we import and generate keys.
|
|
||||||
let spki_der = key_info.to_vec().unwrap();
|
|
||||||
Ok(spki_der.into())
|
|
||||||
}
|
|
||||||
// TODO(@littledivy): jwk
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Algorithm::RsaPss => {
|
|
||||||
match args.format {
|
|
||||||
KeyFormat::Pkcs8 => {
|
|
||||||
// Intentionally unused but required. Not encoded into PKCS#8 (see below).
|
|
||||||
let _hash = args
|
|
||||||
.hash
|
|
||||||
.ok_or_else(|| type_error("Missing argument hash".to_string()))?;
|
|
||||||
|
|
||||||
// private_key is a PKCS#1 DER-encoded private key
|
|
||||||
let private_key = &args.key.data;
|
|
||||||
|
|
||||||
// version is 0 when publickey is None
|
|
||||||
|
|
||||||
let pk_info = rsa::pkcs8::PrivateKeyInfo {
|
|
||||||
attributes: None,
|
|
||||||
public_key: None,
|
|
||||||
algorithm: rsa::pkcs8::AlgorithmIdentifier {
|
|
||||||
// Spec wants the OID to be id-RSASSA-PSS (1.2.840.113549.1.1.10) but ring and RSA do not support it.
|
|
||||||
// Instead, we use rsaEncryption (1.2.840.113549.1.1.1) as specified in RFC 3447.
|
|
||||||
// Node, Chromium and Firefox also use rsaEncryption (1.2.840.113549.1.1.1) and do not support id-RSASSA-PSS.
|
|
||||||
|
|
||||||
// parameters are set to NULL opposed to what spec wants (see above)
|
|
||||||
oid: rsa::pkcs8::ObjectIdentifier::new("1.2.840.113549.1.1.1"),
|
|
||||||
// parameters field should not be ommited (None).
|
|
||||||
// It MUST have ASN.1 type NULL as per defined in RFC 3279 Section 2.3.1
|
|
||||||
parameters: Some(asn1::Any::from(asn1::Null)),
|
|
||||||
},
|
|
||||||
private_key,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(pk_info.to_der().as_ref().to_vec().into())
|
|
||||||
}
|
|
||||||
KeyFormat::Spki => {
|
|
||||||
// Intentionally unused but required. Not encoded into SPKI (see below).
|
|
||||||
let _hash = args
|
|
||||||
.hash
|
|
||||||
.ok_or_else(|| type_error("Missing argument hash".to_string()))?;
|
|
||||||
|
|
||||||
// public_key is a PKCS#1 DER-encoded public key
|
|
||||||
let subject_public_key = &args.key.data;
|
|
||||||
|
|
||||||
// the SPKI structure
|
|
||||||
let key_info = spki::SubjectPublicKeyInfo {
|
|
||||||
algorithm: spki::AlgorithmIdentifier {
|
|
||||||
// rsaEncryption(1)
|
|
||||||
oid: spki::ObjectIdentifier::new("1.2.840.113549.1.1.1"),
|
|
||||||
// parameters field should not be ommited (None).
|
|
||||||
// It MUST have ASN.1 type NULL.
|
|
||||||
parameters: Some(asn1::Any::from(asn1::Null)),
|
|
||||||
},
|
|
||||||
subject_public_key,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Infallible based on spec because of the way we import and generate keys.
|
|
||||||
let spki_der = key_info.to_vec().unwrap();
|
|
||||||
Ok(spki_der.into())
|
|
||||||
}
|
|
||||||
// TODO(@littledivy): jwk
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Algorithm::RsaOaep => {
|
|
||||||
match args.format {
|
|
||||||
KeyFormat::Pkcs8 => {
|
|
||||||
// Intentionally unused but required. Not encoded into PKCS#8 (see below).
|
|
||||||
let _hash = args
|
|
||||||
.hash
|
|
||||||
.ok_or_else(|| type_error("Missing argument hash".to_string()))?;
|
|
||||||
|
|
||||||
// private_key is a PKCS#1 DER-encoded private key
|
|
||||||
let private_key = &args.key.data;
|
|
||||||
|
|
||||||
// version is 0 when publickey is None
|
|
||||||
|
|
||||||
let pk_info = rsa::pkcs8::PrivateKeyInfo {
|
|
||||||
attributes: None,
|
|
||||||
public_key: None,
|
|
||||||
algorithm: rsa::pkcs8::AlgorithmIdentifier {
|
|
||||||
// Spec wants the OID to be id-RSAES-OAEP (1.2.840.113549.1.1.10) but ring and RSA crate do not support it.
|
|
||||||
// Instead, we use rsaEncryption (1.2.840.113549.1.1.1) as specified in RFC 3447.
|
|
||||||
// Chromium and Firefox also use rsaEncryption (1.2.840.113549.1.1.1) and do not support id-RSAES-OAEP.
|
|
||||||
|
|
||||||
// parameters are set to NULL opposed to what spec wants (see above)
|
|
||||||
oid: rsa::pkcs8::ObjectIdentifier::new("1.2.840.113549.1.1.1"),
|
|
||||||
// parameters field should not be ommited (None).
|
|
||||||
// It MUST have ASN.1 type NULL as per defined in RFC 3279 Section 2.3.1
|
|
||||||
parameters: Some(asn1::Any::from(asn1::Null)),
|
|
||||||
},
|
|
||||||
private_key,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(pk_info.to_der().as_ref().to_vec().into())
|
|
||||||
}
|
|
||||||
KeyFormat::Spki => {
|
|
||||||
// Intentionally unused but required. Not encoded into SPKI (see below).
|
|
||||||
let _hash = args
|
|
||||||
.hash
|
|
||||||
.ok_or_else(|| type_error("Missing argument hash".to_string()))?;
|
|
||||||
|
|
||||||
// public_key is a PKCS#1 DER-encoded public key
|
|
||||||
let subject_public_key = &args.key.data;
|
|
||||||
|
|
||||||
// the SPKI structure
|
|
||||||
let key_info = spki::SubjectPublicKeyInfo {
|
|
||||||
algorithm: spki::AlgorithmIdentifier {
|
|
||||||
// rsaEncryption(1)
|
|
||||||
oid: spki::ObjectIdentifier::new("1.2.840.113549.1.1.1"),
|
|
||||||
// parameters field should not be ommited (None).
|
|
||||||
// It MUST have ASN.1 type NULL.
|
|
||||||
parameters: Some(asn1::Any::from(asn1::Null)),
|
|
||||||
},
|
|
||||||
subject_public_key,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Infallible based on spec because of the way we import and generate keys.
|
|
||||||
let spki_der = key_info.to_vec().unwrap();
|
|
||||||
Ok(spki_der.into())
|
|
||||||
}
|
|
||||||
// TODO(@littledivy): jwk
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(type_error("Unsupported algorithm".to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct DeriveKeyArg {
|
pub struct DeriveKeyArg {
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use deno_core::error::custom_error;
|
use deno_core::error::custom_error;
|
||||||
|
use deno_core::error::type_error;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::ZeroCopyBuf;
|
use deno_core::ZeroCopyBuf;
|
||||||
|
use rsa::pkcs1::FromRsaPrivateKey;
|
||||||
|
use rsa::pkcs1::ToRsaPublicKey;
|
||||||
|
use rsa::RsaPrivateKey;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
|
@ -61,6 +65,33 @@ pub enum RawKeyData {
|
||||||
Public(ZeroCopyBuf),
|
Public(ZeroCopyBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RawKeyData {
|
||||||
|
pub fn as_rsa_public_key(&self) -> Result<Cow<'_, [u8]>, AnyError> {
|
||||||
|
match self {
|
||||||
|
RawKeyData::Public(data) => Ok(Cow::Borrowed(data)),
|
||||||
|
RawKeyData::Private(data) => {
|
||||||
|
let private_key = RsaPrivateKey::from_pkcs1_der(data)
|
||||||
|
.map_err(|_| type_error("expected valid private key"))?;
|
||||||
|
|
||||||
|
let public_key_doc = private_key
|
||||||
|
.to_public_key()
|
||||||
|
.to_pkcs1_der()
|
||||||
|
.map_err(|_| type_error("expected valid public key"))?;
|
||||||
|
|
||||||
|
Ok(Cow::Owned(public_key_doc.as_der().into()))
|
||||||
|
}
|
||||||
|
_ => Err(type_error("expected public key")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_rsa_private_key(&self) -> Result<&[u8], AnyError> {
|
||||||
|
match self {
|
||||||
|
RawKeyData::Private(data) => Ok(data),
|
||||||
|
_ => Err(type_error("expected private key")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn data_error(msg: impl Into<Cow<'static, str>>) -> AnyError {
|
pub fn data_error(msg: impl Into<Cow<'static, str>>) -> AnyError {
|
||||||
custom_error("DOMExceptionDataError", msg)
|
custom_error("DOMExceptionDataError", msg)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue