mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-05-29 16:43:43 +02:00
API about wrapped.
This commit is contained in:
parent
ab2870cbb7
commit
b1777f09c8
11 changed files with 547 additions and 101 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -38,3 +38,5 @@ node_modules
|
|||
/*.db
|
||||
/*.opendb
|
||||
/rust-zerotier-core/src/bindings/capi.rs
|
||||
/rust-zerotier-core/target
|
||||
/rust-zerotier-service/target
|
||||
|
|
52
rust-zerotier-core/Cargo.lock
generated
52
rust-zerotier-core/Cargo.lock
generated
|
@ -6,6 +6,18 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.3.3"
|
||||
|
@ -48,8 +60,48 @@ dependencies = [
|
|||
name = "rust-zerotier-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -9,3 +9,6 @@ edition = "2018"
|
|||
[dependencies]
|
||||
num-traits = "0.2.14"
|
||||
num-derive = "0.3.3"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
hex = "0.4.2"
|
||||
|
|
|
@ -1,9 +1,41 @@
|
|||
pub type Address = u64;
|
||||
pub struct Address(pub u64);
|
||||
|
||||
pub fn address_to_string(a: Address) -> String {
|
||||
format!("{:0>10x}", a as u64)
|
||||
impl Address {
|
||||
#[inline]
|
||||
pub fn new_from_string(s: &str) -> Address {
|
||||
return Address(u64::from_str_radix(s, 16).unwrap_or(0));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn address_from_string(s: &str) -> Address {
|
||||
return u64::from_str_radix(s, 16).unwrap_or(0) as Address;
|
||||
impl ToString for Address {
|
||||
#[inline]
|
||||
fn to_string(&self) -> String {
|
||||
format!("{:0>10x}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for Address {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
serializer.serialize_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
struct AddressVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for AddressVisitor {
|
||||
type Value = Address;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("ZeroTier Address in string format")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
|
||||
Ok(Address::new_from_string(s))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for Address {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
||||
deserializer.deserialize_str(AddressVisitor)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,55 +2,173 @@ use crate::*;
|
|||
use crate::bindings::capi as ztcore;
|
||||
use std::ffi::CStr;
|
||||
use std::ptr::copy_nonoverlapping;
|
||||
use std::os::raw::c_char;
|
||||
use std::os::raw::{c_char, c_void};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Maximum length of a string in a certificate (mostly for the certificate name fields).
|
||||
pub const CERTIFICATE_MAX_STRING_LENGTH: u32 = ztcore::ZT_CERTIFICATE_MAX_STRING_LENGTH;
|
||||
|
||||
/// Certificate local trust bit field flag: this certificate self-signs a root CA.
|
||||
pub const CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA: u32 = ztcore::ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA;
|
||||
|
||||
/// Certificate local trust bit field flag: this certificate specifies a set of ZeroTier roots.
|
||||
pub const CERTIFICATE_LOCAL_TRUST_FLAG_ZEROTIER_ROOT_SET: u32 = ztcore::ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ZEROTIER_ROOT_SET;
|
||||
|
||||
/// Length of a NIST P-384 unique ID (public key).
|
||||
pub const CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE: u32 = ztcore::ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE;
|
||||
|
||||
/// Length of a private key corresponding to a NIST P-384 unique ID.
|
||||
pub const CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE: u32 = ztcore::ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE;
|
||||
|
||||
/// Type of certificate subject unique ID
|
||||
#[derive(FromPrimitive,ToPrimitive)]
|
||||
pub enum CertificateUniqueIdType {
|
||||
NistP384 = ztcore::ZT_CertificateUniqueIdType_ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384 as isize
|
||||
}
|
||||
|
||||
impl CertificateUniqueIdType {
|
||||
pub fn new_from_string(s: &str) -> Result<CertificateUniqueIdType, ResultCode> {
|
||||
if s.to_ascii_lowercase() == "nistp384" {
|
||||
return Ok(CertificateUniqueIdType::NistP384);
|
||||
}
|
||||
return Err(ResultCode::ErrorBadParameter);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for CertificateUniqueIdType {
|
||||
fn to_string(&self) -> String {
|
||||
match *self {
|
||||
CertificateUniqueIdType::NistP384 => String::from("NistP384")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for CertificateUniqueIdType {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
serializer.serialize_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
struct CertificateUniqueIdTypeVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for CertificateUniqueIdTypeVisitor {
|
||||
type Value = CertificateUniqueIdType;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("CertificateUniqueIdType value in string form")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
|
||||
let id = CertificateUniqueIdType::new_from_string(s);
|
||||
if id.is_err() {
|
||||
return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self));
|
||||
}
|
||||
return Ok(id.ok().unwrap() as Self::Value);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for CertificateUniqueIdType {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
||||
deserializer.deserialize_str(CertificateUniqueIdTypeVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reasons a certificate may be rejected.
|
||||
#[derive(FromPrimitive,ToPrimitive)]
|
||||
pub enum CertificateError {
|
||||
None = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_NONE as isize,
|
||||
HaveNewerCert = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_HAVE_NEWER_CERT as isize,
|
||||
InvalidFormat = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_FORMAT as isize,
|
||||
InvalidIdentity = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_IDENTITY as isize,
|
||||
InvalidPrimarySignature = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE as isize,
|
||||
InvalidChain = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_CHAIN as isize,
|
||||
InvalidComponentSignature = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE as isize,
|
||||
InvalidUniqueIdProof = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF as isize,
|
||||
MissingRequiredFields = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS as isize,
|
||||
OutOfValidTimeWindow = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW as isize,
|
||||
}
|
||||
|
||||
impl ToString for CertificateError {
|
||||
fn to_string(&self) -> String {
|
||||
String::from(
|
||||
match self {
|
||||
CertificateError::None => "None",
|
||||
CertificateError::HaveNewerCert => "HaveNewerCert",
|
||||
CertificateError::InvalidFormat => "InvalidFormat",
|
||||
CertificateError::InvalidIdentity => "InavlidIdentity",
|
||||
CertificateError::InvalidPrimarySignature => "InvalidPrimarySignature",
|
||||
CertificateError::InvalidChain => "InvalidChain",
|
||||
CertificateError::InvalidComponentSignature => "InvalidComponentSignature",
|
||||
CertificateError::InvalidUniqueIdProof => "InvalidUniqueIdProof",
|
||||
CertificateError::MissingRequiredFields => "MissingRequiredFields",
|
||||
CertificateError::OutOfValidTimeWindow => "OutOfValidTimeWindow"
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CertificateName {
|
||||
pub serial_no: String,
|
||||
pub common_name: String,
|
||||
pub serialNo: String,
|
||||
pub commonName: String,
|
||||
pub country: String,
|
||||
pub organization: String,
|
||||
pub unit: String,
|
||||
pub locality: String,
|
||||
pub province: String,
|
||||
pub street_address: String,
|
||||
pub postal_code: String,
|
||||
pub streetAddress: String,
|
||||
pub postalCode: String,
|
||||
pub email: String,
|
||||
pub url: String,
|
||||
pub host: String
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CertificateNetwork {
|
||||
pub id: NetworkId,
|
||||
pub controller: Fingerprint
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CertificateIdentity {
|
||||
pub identity: Identity,
|
||||
pub locator: Locator
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CertificateSubjectUniqueIdSecret {
|
||||
pub public: Box<[u8]>,
|
||||
pub private: Box<[u8]>,
|
||||
pub type_: CertificateUniqueIdType
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CertificateSubject {
|
||||
pub timestamp: i64,
|
||||
pub identities: Box<[CertificateIdentity]>,
|
||||
pub networks: Box<[CertificateNetwork]>,
|
||||
pub certificates: Box<[[u8; 48]]>,
|
||||
pub update_urls: Box<[String]>,
|
||||
pub certificates: Box<[Box<[u8]>]>,
|
||||
pub updateURLs: Box<[String]>,
|
||||
pub name: CertificateName,
|
||||
pub unique_id: Box<[u8]>,
|
||||
pub unique_id_proof_signature: Box<[u8]>
|
||||
pub uniqueId: Box<[u8]>,
|
||||
pub uniqueIdProofSignature: Box<[u8]>
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Certificate {
|
||||
pub serial_no: [u8; 48],
|
||||
pub serialNo: Box<[u8]>,
|
||||
pub flags: u64,
|
||||
pub timestamp: i64,
|
||||
pub validity: [i64; 2],
|
||||
pub subject: CertificateSubject,
|
||||
pub issuer: Identity,
|
||||
pub issuer_name: CertificateName,
|
||||
pub extended_attributes: Box<[u8]>,
|
||||
pub max_path_length: u32,
|
||||
pub crl: Box<[u8; 48]>,
|
||||
pub issuerName: CertificateName,
|
||||
pub extendedAttributes: Box<[u8]>,
|
||||
pub maxPathLength: u32,
|
||||
pub crl: Box<[Box<[u8]>]>,
|
||||
pub signature: Box<[u8]>
|
||||
}
|
||||
|
||||
|
@ -58,15 +176,15 @@ impl CertificateName {
|
|||
pub(crate) fn new_from_capi(cn: &ztcore::ZT_Certificate_Name) -> CertificateName {
|
||||
unsafe {
|
||||
return CertificateName {
|
||||
serial_no: String::from(CStr::from_ptr(cn.serialNo.as_ptr()).to_str().unwrap()),
|
||||
common_name: String::from(CStr::from_ptr(cn.commonName.as_ptr()).to_str().unwrap()),
|
||||
serialNo: String::from(CStr::from_ptr(cn.serialNo.as_ptr()).to_str().unwrap()),
|
||||
commonName: String::from(CStr::from_ptr(cn.commonName.as_ptr()).to_str().unwrap()),
|
||||
country: String::from(CStr::from_ptr(cn.country.as_ptr()).to_str().unwrap()),
|
||||
organization: String::from(CStr::from_ptr(cn.organization.as_ptr()).to_str().unwrap()),
|
||||
unit: String::from(CStr::from_ptr(cn.unit.as_ptr()).to_str().unwrap()),
|
||||
locality: String::from(CStr::from_ptr(cn.locality.as_ptr()).to_str().unwrap()),
|
||||
province: String::from(CStr::from_ptr(cn.province.as_ptr()).to_str().unwrap()),
|
||||
street_address: String::from(CStr::from_ptr(cn.streetAddress.as_ptr()).to_str().unwrap()),
|
||||
postal_code: String::from(CStr::from_ptr(cn.postalCode.as_ptr()).to_str().unwrap()),
|
||||
streetAddress: String::from(CStr::from_ptr(cn.streetAddress.as_ptr()).to_str().unwrap()),
|
||||
postalCode: String::from(CStr::from_ptr(cn.postalCode.as_ptr()).to_str().unwrap()),
|
||||
email: String::from(CStr::from_ptr(cn.email.as_ptr()).to_str().unwrap()),
|
||||
url: String::from(CStr::from_ptr(cn.url.as_ptr()).to_str().unwrap()),
|
||||
host: String::from(CStr::from_ptr(cn.host.as_ptr()).to_str().unwrap())
|
||||
|
@ -78,9 +196,9 @@ impl CertificateName {
|
|||
impl CertificateNetwork {
|
||||
pub(crate) fn new_from_capi(cn: &ztcore::ZT_Certificate_Network) -> CertificateNetwork {
|
||||
CertificateNetwork{
|
||||
id: cn.id as NetworkId,
|
||||
id: NetworkId(cn.id),
|
||||
controller: Fingerprint{
|
||||
address: cn.controller.address as Address,
|
||||
address: Address(cn.controller.address),
|
||||
hash: cn.controller.hash
|
||||
}
|
||||
}
|
||||
|
@ -112,11 +230,11 @@ impl CertificateSubject {
|
|||
}
|
||||
|
||||
let ccertificates: &[*const u8] = std::slice::from_raw_parts(cs.certificates, cs.certificateCount as usize);
|
||||
let mut certificates: Vec<[u8; 48]> = Vec::new();
|
||||
let mut certificates: Vec<Box<[u8]>> = Vec::new();
|
||||
let mut ctmp: [u8; 48] = [0; 48];
|
||||
for i in ccertificates.iter() {
|
||||
copy_nonoverlapping(*i, ctmp.as_mut_ptr(), 48);
|
||||
certificates.push(ctmp.clone());
|
||||
certificates.push(Box::from(ctmp));
|
||||
}
|
||||
|
||||
let cupdate_urls: &[*const c_char] = std::slice::from_raw_parts(cs.updateURLs, cs.updateURLCount as usize);
|
||||
|
@ -130,14 +248,79 @@ impl CertificateSubject {
|
|||
identities: identities.into_boxed_slice(),
|
||||
networks: networks.into_boxed_slice(),
|
||||
certificates: certificates.into_boxed_slice(),
|
||||
update_urls: update_urls.into_boxed_slice(),
|
||||
updateURLs: update_urls.into_boxed_slice(),
|
||||
name: CertificateName::new_from_capi(&cs.name),
|
||||
unique_id: Box::from(std::slice::from_raw_parts(cs.uniqueId, cs.uniqueIdSize as usize).clone()),
|
||||
unique_id_proof_signature: Box::from(std::slice::from_raw_parts(cs.uniqueIdProofSignature, cs.uniqueIdProofSignatureSize as usize).clone())
|
||||
uniqueId: Box::from(std::slice::from_raw_parts(cs.uniqueId, cs.uniqueIdSize as usize).clone()),
|
||||
uniqueIdProofSignature: Box::from(std::slice::from_raw_parts(cs.uniqueIdProofSignature, cs.uniqueIdProofSignatureSize as usize).clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Certificate {
|
||||
pub(crate) fn new_from_capi(c: &ztcore::ZT_Certificate) -> Certificate {
|
||||
unsafe {
|
||||
let cextended_attributes: &[u8] = std::slice::from_raw_parts(c.extendedAttributes, c.extendedAttributesSize as usize);
|
||||
let mut extended_attributes: Vec<u8> = Vec::new();
|
||||
extended_attributes.extend(cextended_attributes.iter());
|
||||
|
||||
let ccrl: &[*const u8] = std::slice::from_raw_parts(c.crl, c.crlCount as usize);
|
||||
let mut crl: Vec<Box<[u8]>> = Vec::new();
|
||||
let mut ctmp: [u8; 48] = [0; 48];
|
||||
for i in ccrl.iter() {
|
||||
copy_nonoverlapping(*i, ctmp.as_mut_ptr(), 48);
|
||||
crl.push(Box::from(ctmp));
|
||||
}
|
||||
|
||||
let csignature: &[u8] = std::slice::from_raw_parts(c.signature, c.signatureSize as usize);
|
||||
let mut signature: Vec<u8> = Vec::new();
|
||||
signature.extend(csignature.iter());
|
||||
|
||||
return Certificate{
|
||||
serialNo: Box::from(c.serialNo),
|
||||
flags: c.flags,
|
||||
timestamp: c.timestamp,
|
||||
validity: c.validity,
|
||||
subject: CertificateSubject::new_from_capi(&c.subject),
|
||||
issuer: Identity::new_from_capi(c.issuer, false),
|
||||
issuerName: CertificateName::new_from_capi(&c.issuerName),
|
||||
extendedAttributes: extended_attributes.into_boxed_slice(),
|
||||
maxPathLength: c.maxPathLength as u32,
|
||||
crl: crl.into_boxed_slice(),
|
||||
signature: signature.into_boxed_slice()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CertificateSubjectUniqueIdSecret {
|
||||
pub fn new(t: CertificateUniqueIdType) -> Self {
|
||||
unsafe {
|
||||
let mut unique_id: Vec<u8> = Vec::new();
|
||||
let mut unique_id_private: Vec<u8> = Vec::new();
|
||||
unique_id.resize(128, 0);
|
||||
unique_id_private.resize(128, 0);
|
||||
let mut unique_id_size: c_int = 128;
|
||||
let mut unique_id_private_size: c_int = 128;
|
||||
let ct: ztcore::ZT_CertificateUniqueIdType = num_traits::ToPrimitive::to_u32(&t).unwrap();
|
||||
if ztcore::ZT_Certificate_newSubjectUniqueId(ct, unique_id.as_mut_ptr() as *mut c_void, &mut unique_id_size as *mut c_int, unique_id_private.as_mut_ptr() as *mut c_void, &mut unique_id_private_size as *mut c_int) != 0 {
|
||||
panic!("fatal internal error: ZT_Certificate_newSubjectUniqueId failed.");
|
||||
}
|
||||
unique_id.resize(unique_id_size as usize, 0);
|
||||
unique_id_private.resize(unique_id_private_size as usize, 0);
|
||||
return CertificateSubjectUniqueIdSecret{
|
||||
public: unique_id.into_boxed_slice(),
|
||||
private: unique_id_private.into_boxed_slice(),
|
||||
type_: num_traits::FromPrimitive::from_u32(ct as u32).unwrap()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
implement_json_serializable!(CertificateName);
|
||||
implement_json_serializable!(CertificateNetwork);
|
||||
implement_json_serializable!(CertificateIdentity);
|
||||
implement_json_serializable!(CertificateSubject);
|
||||
implement_json_serializable!(Certificate);
|
||||
implement_json_serializable!(CertificateSubjectUniqueIdSecret);
|
||||
|
|
|
@ -6,11 +6,21 @@ use std::ffi::CStr;
|
|||
use std::mem::MaybeUninit;
|
||||
|
||||
pub struct Endpoint {
|
||||
pub ep_type: EndpointType,
|
||||
pub type_: EndpointType,
|
||||
intl: ztcore::ZT_Endpoint
|
||||
}
|
||||
|
||||
impl Endpoint {
|
||||
#[inline]
|
||||
pub(crate) fn new_from_capi(ep: *const ztcore::ZT_Endpoint) -> Endpoint {
|
||||
unsafe {
|
||||
return Endpoint{
|
||||
type_: EndpointType::from_u32((*ep).type_ as u32).unwrap(),
|
||||
intl: *ep
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_from_string(s: &str) -> Result<Endpoint, ResultCode> {
|
||||
unsafe {
|
||||
let mut cep: MaybeUninit<ztcore::ZT_Endpoint> = MaybeUninit::uninit();
|
||||
|
@ -18,22 +28,13 @@ impl Endpoint {
|
|||
if ec == 0 {
|
||||
let epi = cep.assume_init();
|
||||
return Ok(Endpoint{
|
||||
ep_type: EndpointType::from_u32(epi.type_ as u32).unwrap(),
|
||||
type_: EndpointType::from_u32(epi.type_ as u32).unwrap(),
|
||||
intl: epi
|
||||
});
|
||||
}
|
||||
return Err(ResultCode::from_i32(ec).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_from_capi(ep: *const ztcore::ZT_Endpoint) -> Endpoint {
|
||||
unsafe {
|
||||
return Endpoint{
|
||||
ep_type: EndpointType::from_u32((*ep).type_ as u32).unwrap(),
|
||||
intl: *ep
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for Endpoint {
|
||||
|
@ -47,3 +48,33 @@ impl ToString for Endpoint {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for Endpoint {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
serializer.serialize_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
struct EndpointVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for EndpointVisitor {
|
||||
type Value = Endpoint;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("Endpoint value in string form")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
|
||||
let id = Endpoint::new_from_string(s);
|
||||
if id.is_err() {
|
||||
return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self));
|
||||
}
|
||||
return Ok(id.ok().unwrap() as Self::Value);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for Endpoint {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
||||
deserializer.deserialize_str(EndpointVisitor)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ impl Fingerprint {
|
|||
if ztcore::ZT_Fingerprint_fromString(cfp.as_mut_ptr(), s.as_ptr() as *const c_char) != 0 {
|
||||
let fp = cfp.assume_init();
|
||||
return Ok(Fingerprint{
|
||||
address: fp.address as Address,
|
||||
address: Address(fp.address),
|
||||
hash: fp.hash
|
||||
});
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ impl ToString for Fingerprint {
|
|||
let mut buf: [u8; 256] = [0; 256];
|
||||
unsafe {
|
||||
if ztcore::ZT_Fingerprint_toString(&ztcore::ZT_Fingerprint {
|
||||
address: self.address,
|
||||
address: self.address.0,
|
||||
hash: self.hash
|
||||
}, buf.as_mut_ptr() as *mut c_char, buf.len() as c_int).is_null() {
|
||||
return String::from("(invalid)");
|
||||
|
@ -39,3 +39,33 @@ impl ToString for Fingerprint {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for Fingerprint {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
serializer.serialize_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
struct FingerprintVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for FingerprintVisitor {
|
||||
type Value = Fingerprint;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("ZeroTier Fingerprint in string format")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
|
||||
let id = Fingerprint::new_from_string(s);
|
||||
if id.is_err() {
|
||||
return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self));
|
||||
}
|
||||
return Ok(id.ok().unwrap() as Self::Value);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for Fingerprint {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
||||
deserializer.deserialize_str(FingerprintVisitor)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,17 @@ use std::os::raw::*;
|
|||
use std::ffi::CStr;
|
||||
use num_traits::{ToPrimitive, FromPrimitive};
|
||||
|
||||
#[derive(FromPrimitive,ToPrimitive)]
|
||||
pub enum IdentityType {
|
||||
Curve25519 = ztcore::ZT_IdentityType_ZT_IDENTITY_TYPE_C25519 as isize,
|
||||
NistP384 = ztcore::ZT_IdentityType_ZT_IDENTITY_TYPE_P384 as isize,
|
||||
}
|
||||
|
||||
pub struct Identity {
|
||||
pub id_type: IdentityType,
|
||||
pub type_: IdentityType,
|
||||
pub address: Address,
|
||||
capi: *const ztcore::ZT_Identity,
|
||||
requires_delete: bool
|
||||
requires_delete: bool,
|
||||
}
|
||||
|
||||
impl Identity {
|
||||
|
@ -17,15 +23,17 @@ impl Identity {
|
|||
let idt = ztcore::ZT_Identity_type(id);
|
||||
let a = ztcore::ZT_Identity_address(id);
|
||||
return Identity {
|
||||
id_type: FromPrimitive::from_u32(idt as u32).unwrap(),
|
||||
address: a as Address,
|
||||
type_: FromPrimitive::from_u32(idt as u32).unwrap(),
|
||||
address: Address(a),
|
||||
capi: id,
|
||||
requires_delete: requires_delete
|
||||
requires_delete: requires_delete,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate(id_type: IdentityType) -> Result<Identity, ResultCode> {
|
||||
/// Generate a new identity.
|
||||
/// This is time consuming due to one time proof of work. It can take several seconds.
|
||||
pub fn new_generate(id_type: IdentityType) -> Result<Identity, ResultCode> {
|
||||
unsafe {
|
||||
let id = ztcore::ZT_Identity_new(id_type.to_u32().unwrap());
|
||||
if id.is_null() {
|
||||
|
@ -35,7 +43,8 @@ impl Identity {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_from_string(s: String) -> Result<Identity, ResultCode> {
|
||||
/// Construct from a string representation of this identity.
|
||||
pub fn new_from_string(s: &str) -> Result<Identity, ResultCode> {
|
||||
unsafe {
|
||||
let id = ztcore::ZT_Identity_fromString(s.as_ptr() as *const c_char);
|
||||
if id.is_null() {
|
||||
|
@ -45,7 +54,7 @@ impl Identity {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_string(&self, include_private: bool) -> String {
|
||||
fn intl_to_string(&self, include_private: bool) -> String {
|
||||
let mut buf: [u8; 2048] = [0; 2048];
|
||||
unsafe {
|
||||
if ztcore::ZT_Identity_toString(self.capi, buf.as_mut_ptr() as *mut c_char, buf.len() as c_int, if include_private { 1 } else { 0 }).is_null() {
|
||||
|
@ -55,6 +64,14 @@ impl Identity {
|
|||
}
|
||||
}
|
||||
|
||||
/// Convert to a string and include the private key if present.
|
||||
/// If the private key is not present this is the same as to_string().
|
||||
#[inline]
|
||||
pub fn to_secret_string(&self) -> String {
|
||||
self.intl_to_string(true)
|
||||
}
|
||||
|
||||
/// Validate this identity, which can be slightly time consuming in some cases (20-40ms).
|
||||
pub fn validate(&self) -> bool {
|
||||
unsafe {
|
||||
if ztcore::ZT_Identity_validate(self.capi) != 0 {
|
||||
|
@ -64,6 +81,7 @@ impl Identity {
|
|||
false
|
||||
}
|
||||
|
||||
/// Returns true if this Identity includes its corresponding private key.
|
||||
pub fn has_private(&self) -> bool {
|
||||
unsafe {
|
||||
if ztcore::ZT_Identity_hasPrivate(self.capi) != 0 {
|
||||
|
@ -73,16 +91,18 @@ impl Identity {
|
|||
false
|
||||
}
|
||||
|
||||
/// Obtain the full fingerprint of this identity, which includes a SHA384 hash of the public key.
|
||||
pub fn fingerprint(&self) -> Fingerprint {
|
||||
unsafe {
|
||||
let cfp = ztcore::ZT_Identity_fingerprint(self.capi);
|
||||
return Fingerprint {
|
||||
address: (*cfp).address,
|
||||
hash: (*cfp).hash
|
||||
}
|
||||
address: Address((*cfp).address),
|
||||
hash: (*cfp).hash,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Sign some data with this identity.
|
||||
pub fn sign(&self, data: &[u8]) -> Result<Box<[u8]>, ResultCode> {
|
||||
unsafe {
|
||||
let mut sig: Vec<u8> = vec!(0; 128);
|
||||
|
@ -95,6 +115,7 @@ impl Identity {
|
|||
}
|
||||
}
|
||||
|
||||
/// Verify a signature by this identity.
|
||||
pub fn verify(&self, data: &[u8], signature: &[u8]) -> bool {
|
||||
if signature.len() == 0 {
|
||||
return false;
|
||||
|
@ -110,7 +131,7 @@ impl Identity {
|
|||
|
||||
impl Drop for Identity {
|
||||
fn drop(&mut self) {
|
||||
if self.requires_delete && !self.capi.is_null() {
|
||||
if self.requires_delete {
|
||||
unsafe {
|
||||
ztcore::ZT_Identity_delete(self.capi);
|
||||
}
|
||||
|
@ -119,13 +140,38 @@ impl Drop for Identity {
|
|||
}
|
||||
|
||||
impl ToString for Identity {
|
||||
#[inline]
|
||||
fn to_string(&self) -> String {
|
||||
self.to_string(false)
|
||||
self.intl_to_string(false)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Identity> for String {
|
||||
fn from(id: Identity) -> String {
|
||||
id.to_string(false)
|
||||
impl serde::Serialize for Identity {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
serializer.serialize_str(self.intl_to_string(false).as_str())
|
||||
}
|
||||
}
|
||||
|
||||
struct IdentityVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for IdentityVisitor {
|
||||
type Value = Identity;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("ZeroTier Identity in string format")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
|
||||
let id = Identity::new_from_string(s);
|
||||
if id.is_err() {
|
||||
return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self));
|
||||
}
|
||||
return Ok(id.ok().unwrap() as Self::Value);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for Identity {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
||||
deserializer.deserialize_str(IdentityVisitor)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,16 +7,18 @@ mod certificate;
|
|||
mod networkid;
|
||||
mod locator;
|
||||
|
||||
pub use identity::Identity;
|
||||
pub use identity::*;
|
||||
pub use address::*;
|
||||
pub use fingerprint::Fingerprint;
|
||||
pub use endpoint::Endpoint;
|
||||
pub use fingerprint::*;
|
||||
pub use endpoint::*;
|
||||
pub use networkid::*;
|
||||
pub use locator::Locator;
|
||||
pub use locator::*;
|
||||
pub use certificate::*;
|
||||
|
||||
use bindings::capi as ztcore;
|
||||
use num_derive::FromPrimitive;
|
||||
use num_derive::ToPrimitive;
|
||||
use std::os::raw::c_int;
|
||||
|
||||
pub const DEFAULT_PORT: u16 = ztcore::ZT_DEFAULT_PORT as u16;
|
||||
|
||||
|
@ -45,38 +47,6 @@ pub mod RulePacketCharacteristics {
|
|||
pub const TcpFlagFIN: u64 = crate::bindings::capi::ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN as u64;
|
||||
}
|
||||
|
||||
#[derive(FromPrimitive,ToPrimitive)]
|
||||
pub enum IdentityType {
|
||||
Curve25519 = ztcore::ZT_IdentityType_ZT_IDENTITY_TYPE_C25519 as isize,
|
||||
NistP384 = ztcore::ZT_IdentityType_ZT_IDENTITY_TYPE_P384 as isize,
|
||||
}
|
||||
|
||||
pub const CERTIFICATE_MAX_STRING_LENGTH: u32 = ztcore::ZT_CERTIFICATE_MAX_STRING_LENGTH;
|
||||
pub const CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA: u32 = ztcore::ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA;
|
||||
pub const CERTIFICATE_LOCAL_TRUST_FLAG_ZEROTIER_ROOT_SET: u32 = ztcore::ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ZEROTIER_ROOT_SET;
|
||||
|
||||
pub const CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE: u32 = ztcore::ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE;
|
||||
pub const CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE: u32 = ztcore::ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE;
|
||||
|
||||
#[derive(FromPrimitive,ToPrimitive)]
|
||||
pub enum CertificateUniqueIdType {
|
||||
NistP384 = ztcore::ZT_CertificateUniqueIdType_ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384 as isize
|
||||
}
|
||||
|
||||
#[derive(FromPrimitive,ToPrimitive)]
|
||||
pub enum CertificateError {
|
||||
None = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_NONE as isize,
|
||||
HaveNewerCert = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_HAVE_NEWER_CERT as isize,
|
||||
InvalidFormat = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_FORMAT as isize,
|
||||
InvalidIdentity = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_IDENTITY as isize,
|
||||
InvalidPrimarySignature = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE as isize,
|
||||
InvalidChain = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_CHAIN as isize,
|
||||
InvalidComponentSignature = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE as isize,
|
||||
InvalidUniqueIdProof = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF as isize,
|
||||
MissingRequiredFields = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS as isize,
|
||||
OutOfValidTimeWindow = ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW as isize,
|
||||
}
|
||||
|
||||
#[derive(FromPrimitive,ToPrimitive)]
|
||||
pub enum CredentialType {
|
||||
Null = ztcore::ZT_CredentialType_ZT_CREDENTIAL_TYPE_NULL as isize,
|
||||
|
@ -242,6 +212,40 @@ pub enum StateObjectType {
|
|||
Certificate = ztcore::ZT_StateObjectType_ZT_STATE_OBJECT_CERT as isize
|
||||
}
|
||||
|
||||
pub fn version() -> (u32, u32, u32, u32) {
|
||||
let mut major: c_int = 0;
|
||||
let mut minor: c_int = 0;
|
||||
let mut revision: c_int = 0;
|
||||
let mut build: c_int = 0;
|
||||
unsafe {
|
||||
ztcore::ZT_version(&mut major as *mut c_int, &mut minor as *mut c_int, &mut revision as *mut c_int, &mut build as *mut c_int);
|
||||
}
|
||||
(major as u32, minor as u32, revision as u32, build as u32)
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! implement_json_serializable {
|
||||
($struct_name:ident) => {
|
||||
impl $struct_name {
|
||||
pub fn new_from_json(json: &str) -> Result<$struct_name, String> {
|
||||
let r: serde_json::error::Result<$struct_name> = serde_json::from_str(json);
|
||||
if r.is_err() {
|
||||
let e = r.err();
|
||||
if e.is_none() {
|
||||
return Err(String::from("unknown error"));
|
||||
}
|
||||
return Err(e.unwrap().to_string());
|
||||
}
|
||||
Ok(r.unwrap())
|
||||
}
|
||||
|
||||
pub fn to_json(&self) -> String {
|
||||
serde_json::to_string_pretty(self).unwrap()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
|
|
|
@ -9,6 +9,7 @@ pub struct Locator {
|
|||
}
|
||||
|
||||
impl Locator {
|
||||
#[inline]
|
||||
pub(crate) fn new_from_capi(l: *const ztcore::ZT_Locator, requires_delete: bool) -> Locator {
|
||||
Locator{
|
||||
capi: l,
|
||||
|
@ -66,3 +67,33 @@ impl ToString for Locator {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for Locator {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
serializer.serialize_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
struct LocatorVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for LocatorVisitor {
|
||||
type Value = Locator;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("Locator value in string form")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
|
||||
let id = Locator::new_from_string(s);
|
||||
if id.is_err() {
|
||||
return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self));
|
||||
}
|
||||
return Ok(id.ok().unwrap() as Self::Value);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for Locator {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
||||
deserializer.deserialize_str(LocatorVisitor)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,41 @@
|
|||
pub type NetworkId = u64;
|
||||
pub struct NetworkId(pub u64);
|
||||
|
||||
pub fn network_id_to_string(n: NetworkId) -> String {
|
||||
format!("{:0>16x}", n as u64)
|
||||
impl NetworkId {
|
||||
#[inline]
|
||||
pub fn new_from_string(s: &str) -> NetworkId {
|
||||
return NetworkId(u64::from_str_radix(s, 16).unwrap_or(0));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn network_id_from_string(s: &str) -> NetworkId {
|
||||
return u64::from_str_radix(s, 16).unwrap_or(0) as NetworkId;
|
||||
impl ToString for NetworkId {
|
||||
#[inline]
|
||||
fn to_string(&self) -> String {
|
||||
format!("{:0>16x}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for NetworkId {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
serializer.serialize_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
struct NetworkIdVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for NetworkIdVisitor {
|
||||
type Value = NetworkId;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("ZeroTier Address in string format")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
|
||||
Ok(NetworkId::new_from_string(s))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for NetworkId {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
||||
deserializer.deserialize_str(NetworkIdVisitor)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue