Add a subject signature to the certificate to ensure no CRL tampering has occurred, even by the signer.

This commit is contained in:
Adam Ierymenko 2021-04-27 19:10:48 -04:00
parent 76244f0474
commit ec2919ac2e
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
7 changed files with 182 additions and 91 deletions

View file

@ -627,17 +627,17 @@ ZT_Certificate_newKeyPair(const enum ZT_CertificatePublicKeyAlgorithm type, uint
ZT_MAYBE_UNUSED int ZT_Certificate_newCSR(
const ZT_Certificate_Subject* subject,
const void* const certificatePublicKey,
const int certificatePublicKeySize,
const void* const certificatePrivateKey,
const int certificatePrivateKeySize,
const void* const uniqueIdPrivateKey,
const int uniqueIdPrivateKeySize,
void* const csr,
int* const csrSize)
{
try {
if ((! subject) || (! certificatePublicKey) || (certificatePublicKeySize <= 0) || (certificatePublicKeySize > ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE))
if ((! subject) || (! certificatePrivateKey) || (certificatePrivateKeySize <= 0))
return ZT_RESULT_ERROR_BAD_PARAMETER;
const ZeroTier::Vector<uint8_t> csrV(ZeroTier::Certificate::createCSR(*subject, certificatePublicKey, (unsigned int)certificatePublicKeySize, uniqueIdPrivateKey, (unsigned int)uniqueIdPrivateKeySize));
const ZeroTier::Vector<uint8_t> csrV(ZeroTier::Certificate::createCSR(*subject, certificatePrivateKey, (unsigned int)certificatePrivateKeySize, uniqueIdPrivateKey, (unsigned int)uniqueIdPrivateKeySize));
if (csrV.empty() || ((int)csrV.size() > *csrSize))
return ZT_RESULT_ERROR_BAD_PARAMETER;
ZeroTier::Utils::copy(csr, csrV.data(), (unsigned int)csrV.size());

View file

@ -204,6 +204,8 @@ Vector<uint8_t> Certificate::encode(const bool omitSignature) const
if (this->publicKeySize > 0)
d.add("pK", this->publicKey, this->publicKeySize);
if (this->subjectSignatureSize > 0)
d.add("sS", this->subjectSignature, this->subjectSignatureSize);
if ((this->extendedAttributes != nullptr) && (this->extendedAttributesSize > 0))
d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize);
@ -311,6 +313,11 @@ bool Certificate::decode(const void* const data, const unsigned int len)
Utils::copy(this->publicKey, publicKey.data(), publicKey.size());
this->publicKeySize = (unsigned int)publicKey.size();
}
const Vector<uint8_t>& subjectSignature = d["sS"];
if ((! subjectSignature.empty()) && (subjectSignature.size() <= sizeof(this->subjectSignature))) {
Utils::copy(this->subjectSignature, subjectSignature.data(), subjectSignature.size());
this->subjectSignatureSize = (unsigned int)subjectSignature.size();
}
m_extendedAttributes = d["x"];
if (! m_extendedAttributes.empty()) {
@ -414,18 +421,12 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
}
}
if ((this->subject.uniqueIdSize > sizeof(this->subject.uniqueId)) || (this->subject.uniqueIdSignatureSize > sizeof(this->subject.uniqueIdSignature))) {
if ((this->subject.uniqueIdSize > sizeof(this->subject.uniqueId)) || (this->subject.uniqueIdSignatureSize > sizeof(this->subject.uniqueIdSignature)) || (this->issuerPublicKeySize > sizeof(this->issuerPublicKey)) || (this->publicKeySize > sizeof(this->publicKey)) || (this->subjectSignatureSize > sizeof(this->subjectSignature))) {
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
}
if ((this->issuerPublicKeySize > sizeof(this->issuerPublicKey)) || (this->publicKeySize > sizeof(this->publicKey))) {
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
}
if ((this->extendedAttributesSize > 0) && (! this->extendedAttributes)) {
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
}
if (this->signatureSize > sizeof(this->signature)) {
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
}
@ -434,7 +435,7 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
// Signature check fails if main signature is not present or invalid.
// Note that the serial number / SHA384 hash is computed on decode(), so
// this value is not something we blindly trust from input.
if ((this->issuerPublicKeySize > 0) && (this->issuerPublicKeySize <= (unsigned int)sizeof(this->issuerPublicKey))) {
if (this->issuerPublicKeySize > 0) {
switch (this->issuerPublicKey[0]) {
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
if ((this->issuerPublicKeySize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) && (this->signatureSize == ZT_ECC384_SIGNATURE_SIZE)) {
@ -454,6 +455,37 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
}
Dictionary d;
Vector<uint8_t> enc;
// Check subject signature to verify that CRL was intact and the
// public key was the one intended by the CRL creator.
if (this->publicKeySize > 0) {
d.clear();
m_encodeSubject(this->subject, d, false);
d.encode(enc);
switch (this->publicKey[0]) {
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
if ((this->publicKeySize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) && (this->subjectSignatureSize == ZT_ECC384_SIGNATURE_SIZE)) {
uint8_t h[ZT_SHA384_DIGEST_SIZE];
SHA384(h, enc.data(), (unsigned int)enc.size());
if (! ECC384ECDSAVerify(this->publicKey + 1, h, this->subjectSignature)) {
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
}
}
else {
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
}
break;
default:
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
}
}
else {
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
}
// Subject unique ID signatures are optional, so this only fails if it
// is present and invalid. A unique ID with type ALGORITHM_NONE is also
// allowed, but this means its signature is not checked.
@ -464,11 +496,8 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
break;
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
if ((this->subject.uniqueIdSize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) && (this->subject.uniqueIdSignatureSize == ZT_ECC384_SIGNATURE_SIZE)) {
Dictionary d;
d.clear();
m_encodeSubject(this->subject, d, true);
Vector<uint8_t> enc;
enc.reserve(1024);
d.encode(enc);
static_assert(ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE, "ECC384 should take 384-bit hash");
@ -513,7 +542,7 @@ bool Certificate::newKeyPair(const ZT_CertificatePublicKeyAlgorithm type, uint8_
ZeroTier::ECC384GenerateKey(publicKey + 1, privateKey + ZT_ECC384_PUBLIC_KEY_SIZE + 1);
ZeroTier::Utils::copy<ZT_ECC384_PUBLIC_KEY_SIZE + 1>(privateKey, publicKey);
*publicKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1;
*privateKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1 + ZT_ECC384_PRIVATE_KEY_SIZE;
*privateKeySize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE;
return true;
default:
break;
@ -521,18 +550,29 @@ bool Certificate::newKeyPair(const ZT_CertificatePublicKeyAlgorithm type, uint8_
return false;
}
Vector<uint8_t> Certificate::createCSR(const ZT_Certificate_Subject& s, const void* const certificatePublicKey, const unsigned int certificatePublicKeySize, const void* uniqueIdPrivate, unsigned int uniqueIdPrivateSize)
Vector<uint8_t> Certificate::createCSR(const ZT_Certificate_Subject& s, const void* const certificatePrivateKey, const unsigned int certificatePrivateKeySize, const void* uniqueIdPrivate, unsigned int uniqueIdPrivateSize)
{
Vector<uint8_t> enc;
ZT_Certificate_Subject sc;
Utils::copy<sizeof(ZT_Certificate_Subject)>(&sc, &s);
if ((! certificatePrivateKey) || (certificatePrivateKeySize != (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE))
|| (reinterpret_cast<const uint8_t*>(certificatePrivateKey)[0] != ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384))
return enc;
if (m_setSubjectUniqueId(sc, uniqueIdPrivate, uniqueIdPrivateSize)) {
Dictionary d;
m_encodeSubject(sc, d, false);
if (certificatePublicKeySize > 0)
d.add("pK", certificatePublicKey, certificatePublicKeySize);
d.encode(enc);
uint8_t subjectHash[ZT_SHA384_DIGEST_SIZE], subjectSig[ZT_ECC384_SIGNATURE_SIZE];
SHA384(subjectHash, enc.data(), (unsigned int)enc.size());
ECC384ECDSASign(reinterpret_cast<const uint8_t*>(certificatePrivateKey) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, subjectHash, subjectSig);
d.add("pK", reinterpret_cast<const uint8_t*>(certificatePrivateKey), (1 + ZT_ECC384_PUBLIC_KEY_SIZE));
d.add("sS", subjectSig, ZT_ECC384_SIGNATURE_SIZE);
d.encode(enc);
}

View file

@ -182,13 +182,13 @@ class Certificate : public ZT_Certificate {
* Create a CSR that encodes the subject of this certificate
*
* @param s Subject to encode
* @param certificatePublicKey Public key for certificate
* @param certificatePublicKeySize Size of public key
* @param certificatePrivateKey Private key for certificate (includes public)
* @param certificatePrivateKeySize Size of private
* @param uniqueIdPrivate Unique ID private key for proof signature or NULL if none
* @param uniqueIdPrivateSize Size of unique ID private key
* @return Encoded subject (without any unique ID fields) or empty vector on error
*/
static Vector<uint8_t> createCSR(const ZT_Certificate_Subject& s, const void* certificatePublicKey, unsigned int certificatePublicKeySize, const void* uniqueIdPrivate, unsigned int uniqueIdPrivateSize);
static Vector<uint8_t> createCSR(const ZT_Certificate_Subject& s, const void* certificatePrivateKey, unsigned int certificatePrivateKeySize, const void* uniqueIdPrivate, unsigned int uniqueIdPrivateSize);
ZT_INLINE unsigned long hashCode() const noexcept
{

View file

@ -670,6 +670,14 @@ typedef struct {
*/
uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE];
/**
* Signature of subject with public key.
*
* This couples the subject to the public key, ensuring that the CRL was
* not modified in transit or by the signer.
*/
uint8_t subjectSignature[ZT_CERTIFICATE_MAX_SIGNATURE_SIZE];
/**
* Size of issuer public key.
*/
@ -680,6 +688,11 @@ typedef struct {
*/
unsigned int publicKeySize;
/**
* Size of subject signature in bytes
*/
unsigned int subjectSignatureSize;
/**
* Extended attributes set by issuer (in Dictionary format, NULL if none)
*/
@ -2720,15 +2733,15 @@ ZT_Certificate_newKeyPair(enum ZT_CertificatePublicKeyAlgorithm type, uint8_t pu
* supplied subject, these will be ignored.
*
* @param subject Subject filled in with fields for CSR
* @param certificatePublicKey Public key for new certificate
* @param certificatePublicKeySize Public key size in bytes
* @param certificatePrivateKey Private key for new certificate
* @param certificatePrivateKeySize Private key size in bytes
* @param uniqueIdPrivateKey Unique ID private key or NULL if none
* @param uniqueIdPrivateKeySize Size of unique ID private key
* @param csr Buffer to hold CSR (recommended size: 16384 bytes)
* @param csrSize Value/result: size of buffer
* @return OK (0) or error
*/
ZT_SDK_API int ZT_Certificate_newCSR(const ZT_Certificate_Subject* subject, const void* certificatePublicKey, int certificatePublicKeySize, const void* uniqueIdPrivateKey, int uniqueIdPrivateKeySize, void* csr, int* csrSize);
ZT_SDK_API int ZT_Certificate_newCSR(const ZT_Certificate_Subject* subject, const void* certificatePrivateKey, int certificatePrivateKeySize, const void* uniqueIdPrivateKey, int uniqueIdPrivateKeySize, void* csr, int* csrSize);
/**
* Sign a CSR to generate a complete certificate.

View file

@ -13,10 +13,10 @@
use std::ffi::CString;
use std::hash::{Hash, Hasher};
use std::mem::{zeroed, MaybeUninit};
use std::mem::zeroed;
use std::os::raw::{c_char, c_uint, c_void};
use std::pin::Pin;
use std::ptr::{copy_nonoverlapping, null, null_mut, read_unaligned, write_bytes};
use std::ptr::{copy_nonoverlapping, null, null_mut, read_unaligned};
use num_derive::{FromPrimitive, ToPrimitive};
#[allow(unused_imports)]
@ -42,19 +42,6 @@ pub const CERTIFICATE_USAGE_CRL_SIGNING: u64 = ztcore::ZT_CERTIFICATE_USAGE_CRL_
pub const CERTIFICATE_USAGE_EXECUTABLE_SIGNATURE: u64 = ztcore::ZT_CERTIFICATE_USAGE_EXECUTABLE_SIGNATURE as u64;
pub const CERTIFICATE_USAGE_TIMESTAMPING: u64 = ztcore::ZT_CERTIFICATE_USAGE_TIMESTAMPING as u64;
/// All certificate usage flags and their corresponding canonical abbreviations.
pub const ALL_CERTIFICATE_USAGE_FLAGS: [(u64, &'static str); 9] = [
(CERTIFICATE_USAGE_DIGITAL_SIGNATURE, "ds"),
(CERTIFICATE_USAGE_NON_REPUDIATION, "nr"),
(CERTIFICATE_USAGE_KEY_ENCIPHERMENT, "ke"),
(CERTIFICATE_USAGE_DATA_ENCIPHERMENT, "de"),
(CERTIFICATE_USAGE_KEY_AGREEMENT, "ka"),
(CERTIFICATE_USAGE_CERTIFICATE_SIGNING, "cs"),
(CERTIFICATE_USAGE_CRL_SIGNING, "crl"),
(CERTIFICATE_USAGE_EXECUTABLE_SIGNATURE, "es"),
(CERTIFICATE_USAGE_TIMESTAMPING, "ts"),
];
#[inline(always)]
fn vec_to_array<const L: usize>(v: &Vec<u8>) -> [u8; L] {
let mut a = [0_u8; L];
@ -532,7 +519,7 @@ impl CertificateSubject {
/// Create a new certificate signing request.
/// A CSR is a Certificate containing only the subject (with optional unique ID and signature)
/// and its private key. Other fields must be filled in by the owner of the signing certificate.
pub fn new_csr(&self, certificate_public_key: &[u8], subject_unique_id_private_key: Option<&[u8]>) -> Result<Vec<u8>, ResultCode> {
pub fn new_csr(&self, certifcate_private_key: &[u8], subject_unique_id_private_key: Option<&[u8]>) -> Result<Vec<u8>, ResultCode> {
let mut csr: Vec<u8> = Vec::new();
csr.resize(65536, 0);
let mut csr_size: c_int = 65536;
@ -540,7 +527,7 @@ impl CertificateSubject {
let (uid, uid_size) = subject_unique_id_private_key.map_or((null::<u8>(), 0 as c_int), |b| (b.as_ptr(), b.len() as c_int));
let r = unsafe {
let s = self.to_capi();
ztcore::ZT_Certificate_newCSR(&s.subject, certificate_public_key.as_ptr().cast(), certificate_public_key.len() as c_int, uid.cast(), uid_size, csr.as_mut_ptr().cast(), &mut csr_size)
ztcore::ZT_Certificate_newCSR(&s.subject, certifcate_private_key.as_ptr().cast(), certifcate_private_key.len() as c_int, uid.cast(), uid_size, csr.as_mut_ptr().cast(), &mut csr_size)
};
if r == 0 {
@ -569,6 +556,8 @@ pub struct Certificate {
pub issuer_public_key: Vec<u8>,
#[serde(rename = "publicKey")]
pub public_key: Vec<u8>,
#[serde(rename = "subjectSignature")]
pub subject_signature: Vec<u8>,
#[serde(rename = "extendedAttributes")]
pub extended_attributes: Vec<u8>,
#[serde(with = "Base64URLSafeNoPad")]
@ -615,6 +604,7 @@ impl Certificate {
issuer: CertificateSerialNo::new(),
issuer_public_key: Vec::new(),
public_key: Vec::new(),
subject_signature: Vec::new(),
extended_attributes: Vec::new(),
max_path_length: 0,
signature: Vec::new(),
@ -631,6 +621,7 @@ impl Certificate {
issuer: CertificateSerialNo(c.issuer),
issuer_public_key: c.issuerPublicKey[0..(c.issuerPublicKeySize as usize)].to_vec(),
public_key: c.publicKey[0..(c.publicKeySize as usize)].to_vec(),
subject_signature: c.subjectSignature[0..(c.subjectSignatureSize as usize)].to_vec(),
extended_attributes: Vec::from(std::slice::from_raw_parts(c.extendedAttributes, c.extendedAttributesSize as usize)),
max_path_length: c.maxPathLength as u32,
signature: c.signature[0..(c.signatureSize as usize)].to_vec(),
@ -649,8 +640,10 @@ impl Certificate {
issuer: self.issuer.0,
issuerPublicKey: vec_to_array(&self.issuer_public_key),
publicKey: vec_to_array(&self.public_key),
subjectSignature: vec_to_array(&self.subject_signature),
issuerPublicKeySize: self.issuer_public_key.len() as c_uint,
publicKeySize: self.public_key.len() as c_uint,
subjectSignatureSize: self.subject_signature.len() as c_uint,
extendedAttributes: self.extended_attributes.as_ptr(),
extendedAttributesSize: self.extended_attributes.len() as c_uint,
maxPathLength: self.max_path_length as c_uint,
@ -747,6 +740,7 @@ mod tests {
issuer: CertificateSerialNo::new(),
issuer_public_key: issuer_pubk,
public_key: pubk.clone(),
subject_signature: Vec::new(),
extended_attributes: Vec::new(),
max_path_length: 123,
signature: Vec::new()

View file

@ -22,8 +22,49 @@ use crate::store::Store;
use crate::utils::{read_limit, ms_since_epoch, to_json_pretty};
use crate::GlobalFlags;
/// Dump a certificate in human-readable format to stdout.
fn dump_cert(certificate: &Certificate) {
fn cert_usage_flags_to_string(flags: u64) -> String {
let mut flags_str = String::new();
for f in [
(CERTIFICATE_USAGE_DIGITAL_SIGNATURE, "s"),
(CERTIFICATE_USAGE_NON_REPUDIATION, "n"),
(CERTIFICATE_USAGE_KEY_ENCIPHERMENT, "e"),
(CERTIFICATE_USAGE_DATA_ENCIPHERMENT, "d"),
(CERTIFICATE_USAGE_KEY_AGREEMENT, "a"),
(CERTIFICATE_USAGE_CERTIFICATE_SIGNING, "c"),
(CERTIFICATE_USAGE_CRL_SIGNING, "r"),
(CERTIFICATE_USAGE_EXECUTABLE_SIGNATURE, "x"),
(CERTIFICATE_USAGE_TIMESTAMPING, "t"),
].iter() {
if (flags & (*f).0) != 0 {
if !flags_str.is_empty() {
flags_str.push(',');
}
flags_str.push_str((*f).1);
}
}
flags_str
}
fn cert_string_to_usage_flags(flags_str: &str) -> u64 {
let mut flags: u64 = 0;
for c in flags_str.chars().into_iter() {
flags |= match c {
's' => CERTIFICATE_USAGE_DIGITAL_SIGNATURE,
'n' => CERTIFICATE_USAGE_NON_REPUDIATION,
'e' => CERTIFICATE_USAGE_KEY_ENCIPHERMENT,
'd' => CERTIFICATE_USAGE_DATA_ENCIPHERMENT,
'a' => CERTIFICATE_USAGE_KEY_AGREEMENT,
'c' => CERTIFICATE_USAGE_CERTIFICATE_SIGNING,
'r' => CERTIFICATE_USAGE_CRL_SIGNING,
'x' => CERTIFICATE_USAGE_EXECUTABLE_SIGNATURE,
't' => CERTIFICATE_USAGE_TIMESTAMPING,
_ => 0,
}
}
flags
}
fn cert_print(certificate: &Certificate) {
let mut subject_identities = String::new();
let mut subject_networks = String::new();
let mut subject_update_urls = String::new();
@ -74,14 +115,7 @@ fn dump_cert(certificate: &Certificate) {
if certificate.usage_flags != 0 {
usage_flags.push_str(" (");
for f in ALL_CERTIFICATE_USAGE_FLAGS.iter() {
if (certificate.usage_flags & (*f).0) != 0 {
if !usage_flags.is_empty() {
usage_flags.push(',');
}
usage_flags.push_str((*f).1);
}
}
usage_flags.push_str(cert_usage_flags_to_string(certificate.usage_flags).as_str());
usage_flags.push(')');
}
@ -163,7 +197,7 @@ fn show<'a>(store: &Arc<Store>, global_flags: &GlobalFlags, cli_args: &ArgMatche
if global_flags.json_output {
println!("{}", to_json_pretty(&certificate));
} else {
dump_cert(&certificate);
cert_print(&certificate);
}
let cv = certificate.verify(ms_since_epoch());
if cv != CertificateError::None {
@ -347,7 +381,7 @@ fn newcsr(cli_args: &ArgMatches) -> i32 {
println!("Certificate name information (all fields are optional)");
let name = CertificateName {
serial_no: Input::with_theme(theme).with_prompt(" Serial").allow_empty(true).interact_text().unwrap_or_default(),
serial_no: Input::with_theme(theme).with_prompt(" Serial (user-defined)").allow_empty(true).interact_text().unwrap_or_default(),
common_name: Input::with_theme(theme).with_prompt(" Common Name").allow_empty(true).interact_text().unwrap_or_default(),
organization: Input::with_theme(theme).with_prompt(" Organization").allow_empty(true).interact_text().unwrap_or_default(),
unit: Input::with_theme(theme).with_prompt(" Organizational Unit").allow_empty(true).interact_text().unwrap_or_default(),
@ -370,8 +404,9 @@ fn newcsr(cli_args: &ArgMatches) -> i32 {
unique_id: Vec::new(),
unique_id_signature: Vec::new(),
};
let (pubk, privk) = Certificate::new_key_pair(CertificatePublicKeyAlgorithm::ECDSANistP384).ok().unwrap();
subject.new_csr(pubk.as_ref(), subject_unique_id_private_key.as_ref().map(|k| k.as_ref())).map_or_else(|e| {
let (_, privk) = Certificate::new_key_pair(CertificatePublicKeyAlgorithm::ECDSANistP384).ok().unwrap();
subject.new_csr(privk.as_ref(), subject_unique_id_private_key.as_ref().map(|k| k.as_ref())).map_or_else(|e| {
println!("ERROR: error creating CRL: {}", e.to_str());
1
}, |csr| {
@ -394,6 +429,8 @@ fn newcsr(cli_args: &ArgMatches) -> i32 {
}
fn sign<'a>(store: &Arc<Store>, cli_args: &ArgMatches<'a>) -> i32 {
let theme = &dialoguer::theme::SimpleTheme;
0
}

View file

@ -56,7 +56,8 @@ Global Options:
Common Operations:
help Show this help
version Print version
oldhelp Show v1.x legacy commands
version Print version (of this binary)
· status Show node status and configuration
@ -118,9 +119,9 @@ Advanced Operations:
cert <command> [args]
· list List certificates at local node
show <@cert|·serial> Show certificate details
newsuid [@secret] Create a subject unique ID secret
newcsr <@csr> <@secret> Create a CSR (interactive)
sign <@csr> <@secret> <@cert> Sign a CSR to create a certificate
newsuid [@secret out] Create a subject unique ID secret
newcsr <@csr> <@secret out> Create a CSR (interactive)
sign <@csr> <@secret> <@cert out> Sign a CSR to create a certificate
verify <@cert> Internally verify certificate
· import <@cert> [trust,trust,...] Import certificate into this node
trust flag: rootca Root (or self-signed) CA
@ -130,8 +131,8 @@ Advanced Operations:
· factoryreset Re-import compiled-in default certs
· Command (or command with argument type) requires a running node.
@ Argument is a path to an object, not the object itself.
? Argument can be either an inline value or a path to it.
@ Argument is the path to a file containing the object.
? Argument can be either the object or a path to it (auto-detected).
"###, ver.0, ver.1, ver.2)
}
@ -313,34 +314,40 @@ fn main() {
args
};
std::process::exit(match cli_args.subcommand() {
("help", _) => {
print_help();
0
}
("version", _) => {
let ver = zerotier_core::version();
println!("{}.{}.{}", ver.0, ver.1, ver.2);
0
}
("status", _) => crate::httpclient::run_command(make_store(&cli_args), get_global_flags(&cli_args), crate::commands::status::run),
("set", Some(sub_cli_args)) => { 0 }
("peer", Some(sub_cli_args)) => { 0 }
("network", Some(sub_cli_args)) => { 0 }
("join", Some(sub_cli_args)) => { 0 }
("leave", Some(sub_cli_args)) => { 0 }
("service", _) => {
let store = make_store(&cli_args);
drop(cli_args); // free no longer needed memory before entering service
service::run(store)
},
("controller", Some(sub_cli_args)) => { 0 }
("identity", Some(sub_cli_args)) => crate::commands::identity::run(sub_cli_args),
("locator", Some(sub_cli_args)) => crate::commands::locator::run(sub_cli_args),
("cert", Some(sub_cli_args)) => crate::commands::cert::run(make_store(&cli_args), get_global_flags(&cli_args), sub_cli_args),
_ => {
print_help();
1
std::process::exit({
match cli_args.subcommand() {
("help", _) => {
print_help();
0
}
("oldhelp", _) => {
// TODO
0
}
("version", _) => {
let ver = zerotier_core::version();
println!("{}.{}.{}", ver.0, ver.1, ver.2);
0
}
("status", _) => crate::httpclient::run_command(make_store(&cli_args), get_global_flags(&cli_args), crate::commands::status::run),
("set", Some(sub_cli_args)) => { 0 }
("peer", Some(sub_cli_args)) => { 0 }
("network", Some(sub_cli_args)) => { 0 }
("join", Some(sub_cli_args)) => { 0 }
("leave", Some(sub_cli_args)) => { 0 }
("service", _) => {
let store = make_store(&cli_args);
drop(cli_args); // free no longer needed memory before entering service
service::run(store)
},
("controller", Some(sub_cli_args)) => { 0 }
("identity", Some(sub_cli_args)) => crate::commands::identity::run(sub_cli_args),
("locator", Some(sub_cli_args)) => crate::commands::locator::run(sub_cli_args),
("cert", Some(sub_cli_args)) => crate::commands::cert::run(make_store(&cli_args), get_global_flags(&cli_args), sub_cli_args),
_ => {
print_help();
1
}
}
});
}