summaryrefslogtreecommitdiff
path: root/ext/crypto/lib.rs
diff options
context:
space:
mode:
authorDivy Srivastava <dj.srivastava23@gmail.com>2021-09-13 15:03:28 +0530
committerGitHub <noreply@github.com>2021-09-13 11:33:28 +0200
commit2199bdaf64c59c69f53079362e902355325cfa37 (patch)
treebaeca465179956e1a34d9501ab4e872d58db2488 /ext/crypto/lib.rs
parent84f874715763df71bb3bbf77f0714f8afdc17bb3 (diff)
feat(ext/crypto): export RSA keys as pkcs#8 (#11880)
Diffstat (limited to 'ext/crypto/lib.rs')
-rw-r--r--ext/crypto/lib.rs151
1 files changed, 142 insertions, 9 deletions
diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs
index 319f26c22..cf2c379a0 100644
--- a/ext/crypto/lib.rs
+++ b/ext/crypto/lib.rs
@@ -37,8 +37,9 @@ use ring::signature::EcdsaSigningAlgorithm;
use ring::signature::EcdsaVerificationAlgorithm;
use ring::signature::KeyPair;
use rsa::padding::PaddingScheme;
-use rsa::pkcs8::FromPrivateKey;
-use rsa::pkcs8::ToPrivateKey;
+use rsa::pkcs1::FromRsaPrivateKey;
+use rsa::pkcs1::ToRsaPrivateKey;
+use rsa::pkcs8::der::asn1;
use rsa::BigUint;
use rsa::PublicKey;
use rsa::RsaPrivateKey;
@@ -81,6 +82,7 @@ pub fn init(maybe_seed: Option<u64>) -> Extension {
("op_crypto_sign_key", op_async(op_crypto_sign_key)),
("op_crypto_verify_key", op_async(op_crypto_verify_key)),
("op_crypto_derive_bits", op_async(op_crypto_derive_bits)),
+ ("op_crypto_export_key", op_async(op_crypto_export_key)),
("op_crypto_encrypt_key", op_async(op_crypto_encrypt_key)),
("op_crypto_decrypt_key", op_async(op_crypto_decrypt_key)),
("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)),
@@ -164,7 +166,7 @@ pub async fn op_crypto_generate_key(
.unwrap()
.map_err(|e| custom_error("DOMExceptionOperationError", e.to_string()))?;
- private_key.to_pkcs8_der()?.as_ref().to_vec()
+ private_key.to_pkcs1_der()?.as_ref().to_vec()
}
Algorithm::Ecdsa => {
let curve: &EcdsaSigningAlgorithm =
@@ -270,7 +272,7 @@ pub async fn op_crypto_sign_key(
let signature = match algorithm {
Algorithm::RsassaPkcs1v15 => {
- let private_key = RsaPrivateKey::from_pkcs8_der(&*args.key.data)?;
+ let private_key = RsaPrivateKey::from_pkcs1_der(&*args.key.data)?;
let (padding, hashed) = match args
.hash
.ok_or_else(|| type_error("Missing argument hash".to_string()))?
@@ -320,7 +322,7 @@ pub async fn op_crypto_sign_key(
private_key.sign(padding, &hashed)?
}
Algorithm::RsaPss => {
- let private_key = RsaPrivateKey::from_pkcs8_der(&*args.key.data)?;
+ let private_key = RsaPrivateKey::from_pkcs1_der(&*args.key.data)?;
let salt_len = args
.salt_length
@@ -426,7 +428,7 @@ pub async fn op_crypto_verify_key(
let verification = match algorithm {
Algorithm::RsassaPkcs1v15 => {
let public_key: RsaPublicKey =
- RsaPrivateKey::from_pkcs8_der(&*args.key.data)?.to_public_key();
+ RsaPrivateKey::from_pkcs1_der(&*args.key.data)?.to_public_key();
let (padding, hashed) = match args
.hash
.ok_or_else(|| type_error("Missing argument hash".to_string()))?
@@ -483,7 +485,7 @@ pub async fn op_crypto_verify_key(
.ok_or_else(|| type_error("Missing argument saltLength".to_string()))?
as usize;
let public_key: RsaPublicKey =
- RsaPrivateKey::from_pkcs8_der(&*args.key.data)?.to_public_key();
+ RsaPrivateKey::from_pkcs1_der(&*args.key.data)?.to_public_key();
let rng = OsRng;
let (padding, hashed) = match args
@@ -554,6 +556,137 @@ pub async fn op_crypto_verify_key(
#[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,
+ _zero_copy: Option<ZeroCopyBuf>,
+) -> 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())
+ }
+ // TODO(@littledivy): spki
+ // 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())
+ }
+ // TODO(@littledivy): spki
+ // 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())
+ }
+ // TODO(@littledivy): spki
+ // TODO(@littledivy): jwk
+ _ => unreachable!(),
+ }
+ }
+ _ => Err(type_error("Unsupported algorithm".to_string())),
+ }
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
pub struct DeriveKeyArg {
key: KeyData,
algorithm: Algorithm,
@@ -642,7 +775,7 @@ pub async fn op_crypto_encrypt_key(
match algorithm {
Algorithm::RsaOaep => {
let public_key: RsaPublicKey =
- RsaPrivateKey::from_pkcs8_der(&*args.key.data)?.to_public_key();
+ RsaPrivateKey::from_pkcs1_der(&*args.key.data)?.to_public_key();
let label = args.label.map(|l| String::from_utf8_lossy(&*l).to_string());
let mut rng = OsRng;
let padding = match args
@@ -705,7 +838,7 @@ pub async fn op_crypto_decrypt_key(
match algorithm {
Algorithm::RsaOaep => {
let private_key: RsaPrivateKey =
- RsaPrivateKey::from_pkcs8_der(&*args.key.data)?;
+ RsaPrivateKey::from_pkcs1_der(&*args.key.data)?;
let label = args.label.map(|l| String::from_utf8_lossy(&*l).to_string());
let padding = match args
.hash