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::bindings::capi as ztcore;
use crate::bindings::capi::ZT_CertificateError;
/// 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.
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]);
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> {
let b = hex::decode(s);
if b.is_err() {
return Err(ResultCode::ErrorBadParameter);
}
return Ok(CertificateSerialNo::from(b.unwrap()));
return Ok(CertificateSerialNo::from(b.unwrap().as_slice()));
}
}
impl From<Vec<u8>> for CertificateSerialNo {
fn from(v: Vec<u8>) -> CertificateSerialNo {
impl From<&[u8; 48]> for CertificateSerialNo {
fn from(a: &[u8; 48]) -> CertificateSerialNo {
CertificateSerialNo(*a)
}
}
impl From<&[u8]> for CertificateSerialNo {
fn from(v: &[u8]) -> CertificateSerialNo {
let mut l = v.len();
if l > 48 {
l = 48;
}
unsafe {
let mut r: [u8; 48] = MaybeUninit::uninit().assume_init();
copy_nonoverlapping(v.as_ptr(), r.as_mut_ptr(), l);
while l < 48 {
r[l] = 0;
l += 1;
}
return CertificateSerialNo(r);
}
let mut s = CertificateSerialNo::new();
s.0[0..l].copy_from_slice(&v[0..l]);
s
}
}
@ -158,22 +165,24 @@ pub struct CertificateSubjectUniqueIdSecret {
pub type_: CertificateUniqueIdType,
}
const CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE: usize = 128;
impl CertificateSubjectUniqueIdSecret {
pub fn new(t: CertificateUniqueIdType) -> Self {
let mut unique_id: [u8; CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE] = [0; CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE];
let mut unique_id_private: [u8; CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE] = [0; CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE];
let mut unique_id_size = CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE as c_int;
let mut unique_id_private_size = CERTIFICATE_UNIQUE_ID_CREATE_BUF_SIZE as c_int;
let ct: ztcore::ZT_CertificateUniqueIdType = num_traits::ToPrimitive::to_u32(&t).unwrap();
unsafe {
let mut unique_id: [u8; 128] = zeroed();
let mut unique_id_private: [u8; 128] = zeroed();
let mut unique_id_size: c_int = unique_id.len() 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();
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 {
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.");
}
return CertificateSubjectUniqueIdSecret {
public: Vec::from(&unique_id[0..unique_id_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(),
};
}
CertificateSubjectUniqueIdSecret {
public: Vec::from(&unique_id[0..unique_id_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(),
}
}
}
@ -235,56 +244,56 @@ pub struct CertificateName {
pub host: String,
}
unsafe fn str_to_cert_cstr(s: &String, cs: &mut [c_char; 128]) {
let mut l = s.len();
if l == 0 {
cs[0] = 0;
return;
}
if l > 126 {
l = 126;
}
unsafe {
copy_nonoverlapping(s.as_ptr(), cs.as_mut_ptr() as *mut u8, l);
}
cs[l + 1] = 0;
}
impl CertificateName {
pub(crate) fn new_from_capi(cn: &ztcore::ZT_Certificate_Name) -> CertificateName {
pub(crate) unsafe 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()),
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();
if l == 0 {
cs[0] = 0;
return;
}
if l > 126 {
l = 126;
}
unsafe {
copy_nonoverlapping(s.as_ptr(), cs.as_mut_ptr() as *mut u8, l);
}
cs[l + 1] = 0;
}
pub(crate) unsafe fn to_capi(&self) -> ztcore::ZT_Certificate_Name {
unsafe {
let mut cn: ztcore::ZT_Certificate_Name = zeroed();
str_to_cert_cstr(&self.serialNo, &mut cn.serialNo);
str_to_cert_cstr(&self.commonName, &mut cn.commonName);
str_to_cert_cstr(&self.country, &mut cn.country);
str_to_cert_cstr(&self.organization, &mut cn.organization);
str_to_cert_cstr(&self.unit, &mut cn.unit);
str_to_cert_cstr(&self.locality, &mut cn.locality);
str_to_cert_cstr(&self.province, &mut cn.province);
str_to_cert_cstr(&self.streetAddress, &mut cn.streetAddress);
str_to_cert_cstr(&self.postalCode, &mut cn.postalCode);
str_to_cert_cstr(&self.email, &mut cn.email);
str_to_cert_cstr(&self.url, &mut cn.url);
str_to_cert_cstr(&self.host, &mut cn.host);
Self::str_to_cert_cstr(&self.serialNo, &mut cn.serialNo);
Self::str_to_cert_cstr(&self.commonName, &mut cn.commonName);
Self::str_to_cert_cstr(&self.country, &mut cn.country);
Self::str_to_cert_cstr(&self.organization, &mut cn.organization);
Self::str_to_cert_cstr(&self.unit, &mut cn.unit);
Self::str_to_cert_cstr(&self.locality, &mut cn.locality);
Self::str_to_cert_cstr(&self.province, &mut cn.province);
Self::str_to_cert_cstr(&self.streetAddress, &mut cn.streetAddress);
Self::str_to_cert_cstr(&self.postalCode, &mut cn.postalCode);
Self::str_to_cert_cstr(&self.email, &mut cn.email);
Self::str_to_cert_cstr(&self.url, &mut cn.url);
Self::str_to_cert_cstr(&self.host, &mut cn.host);
return cn;
}
}
@ -329,21 +338,24 @@ implement_to_from_json!(CertificateNetwork);
#[derive(Serialize, Deserialize)]
pub struct CertificateIdentity {
pub identity: Identity,
pub locator: Locator,
pub locator: Option<Locator>,
}
impl CertificateIdentity {
pub(crate) fn new_from_capi(ci: &ztcore::ZT_Certificate_Identity) -> CertificateIdentity {
CertificateIdentity {
identity: Identity::new_from_capi(ci.identity, false).clone(),
locator: Locator::new_from_capi(ci.locator, false).clone(),
pub(crate) unsafe fn new_from_capi(ci: &ztcore::ZT_Certificate_Identity) -> Option<CertificateIdentity> {
if ci.identity.is_null() {
return None;
}
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 {
ztcore::ZT_Certificate_Identity {
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 {
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 {
let cidentities: &[ztcore::ZT_Certificate_Identity] = std::slice::from_raw_parts(cs.identities, cs.identityCount as usize);
let mut identities: Vec<CertificateIdentity> = Vec::new();
for i in cidentities.iter() {
identities.push(CertificateIdentity::new_from_capi(i));
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() {
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();
for i in cnetworks.iter() {
networks.push(CertificateNetwork::new_from_capi(i));
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() {
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 ctmp: [u8; 48] = [0; 48];
for i in ccertificates.iter() {
copy_nonoverlapping(*i, ctmp.as_mut_ptr(), 48);
certificates.push(CertificateSerialNo(ctmp));
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];
for i in ccertificates.iter() {
copy_nonoverlapping(*i, ctmp.as_mut_ptr(), 48);
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();
for i in cupdate_urls.iter() {
update_urls.push(CStr::from_ptr(*i).to_str().unwrap().to_string());
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() {
update_urls.push(cstr_to_string(*i, CERTIFICATE_MAX_STRING_LENGTH - 1));
}
}
return CertificateSubject {
@ -417,90 +440,86 @@ impl CertificateSubject {
}
pub(crate) unsafe fn to_capi(&self) -> CertificateSubjectCAPIContainer {
unsafe {
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_certificates: Vec<*const u8> = Vec::new();
let mut capi_urls: Vec<*const c_char> = Vec::new();
let mut capi_urls_strs: Vec<CString> = 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_certificates: Vec<*const u8> = Vec::new();
let mut capi_urls: Vec<*const c_char> = Vec::new();
let mut capi_urls_strs: Vec<CString> = Vec::new();
if !self.identities.is_empty() {
capi_identities.reserve(self.identities.len());
for i in self.identities.iter() {
capi_identities.push((*i).to_capi());
}
}
if !self.networks.is_empty() {
capi_networks.reserve(self.networks.len());
for i in self.networks.iter() {
capi_networks.push((*i).to_capi());
}
}
if !self.certificates.is_empty() {
capi_certificates.reserve(self.certificates.len());
for i in self.certificates.iter() {
capi_certificates.push((*i).0.as_ptr());
}
}
if !self.updateURLs.is_empty() {
capi_urls.reserve(self.updateURLs.len());
for i in self.updateURLs.iter() {
let cs = CString::new((*i).as_str());
if cs.is_ok() {
capi_urls_strs.push(cs.unwrap());
capi_urls.push(capi_urls_strs.last().unwrap().as_ptr());
}
if !self.identities.is_empty() {
capi_identities.reserve(self.identities.len());
for i in self.identities.iter() {
capi_identities.push(unsafe { (*i).to_capi() });
}
}
if !self.networks.is_empty() {
capi_networks.reserve(self.networks.len());
for i in self.networks.iter() {
capi_networks.push((*i).to_capi());
}
}
if !self.certificates.is_empty() {
capi_certificates.reserve(self.certificates.len());
for i in self.certificates.iter() {
capi_certificates.push((*i).0.as_ptr());
}
}
if !self.updateURLs.is_empty() {
capi_urls.reserve(self.updateURLs.len());
for i in self.updateURLs.iter() {
let cs = CString::new((*i).as_str());
if cs.is_ok() {
capi_urls_strs.push(cs.unwrap());
capi_urls.push(capi_urls_strs.last().unwrap().as_ptr());
}
}
}
return CertificateSubjectCAPIContainer {
subject: ztcore::ZT_Certificate_Subject {
timestamp: self.timestamp,
identities: capi_identities.as_mut_ptr(),
networks: capi_networks.as_mut_ptr(),
certificates: capi_certificates.as_ptr(),
updateURLs: capi_urls.as_ptr(),
identityCount: capi_identities.len() as c_uint,
networkCount: capi_networks.len() as c_uint,
certificateCount: capi_certificates.len() as c_uint,
updateURLCount: capi_urls.len() as c_uint,
name: self.name.to_capi(),
uniqueId: self.uniqueId.as_ptr(),
uniqueIdProofSignature: self.uniqueIdProofSignature.as_ptr(),
uniqueIdSize: self.uniqueId.len() as c_uint,
uniqueIdProofSignatureSize: self.uniqueIdProofSignature.len() as c_uint,
},
subject_identities: capi_identities,
subject_networks: capi_networks,
subject_certificates: capi_certificates,
subject_urls: capi_urls,
subject_urls_strs: capi_urls_strs,
};
CertificateSubjectCAPIContainer {
subject: ztcore::ZT_Certificate_Subject {
timestamp: self.timestamp,
identities: capi_identities.as_mut_ptr(),
networks: capi_networks.as_mut_ptr(),
certificates: capi_certificates.as_ptr(),
updateURLs: capi_urls.as_ptr(),
identityCount: capi_identities.len() as c_uint,
networkCount: capi_networks.len() as c_uint,
certificateCount: capi_certificates.len() as c_uint,
updateURLCount: capi_urls.len() as c_uint,
name: unsafe { self.name.to_capi() },
uniqueId: self.uniqueId.as_ptr(),
uniqueIdProofSignature: self.uniqueIdProofSignature.as_ptr(),
uniqueIdSize: self.uniqueId.len() as c_uint,
uniqueIdProofSignatureSize: self.uniqueIdProofSignature.len() as c_uint,
},
subject_identities: capi_identities,
subject_networks: capi_networks,
subject_certificates: capi_certificates,
subject_urls: capi_urls,
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> {
let mut csr: Vec<u8> = Vec::new();
csr.resize(16384, 0);
let mut csr_size: c_int = 16384;
unsafe {
let capi = self.to_capi();
let mut csr: Vec<u8> = Vec::new();
csr.resize(16384, 0);
let mut csr_size: c_int = 16384;
if uid.is_some() {
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);
}
} 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);
}
}
csr.resize(csr_size as usize, 0);
return Ok(csr);
}
return Ok(csr.into_boxed_slice());
}
}
@ -531,14 +550,18 @@ pub(crate) struct CertificateCAPIContainer {
}
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 {
let ccrl: &[*const u8] = std::slice::from_raw_parts(c.crl, c.crlCount as usize);
let mut crl: Vec<CertificateSerialNo> = Vec::new();
let mut ctmp: [u8; 48] = [0; 48];
for i in ccrl.iter() {
copy_nonoverlapping(*i, ctmp.as_mut_ptr(), 48);
crl.push(CertificateSerialNo(ctmp));
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];
for i in ccrl.iter() {
if !(*i).is_null() {
copy_nonoverlapping(*i, ctmp.as_mut_ptr(), 48);
crl.push(CertificateSerialNo(ctmp));
}
}
}
return Certificate {
@ -557,85 +580,82 @@ impl Certificate {
}
}
pub(crate) unsafe fn to_capi(&self) -> CertificateCAPIContainer {
let mut capi_crls: Vec<*const u8> = Vec::new();
capi_crls.reserve(self.crl.len());
for i in self.crl.iter() {
capi_crls.push((*i).0.as_ptr());
}
let subject = unsafe { self.subject.to_capi() };
CertificateCAPIContainer {
certificate: ztcore::ZT_Certificate {
serialNo: self.serialNo.0,
flags: self.flags,
timestamp: self.timestamp,
validity: self.validity,
subject: subject.subject,
issuer: self.issuer.capi,
issuerName: unsafe { self.issuerName.to_capi() },
extendedAttributes: self.extendedAttributes.as_ptr(),
extendedAttributesSize: self.extendedAttributes.len() as c_uint,
maxPathLength: self.maxPathLength as c_uint,
crl: capi_crls.as_ptr(),
crlCount: capi_crls.len() as c_uint,
signature: self.signature.as_ptr(),
signatureSize: self.signature.len() as c_uint,
},
certificate_crls: capi_crls,
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 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 {
unsafe {
let subject = self.subject.to_capi();
let mut capi_crls: Vec<*const u8> = Vec::new();
capi_crls.reserve(self.crl.len());
for i in self.crl.iter() {
capi_crls.push((*i).0.as_ptr());
}
return CertificateCAPIContainer {
certificate: ztcore::ZT_Certificate {
serialNo: self.serialNo.0,
flags: self.flags,
timestamp: self.timestamp,
validity: self.validity,
subject: subject.subject,
issuer: self.issuer.capi,
issuerName: self.issuerName.to_capi(),
extendedAttributes: self.extendedAttributes.as_ptr(),
extendedAttributesSize: self.extendedAttributes.len() as c_uint,
maxPathLength: self.maxPathLength as c_uint,
crl: capi_crls.as_ptr(),
crlCount: capi_crls.len() as c_uint,
signature: self.signature.as_ptr(),
signatureSize: self.signature.len() as c_uint,
},
certificate_crls: capi_crls,
subject_container: subject,
};
}
}
pub fn to_bytes(&self) -> Result<Box<[u8]>, ResultCode> {
let mut cert: Vec<u8> = Vec::new();
cert.resize(16384, 0);
let mut cert_size: c_int = 16384;
unsafe {
let mut cert: Vec<u8> = Vec::new();
cert.resize(16384, 0);
let mut cert_size: c_int = 16384;
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 {
return Err(ResultCode::ErrorInternalNonFatal);
}
cert.resize(cert_size as usize, 0);
return Ok(cert.into_boxed_slice());
}
cert.resize(cert_size as usize, 0);
return Ok(cert.into_boxed_slice());
}
pub fn sign(&self, id: &Identity) -> Result<Vec<u8>, ResultCode> {
if !id.has_private() {
return Err(ResultCode::ErrorBadParameter);
}
let mut signed_cert: Vec<u8> = Vec::new();
signed_cert.resize(16384, 0);
let mut signed_cert_size: c_int = 16384;
unsafe {
let capi = self.to_capi();
let mut signed_cert: Vec<u8> = Vec::new();
signed_cert.resize(16384, 0);
let mut signed_cert_size: c_int = 16384;
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);
}
signed_cert.resize(signed_cert_size as usize, 0);
return Ok(signed_cert);
}
signed_cert.resize(signed_cert_size as usize, 0);
return Ok(signed_cert);
}
pub fn verify(&self) -> CertificateError {

View file

@ -1,4 +1,8 @@
use std::os::raw::{c_char, c_int};
use num_derive::{FromPrimitive, ToPrimitive};
mod bindings;
mod identity;
mod address;
mod fingerprint;
@ -14,13 +18,15 @@ mod buffer;
mod portableatomici64;
mod virtualnetworkconfig;
pub use identity::{Identity, IdentityType};
use bindings::capi as ztcore;
pub use identity::*;
pub use address::Address;
pub use fingerprint::Fingerprint;
pub use endpoint::Endpoint;
pub use certificate::*;
pub use networkid::NetworkId;
pub use locator::Locator;
pub use certificate::*;
pub use path::Path;
pub use peer::Peer;
pub use node::Node;
@ -29,10 +35,6 @@ pub use buffer::Buffer;
pub use portableatomici64::PortableAtomicI64;
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 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
}
/// 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_rules! implement_to_from_json {
($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);
}
}