update ssl utils

This commit is contained in:
DecDuck
2024-10-08 21:18:30 +11:00
parent 98f8801f57
commit 946ec23606
3 changed files with 201 additions and 63 deletions

View File

@ -15,19 +15,8 @@ rayon = "1.10.0"
serde = "1.0.210"
ciborium = "0.2.2"
time = "0.3.36"
[dependencies.x509-verify]
version = "0.4.6"
features = [
"pem",
"ecdsa"
]
[dependencies.rcgen]
version = "0.13.1"
features = [
"x509-parser"
]
openssl = "0.10.66"
hex = "0.4.3"
[dependencies.uuid]
version = "1.10.0"

View File

@ -1,6 +1,6 @@
{
"name": "@drop/droplet",
"version": "0.2.0",
"version": "0.3.0",
"main": "index.js",
"types": "index.d.ts",
"napi": {

View File

@ -1,37 +1,80 @@
use napi::Error;
use rcgen::{
date_time_ymd, generate_simple_self_signed, BasicConstraints, Certificate, CertificateParams,
DistinguishedName, DnType, Ia5String, IsCa, KeyIdMethod, KeyPair, KeyUsagePurpose, SanType,
PKCS_ECDSA_P384_SHA384,
use openssl::{
asn1::Asn1Time,
bn::{BigNum, MsbOption},
ec::{EcGroup, EcKey},
hash::MessageDigest,
nid::Nid,
pkey::PKey,
sign::{Signer, Verifier},
ssl::{SslConnector, SslContext, SslMethod},
stack::Stack,
x509::{
extension::{AuthorityKeyIdentifier, BasicConstraints, KeyUsage, SubjectKeyIdentifier},
store::X509StoreBuilder,
X509Builder, X509NameBuilder, X509ReqBuilder, X509StoreContext, X509,
},
};
use time::{Duration, OffsetDateTime};
use x509_verify::der::DecodePem;
const YEAR: i64 = 60 * 60 * 24 * 365;
#[napi]
pub fn generate_root_ca() -> Result<Vec<String>, Error> {
let mut params = CertificateParams::new(Vec::new()).unwrap();
let nid = Nid::X9_62_PRIME256V1;
let group = EcGroup::from_curve_name(nid).unwrap();
let private_key = EcKey::generate(&group).unwrap();
let mut name = DistinguishedName::new();
name.push(DnType::CommonName, "Drop Root CA");
name.push(DnType::OrganizationName, "Drop");
let mut x509_builder = X509Builder::new().unwrap();
x509_builder.set_version(2).unwrap();
params.distinguished_name = name;
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
params.key_usages = vec![
KeyUsagePurpose::DigitalSignature,
KeyUsagePurpose::KeyCertSign,
];
let serial_number = {
let mut serial = BigNum::new().unwrap();
serial.rand(159, MsbOption::MAYBE_ZERO, false).unwrap();
serial.to_asn1_integer().unwrap()
};
x509_builder.set_serial_number(&serial_number).unwrap();
let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P384_SHA384).unwrap();
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 root_ca = CertificateParams::self_signed(params, &key_pair).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(),
)
.unwrap();
let key_pair = PKey::from_ec_key(private_key).unwrap();
x509_builder.set_pubkey(&key_pair).unwrap();
x509_builder
.sign(&key_pair, MessageDigest::sha256())
.unwrap();
let x509 = x509_builder.build();
return Ok(vec![
key_pair.serialize_pem(),
key_pair.public_key_pem(),
root_ca.pem(),
String::from_utf8(x509.to_pem().unwrap()).unwrap(),
String::from_utf8(key_pair.private_key_to_pem_pkcs8().unwrap()).unwrap(),
]);
}
@ -42,43 +85,149 @@ pub fn generate_client_certificate(
root_ca: String,
root_ca_private: String,
) -> Result<Vec<String>, Error> {
let root_key_pair = KeyPair::from_pem(&root_ca_private).unwrap();
let root_ca_params = CertificateParams::from_ca_cert_pem(&root_ca).unwrap();
let root_ca = root_ca_params.self_signed(&root_key_pair).unwrap();
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 mut params = CertificateParams::new(Vec::new()).unwrap();
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 name = DistinguishedName::new();
name.push(DnType::CommonName, client_id);
name.push(DnType::OrganizationName, "Drop");
/* Generate req and sign it */
let mut req_builder = X509ReqBuilder::new().unwrap();
req_builder.set_pubkey(&key_pair).unwrap();
params.distinguished_name = name;
params.subject_alt_names = vec![SanType::DnsName(Ia5String::try_from(client_name).unwrap())];
params.key_usages = vec![
KeyUsagePurpose::DigitalSignature,
KeyUsagePurpose::KeyCertSign,
];
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();
let client_key_pair = KeyPair::generate_for(&PKCS_ECDSA_P384_SHA384).unwrap();
let client_certificate = params
.signed_by(&client_key_pair, &root_ca, &root_key_pair)
req_builder.set_subject_name(&x509_name_built).unwrap();
req_builder
.sign(&key_pair, MessageDigest::sha256())
.unwrap();
let req = req_builder.build();
/* 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 = {
let mut serial = BigNum::new().unwrap();
serial.rand(159, MsbOption::MAYBE_ZERO, false).unwrap();
serial.to_asn1_integer().unwrap()
};
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();
return Ok(vec![
root_key_pair.serialize_pem(),
root_key_pair.public_key_pem(),
client_certificate.pem(),
String::from_utf8(x509.to_pem().unwrap()).unwrap(),
String::from_utf8(key_pair.private_key_to_pem_pkcs8().unwrap()).unwrap(),
]);
}
#[napi]
pub fn verify_client_certificate(client_cert: String, root_ca: String) -> Result<bool, Error> {
let ca = x509_verify::x509_cert::Certificate::from_pem(root_ca).unwrap();
let client = x509_verify::x509_cert::Certificate::from_pem(client_cert).unwrap();
let root_ca_cert = X509::from_pem(root_ca.as_bytes()).unwrap();
let key = x509_verify::VerifyingKey::try_from(&ca).unwrap();
return Ok(match key.verify(&client) {
Ok(_) => true,
Err(_) => false,
});
let mut store_builder = X509StoreBuilder::new().unwrap();
store_builder.add_cert(root_ca_cert).unwrap();
let store = store_builder.build();
let client_cert: X509 = X509::from_pem(client_cert.as_bytes()).unwrap();
let chain = Stack::new().unwrap();
let mut store_ctx = X509StoreContext::new().unwrap();
let result = store_ctx
.init(&store, &client_cert, &chain, |c| c.verify_cert())
.unwrap();
return Ok(result);
}
#[napi]
pub fn sign_nonce(private_key: String, nonce: String) -> Result<String, Error> {
let client_private_key = EcKey::private_key_from_pem(private_key.as_bytes()).unwrap();
let pkey_private_key = PKey::from_ec_key(client_private_key).unwrap();
let mut signer = Signer::new(MessageDigest::sha256(), &pkey_private_key).unwrap();
signer.update(nonce.as_bytes()).unwrap();
let signature = signer.sign_to_vec().unwrap();
let hex_signature = hex::encode(signature);
return Ok(hex_signature);
}
#[napi]
pub fn verify_nonce(public_cert: String, nonce: String, signature: String) -> Result<bool, Error> {
let client_public_cert = X509::from_pem(public_cert.as_bytes()).unwrap();
let client_public_key = client_public_cert.public_key().unwrap();
let signature = hex::decode(signature).unwrap();
let mut verifier = Verifier::new(
MessageDigest::sha256(),
&client_public_key,
)
.unwrap();
verifier.update(nonce.as_bytes()).unwrap();
let result = verifier.verify(&signature).unwrap();
return Ok(result);
}