mirror of
https://github.com/denoland/deno.git
synced 2024-12-23 15:49:44 -05:00
fix(ext/node): exporting rsa public keys (#23596)
Initial support for exporting rsa public KeyObject. Current assumption is that RSA keys are stored in pkcs1 der format in key storage. Ref https://github.com/denoland/deno/issues/23471 Ref https://github.com/denoland/deno/issues/18928 Ref https://github.com/denoland/deno/issues/21124
This commit is contained in:
parent
7d93704591
commit
b02ffec37c
5 changed files with 73 additions and 10 deletions
|
@ -241,6 +241,8 @@ deno_core::extension!(deno_node,
|
|||
ops::crypto::op_node_ecdh_compute_secret,
|
||||
ops::crypto::op_node_ecdh_compute_public_key,
|
||||
ops::crypto::op_node_ecdh_encode_pubkey,
|
||||
ops::crypto::op_node_export_rsa_public_pem,
|
||||
ops::crypto::op_node_export_rsa_spki_der,
|
||||
ops::crypto::x509::op_node_x509_parse,
|
||||
ops::crypto::x509::op_node_x509_ca,
|
||||
ops::crypto::x509::op_node_x509_check_email,
|
||||
|
|
|
@ -42,6 +42,7 @@ use rsa::Oaep;
|
|||
use rsa::Pkcs1v15Encrypt;
|
||||
use rsa::RsaPrivateKey;
|
||||
use rsa::RsaPublicKey;
|
||||
use spki::EncodePublicKey;
|
||||
|
||||
mod cipher;
|
||||
mod dh;
|
||||
|
@ -681,13 +682,32 @@ pub async fn op_node_generate_rsa_async(
|
|||
spawn_blocking(move || generate_rsa(modulus_length, public_exponent)).await?
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[string]
|
||||
pub fn op_node_export_rsa_public_pem(
|
||||
#[buffer] pkcs1_der: &[u8],
|
||||
) -> Result<String, AnyError> {
|
||||
let public_key = RsaPublicKey::from_pkcs1_der(pkcs1_der)?;
|
||||
let export = public_key.to_public_key_pem(Default::default())?;
|
||||
Ok(export)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
pub fn op_node_export_rsa_spki_der(
|
||||
#[buffer] pkcs1_der: &[u8],
|
||||
) -> Result<ToJsBuffer, AnyError> {
|
||||
let public_key = RsaPublicKey::from_pkcs1_der(pkcs1_der)?;
|
||||
let export = public_key.to_public_key_der()?.to_vec();
|
||||
Ok(export.into())
|
||||
}
|
||||
|
||||
fn dsa_generate(
|
||||
modulus_length: usize,
|
||||
divisor_length: usize,
|
||||
) -> Result<(ToJsBuffer, ToJsBuffer), AnyError> {
|
||||
let mut rng = rand::thread_rng();
|
||||
use dsa::pkcs8::EncodePrivateKey;
|
||||
use dsa::pkcs8::EncodePublicKey;
|
||||
use dsa::Components;
|
||||
use dsa::KeySize;
|
||||
use dsa::SigningKey;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
import { KeyObject } from "ext:deno_node/internal/crypto/keys.ts";
|
||||
import { kAesKeyLengths } from "ext:deno_node/internal/crypto/util.ts";
|
||||
import {
|
||||
PrivateKeyObject,
|
||||
PublicKeyObject,
|
||||
SecretKeyObject,
|
||||
setOwnedKey,
|
||||
} from "ext:deno_node/internal/crypto/keys.ts";
|
||||
|
@ -564,8 +566,8 @@ export function generateKeyPair(
|
|||
) => void,
|
||||
) {
|
||||
createJob(kAsync, type, options).then(([privateKey, publicKey]) => {
|
||||
privateKey = new KeyObject("private", setOwnedKey(privateKey));
|
||||
publicKey = new KeyObject("public", setOwnedKey(publicKey));
|
||||
privateKey = new PrivateKeyObject(setOwnedKey(privateKey), { type });
|
||||
publicKey = new PublicKeyObject(setOwnedKey(publicKey), { type });
|
||||
|
||||
if (typeof options === "object" && options !== null) {
|
||||
const { publicKeyEncoding, privateKeyEncoding } = options as any;
|
||||
|
@ -766,8 +768,8 @@ export function generateKeyPairSync(
|
|||
| KeyPairSyncResult<string | Buffer, string | Buffer> {
|
||||
let [privateKey, publicKey] = createJob(kSync, type, options);
|
||||
|
||||
privateKey = new KeyObject("private", setOwnedKey(privateKey));
|
||||
publicKey = new KeyObject("public", setOwnedKey(publicKey));
|
||||
privateKey = new PrivateKeyObject(setOwnedKey(privateKey), { type });
|
||||
publicKey = new PublicKeyObject(setOwnedKey(publicKey), { type });
|
||||
|
||||
if (typeof options === "object" && options !== null) {
|
||||
const { publicKeyEncoding, privateKeyEncoding } = options as any;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
import {
|
||||
op_node_create_private_key,
|
||||
op_node_create_public_key,
|
||||
op_node_export_rsa_public_pem,
|
||||
op_node_export_rsa_spki_der,
|
||||
} from "ext:core/ops";
|
||||
|
||||
import {
|
||||
|
@ -360,7 +362,7 @@ class AsymmetricKeyObject extends KeyObject {
|
|||
}
|
||||
}
|
||||
|
||||
class PrivateKeyObject extends AsymmetricKeyObject {
|
||||
export class PrivateKeyObject extends AsymmetricKeyObject {
|
||||
constructor(handle: unknown, details: unknown) {
|
||||
super("private", handle, details);
|
||||
}
|
||||
|
@ -370,13 +372,35 @@ class PrivateKeyObject extends AsymmetricKeyObject {
|
|||
}
|
||||
}
|
||||
|
||||
class PublicKeyObject extends AsymmetricKeyObject {
|
||||
export class PublicKeyObject extends AsymmetricKeyObject {
|
||||
constructor(handle: unknown, details: unknown) {
|
||||
super("public", handle, details);
|
||||
}
|
||||
|
||||
export(_options: unknown) {
|
||||
notImplemented("crypto.PublicKeyObject.prototype.export");
|
||||
export(options: unknown) {
|
||||
const key = KEY_STORE.get(this[kHandle]);
|
||||
switch (this.asymmetricKeyType) {
|
||||
case "rsa":
|
||||
case "rsa-pss": {
|
||||
switch (options.format) {
|
||||
case "pem":
|
||||
return op_node_export_rsa_public_pem(key);
|
||||
case "der": {
|
||||
if (options.type == "pkcs1") {
|
||||
return key;
|
||||
} else {
|
||||
return op_node_export_rsa_spki_der(key);
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new TypeError(`exporting ${options.type} is not implemented`);
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new TypeError(
|
||||
`exporting ${this.asymmetricKeyType} is not implemented`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -414,4 +438,6 @@ export default {
|
|||
prepareSecretKey,
|
||||
setOwnedKey,
|
||||
SecretKeyObject,
|
||||
PrivateKeyObject,
|
||||
PublicKeyObject,
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
} from "node:crypto";
|
||||
import { promisify } from "node:util";
|
||||
import { Buffer } from "node:buffer";
|
||||
import { assertEquals, assertThrows } from "@std/assert/mod.ts";
|
||||
import { assert, assertEquals, assertThrows } from "@std/assert/mod.ts";
|
||||
|
||||
const RUN_SLOW_TESTS = Deno.env.get("SLOW_TESTS") === "1";
|
||||
|
||||
|
@ -402,3 +402,16 @@ SogaIHQjE81ZkmNtU5gM5Q==
|
|||
`jEwckJ/d5GkF/8TTm+wllq2JNghG/m2JYJIW7vS8Vms53zCTTNSSegTSoIVoxWymwTPw2dTtZi41Lg0O271/WvEmQhiWD2dnjz6D/0F4eyn+QUhcmGCadDFyfp7+8x1XOppSw2YB8vL5WCL0QDdp3TAa/rWI0Hn4OftHMa6HPvatkGs+8XlQOGCCfd3TLg+t1UROgpgmetjoAM67mlwxXMGGu/Tr/EbXnnINKeB0iuSmD1FCxlrgFuYWDKxd79n2jZ74FrS/zto+bqWSI5uUa4Ar7yvXtek1Cu1OFM6vgdN9Y6Po2UD9+IT04EhU03LUDY5paYOO8yohz7p7kqHvpA==`,
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("generate rsa export public key", async function () {
|
||||
const { publicKey } = await generateKeyPairAsync("rsa", {
|
||||
modulusLength: 2048,
|
||||
});
|
||||
|
||||
const spkiPem = publicKey.export({ format: "pem", type: "spki" });
|
||||
assert(typeof spkiPem === "string");
|
||||
assert(spkiPem.startsWith("-----BEGIN PUBLIC KEY-----"));
|
||||
|
||||
const der = publicKey.export({ format: "der", type: "spki" });
|
||||
assert(der instanceof Uint8Array);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue