chore: update partial ssl.rs to rcgen

This commit is contained in:
DecDuck
2025-03-20 16:24:26 +11:00
parent 5313622341
commit 3209bcd01d
6 changed files with 168 additions and 185 deletions
+13 -7
View File
@@ -1,25 +1,31 @@
[package]
edition = "2021"
name = "droplet"
version = "0.0.0"
version = "0.7.0"
[lib]
crate-type = ["cdylib"]
[dependencies]
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { version = "2.12.2", default-features = false, features = ["napi4", "async"] }
napi = { version = "2.12.2", default-features = false, features = [
"napi4",
"async",
] }
napi-derive = "2.12.2"
time = "0.3.36"
hex = "0.4.3"
serde_json = "1.0.128"
md5 = "0.7.0"
time-macros = "=0.2.21"
time = "0.3.40"
[dependencies.rcgen]
version = "0.13.2"
features = ["crypto", "pem", "x509-parser"]
[dependencies.serde]
version = "1.0.210"
features = [
"serde_derive"
]
features = ["serde_derive"]
[dependencies.openssl]
version = "0.10.66"
@@ -37,4 +43,4 @@ napi-build = "2.0.1"
[profile.release]
lto = true
strip = "symbols"
strip = "symbols"
+1 -1
View File
@@ -75,7 +75,7 @@ test("single large file", async (t) => {
const writeStream = fs.createWriteStream(testFile);
randomReadStream.pipe(writeStream);
await new Promise((r) => randomReadStream.on("end", r));
await new Promise<void>((r) => randomReadStream.on("end", r));
const manifest: {
[key: string]: { lengths: number[] };
+44
View File
@@ -4,7 +4,10 @@ import {
generateRootCa,
generateClientCertificate,
verifyClientCertificate,
signNonce,
verifyNonce,
} from "../index.js";
import { randomUUID, sign } from "crypto";
test("generate ca", (t) => {
const [pub, priv] = generateRootCa();
@@ -36,7 +39,48 @@ test("trust chain", (t) => {
priv
);
const [invalidPub, invalidPriv] = generateRootCa();
const valid = verifyClientCertificate(clientPub, pub);
if (valid) return t.pass();
const invalid = verifyClientCertificate(invalidPub, pub);
if (!invalid) return t.pass();
return t.fail();
});
test("nonce signing", (t) => {
const [pub, priv] = generateRootCa();
const [clientPub, clientPriv] = generateClientCertificate(
"test",
"test",
pub,
priv
);
const nonce = randomUUID();
const signature = signNonce(clientPriv, nonce);
return t.pass();
});
test("nonce signing, and verification", (t) => {
const [pub, priv] = generateRootCa();
const [clientPub, clientPriv] = generateClientCertificate(
"test",
"test",
pub,
priv
);
const nonce = randomUUID();
const signature = signNonce(clientPriv, nonce);
const valid = verifyNonce(clientPub, nonce, signature);
if (!valid) return t.fail();
return t.pass();
});
+1
View File
@@ -26,6 +26,7 @@
"license": "MIT",
"devDependencies": {
"@napi-rs/cli": "^2.18.4",
"@types/node": "^22.13.10",
"ava": "^6.0.1"
},
"ava": {
+44 -129
View File
@@ -15,6 +15,11 @@ use openssl::{
X509Builder, X509NameBuilder, X509ReqBuilder, X509StoreContext, X509,
},
};
use rcgen::{
Certificate, CertificateParams, DistinguishedName, ExtendedKeyUsagePurpose, Ia5String, IsCa,
KeyPair, KeyUsagePurpose, SanType, SerialNumber,
};
use time::{Duration, OffsetDateTime};
fn create_serial_number() -> Asn1Integer {
let mut serial = BigNum::new().unwrap();
@@ -24,60 +29,33 @@ fn create_serial_number() -> Asn1Integer {
#[napi]
pub fn generate_root_ca() -> Result<Vec<String>, Error> {
let nid = Nid::X9_62_PRIME256V1;
let group = EcGroup::from_curve_name(nid).unwrap();
let private_key = EcKey::generate(&group).unwrap();
let mut params = CertificateParams::default();
let mut x509_builder = X509Builder::new().unwrap();
x509_builder.set_version(2).unwrap();
let mut name = DistinguishedName::new();
name.push(rcgen::DnType::CommonName, "Drop Root Server");
name.push(rcgen::DnType::OrganizationName, "Drop");
let serial_number = create_serial_number();
x509_builder.set_serial_number(&serial_number).unwrap();
params.distinguished_name = name;
let mut x509_name = X509NameBuilder::new().unwrap();
x509_name
.append_entry_by_nid(Nid::COMMONNAME, "Drop Root Server")
.unwrap();
x509_name
.append_entry_by_nid(Nid::ORGANIZATIONNAME, "Drop")
.unwrap();
let x509_name_built = x509_name.build();
x509_builder.set_subject_name(&x509_name_built).unwrap();
x509_builder.set_issuer_name(&x509_name_built).unwrap();
let not_before = Asn1Time::days_from_now(0).unwrap();
x509_builder.set_not_before(&not_before).unwrap();
let not_after = Asn1Time::days_from_now(365 * 1000).unwrap();
x509_builder.set_not_after(&not_after).unwrap();
x509_builder
.append_extension(BasicConstraints::new().critical().ca().build().unwrap())
.unwrap();
x509_builder
.append_extension(
KeyUsage::new()
.critical()
.key_cert_sign()
.crl_sign()
.digital_signature()
.build()
.unwrap(),
)
params.not_before = OffsetDateTime::now_utc();
params.not_after = OffsetDateTime::now_utc()
.checked_add(Duration::days(365 * 1000))
.unwrap();
let key_pair = PKey::from_ec_key(private_key).unwrap();
x509_builder.set_pubkey(&key_pair).unwrap();
params.is_ca = IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
x509_builder
.sign(&key_pair, MessageDigest::sha256())
.unwrap();
params.key_usages = vec![
KeyUsagePurpose::CrlSign,
KeyUsagePurpose::KeyCertSign,
KeyUsagePurpose::DigitalSignature,
];
let x509 = x509_builder.build();
let key_pair = KeyPair::generate().map_err(|e| napi::Error::from_reason(e.to_string()))?;
let certificate = CertificateParams::self_signed(params, &key_pair)
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(vec![
String::from_utf8(x509.to_pem().unwrap()).unwrap(),
String::from_utf8(key_pair.private_key_to_pem_pkcs8().unwrap()).unwrap(),
])
// Returns certificate, then private key
Ok(vec![certificate.pem(), key_pair.serialize_pem()])
}
#[napi]
@@ -87,94 +65,31 @@ pub fn generate_client_certificate(
root_ca: String,
root_ca_private: String,
) -> Result<Vec<String>, Error> {
let root_ca_cert = X509::from_pem(root_ca.as_bytes()).unwrap();
let root_ca_key = EcKey::private_key_from_pem(root_ca_private.as_bytes()).unwrap();
let root_ca_key_pair = PKey::from_ec_key(root_ca_key).unwrap();
let root_key_pair =
KeyPair::from_pem(&root_ca_private).map_err(|e| napi::Error::from_reason(e.to_string()))?;
let certificate_params = CertificateParams::from_ca_cert_pem(&root_ca)
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
let root_ca = CertificateParams::self_signed(certificate_params, &root_key_pair)
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
let nid = Nid::X9_62_PRIME256V1;
let group = EcGroup::from_curve_name(nid).unwrap();
let private_key = EcKey::generate(&group).unwrap();
let key_pair = PKey::from_ec_key(private_key).unwrap();
let mut params = CertificateParams::default();
/* Generate req and sign it */
let mut req_builder = X509ReqBuilder::new().unwrap();
req_builder.set_pubkey(&key_pair).unwrap();
let mut name = DistinguishedName::new();
name.push(rcgen::DnType::CommonName, client_id);
name.push(rcgen::DnType::OrganizationName, "Drop");
params.distinguished_name = name;
let mut x509_name = X509NameBuilder::new().unwrap();
x509_name
.append_entry_by_nid(Nid::COMMONNAME, &client_id)
.unwrap();
x509_name
.append_entry_by_nid(Nid::SUBJECT_ALT_NAME, &client_name)
.unwrap();
x509_name
.append_entry_by_nid(Nid::ORGANIZATIONNAME, "Drop")
.unwrap();
let x509_name_built = x509_name.build();
params.key_usages = vec![
KeyUsagePurpose::DigitalSignature,
KeyUsagePurpose::DataEncipherment,
];
req_builder.set_subject_name(&x509_name_built).unwrap();
req_builder
.sign(&key_pair, MessageDigest::sha256())
.unwrap();
let req = req_builder.build();
let key_pair = KeyPair::generate().map_err(|e| napi::Error::from_reason(e.to_string()))?;
let certificate = CertificateParams::signed_by(params, &key_pair, &root_ca, &root_key_pair)
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
/* Generate certificate from req and sign it using CA */
let mut x509_builder = X509Builder::new().unwrap();
x509_builder.set_version(2).unwrap();
x509_builder.set_pubkey(&key_pair).unwrap();
let serial_number = create_serial_number();
x509_builder.set_serial_number(&serial_number).unwrap();
x509_builder.set_subject_name(req.subject_name()).unwrap();
x509_builder
.set_issuer_name(root_ca_cert.issuer_name())
.unwrap();
let not_before = Asn1Time::days_from_now(0).unwrap();
x509_builder.set_not_before(&not_before).unwrap();
let not_after = Asn1Time::days_from_now(365 * 100).unwrap();
x509_builder.set_not_after(&not_after).unwrap();
x509_builder
.append_extension(BasicConstraints::new().build().unwrap())
.unwrap();
x509_builder
.append_extension(
KeyUsage::new()
.critical()
.non_repudiation()
.digital_signature()
.data_encipherment()
.build()
.unwrap(),
)
.unwrap();
let subject_key_identifier = SubjectKeyIdentifier::new()
.build(&x509_builder.x509v3_context(Some(&root_ca_cert), None))
.unwrap();
x509_builder
.append_extension(subject_key_identifier)
.unwrap();
let auth_key_identifier = AuthorityKeyIdentifier::new()
.keyid(false)
.issuer(false)
.build(&x509_builder.x509v3_context(Some(&root_ca_cert), None))
.unwrap();
x509_builder.append_extension(auth_key_identifier).unwrap();
x509_builder
.sign(&root_ca_key_pair, MessageDigest::sha256())
.unwrap();
let x509 = x509_builder.build();
Ok(vec![
String::from_utf8(x509.to_pem().unwrap()).unwrap(),
String::from_utf8(key_pair.private_key_to_pem_pkcs8().unwrap()).unwrap(),
])
// Returns certificate, then private key
Ok(vec![certificate.pem(), key_pair.serialize_pem()])
}
#[napi]
+65 -48
View File
@@ -10,6 +10,7 @@ __metadata:
resolution: "@drop/droplet@workspace:."
dependencies:
"@napi-rs/cli": "npm:^2.18.4"
"@types/node": "npm:^22.13.10"
ava: "npm:^6.0.1"
languageName: unknown
linkType: soft
@@ -127,6 +128,15 @@ __metadata:
languageName: node
linkType: hard
"@types/node@npm:^22.13.10":
version: 22.13.10
resolution: "@types/node@npm:22.13.10"
dependencies:
undici-types: "npm:~6.20.0"
checksum: 10c0/a3865f9503d6f718002374f7b87efaadfae62faa499c1a33b12c527cfb9fd86f733e1a1b026b80c5a0e4a965701174bc3305595a7d36078aa1abcf09daa5dee9
languageName: node
linkType: hard
"@vercel/nft@npm:^0.27.5":
version: 0.27.10
resolution: "@vercel/nft@npm:0.27.10"
@@ -175,11 +185,11 @@ __metadata:
linkType: hard
"acorn@npm:^8.11.0, acorn@npm:^8.13.0, acorn@npm:^8.6.0":
version: 8.14.0
resolution: "acorn@npm:8.14.0"
version: 8.14.1
resolution: "acorn@npm:8.14.1"
bin:
acorn: bin/acorn
checksum: 10c0/6d4ee461a7734b2f48836ee0fbb752903606e576cc100eb49340295129ca0b452f3ba91ddd4424a1d4406a98adfb2ebb6bd0ff4c49d7a0930c10e462719bbfd7
checksum: 10c0/dbd36c1ed1d2fa3550140000371fcf721578095b18777b85a79df231ca093b08edc6858d75d6e48c73e431c174dcf9214edbd7e6fa5911b93bd8abfa54e47123
languageName: node
linkType: hard
@@ -401,9 +411,9 @@ __metadata:
linkType: hard
"ci-info@npm:^4.0.0":
version: 4.1.0
resolution: "ci-info@npm:4.1.0"
checksum: 10c0/0f969ce32a974c542bc8abe4454b220d9d9323bb9415054c92a900faa5fdda0bb222eda68c490127c1d78503510d46b6aca614ecaba5a60515b8ac7e170119e6
version: 4.2.0
resolution: "ci-info@npm:4.2.0"
checksum: 10c0/37a2f4b6a213a5cf835890eb0241f0d5b022f6cfefde58a69e9af8e3a0e71e06d6ad7754b0d4efb9cd2613e58a7a33996d71b56b0d04242722e86666f3f3d058
languageName: node
linkType: hard
@@ -491,9 +501,9 @@ __metadata:
linkType: hard
"consola@npm:^3.2.3":
version: 3.4.0
resolution: "consola@npm:3.4.0"
checksum: 10c0/bc7f7ad46514375109a80f3ae8330097eb1e5d89232a24eb830f3ac383e22036a62c53d33561cd73d7cda4b3691fba85e3dcf35229ef7721b324aae291ceb40c
version: 3.4.2
resolution: "consola@npm:3.4.2"
checksum: 10c0/7cebe57ecf646ba74b300bcce23bff43034ed6fbec9f7e39c27cee1dc00df8a21cd336b466ad32e304ea70fba04ec9e890c200270de9a526ce021ba8a7e4c11a
languageName: node
linkType: hard
@@ -504,7 +514,7 @@ __metadata:
languageName: node
linkType: hard
"cross-spawn@npm:^7.0.0":
"cross-spawn@npm:^7.0.6":
version: 7.0.6
resolution: "cross-spawn@npm:7.0.6"
dependencies:
@@ -639,7 +649,7 @@ __metadata:
languageName: node
linkType: hard
"fast-glob@npm:^3.3.2":
"fast-glob@npm:^3.3.3":
version: 3.3.3
resolution: "fast-glob@npm:3.3.3"
dependencies:
@@ -653,11 +663,11 @@ __metadata:
linkType: hard
"fastq@npm:^1.6.0":
version: 1.19.0
resolution: "fastq@npm:1.19.0"
version: 1.19.1
resolution: "fastq@npm:1.19.1"
dependencies:
reusify: "npm:^1.0.4"
checksum: 10c0/d6a001638f1574a696660fcbba5300d017760432372c801632c325ca7c16819604841c92fd3ccadcdacec0966ca336363a5ff57bc5f0be335d8ea7ac6087b98f
checksum: 10c0/ebc6e50ac7048daaeb8e64522a1ea7a26e92b3cee5cd1c7f2316cdca81ba543aa40a136b53891446ea5c3a67ec215fbaca87ad405f102dd97012f62916905630
languageName: node
linkType: hard
@@ -687,19 +697,19 @@ __metadata:
linkType: hard
"find-up-simple@npm:^1.0.0":
version: 1.0.0
resolution: "find-up-simple@npm:1.0.0"
checksum: 10c0/de1ad5e55c8c162f5600fe3297bb55a3da5cd9cb8c6755e463ec1d52c4c15a84e312a68397fb5962d13263b3dbd4ea294668c465ccacc41291d7cc97588769f9
version: 1.0.1
resolution: "find-up-simple@npm:1.0.1"
checksum: 10c0/ad34de157b7db925d50ff78302fefb28e309f3bc947c93ffca0f9b0bccf9cf1a2dc57d805d5c94ec9fc60f4838f5dbdfd2a48ecd77c23015fa44c6dd5f60bc40
languageName: node
linkType: hard
"foreground-child@npm:^3.1.0":
version: 3.3.0
resolution: "foreground-child@npm:3.3.0"
version: 3.3.1
resolution: "foreground-child@npm:3.3.1"
dependencies:
cross-spawn: "npm:^7.0.0"
cross-spawn: "npm:^7.0.6"
signal-exit: "npm:^4.0.1"
checksum: 10c0/028f1d41000553fcfa6c4bb5c372963bf3d9bf0b1f25a87d1a6253014343fb69dfb1b42d9625d7cf44c8ba429940f3d0ff718b62105d4d4a4f6ef8ca0a53faa2
checksum: 10c0/8986e4af2430896e65bc2788d6679067294d6aee9545daefc84923a0a4b399ad9c7a3ea7bd8c0b2b80fdf4a92de4c69df3f628233ff3224260e9c1541a9e9ed3
languageName: node
linkType: hard
@@ -764,16 +774,16 @@ __metadata:
linkType: hard
"globby@npm:^14.0.2":
version: 14.0.2
resolution: "globby@npm:14.0.2"
version: 14.1.0
resolution: "globby@npm:14.1.0"
dependencies:
"@sindresorhus/merge-streams": "npm:^2.1.0"
fast-glob: "npm:^3.3.2"
ignore: "npm:^5.2.4"
path-type: "npm:^5.0.0"
fast-glob: "npm:^3.3.3"
ignore: "npm:^7.0.3"
path-type: "npm:^6.0.0"
slash: "npm:^5.1.0"
unicorn-magic: "npm:^0.1.0"
checksum: 10c0/3f771cd683b8794db1e7ebc8b6b888d43496d93a82aad4e9d974620f578581210b6c5a6e75ea29573ed16a1345222fab6e9b877a8d1ed56eeb147e09f69c6f78
unicorn-magic: "npm:^0.3.0"
checksum: 10c0/527a1063c5958255969620c6fa4444a2b2e9278caddd571d46dfbfa307cb15977afb746e84d682ba5b6c94fc081e8997f80ff05dd235441ba1cb16f86153e58e
languageName: node
linkType: hard
@@ -801,10 +811,10 @@ __metadata:
languageName: node
linkType: hard
"ignore@npm:^5.2.4":
version: 5.3.2
resolution: "ignore@npm:5.3.2"
checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337
"ignore@npm:^7.0.3":
version: 7.0.3
resolution: "ignore@npm:7.0.3"
checksum: 10c0/8e21637513cbcd888a4873d34d5c651a2e24b3c4c9a6b159335a26bed348c3c386c51d6fab23577f59140e1b226323138fbd50e63882d4568fd12aa6c822029e
languageName: node
linkType: hard
@@ -983,11 +993,11 @@ __metadata:
linkType: hard
"memoize@npm:^10.0.0":
version: 10.0.0
resolution: "memoize@npm:10.0.0"
version: 10.1.0
resolution: "memoize@npm:10.1.0"
dependencies:
mimic-function: "npm:^5.0.0"
checksum: 10c0/1584351834564be66b21d47b7afe495851f622669ad49e2f4fa4f35d5633471b93176cf602130a95f71fa0aee65a20179817ffac2dd11fa354aa19a8109a14e8
mimic-function: "npm:^5.0.1"
checksum: 10c0/6cf71f673b89778b05cd1131f573ba858627daa8fec60f2197328386acf7ab184a89e52527abbd5a605b5ccf5ee12dc0cb96efb651d9a30dcfcc89e9baacc84d
languageName: node
linkType: hard
@@ -1008,7 +1018,7 @@ __metadata:
languageName: node
linkType: hard
"mimic-function@npm:^5.0.0":
"mimic-function@npm:^5.0.1":
version: 5.0.1
resolution: "mimic-function@npm:5.0.1"
checksum: 10c0/f3d9464dd1816ecf6bdf2aec6ba32c0728022039d992f178237d8e289b48764fee4131319e72eedd4f7f094e22ded0af836c3187a7edc4595d28dd74368fd81d
@@ -1173,10 +1183,10 @@ __metadata:
languageName: node
linkType: hard
"path-type@npm:^5.0.0":
version: 5.0.0
resolution: "path-type@npm:5.0.0"
checksum: 10c0/e8f4b15111bf483900c75609e5e74e3fcb79f2ddb73e41470028fcd3e4b5162ec65da9907be077ee5012c18801ff7fffb35f9f37a077f3f81d85a0b7d6578efd
"path-type@npm:^6.0.0":
version: 6.0.0
resolution: "path-type@npm:6.0.0"
checksum: 10c0/55baa8b1187d6dc683d5a9cfcc866168d6adff58e5db91126795376d818eee46391e00b2a4d53e44d844c7524a7d96aa68cc68f4f3e500d3d069a39e6535481c
languageName: node
linkType: hard
@@ -1243,9 +1253,9 @@ __metadata:
linkType: hard
"reusify@npm:^1.0.4":
version: 1.0.4
resolution: "reusify@npm:1.0.4"
checksum: 10c0/c19ef26e4e188f408922c46f7ff480d38e8dfc55d448310dfb518736b23ed2c4f547fb64a6ed5bdba92cd7e7ddc889d36ff78f794816d5e71498d645ef476107
version: 1.1.0
resolution: "reusify@npm:1.1.0"
checksum: 10c0/4eff0d4a5f9383566c7d7ec437b671cc51b25963bd61bf127c3f3d3f68e44a026d99b8d2f1ad344afff8d278a8fe70a8ea092650a716d22287e8bef7126bb2fa
languageName: node
linkType: hard
@@ -1457,10 +1467,17 @@ __metadata:
languageName: node
linkType: hard
"unicorn-magic@npm:^0.1.0":
version: 0.1.0
resolution: "unicorn-magic@npm:0.1.0"
checksum: 10c0/e4ed0de05b0a05e735c7d8a2930881e5efcfc3ec897204d5d33e7e6247f4c31eac92e383a15d9a6bccb7319b4271ee4bea946e211bf14951fec6ff2cbbb66a92
"undici-types@npm:~6.20.0":
version: 6.20.0
resolution: "undici-types@npm:6.20.0"
checksum: 10c0/68e659a98898d6a836a9a59e6adf14a5d799707f5ea629433e025ac90d239f75e408e2e5ff086afc3cace26f8b26ee52155293564593fbb4a2f666af57fc59bf
languageName: node
linkType: hard
"unicorn-magic@npm:^0.3.0":
version: 0.3.0
resolution: "unicorn-magic@npm:0.3.0"
checksum: 10c0/0a32a997d6c15f1c2a077a15b1c4ca6f268d574cf5b8975e778bb98e6f8db4ef4e86dfcae4e158cd4c7e38fb4dd383b93b13eefddc7f178dea13d3ac8a603271
languageName: node
linkType: hard