diff --git a/core/CAPI.cpp b/core/CAPI.cpp index 7e43621a6..1d2ff834f 100644 --- a/core/CAPI.cpp +++ b/core/CAPI.cpp @@ -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 csrV(ZeroTier::Certificate::createCSR(*subject, certificatePublicKey, (unsigned int)certificatePublicKeySize, uniqueIdPrivateKey, (unsigned int)uniqueIdPrivateKeySize)); + const ZeroTier::Vector 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()); diff --git a/core/Certificate.cpp b/core/Certificate.cpp index 2fd16c813..4a7826025 100644 --- a/core/Certificate.cpp +++ b/core/Certificate.cpp @@ -204,6 +204,8 @@ Vector 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& 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 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 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(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 Certificate::createCSR(const ZT_Certificate_Subject& s, const void* const certificatePublicKey, const unsigned int certificatePublicKeySize, const void* uniqueIdPrivate, unsigned int uniqueIdPrivateSize) +Vector Certificate::createCSR(const ZT_Certificate_Subject& s, const void* const certificatePrivateKey, const unsigned int certificatePrivateKeySize, const void* uniqueIdPrivate, unsigned int uniqueIdPrivateSize) { Vector enc; ZT_Certificate_Subject sc; Utils::copy(&sc, &s); + if ((! certificatePrivateKey) || (certificatePrivateKeySize != (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE)) + || (reinterpret_cast(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(certificatePrivateKey) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, subjectHash, subjectSig); + + d.add("pK", reinterpret_cast(certificatePrivateKey), (1 + ZT_ECC384_PUBLIC_KEY_SIZE)); + d.add("sS", subjectSig, ZT_ECC384_SIGNATURE_SIZE); + d.encode(enc); } diff --git a/core/Certificate.hpp b/core/Certificate.hpp index fdc8afd3e..9c589f715 100644 --- a/core/Certificate.hpp +++ b/core/Certificate.hpp @@ -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 createCSR(const ZT_Certificate_Subject& s, const void* certificatePublicKey, unsigned int certificatePublicKeySize, const void* uniqueIdPrivate, unsigned int uniqueIdPrivateSize); + static Vector 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 { diff --git a/core/zerotier.h b/core/zerotier.h index 1912c25de..4c5945fcf 100644 --- a/core/zerotier.h +++ b/core/zerotier.h @@ -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. diff --git a/rust-zerotier-core/src/certificate.rs b/rust-zerotier-core/src/certificate.rs index bd4b142fa..4ccf8ae25 100644 --- a/rust-zerotier-core/src/certificate.rs +++ b/rust-zerotier-core/src/certificate.rs @@ -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(v: &Vec) -> [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, ResultCode> { + pub fn new_csr(&self, certifcate_private_key: &[u8], subject_unique_id_private_key: Option<&[u8]>) -> Result, ResultCode> { let mut csr: Vec = 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::(), 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, #[serde(rename = "publicKey")] pub public_key: Vec, + #[serde(rename = "subjectSignature")] + pub subject_signature: Vec, #[serde(rename = "extendedAttributes")] pub extended_attributes: Vec, #[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() diff --git a/service/src/commands/cert.rs b/service/src/commands/cert.rs index 422d18553..5a668fef7 100644 --- a/service/src/commands/cert.rs +++ b/service/src/commands/cert.rs @@ -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, 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, cli_args: &ArgMatches<'a>) -> i32 { + let theme = &dialoguer::theme::SimpleTheme; + 0 } diff --git a/service/src/main.rs b/service/src/main.rs index 194500598..345e77d09 100644 --- a/service/src/main.rs +++ b/service/src/main.rs @@ -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 [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 + } } }); }