mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-10 06:23:44 +02:00
Add a subject signature to the certificate to ensure no CRL tampering has occurred, even by the signer.
This commit is contained in:
parent
76244f0474
commit
ec2919ac2e
7 changed files with 182 additions and 91 deletions
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue