diff --git a/rust-zerotier-core/src/certificate.rs b/rust-zerotier-core/src/certificate.rs index bc61c14f0..53763443c 100644 --- a/rust-zerotier-core/src/certificate.rs +++ b/rust-zerotier-core/src/certificate.rs @@ -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 { 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> for CertificateSerialNo { - fn from(v: Vec) -> 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, } 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 { + 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 = 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 = 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 = 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 = 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 = Vec::new(); - let mut capi_networks: Vec = 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 = Vec::new(); + let mut capi_identities: Vec = Vec::new(); + let mut capi_networks: Vec = 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 = 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, ResultCode> { + pub fn new_csr(&self, uid: Option<&CertificateSubjectUniqueIdSecret>) -> Result, ResultCode> { + let mut csr: Vec = Vec::new(); + csr.resize(16384, 0); + let mut csr_size: c_int = 16384; + unsafe { let capi = self.to_capi(); - - let mut csr: Vec = 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 = 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 { + 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, ResultCode> { + let mut cert: Vec = Vec::new(); + cert.resize(16384, 0); + let mut cert_size: c_int = 16384; unsafe { - let mut cert: Vec = 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, ResultCode> { if !id.has_private() { return Err(ResultCode::ErrorBadParameter); } + let mut signed_cert: Vec = 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 = 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 { diff --git a/rust-zerotier-core/src/lib.rs b/rust-zerotier-core/src/lib.rs index 5c3f30363..02f4bd613 100644 --- a/rust-zerotier-core/src/lib.rs +++ b/rust-zerotier-core/src/lib.rs @@ -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); - } -}