Clean up some n00b Rust code and reduce the use of unsafe.

This commit is contained in:
Adam Ierymenko 2020-12-31 18:31:35 -05:00
parent 83d74d8b67
commit 890e7f5442
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
2 changed files with 255 additions and 223 deletions

View file

@ -10,9 +10,10 @@ use serde::{Deserialize, Serialize};
use crate::*; use crate::*;
use crate::bindings::capi as ztcore; use crate::bindings::capi as ztcore;
use crate::bindings::capi::ZT_CertificateError;
/// Maximum length of a string in a certificate (mostly for the certificate name fields). /// 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; pub const CERTIFICATE_MAX_STRING_LENGTH: isize = ztcore::ZT_CERTIFICATE_MAX_STRING_LENGTH as isize;
/// Certificate local trust bit field flag: this certificate self-signs a root CA. /// 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; pub const CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA: u32 = ztcore::ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA;
@ -31,30 +32,36 @@ pub const CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE: u32 = ztcore::ZT_C
pub struct CertificateSerialNo(pub [u8; 48]); pub struct CertificateSerialNo(pub [u8; 48]);
impl CertificateSerialNo { impl CertificateSerialNo {
/// Create a new empty (all zero) serial number.
#[inline(always)]
pub fn new() -> CertificateSerialNo {
CertificateSerialNo([0; 48])
}
pub fn new_from_string(s: &str) -> Result<CertificateSerialNo, ResultCode> { pub fn new_from_string(s: &str) -> Result<CertificateSerialNo, ResultCode> {
let b = hex::decode(s); let b = hex::decode(s);
if b.is_err() { if b.is_err() {
return Err(ResultCode::ErrorBadParameter); return Err(ResultCode::ErrorBadParameter);
} }
return Ok(CertificateSerialNo::from(b.unwrap())); return Ok(CertificateSerialNo::from(b.unwrap().as_slice()));
} }
} }
impl From<Vec<u8>> for CertificateSerialNo { impl From<&[u8; 48]> for CertificateSerialNo {
fn from(v: Vec<u8>) -> CertificateSerialNo { fn from(a: &[u8; 48]) -> CertificateSerialNo {
CertificateSerialNo(*a)
}
}
impl From<&[u8]> for CertificateSerialNo {
fn from(v: &[u8]) -> CertificateSerialNo {
let mut l = v.len(); let mut l = v.len();
if l > 48 { if l > 48 {
l = 48; l = 48;
} }
unsafe { let mut s = CertificateSerialNo::new();
let mut r: [u8; 48] = MaybeUninit::uninit().assume_init(); s.0[0..l].copy_from_slice(&v[0..l]);
copy_nonoverlapping(v.as_ptr(), r.as_mut_ptr(), l); s
while l < 48 {
r[l] = 0;
l += 1;
}
return CertificateSerialNo(r);
}
} }
} }
@ -158,22 +165,24 @@ pub struct CertificateSubjectUniqueIdSecret {
pub type_: CertificateUniqueIdType, pub type_: CertificateUniqueIdType,
} }
const CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE: usize = 128;
impl CertificateSubjectUniqueIdSecret { impl CertificateSubjectUniqueIdSecret {
pub fn new(t: CertificateUniqueIdType) -> Self { pub fn new(t: CertificateUniqueIdType) -> Self {
unsafe { let mut unique_id: [u8; CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE] = [0; CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE];
let mut unique_id: [u8; 128] = zeroed(); let mut unique_id_private: [u8; CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE] = [0; CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE];
let mut unique_id_private: [u8; 128] = zeroed(); let mut unique_id_size = CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE as c_int;
let mut unique_id_size: c_int = unique_id.len() as c_int; let mut unique_id_private_size = CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE as c_int;
let mut unique_id_private_size: c_int = unique_id_private.len() as c_int;
let ct: ztcore::ZT_CertificateUniqueIdType = num_traits::ToPrimitive::to_u32(&t).unwrap(); 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 { unsafe {
if ztcore::ZT_Certificate_newSubjectUniqueId(ct, unique_id.as_mut_ptr() as *mut c_void, &mut unique_id_size, unique_id_private.as_mut_ptr() as *mut c_void, &mut unique_id_private_size) != 0 {
panic!("fatal internal error: ZT_Certificate_newSubjectUniqueId failed."); panic!("fatal internal error: ZT_Certificate_newSubjectUniqueId failed.");
} }
return CertificateSubjectUniqueIdSecret { }
CertificateSubjectUniqueIdSecret {
public: Vec::from(&unique_id[0..unique_id_size as usize]), public: Vec::from(&unique_id[0..unique_id_size as usize]),
private: Vec::from(&unique_id_private[0..unique_id_private_size as usize]), private: Vec::from(&unique_id_private[0..unique_id_private_size as usize]),
type_: num_traits::FromPrimitive::from_u32(ct as u32).unwrap(), type_: num_traits::FromPrimitive::from_u32(ct as u32).unwrap(),
};
} }
} }
} }
@ -235,7 +244,27 @@ pub struct CertificateName {
pub host: String, pub host: String,
} }
unsafe fn str_to_cert_cstr(s: &String, cs: &mut [c_char; 128]) { impl CertificateName {
pub(crate) unsafe fn new_from_capi(cn: &ztcore::ZT_Certificate_Name) -> CertificateName {
unsafe {
return CertificateName {
serialNo: cstr_to_string(cn.serialNo.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1),
commonName: cstr_to_string(cn.commonName.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1),
country: cstr_to_string(cn.country.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1),
organization: cstr_to_string(cn.organization.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1),
unit: cstr_to_string(cn.unit.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1),
locality: cstr_to_string(cn.locality.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1),
province: cstr_to_string(cn.province.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1),
streetAddress: cstr_to_string(cn.streetAddress.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1),
postalCode: cstr_to_string(cn.postalCode.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1),
email: cstr_to_string(cn.email.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1),
url: cstr_to_string(cn.url.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1),
host: cstr_to_string(cn.host.as_ptr(), CERTIFICATE_MAX_STRING_LENGTH - 1)
};
}
}
fn str_to_cert_cstr(s: &String, cs: &mut [c_char; 128]) {
let mut l = s.len(); let mut l = s.len();
if l == 0 { if l == 0 {
cs[0] = 0; cs[0] = 0;
@ -248,43 +277,23 @@ unsafe fn str_to_cert_cstr(s: &String, cs: &mut [c_char; 128]) {
copy_nonoverlapping(s.as_ptr(), cs.as_mut_ptr() as *mut u8, l); copy_nonoverlapping(s.as_ptr(), cs.as_mut_ptr() as *mut u8, l);
} }
cs[l + 1] = 0; cs[l + 1] = 0;
}
impl CertificateName {
pub(crate) fn new_from_capi(cn: &ztcore::ZT_Certificate_Name) -> CertificateName {
unsafe {
return CertificateName {
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()),
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()),
};
}
} }
pub(crate) unsafe fn to_capi(&self) -> ztcore::ZT_Certificate_Name { pub(crate) unsafe fn to_capi(&self) -> ztcore::ZT_Certificate_Name {
unsafe { unsafe {
let mut cn: ztcore::ZT_Certificate_Name = zeroed(); let mut cn: ztcore::ZT_Certificate_Name = zeroed();
str_to_cert_cstr(&self.serialNo, &mut cn.serialNo); Self::str_to_cert_cstr(&self.serialNo, &mut cn.serialNo);
str_to_cert_cstr(&self.commonName, &mut cn.commonName); Self::str_to_cert_cstr(&self.commonName, &mut cn.commonName);
str_to_cert_cstr(&self.country, &mut cn.country); Self::str_to_cert_cstr(&self.country, &mut cn.country);
str_to_cert_cstr(&self.organization, &mut cn.organization); Self::str_to_cert_cstr(&self.organization, &mut cn.organization);
str_to_cert_cstr(&self.unit, &mut cn.unit); Self::str_to_cert_cstr(&self.unit, &mut cn.unit);
str_to_cert_cstr(&self.locality, &mut cn.locality); Self::str_to_cert_cstr(&self.locality, &mut cn.locality);
str_to_cert_cstr(&self.province, &mut cn.province); Self::str_to_cert_cstr(&self.province, &mut cn.province);
str_to_cert_cstr(&self.streetAddress, &mut cn.streetAddress); Self::str_to_cert_cstr(&self.streetAddress, &mut cn.streetAddress);
str_to_cert_cstr(&self.postalCode, &mut cn.postalCode); Self::str_to_cert_cstr(&self.postalCode, &mut cn.postalCode);
str_to_cert_cstr(&self.email, &mut cn.email); Self::str_to_cert_cstr(&self.email, &mut cn.email);
str_to_cert_cstr(&self.url, &mut cn.url); Self::str_to_cert_cstr(&self.url, &mut cn.url);
str_to_cert_cstr(&self.host, &mut cn.host); Self::str_to_cert_cstr(&self.host, &mut cn.host);
return cn; return cn;
} }
} }
@ -329,21 +338,24 @@ implement_to_from_json!(CertificateNetwork);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct CertificateIdentity { pub struct CertificateIdentity {
pub identity: Identity, pub identity: Identity,
pub locator: Locator, pub locator: Option<Locator>,
} }
impl CertificateIdentity { impl CertificateIdentity {
pub(crate) fn new_from_capi(ci: &ztcore::ZT_Certificate_Identity) -> CertificateIdentity { pub(crate) unsafe fn new_from_capi(ci: &ztcore::ZT_Certificate_Identity) -> Option<CertificateIdentity> {
CertificateIdentity { if ci.identity.is_null() {
identity: Identity::new_from_capi(ci.identity, false).clone(), return None;
locator: Locator::new_from_capi(ci.locator, false).clone(),
} }
Some(CertificateIdentity {
identity: Identity::new_from_capi(ci.identity, false).clone(),
locator: if ci.locator.is_null() { None } else { Some(Locator::new_from_capi(ci.locator, false).clone()) },
})
} }
pub(crate) unsafe fn to_capi(&self) -> ztcore::ZT_Certificate_Identity { pub(crate) unsafe fn to_capi(&self) -> ztcore::ZT_Certificate_Identity {
ztcore::ZT_Certificate_Identity { ztcore::ZT_Certificate_Identity {
identity: self.identity.capi, identity: self.identity.capi,
locator: self.locator.capi, locator: if self.locator.is_some() { self.locator.as_ref().unwrap().capi } else { null() },
} }
} }
} }
@ -375,32 +387,43 @@ pub(crate) struct CertificateSubjectCAPIContainer {
} }
impl CertificateSubject { impl CertificateSubject {
pub(crate) fn new_from_capi(cs: &ztcore::ZT_Certificate_Subject) -> CertificateSubject { pub(crate) unsafe fn new_from_capi(cs: &ztcore::ZT_Certificate_Subject) -> CertificateSubject {
unsafe { unsafe {
let cidentities: &[ztcore::ZT_Certificate_Identity] = std::slice::from_raw_parts(cs.identities, cs.identityCount as usize);
let mut identities: Vec<CertificateIdentity> = Vec::new(); let mut identities: Vec<CertificateIdentity> = Vec::new();
if !cs.identities.is_null() && cs.identityCount > 0 {
let cidentities: &[ztcore::ZT_Certificate_Identity] = std::slice::from_raw_parts(cs.identities, cs.identityCount as usize);
for i in cidentities.iter() { for i in cidentities.iter() {
identities.push(CertificateIdentity::new_from_capi(i)); let ci = CertificateIdentity::new_from_capi(i);
if ci.is_some() {
identities.push(ci.unwrap());
}
}
} }
let cnetworks: &[ztcore::ZT_Certificate_Network] = std::slice::from_raw_parts(cs.networks, cs.networkCount as usize);
let mut networks: Vec<CertificateNetwork> = Vec::new(); let mut networks: Vec<CertificateNetwork> = Vec::new();
if !cs.networks.is_null() && cs.networkCount > 0 {
let cnetworks: &[ztcore::ZT_Certificate_Network] = std::slice::from_raw_parts(cs.networks, cs.networkCount as usize);
for i in cnetworks.iter() { for i in cnetworks.iter() {
networks.push(CertificateNetwork::new_from_capi(i)); networks.push(CertificateNetwork::new_from_capi(i));
} }
}
let ccertificates: &[*const u8] = std::slice::from_raw_parts(cs.certificates, cs.certificateCount as usize);
let mut certificates: Vec<CertificateSerialNo> = Vec::new(); let mut certificates: Vec<CertificateSerialNo> = Vec::new();
if !cs.certificates.is_null() && cs.certificateCount > 0 {
let ccertificates: &[*const u8] = std::slice::from_raw_parts(cs.certificates, cs.certificateCount as usize);
let mut ctmp: [u8; 48] = [0; 48]; let mut ctmp: [u8; 48] = [0; 48];
for i in ccertificates.iter() { for i in ccertificates.iter() {
copy_nonoverlapping(*i, ctmp.as_mut_ptr(), 48); copy_nonoverlapping(*i, ctmp.as_mut_ptr(), 48);
certificates.push(CertificateSerialNo(ctmp)); certificates.push(CertificateSerialNo(ctmp));
} }
}
let cupdate_urls: &[*const c_char] = std::slice::from_raw_parts(cs.updateURLs, cs.updateURLCount as usize);
let mut update_urls: Vec<String> = Vec::new(); let mut update_urls: Vec<String> = Vec::new();
if !cs.updateURLs.is_null() && cs.updateURLCount > 0 {
let cupdate_urls: &[*const c_char] = std::slice::from_raw_parts(cs.updateURLs, cs.updateURLCount as usize);
for i in cupdate_urls.iter() { for i in cupdate_urls.iter() {
update_urls.push(CStr::from_ptr(*i).to_str().unwrap().to_string()); update_urls.push(cstr_to_string(*i, CERTIFICATE_MAX_STRING_LENGTH - 1));
}
} }
return CertificateSubject { return CertificateSubject {
@ -417,7 +440,6 @@ impl CertificateSubject {
} }
pub(crate) unsafe fn to_capi(&self) -> CertificateSubjectCAPIContainer { pub(crate) unsafe fn to_capi(&self) -> CertificateSubjectCAPIContainer {
unsafe {
let mut capi_identities: Vec<ztcore::ZT_Certificate_Identity> = Vec::new(); let mut capi_identities: Vec<ztcore::ZT_Certificate_Identity> = Vec::new();
let mut capi_networks: Vec<ztcore::ZT_Certificate_Network> = Vec::new(); let mut capi_networks: Vec<ztcore::ZT_Certificate_Network> = Vec::new();
let mut capi_certificates: Vec<*const u8> = Vec::new(); let mut capi_certificates: Vec<*const u8> = Vec::new();
@ -427,7 +449,7 @@ impl CertificateSubject {
if !self.identities.is_empty() { if !self.identities.is_empty() {
capi_identities.reserve(self.identities.len()); capi_identities.reserve(self.identities.len());
for i in self.identities.iter() { for i in self.identities.iter() {
capi_identities.push((*i).to_capi()); capi_identities.push(unsafe { (*i).to_capi() });
} }
} }
if !self.networks.is_empty() { if !self.networks.is_empty() {
@ -453,7 +475,7 @@ impl CertificateSubject {
} }
} }
return CertificateSubjectCAPIContainer { CertificateSubjectCAPIContainer {
subject: ztcore::ZT_Certificate_Subject { subject: ztcore::ZT_Certificate_Subject {
timestamp: self.timestamp, timestamp: self.timestamp,
identities: capi_identities.as_mut_ptr(), identities: capi_identities.as_mut_ptr(),
@ -464,7 +486,7 @@ impl CertificateSubject {
networkCount: capi_networks.len() as c_uint, networkCount: capi_networks.len() as c_uint,
certificateCount: capi_certificates.len() as c_uint, certificateCount: capi_certificates.len() as c_uint,
updateURLCount: capi_urls.len() as c_uint, updateURLCount: capi_urls.len() as c_uint,
name: self.name.to_capi(), name: unsafe { self.name.to_capi() },
uniqueId: self.uniqueId.as_ptr(), uniqueId: self.uniqueId.as_ptr(),
uniqueIdProofSignature: self.uniqueIdProofSignature.as_ptr(), uniqueIdProofSignature: self.uniqueIdProofSignature.as_ptr(),
uniqueIdSize: self.uniqueId.len() as c_uint, uniqueIdSize: self.uniqueId.len() as c_uint,
@ -475,32 +497,29 @@ impl CertificateSubject {
subject_certificates: capi_certificates, subject_certificates: capi_certificates,
subject_urls: capi_urls, subject_urls: capi_urls,
subject_urls_strs: capi_urls_strs, subject_urls_strs: capi_urls_strs,
};
} }
} }
pub fn new_csr(&self, uid: Option<&CertificateSubjectUniqueIdSecret>) -> Result<Vec<u8>, ResultCode> { pub fn new_csr(&self, uid: Option<&CertificateSubjectUniqueIdSecret>) -> Result<Box<[u8]>, ResultCode> {
unsafe {
let capi = self.to_capi();
let mut csr: Vec<u8> = Vec::new(); let mut csr: Vec<u8> = Vec::new();
csr.resize(16384, 0); csr.resize(16384, 0);
let mut csr_size: c_int = 16384; let mut csr_size: c_int = 16384;
unsafe {
let capi = self.to_capi();
if uid.is_some() { if uid.is_some() {
let uid2 = uid.unwrap(); let uid2 = uid.unwrap();
if ztcore::ZT_Certificate_newCSR(&capi.subject as *const ztcore::ZT_Certificate_Subject, uid2.public.as_ptr() as *const c_void, uid2.public.len() as c_int, uid2.private.as_ptr() as *const c_void, uid2.private.len() as c_int, csr.as_mut_ptr() as *mut c_void, &mut csr_size as *mut c_int) != 0 { if ztcore::ZT_Certificate_newCSR(&capi.subject as *const ztcore::ZT_Certificate_Subject, uid2.public.as_ptr() as *const c_void, uid2.public.len() as c_int, uid2.private.as_ptr() as *const c_void, uid2.private.len() as c_int, csr.as_mut_ptr() as *mut c_void, &mut csr_size) != 0 {
return Err(ResultCode::ErrorBadParameter); return Err(ResultCode::ErrorBadParameter);
} }
} else { } else {
if ztcore::ZT_Certificate_newCSR(&capi.subject, null(), -1, null(), -1, csr.as_mut_ptr() as *mut c_void, &mut csr_size as *mut c_int) != 0 { if ztcore::ZT_Certificate_newCSR(&capi.subject, null(), -1, null(), -1, csr.as_mut_ptr() as *mut c_void, &mut csr_size) != 0 {
return Err(ResultCode::ErrorBadParameter); return Err(ResultCode::ErrorBadParameter);
} }
} }
csr.resize(csr_size as usize, 0);
return Ok(csr);
} }
return Ok(csr.into_boxed_slice());
} }
} }
@ -531,15 +550,19 @@ pub(crate) struct CertificateCAPIContainer {
} }
impl Certificate { impl Certificate {
pub(crate) fn new_from_capi(c: &ztcore::ZT_Certificate) -> Certificate { pub(crate) unsafe fn new_from_capi(c: &ztcore::ZT_Certificate) -> Certificate {
unsafe { unsafe {
let ccrl: &[*const u8] = std::slice::from_raw_parts(c.crl, c.crlCount as usize);
let mut crl: Vec<CertificateSerialNo> = Vec::new(); let mut crl: Vec<CertificateSerialNo> = Vec::new();
if !c.crl.is_null() && c.crlCount > 0 {
let ccrl: &[*const u8] = std::slice::from_raw_parts(c.crl, c.crlCount as usize);
let mut ctmp: [u8; 48] = [0; 48]; let mut ctmp: [u8; 48] = [0; 48];
for i in ccrl.iter() { for i in ccrl.iter() {
if !(*i).is_null() {
copy_nonoverlapping(*i, ctmp.as_mut_ptr(), 48); copy_nonoverlapping(*i, ctmp.as_mut_ptr(), 48);
crl.push(CertificateSerialNo(ctmp)); crl.push(CertificateSerialNo(ctmp));
} }
}
}
return Certificate { return Certificate {
serialNo: CertificateSerialNo(c.serialNo), serialNo: CertificateSerialNo(c.serialNo),
@ -557,34 +580,15 @@ impl Certificate {
} }
} }
pub fn new_from_bytes(b: &[u8], verify: bool) -> Result<Certificate, CertificateError> {
unsafe {
let mut capi_cert: *const ztcore::ZT_Certificate = null_mut();
let capi_verify: c_int = if verify { 1 } else { 0 };
let result = ztcore::ZT_Certificate_decode(&mut capi_cert as *mut *const ztcore::ZT_Certificate, b.as_ptr() as *const c_void, b.len() as c_int, capi_verify);
if result != ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_NONE {
return Err(CertificateError::from_u32(result as u32).unwrap_or(CertificateError::InvalidFormat));
}
if capi_cert.is_null() {
return Err(CertificateError::InvalidFormat);
}
let cert = Certificate::new_from_capi(&*capi_cert);
ztcore::ZT_Certificate_delete(capi_cert);
return Ok(cert);
}
}
pub(crate) unsafe fn to_capi(&self) -> CertificateCAPIContainer { pub(crate) unsafe fn to_capi(&self) -> CertificateCAPIContainer {
unsafe {
let subject = self.subject.to_capi();
let mut capi_crls: Vec<*const u8> = Vec::new(); let mut capi_crls: Vec<*const u8> = Vec::new();
capi_crls.reserve(self.crl.len()); capi_crls.reserve(self.crl.len());
for i in self.crl.iter() { for i in self.crl.iter() {
capi_crls.push((*i).0.as_ptr()); capi_crls.push((*i).0.as_ptr());
} }
return CertificateCAPIContainer { let subject = unsafe { self.subject.to_capi() };
CertificateCAPIContainer {
certificate: ztcore::ZT_Certificate { certificate: ztcore::ZT_Certificate {
serialNo: self.serialNo.0, serialNo: self.serialNo.0,
flags: self.flags, flags: self.flags,
@ -592,7 +596,7 @@ impl Certificate {
validity: self.validity, validity: self.validity,
subject: subject.subject, subject: subject.subject,
issuer: self.issuer.capi, issuer: self.issuer.capi,
issuerName: self.issuerName.to_capi(), issuerName: unsafe { self.issuerName.to_capi() },
extendedAttributes: self.extendedAttributes.as_ptr(), extendedAttributes: self.extendedAttributes.as_ptr(),
extendedAttributesSize: self.extendedAttributes.len() as c_uint, extendedAttributesSize: self.extendedAttributes.len() as c_uint,
maxPathLength: self.maxPathLength as c_uint, maxPathLength: self.maxPathLength as c_uint,
@ -603,40 +607,56 @@ impl Certificate {
}, },
certificate_crls: capi_crls, certificate_crls: capi_crls,
subject_container: subject, subject_container: subject,
}; }
}
pub fn new_from_bytes(b: &[u8], verify: bool) -> Result<Certificate, CertificateError> {
let mut capi_cert: *const ztcore::ZT_Certificate = null_mut();
let capi_verify: c_int = if verify { 1 } else { 0 };
let result = unsafe { ztcore::ZT_Certificate_decode(&mut capi_cert as *mut *const ztcore::ZT_Certificate, b.as_ptr() as *const c_void, b.len() as c_int, capi_verify) };
if result != ztcore::ZT_CertificateError_ZT_CERTIFICATE_ERROR_NONE {
return Err(CertificateError::from_u32(result as u32).unwrap_or(CertificateError::InvalidFormat));
}
if capi_cert.is_null() {
return Err(CertificateError::InvalidFormat);
}
unsafe {
let cert = Certificate::new_from_capi(&*capi_cert);
ztcore::ZT_Certificate_delete(capi_cert);
return Ok(cert);
} }
} }
pub fn to_bytes(&self) -> Result<Box<[u8]>, ResultCode> { pub fn to_bytes(&self) -> Result<Box<[u8]>, ResultCode> {
unsafe {
let mut cert: Vec<u8> = Vec::new(); let mut cert: Vec<u8> = Vec::new();
cert.resize(16384, 0); cert.resize(16384, 0);
let mut cert_size: c_int = 16384; let mut cert_size: c_int = 16384;
unsafe {
let capi = self.to_capi(); let capi = self.to_capi();
if ztcore::ZT_Certificate_encode(&capi.certificate as *const ztcore::ZT_Certificate, cert.as_mut_ptr() as *mut c_void, &mut cert_size) != 0 { if ztcore::ZT_Certificate_encode(&capi.certificate as *const ztcore::ZT_Certificate, cert.as_mut_ptr() as *mut c_void, &mut cert_size) != 0 {
return Err(ResultCode::ErrorInternalNonFatal); return Err(ResultCode::ErrorInternalNonFatal);
} }
}
cert.resize(cert_size as usize, 0); cert.resize(cert_size as usize, 0);
return Ok(cert.into_boxed_slice()); return Ok(cert.into_boxed_slice());
} }
}
pub fn sign(&self, id: &Identity) -> Result<Vec<u8>, ResultCode> { pub fn sign(&self, id: &Identity) -> Result<Vec<u8>, ResultCode> {
if !id.has_private() { if !id.has_private() {
return Err(ResultCode::ErrorBadParameter); return Err(ResultCode::ErrorBadParameter);
} }
unsafe {
let capi = self.to_capi();
let mut signed_cert: Vec<u8> = Vec::new(); let mut signed_cert: Vec<u8> = Vec::new();
signed_cert.resize(16384, 0); signed_cert.resize(16384, 0);
let mut signed_cert_size: c_int = 16384; let mut signed_cert_size: c_int = 16384;
unsafe {
let capi = self.to_capi();
if ztcore::ZT_Certificate_sign(&capi.certificate as *const ztcore::ZT_Certificate, id.capi, signed_cert.as_mut_ptr() as *mut c_void, &mut signed_cert_size) != 0 { if ztcore::ZT_Certificate_sign(&capi.certificate as *const ztcore::ZT_Certificate, id.capi, signed_cert.as_mut_ptr() as *mut c_void, &mut signed_cert_size) != 0 {
return Err(ResultCode::ErrorBadParameter); return Err(ResultCode::ErrorBadParameter);
} }
}
signed_cert.resize(signed_cert_size as usize, 0); signed_cert.resize(signed_cert_size as usize, 0);
return Ok(signed_cert); return Ok(signed_cert);
} }
}
pub fn verify(&self) -> CertificateError { pub fn verify(&self) -> CertificateError {
unsafe { unsafe {

View file

@ -1,4 +1,8 @@
use std::os::raw::{c_char, c_int};
use num_derive::{FromPrimitive, ToPrimitive};
mod bindings; mod bindings;
mod identity; mod identity;
mod address; mod address;
mod fingerprint; mod fingerprint;
@ -14,13 +18,15 @@ mod buffer;
mod portableatomici64; mod portableatomici64;
mod virtualnetworkconfig; mod virtualnetworkconfig;
pub use identity::{Identity, IdentityType}; use bindings::capi as ztcore;
pub use identity::*;
pub use address::Address; pub use address::Address;
pub use fingerprint::Fingerprint; pub use fingerprint::Fingerprint;
pub use endpoint::Endpoint; pub use endpoint::Endpoint;
pub use certificate::*;
pub use networkid::NetworkId; pub use networkid::NetworkId;
pub use locator::Locator; pub use locator::Locator;
pub use certificate::*;
pub use path::Path; pub use path::Path;
pub use peer::Peer; pub use peer::Peer;
pub use node::Node; pub use node::Node;
@ -29,10 +35,6 @@ pub use buffer::Buffer;
pub use portableatomici64::PortableAtomicI64; pub use portableatomici64::PortableAtomicI64;
pub use virtualnetworkconfig::*; pub use virtualnetworkconfig::*;
use bindings::capi as ztcore;
use num_derive::{FromPrimitive, ToPrimitive};
use std::os::raw::c_int;
pub const DEFAULT_PORT: u16 = ztcore::ZT_DEFAULT_PORT as u16; pub const DEFAULT_PORT: u16 = ztcore::ZT_DEFAULT_PORT as u16;
pub const BUF_SIZE: u32 = ztcore::ZT_BUF_SIZE; pub const BUF_SIZE: u32 = ztcore::ZT_BUF_SIZE;
@ -182,6 +184,24 @@ pub fn now() -> i64 {
(std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis() & 0x7fffffffffffffff) as i64 (std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis() & 0x7fffffffffffffff) as i64
} }
/// The CStr stuff is cumbersome, so this is an easier to use function to turn a C string into a String.
/// This returns an empty string on a null pointer or invalid UTF-8. It's unsafe because it can crash if
/// the string is not zero-terminated. A size limit can be passed in if available to reduce this risk, or
/// the max_len parameter can be -1 if there is no known limit.
pub unsafe fn cstr_to_string(cstr: *const c_char, max_len: isize) -> String {
if !cstr.is_null() {
let mut cstr_len: isize = 0;
while max_len < 0 || cstr_len < max_len {
if (unsafe { *cstr.offset(cstr_len) } == 0) {
break;
}
cstr_len += 1;
}
return String::from(std::str::from_utf8(unsafe { std::slice::from_raw_parts(cstr as *const u8, cstr_len as usize) }).unwrap_or(""));
}
String::new()
}
#[macro_export(crate)] #[macro_export(crate)]
macro_rules! implement_to_from_json { macro_rules! implement_to_from_json {
($struct_name:ident) => { ($struct_name:ident) => {
@ -204,11 +224,3 @@ macro_rules! implement_to_from_json {
} }
}; };
} }
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}