mirror of
https://github.com/denoland/deno.git
synced 2024-12-23 23:59:59 -05:00
feat(ext/crypto): export spki for RSA (#12114)
This commit is contained in:
parent
d5b38a9929
commit
3aa8591595
5 changed files with 162 additions and 10 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -733,6 +733,7 @@ dependencies = [
|
|||
"serde",
|
||||
"sha-1",
|
||||
"sha2",
|
||||
"spki",
|
||||
"tokio",
|
||||
"uuid",
|
||||
]
|
||||
|
@ -3302,9 +3303,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "987637c5ae6b3121aba9d513f869bd2bff11c4cc086c22473befd6649c0bd521"
|
||||
checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32"
|
||||
dependencies = [
|
||||
"der",
|
||||
]
|
||||
|
|
|
@ -441,7 +441,7 @@ const asn1AlgorithmIdentifier = new Uint8Array([
|
|||
0x05, 0x00, // NULL
|
||||
]);
|
||||
|
||||
unitTest(async function rsaExportPkcs8() {
|
||||
unitTest(async function rsaExport() {
|
||||
for (const algorithm of ["RSASSA-PKCS1-v1_5", "RSA-PSS", "RSA-OAEP"]) {
|
||||
const keyPair = await crypto.subtle.generateKey(
|
||||
{
|
||||
|
@ -458,21 +458,34 @@ unitTest(async function rsaExportPkcs8() {
|
|||
assert(keyPair.publicKey);
|
||||
assertEquals(keyPair.privateKey.extractable, true);
|
||||
|
||||
const exportedKey = await crypto.subtle.exportKey(
|
||||
const exportedPrivateKey = await crypto.subtle.exportKey(
|
||||
"pkcs8",
|
||||
keyPair.privateKey,
|
||||
);
|
||||
|
||||
assert(exportedKey);
|
||||
assert(exportedKey instanceof ArrayBuffer);
|
||||
assert(exportedPrivateKey);
|
||||
assert(exportedPrivateKey instanceof ArrayBuffer);
|
||||
|
||||
const pkcs8 = new Uint8Array(exportedKey);
|
||||
const pkcs8 = new Uint8Array(exportedPrivateKey);
|
||||
assert(pkcs8.length > 0);
|
||||
|
||||
assertEquals(
|
||||
pkcs8.slice(4, asn1AlgorithmIdentifier.byteLength + 4),
|
||||
asn1AlgorithmIdentifier,
|
||||
);
|
||||
|
||||
const exportedPublicKey = await crypto.subtle.exportKey(
|
||||
"spki",
|
||||
keyPair.publicKey,
|
||||
);
|
||||
|
||||
const spki = new Uint8Array(exportedPublicKey);
|
||||
assert(spki.length > 0);
|
||||
|
||||
assertEquals(
|
||||
spki.slice(4, asn1AlgorithmIdentifier.byteLength + 1),
|
||||
asn1AlgorithmIdentifier.slice(3),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1278,6 +1278,28 @@
|
|||
// 3.
|
||||
return data.buffer;
|
||||
}
|
||||
case "spki": {
|
||||
// 1.
|
||||
if (key[_type] !== "public") {
|
||||
throw new DOMException(
|
||||
"Key is not a public key",
|
||||
"InvalidAccessError",
|
||||
);
|
||||
}
|
||||
|
||||
// 2.
|
||||
const data = await core.opAsync(
|
||||
"op_crypto_export_key",
|
||||
{
|
||||
key: innerKey,
|
||||
format: "spki",
|
||||
algorithm: "RSASSA-PKCS1-v1_5",
|
||||
},
|
||||
);
|
||||
|
||||
// 3.
|
||||
return data.buffer;
|
||||
}
|
||||
default:
|
||||
throw new DOMException("Not implemented", "NotSupportedError");
|
||||
}
|
||||
|
@ -1307,6 +1329,29 @@
|
|||
// 3.
|
||||
return data.buffer;
|
||||
}
|
||||
case "spki": {
|
||||
// 1.
|
||||
if (key[_type] !== "public") {
|
||||
throw new DOMException(
|
||||
"Key is not a public key",
|
||||
"InvalidAccessError",
|
||||
);
|
||||
}
|
||||
|
||||
// 2.
|
||||
const data = await core.opAsync(
|
||||
"op_crypto_export_key",
|
||||
{
|
||||
key: innerKey,
|
||||
format: "spki",
|
||||
algorithm: "RSA-PSS",
|
||||
hash: key[_algorithm].hash.name,
|
||||
},
|
||||
);
|
||||
|
||||
// 3.
|
||||
return data.buffer;
|
||||
}
|
||||
default:
|
||||
throw new DOMException("Not implemented", "NotSupportedError");
|
||||
}
|
||||
|
@ -1336,6 +1381,29 @@
|
|||
// 3.
|
||||
return data.buffer;
|
||||
}
|
||||
case "spki": {
|
||||
// 1.
|
||||
if (key[_type] !== "public") {
|
||||
throw new DOMException(
|
||||
"Key is not a public key",
|
||||
"InvalidAccessError",
|
||||
);
|
||||
}
|
||||
|
||||
// 2.
|
||||
const data = await core.opAsync(
|
||||
"op_crypto_export_key",
|
||||
{
|
||||
key: innerKey,
|
||||
format: "spki",
|
||||
algorithm: "RSA-OAEP",
|
||||
hash: key[_algorithm].hash.name,
|
||||
},
|
||||
);
|
||||
|
||||
// 3.
|
||||
return data.buffer;
|
||||
}
|
||||
default:
|
||||
throw new DOMException("Not implemented", "NotSupportedError");
|
||||
}
|
||||
|
|
|
@ -24,5 +24,6 @@ rsa = { version = "0.5.0", default-features = false, features = ["std"] }
|
|||
serde = { version = "1.0.129", features = ["derive"] }
|
||||
sha-1 = "0.9.7"
|
||||
sha2 = "0.9.5"
|
||||
spki = "0.4.1"
|
||||
tokio = { version = "1.10.1", features = ["full"] }
|
||||
uuid = { version = "0.8.2", features = ["v4"] }
|
||||
|
|
|
@ -271,6 +271,7 @@ pub async fn op_crypto_generate_key(
|
|||
pub enum KeyFormat {
|
||||
Raw,
|
||||
Pkcs8,
|
||||
Spki,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -631,7 +632,27 @@ pub async fn op_crypto_export_key(
|
|||
|
||||
Ok(pk_info.to_der().as_ref().to_vec().into())
|
||||
}
|
||||
// TODO(@littledivy): spki
|
||||
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!(),
|
||||
}
|
||||
|
@ -668,7 +689,31 @@ pub async fn op_crypto_export_key(
|
|||
|
||||
Ok(pk_info.to_der().as_ref().to_vec().into())
|
||||
}
|
||||
// TODO(@littledivy): spki
|
||||
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!(),
|
||||
}
|
||||
|
@ -705,7 +750,31 @@ pub async fn op_crypto_export_key(
|
|||
|
||||
Ok(pk_info.to_der().as_ref().to_vec().into())
|
||||
}
|
||||
// TODO(@littledivy): spki
|
||||
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!(),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue