First version of basic self-CA
This commit is contained in:
parent
23c040930f
commit
8c4921f797
13 changed files with 419 additions and 12 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
# Private files
|
# Private files
|
||||||
.env
|
.env
|
||||||
|
private-key.pem
|
||||||
|
private-bytes
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
regexes.yaml
|
regexes.yaml
|
62
Cargo.lock
generated
62
Cargo.lock
generated
|
@ -17,6 +17,16 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aead"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aes"
|
name = "aes"
|
||||||
version = "0.7.5"
|
version = "0.7.5"
|
||||||
|
@ -35,7 +45,7 @@ version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6"
|
checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aead",
|
"aead 0.4.3",
|
||||||
"aes",
|
"aes",
|
||||||
"cipher 0.3.0",
|
"cipher 0.3.0",
|
||||||
"ctr",
|
"ctr",
|
||||||
|
@ -549,6 +559,30 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chacha20"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7fc89c7c5b9e7a02dfe45cd2367bae382f9ed31c61ca8debe5f827c420a2f08"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher 0.4.3",
|
||||||
|
"cpufeatures",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chacha20poly1305"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
|
||||||
|
dependencies = [
|
||||||
|
"aead 0.5.1",
|
||||||
|
"chacha20",
|
||||||
|
"cipher 0.4.3",
|
||||||
|
"poly1305",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.22"
|
version = "0.4.22"
|
||||||
|
@ -582,6 +616,7 @@ checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crypto-common",
|
"crypto-common",
|
||||||
"inout",
|
"inout",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -727,6 +762,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
|
"rand_core",
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -896,6 +932,7 @@ dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"base64ct",
|
"base64ct",
|
||||||
"blake3",
|
"blake3",
|
||||||
|
"chacha20poly1305",
|
||||||
"chrono",
|
"chrono",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -1966,6 +2003,17 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "poly1305"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
|
||||||
|
dependencies = [
|
||||||
|
"cpufeatures",
|
||||||
|
"opaque-debug",
|
||||||
|
"universal-hash 0.5.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polyval"
|
name = "polyval"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
|
@ -1975,7 +2023,7 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
"opaque-debug",
|
"opaque-debug",
|
||||||
"universal-hash",
|
"universal-hash 0.4.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3150,6 +3198,16 @@ dependencies = [
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "universal-hash"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
|
|
@ -22,12 +22,12 @@ ulid = "1.0.0"
|
||||||
axum = "0.6.0-rc.1"
|
axum = "0.6.0-rc.1"
|
||||||
tower = "0.4.13"
|
tower = "0.4.13"
|
||||||
|
|
||||||
|
chacha20poly1305 = "0.10.1"
|
||||||
|
argon2 = "0.4.1"
|
||||||
blake3 = "1.3.1"
|
blake3 = "1.3.1"
|
||||||
base64ct = { version = "1.5.2", features = ["alloc"] }
|
base64ct = { version = "1.5.2", features = ["alloc"] }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
|
||||||
argon2 = "0.4.1"
|
|
||||||
|
|
||||||
tokio = { version = "1.21.0", features = ["full"] }
|
tokio = { version = "1.21.0", features = ["full"] }
|
||||||
|
|
||||||
pretty_env_logger = "0.4.0"
|
pretty_env_logger = "0.4.0"
|
||||||
|
@ -48,3 +48,6 @@ user-agent-parser = "0.3.3"
|
||||||
lapin = "2.1.1"
|
lapin = "2.1.1"
|
||||||
|
|
||||||
picky = "7.0.0-rc.3"
|
picky = "7.0.0-rc.3"
|
||||||
|
|
||||||
|
[profile.dev.package.num-bigint-dig]
|
||||||
|
opt-level = 3
|
|
@ -23,7 +23,8 @@ For more information, visit https://driptorch.net/
|
||||||
| DATABASE_URL | PostgreSQL database connection URL | Y |
|
| DATABASE_URL | PostgreSQL database connection URL | Y |
|
||||||
| AMQP_ADDR | Message queue (RabbitMQ) connection URL | Y |
|
| AMQP_ADDR | Message queue (RabbitMQ) connection URL | Y |
|
||||||
| UAP_REGEXES | Path to the [BrowserScope UA regex YAML](https://github.com/ua-parser/uap-core/blob/master/regexes.yaml) | N |
|
| UAP_REGEXES | Path to the [BrowserScope UA regex YAML](https://github.com/ua-parser/uap-core/blob/master/regexes.yaml) | N |
|
||||||
| RSA_KEY | Path to the RSA private key used to create certificates !!! KEEP THIS SAFE !!! SERIOUSLY !!! | Y |
|
| RSA_KEY | Path to the RSA private key used to create certificates !!! KEEP THIS SAFE | Y |
|
||||||
|
| XCC20_KEY | Path to the XChaCha20-Poly1305 key used to encrypt private keys !!! KEEP THIS SAFE | Y |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,11 @@ impl MigrationTrait for Migration {
|
||||||
.binary()
|
.binary()
|
||||||
.not_null()
|
.not_null()
|
||||||
)
|
)
|
||||||
|
.col(ColumnDef::new(Certificate::Nonce)
|
||||||
|
.binary()
|
||||||
|
.not_null()
|
||||||
|
.unique_key()
|
||||||
|
)
|
||||||
.col(ColumnDef::new(Certificate::CertType)
|
.col(ColumnDef::new(Certificate::CertType)
|
||||||
.string()
|
.string()
|
||||||
.not_null()
|
.not_null()
|
||||||
|
@ -52,5 +57,6 @@ pub enum Certificate {
|
||||||
Id,
|
Id,
|
||||||
Data,
|
Data,
|
||||||
Key,
|
Key,
|
||||||
|
Nonce,
|
||||||
CertType
|
CertType
|
||||||
}
|
}
|
||||||
|
|
76
src/cert/generate.rs
Normal file
76
src/cert/generate.rs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
use std::fmt;
|
||||||
|
use std::fmt::Formatter;
|
||||||
|
use picky::x509::{Cert, KeyIdGenMethod};
|
||||||
|
use picky::x509::certificate::{CertError, CertificateBuilder};
|
||||||
|
use picky::x509::date::UtcDate;
|
||||||
|
|
||||||
|
use chrono::prelude::*;
|
||||||
|
use picky::hash::HashAlgorithm;
|
||||||
|
use picky::key::PrivateKey;
|
||||||
|
use picky::signature::SignatureAlgorithm;
|
||||||
|
use picky::x509::name::DirectoryName;
|
||||||
|
|
||||||
|
pub enum InterTarget {
|
||||||
|
CLIENT,
|
||||||
|
PROXY
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for InterTarget {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
InterTarget::CLIENT => write!(f, "CLIENT"),
|
||||||
|
InterTarget::PROXY => write!(f, "PROXY")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn generate_root_cert(key: &PrivateKey) -> Result<Cert, CertError> {
|
||||||
|
let current_date: DateTime<Utc> = Utc::now();
|
||||||
|
|
||||||
|
CertificateBuilder::new()
|
||||||
|
.validity(
|
||||||
|
UtcDate::ymd(
|
||||||
|
current_date.year() as u16,
|
||||||
|
current_date.month() as u8,
|
||||||
|
current_date.day() as u8
|
||||||
|
).unwrap(),
|
||||||
|
UtcDate::ymd(
|
||||||
|
(current_date.year() + 20) as u16,
|
||||||
|
current_date.month() as u8,
|
||||||
|
current_date.day() as u8
|
||||||
|
).unwrap()
|
||||||
|
)
|
||||||
|
.self_signed(DirectoryName::new_common_name("Driptorch"), key)
|
||||||
|
.ca(true)
|
||||||
|
.signature_hash_type(SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_512))
|
||||||
|
.key_id_gen_method(KeyIdGenMethod::SPKFullDER(HashAlgorithm::SHA2_512))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn generate_inter_cert(key: &PrivateKey, target: InterTarget, root: (&Cert, &PrivateKey)) -> Result<Cert, CertError> {
|
||||||
|
let current_date: DateTime<Utc> = Utc::now();
|
||||||
|
|
||||||
|
CertificateBuilder::new()
|
||||||
|
.validity(
|
||||||
|
UtcDate::ymd(
|
||||||
|
current_date.year() as u16,
|
||||||
|
current_date.month() as u8,
|
||||||
|
current_date.day() as u8
|
||||||
|
).unwrap(),
|
||||||
|
UtcDate::ymd(
|
||||||
|
(current_date.year() + 5) as u16,
|
||||||
|
current_date.month() as u8,
|
||||||
|
current_date.day() as u8
|
||||||
|
).unwrap()
|
||||||
|
)
|
||||||
|
.issuer_cert(&root.0, &root.1)
|
||||||
|
.ca(true)
|
||||||
|
.signature_hash_type(SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_512))
|
||||||
|
.key_id_gen_method(KeyIdGenMethod::SPKFullDER(HashAlgorithm::SHA2_512))
|
||||||
|
.pathlen(0)
|
||||||
|
.subject(
|
||||||
|
DirectoryName::new_common_name(format!("Driptorch {}", target.to_string())),
|
||||||
|
key.to_public_key()
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
}
|
39
src/cert/mod.rs
Normal file
39
src/cert/mod.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
use std::{env, fmt, fs};
|
||||||
|
use std::fmt::Formatter;
|
||||||
|
use std::path::Path;
|
||||||
|
use chacha20poly1305::{AeadCore, KeyInit, XChaCha20Poly1305};
|
||||||
|
use chacha20poly1305::aead::{Aead, OsRng};
|
||||||
|
|
||||||
|
pub mod generate;
|
||||||
|
|
||||||
|
pub enum Types {
|
||||||
|
ROOT,
|
||||||
|
CLIENTINTER,
|
||||||
|
PROXYINTER,
|
||||||
|
CLIENTLEAF,
|
||||||
|
PROXYLEAF
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Types {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Types::ROOT => write!(f, "ROOT"),
|
||||||
|
Types::CLIENTINTER => write!(f, "CLIENTINTER"),
|
||||||
|
Types::PROXYINTER => write!(f, "PROXYINTER"),
|
||||||
|
Types::CLIENTLEAF => write!(f, "CLIENTLEAF"),
|
||||||
|
Types::PROXYLEAF => write!(f, "PROXYLEAF")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn encrypt_priv_key(key: Vec<u8>) -> (Vec<u8>, Vec<u8>) {
|
||||||
|
let cipher = XChaCha20Poly1305::new_from_slice(
|
||||||
|
fs::read(
|
||||||
|
Path::new(&env::var("XCC20_KEY").expect("XCC20_KEY must be set!"))
|
||||||
|
).expect("Failed to load the XCC20 key!").as_slice()
|
||||||
|
).expect("Error creating chacha20 cipher!");
|
||||||
|
|
||||||
|
let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
|
||||||
|
|
||||||
|
(nonce.to_vec(), cipher.encrypt(&nonce, key.as_slice()).expect("Failed to encrypt private key!"))
|
||||||
|
}
|
37
src/entities/certificate.rs
Normal file
37
src/entities/certificate.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.2
|
||||||
|
|
||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "certificate")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id: String,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
pub key: Vec<u8>,
|
||||||
|
#[sea_orm(unique)]
|
||||||
|
pub nonce: Vec<u8>,
|
||||||
|
pub cert_type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {
|
||||||
|
#[sea_orm(has_many = "super::proxy::Entity")]
|
||||||
|
Proxy,
|
||||||
|
#[sea_orm(has_many = "super::client::Entity")]
|
||||||
|
Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::proxy::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Proxy.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::client::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Client.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
|
@ -15,14 +15,24 @@ pub struct Model {
|
||||||
pub dns: bool,
|
pub dns: bool,
|
||||||
pub proxy: bool,
|
pub proxy: bool,
|
||||||
pub health: String,
|
pub health: String,
|
||||||
|
pub certificate: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {}
|
pub enum Relation {
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::certificate::Entity",
|
||||||
|
from = "Column::Certificate",
|
||||||
|
to = "super::certificate::Column::Id",
|
||||||
|
on_update = "NoAction",
|
||||||
|
on_delete = "Cascade"
|
||||||
|
)]
|
||||||
|
Certificate,
|
||||||
|
}
|
||||||
|
|
||||||
impl RelationTrait for Relation {
|
impl Related<super::certificate::Entity> for Entity {
|
||||||
fn def(&self) -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
panic!("No RelationDef")
|
Relation::Certificate.def()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
|
||||||
|
pub mod certificate;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod proxy;
|
pub mod proxy;
|
||||||
pub mod record;
|
pub mod record;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.2
|
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.2
|
||||||
|
|
||||||
|
pub use super::certificate::Entity as Certificate;
|
||||||
pub use super::client::Entity as Client;
|
pub use super::client::Entity as Client;
|
||||||
pub use super::proxy::Entity as Proxy;
|
pub use super::proxy::Entity as Proxy;
|
||||||
pub use super::record::Entity as Record;
|
pub use super::record::Entity as Record;
|
||||||
|
|
|
@ -10,10 +10,19 @@ pub struct Model {
|
||||||
pub record: String,
|
pub record: String,
|
||||||
pub port: i32,
|
pub port: i32,
|
||||||
pub active: bool,
|
pub active: bool,
|
||||||
|
pub certificate: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {
|
pub enum Relation {
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::certificate::Entity",
|
||||||
|
from = "Column::Certificate",
|
||||||
|
to = "super::certificate::Column::Id",
|
||||||
|
on_update = "NoAction",
|
||||||
|
on_delete = "Cascade"
|
||||||
|
)]
|
||||||
|
Certificate,
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
belongs_to = "super::record::Entity",
|
belongs_to = "super::record::Entity",
|
||||||
from = "Column::Record",
|
from = "Column::Record",
|
||||||
|
@ -24,6 +33,12 @@ pub enum Relation {
|
||||||
Record,
|
Record,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Related<super::certificate::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Certificate.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Related<super::record::Entity> for Entity {
|
impl Related<super::record::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::Record.def()
|
Relation::Record.def()
|
||||||
|
|
160
src/main.rs
160
src/main.rs
|
@ -10,15 +10,24 @@ use axum::routing::{delete, get, post};
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
use lapin::ConnectionProperties;
|
use lapin::ConnectionProperties;
|
||||||
use picky::key::PrivateKey;
|
use picky::key::PrivateKey;
|
||||||
use sea_orm::{ConnectOptions, Database};
|
use picky::x509::Cert;
|
||||||
|
use sea_orm::{ActiveValue, ColumnTrait, ConnectOptions, Database, EntityTrait, QueryFilter};
|
||||||
use sea_orm_migration::prelude::*;
|
use sea_orm_migration::prelude::*;
|
||||||
use tower::ServiceBuilder;
|
use tower::ServiceBuilder;
|
||||||
|
use ulid::Ulid;
|
||||||
|
use crate::cert::encrypt_priv_key;
|
||||||
|
use crate::cert::generate::{generate_inter_cert, generate_root_cert};
|
||||||
|
use crate::cert::generate::InterTarget::{CLIENT, PROXY};
|
||||||
|
use crate::cert::Types::{CLIENTINTER, PROXYINTER, ROOT};
|
||||||
|
use crate::certificate::Model;
|
||||||
|
use crate::entities::certificate;
|
||||||
|
|
||||||
mod entities;
|
mod entities;
|
||||||
mod dns;
|
mod dns;
|
||||||
mod util;
|
mod util;
|
||||||
mod routes;
|
mod routes;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
|
mod cert;
|
||||||
|
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
@ -58,6 +67,9 @@ async fn main() {
|
||||||
if !Path::new(&env::var("RSA_KEY").expect("RSA_KEY must be set! Halting start-up.")).exists() {
|
if !Path::new(&env::var("RSA_KEY").expect("RSA_KEY must be set! Halting start-up.")).exists() {
|
||||||
error!("Please generate an RSA private key for creating certificates!")
|
error!("Please generate an RSA private key for creating certificates!")
|
||||||
}
|
}
|
||||||
|
if !Path::new(&env::var("XCC20_KEY").expect("XCC20_KEY must be set! Halting start-up.")).exists() {
|
||||||
|
error!("Please generate a 32 bits of randomness to encrypt private keys!")
|
||||||
|
}
|
||||||
|
|
||||||
let root_rsa_key = PrivateKey::from_pem_str(
|
let root_rsa_key = PrivateKey::from_pem_str(
|
||||||
&*fs::read_to_string(
|
&*fs::read_to_string(
|
||||||
|
@ -78,6 +90,152 @@ async fn main() {
|
||||||
.await
|
.await
|
||||||
.expect("Failed to run migrations! Halting start-up.");
|
.expect("Failed to run migrations! Halting start-up.");
|
||||||
|
|
||||||
|
info!("Checking for root cert...");
|
||||||
|
let root_cert_model: Option<Model> = certificate::Entity::find()
|
||||||
|
.filter(certificate::Column::CertType.eq(cert::Types::ROOT.to_string()))
|
||||||
|
.one(&connection)
|
||||||
|
.await
|
||||||
|
.expect("Failed to retrieve the root cert from the database! Halting start-up.");
|
||||||
|
|
||||||
|
let root_cert: Cert;
|
||||||
|
|
||||||
|
match root_cert_model {
|
||||||
|
None => {
|
||||||
|
info!("Generating new root cert...");
|
||||||
|
|
||||||
|
let new_root_cert = generate_root_cert(&root_rsa_key)
|
||||||
|
.await
|
||||||
|
.expect("Failed to generate the root cert from private key! Halting start-up.");
|
||||||
|
|
||||||
|
root_cert = new_root_cert.clone();
|
||||||
|
|
||||||
|
let root_insert = certificate::Entity::insert(certificate::ActiveModel {
|
||||||
|
id: ActiveValue::Set(Ulid::new().to_string()),
|
||||||
|
data: ActiveValue::Set(
|
||||||
|
new_root_cert.to_der().expect("Failed to convert cert into der!")
|
||||||
|
),
|
||||||
|
key: ActiveValue::set(vec![145, 66, 62, 61, 56, 156, 145, 164]),
|
||||||
|
nonce: ActiveValue::set(vec![145, 71, 62, 66, 56, 156, 145, 164]),
|
||||||
|
cert_type: ActiveValue::Set(ROOT.to_string())
|
||||||
|
})
|
||||||
|
.exec(&connection)
|
||||||
|
.await
|
||||||
|
.expect("Failed to insert new root cert into database! Halting start-up.");
|
||||||
|
|
||||||
|
info!("Generated new root cert: {}", root_insert.last_insert_id);
|
||||||
|
}
|
||||||
|
Some(root_cert_model) => {
|
||||||
|
info!("Found root cert: {}", root_cert_model.id);
|
||||||
|
|
||||||
|
root_cert = Cert::from_der(&root_cert_model.data)
|
||||||
|
.expect("Failed to decode root cert!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Checking for proxy intermediate cert...");
|
||||||
|
let proxy_inter_model: Option<Model> = certificate::Entity::find()
|
||||||
|
.filter(certificate::Column::CertType.eq(PROXYINTER.to_string()))
|
||||||
|
.one(&connection)
|
||||||
|
.await
|
||||||
|
.expect("Failed to retrieve the proxy intermediate cert from the database! Halting start-up.");
|
||||||
|
|
||||||
|
let proxy_inter_cert: Cert;
|
||||||
|
|
||||||
|
match proxy_inter_model {
|
||||||
|
None => {
|
||||||
|
info!("Generating proxy intermediate cert...");
|
||||||
|
|
||||||
|
// Generate 4096 bit RSA private key
|
||||||
|
let priv_key = PrivateKey::generate_rsa(4096)
|
||||||
|
.expect("Failed to generate a key");
|
||||||
|
|
||||||
|
let encrypted_priv_key = encrypt_priv_key(priv_key
|
||||||
|
.clone()
|
||||||
|
.to_pkcs8()
|
||||||
|
.expect("Failed to convert generated private key to pkcs8!")
|
||||||
|
).await;
|
||||||
|
|
||||||
|
let new_proxy_inter_cert = generate_inter_cert(&priv_key, PROXY, (&root_cert, &root_rsa_key))
|
||||||
|
.await
|
||||||
|
.expect("Failed to generate new proxy intermediate cert");
|
||||||
|
|
||||||
|
proxy_inter_cert = new_proxy_inter_cert.clone();
|
||||||
|
|
||||||
|
let proxy_inter_insert = certificate::Entity::insert(certificate::ActiveModel {
|
||||||
|
id: ActiveValue::Set(Ulid::new().to_string()),
|
||||||
|
data: ActiveValue::Set(
|
||||||
|
new_proxy_inter_cert.to_der().expect("Failed to convert cert into der!")
|
||||||
|
),
|
||||||
|
key: ActiveValue::set(encrypted_priv_key.1),
|
||||||
|
nonce: ActiveValue::set(encrypted_priv_key.0),
|
||||||
|
cert_type: ActiveValue::Set(PROXYINTER.to_string())
|
||||||
|
})
|
||||||
|
.exec(&connection)
|
||||||
|
.await
|
||||||
|
.expect("Failed to insert new proxy intermediate cert into database! Halting start-up.");
|
||||||
|
|
||||||
|
info!("Generated new proxy intermediate cert: {}", proxy_inter_insert.last_insert_id)
|
||||||
|
}
|
||||||
|
Some(proxy_inter_model) => {
|
||||||
|
info!("Found proxy intermediate cert: {}", proxy_inter_model.id);
|
||||||
|
|
||||||
|
proxy_inter_cert = Cert::from_der(&proxy_inter_model.data)
|
||||||
|
.expect("Failed to decode proxy intermediate cert!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Checking for client intermediate cert...");
|
||||||
|
let client_inter_model: Option<Model> = certificate::Entity::find()
|
||||||
|
.filter(certificate::Column::CertType.eq(CLIENTINTER.to_string()))
|
||||||
|
.one(&connection)
|
||||||
|
.await
|
||||||
|
.expect("Failed to retrieve the client intermediate cert from the database! Halting start-up.");
|
||||||
|
|
||||||
|
let client_inter_cert: Cert;
|
||||||
|
|
||||||
|
match client_inter_model {
|
||||||
|
None => {
|
||||||
|
info!("Generating client intermediate cert...");
|
||||||
|
|
||||||
|
// Generate 4096 bit RSA private key
|
||||||
|
let priv_key = PrivateKey::generate_rsa(4096)
|
||||||
|
.expect("Failed to generate a key");
|
||||||
|
|
||||||
|
let encrypted_priv_key = encrypt_priv_key(priv_key
|
||||||
|
.clone()
|
||||||
|
.to_pkcs8()
|
||||||
|
.expect("Failed to convert generated private key to pkcs8!")
|
||||||
|
).await;
|
||||||
|
|
||||||
|
let new_client_inter_cert = generate_inter_cert(&priv_key, CLIENT, (&root_cert, &root_rsa_key))
|
||||||
|
.await
|
||||||
|
.expect("Failed to generate new client intermediate cert");
|
||||||
|
|
||||||
|
client_inter_cert = new_client_inter_cert.clone();
|
||||||
|
|
||||||
|
let client_inter_insert = certificate::Entity::insert(certificate::ActiveModel {
|
||||||
|
id: ActiveValue::Set(Ulid::new().to_string()),
|
||||||
|
data: ActiveValue::Set(
|
||||||
|
new_client_inter_cert.to_der().expect("Failed to convert cert into der!")
|
||||||
|
),
|
||||||
|
key: ActiveValue::set(encrypted_priv_key.1),
|
||||||
|
nonce: ActiveValue::set(encrypted_priv_key.0),
|
||||||
|
cert_type: ActiveValue::Set(CLIENTINTER.to_string())
|
||||||
|
})
|
||||||
|
.exec(&connection)
|
||||||
|
.await
|
||||||
|
.expect("Failed to insert new client intermediate cert into database! Halting start-up.");
|
||||||
|
|
||||||
|
info!("Generated new client intermediate cert: {}", client_inter_insert.last_insert_id)
|
||||||
|
}
|
||||||
|
Some(client_inter_model) => {
|
||||||
|
info!("Found client intermediate cert: {}", client_inter_model.id);
|
||||||
|
|
||||||
|
client_inter_cert = Cert::from_der(&client_inter_model.data)
|
||||||
|
.expect("Failed to decode client intermediate cert!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
info!("Connecting to message broker...");
|
info!("Connecting to message broker...");
|
||||||
let amqp_addr = env::var("AMQP_ADDR")
|
let amqp_addr = env::var("AMQP_ADDR")
|
||||||
.expect("AMQP_ADDR mut be set! Halting start-up.");
|
.expect("AMQP_ADDR mut be set! Halting start-up.");
|
||||||
|
|
Loading…
Add table
Reference in a new issue