Certificate.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /*
  2. * Copyright (c)2013-2020 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2024-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. #include "Certificate.hpp"
  14. #include "SHA512.hpp"
  15. #include "ECC384.hpp"
  16. namespace ZeroTier {
  17. void Certificate::clear()
  18. {
  19. Utils::zero< sizeof(ZT_Certificate) >((ZT_Certificate *)this);
  20. m_identities.clear();
  21. m_locators.clear();
  22. m_strings.clear();
  23. m_serials.clear();
  24. m_subjectIdentities.clear();
  25. m_subjectNetworks.clear();
  26. m_updateUrls.clear();
  27. m_subjectCertificates.clear();
  28. m_extendedAttributes.clear();
  29. m_subjectUniqueId.clear();
  30. m_subjectUniqueIdProofSignature.clear();
  31. m_signature.clear();
  32. }
  33. Certificate &Certificate::operator=(const ZT_Certificate &apiCert)
  34. {
  35. clear();
  36. Utils::copy< sizeof(ZT_Certificate) >((ZT_Certificate *)this, &apiCert);
  37. return *this;
  38. }
  39. Certificate &Certificate::operator=(const Certificate &cert)
  40. {
  41. *this = *((const ZT_Certificate *)(&cert));
  42. // Zero these since we must explicitly attach all the objects from
  43. // the other certificate to copy them into our containers.
  44. this->subject.identities = nullptr;
  45. this->subject.identityCount = 0;
  46. this->subject.networks = nullptr;
  47. this->subject.networkCount = 0;
  48. this->subject.certificates = nullptr;
  49. this->subject.certificateCount = 0;
  50. this->subject.updateUrls = nullptr;
  51. this->subject.updateUrlCount = 0;
  52. this->extendedAttributes = nullptr;
  53. this->extendedAttributesSize = 0;
  54. this->issuer = nullptr;
  55. for (unsigned int i = 0; i < cert.subject.identityCount; ++i) {
  56. if (cert.subject.identities[i].identity) {
  57. if (cert.subject.identities[i].locator)
  58. addSubjectIdentity(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity), *reinterpret_cast<const Locator *>(cert.subject.identities[i].locator));
  59. else addSubjectIdentity(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity));
  60. }
  61. }
  62. for (unsigned int i = 0; i < cert.subject.networkCount; ++i) {
  63. if (cert.subject.networks[i].id)
  64. addSubjectNetwork(cert.subject.networks[i].id, cert.subject.networks[i].controller);
  65. }
  66. for (unsigned int i = 0; i < cert.subject.certificateCount; ++i) {
  67. if (cert.subject.certificates[i])
  68. addSubjectCertificate(cert.subject.certificates[i]);
  69. }
  70. if (cert.subject.updateUrls) {
  71. for (unsigned int i = 0; i < cert.subject.updateUrlCount; ++i) {
  72. if (cert.subject.updateUrls[i])
  73. addSubjectUpdateUrl(cert.subject.updateUrls[i]);
  74. }
  75. }
  76. if ((cert.extendedAttributes) && (cert.extendedAttributesSize > 0)) {
  77. m_extendedAttributes.assign(cert.extendedAttributes, cert.extendedAttributes + cert.extendedAttributesSize);
  78. this->extendedAttributes = m_extendedAttributes.data();
  79. this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size();
  80. }
  81. if (cert.issuer) {
  82. m_identities.push_back(*reinterpret_cast<const Identity *>(cert.issuer));
  83. this->issuer = &(m_identities.back());
  84. }
  85. return *this;
  86. }
  87. ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id)
  88. {
  89. // Enlarge array of ZT_Certificate_Identity structs and set pointer to potentially reallocated array.
  90. m_subjectIdentities.resize(++this->subject.identityCount);
  91. this->subject.identities = m_subjectIdentities.data();
  92. // Store a local copy of the actual identity.
  93. m_identities.push_back(id);
  94. // Set ZT_Certificate_Identity struct fields to point to local copy of identity.
  95. m_subjectIdentities.back().identity = &(m_identities.back());
  96. m_subjectIdentities.back().locator = nullptr;
  97. return &(m_subjectIdentities.back());
  98. }
  99. ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id, const Locator &loc)
  100. {
  101. // Add identity as above.
  102. ZT_Certificate_Identity *const n = addSubjectIdentity(id);
  103. // Store local copy of locator.
  104. m_locators.push_back(loc);
  105. // Set pointer to stored local copy of locator.
  106. n->locator = &(m_locators.back());
  107. return n;
  108. }
  109. ZT_Certificate_Network *Certificate::addSubjectNetwork(const uint64_t id, const ZT_Fingerprint &controller)
  110. {
  111. // Enlarge array of ZT_Certificate_Network and set pointer to potentially reallocated array.
  112. m_subjectNetworks.resize(++this->subject.networkCount);
  113. this->subject.networks = m_subjectNetworks.data();
  114. // Set fields in new ZT_Certificate_Network structure.
  115. m_subjectNetworks.back().id = id;
  116. Utils::copy< sizeof(ZT_Fingerprint) >(&(m_subjectNetworks.back().controller), &controller);
  117. return &(m_subjectNetworks.back());
  118. }
  119. void Certificate::addSubjectCertificate(const uint8_t serialNo[ZT_SHA384_DIGEST_SIZE])
  120. {
  121. // Store local copy of serial in m_serials container.
  122. m_serials.push_back(SHA384Hash(serialNo));
  123. // Enlarge array of uint8_t pointers, set new pointer to local copy of serial, and set
  124. // certificates to point to potentially reallocated array.
  125. m_subjectCertificates.resize(++this->subject.certificateCount);
  126. m_subjectCertificates.back() = m_serials.back().data;
  127. this->subject.certificates = m_subjectCertificates.data();
  128. }
  129. void Certificate::addSubjectUpdateUrl(const char *url)
  130. {
  131. // Store local copy of URL.
  132. m_strings.push_back(url);
  133. // Add pointer to local copy to pointer array and update C structure to point to
  134. // potentially reallocated array.
  135. m_updateUrls.push_back(m_strings.back().c_str());
  136. this->subject.updateUrls = m_updateUrls.data();
  137. this->subject.updateUrlCount = (unsigned int)m_updateUrls.size();
  138. }
  139. Vector< uint8_t > Certificate::encode(const bool omitSignature) const
  140. {
  141. Vector< uint8_t > enc;
  142. Dictionary d;
  143. // A Dictionary is used to encode certificates as it's a common and extensible
  144. // format. Custom packed formats are used for credentials as these are smaller
  145. // and faster to marshal/unmarshal.
  146. if (this->flags != 0)
  147. d.add("f", this->flags);
  148. d.add("t", (uint64_t)this->timestamp);
  149. d.add("v#0", (uint64_t)this->validity[0]);
  150. d.add("v#1", (uint64_t)this->validity[1]);
  151. if ((this->extendedAttributes) && (this->extendedAttributesSize > 0))
  152. d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize);
  153. d.add("mP", (uint64_t)this->maxPathLength);
  154. m_encodeSubject(this->subject, d, false);
  155. if (this->issuer)
  156. d.addO("i", *reinterpret_cast<const Identity *>(this->issuer));
  157. if (this->issuerName.country[0])
  158. d.add("iN.c", this->issuerName.country);
  159. if (this->issuerName.organization[0])
  160. d.add("iN.o", this->issuerName.organization);
  161. if (this->issuerName.unit[0])
  162. d.add("iN.u", this->issuerName.unit);
  163. if (this->issuerName.locality[0])
  164. d.add("iN.l", this->issuerName.locality);
  165. if (this->issuerName.province[0])
  166. d.add("iN.p", this->issuerName.province);
  167. if (this->issuerName.streetAddress[0])
  168. d.add("iN.sA", this->issuerName.streetAddress);
  169. if (this->issuerName.postalCode[0])
  170. d.add("iN.pC", this->issuerName.postalCode);
  171. if (this->issuerName.commonName[0])
  172. d.add("iN.cN", this->issuerName.commonName);
  173. if (this->issuerName.serialNo[0])
  174. d.add("iN.sN", this->issuerName.serialNo);
  175. if (this->issuerName.email[0])
  176. d.add("iN.e", this->issuerName.email);
  177. if (this->issuerName.url[0])
  178. d.add("iN.ur", this->issuerName.url);
  179. if (this->issuerName.host[0])
  180. d.add("iN.h", this->issuerName.host);
  181. if ((!omitSignature) && (this->signatureSize > 0) && (this->signatureSize <= sizeof(this->signature)))
  182. d["si"].assign(this->signature, this->signature + this->signatureSize);
  183. d.encode(enc);
  184. return enc;
  185. }
  186. bool Certificate::decode(const Vector< uint8_t > &data)
  187. {
  188. char tmp[256], tmp2[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1];
  189. clear();
  190. Dictionary d;
  191. if (!d.decode(data.data(), (unsigned int)data.size()))
  192. return false;
  193. this->flags = d.getUI("f");
  194. this->timestamp = (int64_t)d.getUI("t");
  195. this->validity[0] = (int64_t)d.getUI("v#0");
  196. this->validity[1] = (int64_t)d.getUI("v#1");
  197. this->maxPathLength = (unsigned int)d.getUI("mP");
  198. m_extendedAttributes = d["x"];
  199. if (!m_extendedAttributes.empty()) {
  200. this->extendedAttributes = m_extendedAttributes.data();
  201. this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size();
  202. }
  203. this->subject.timestamp = (int64_t)d.getUI("s.t");
  204. unsigned int cnt = (unsigned int)d.getUI("s.i$");
  205. for (unsigned int i = 0; i < cnt; ++i) {
  206. const Vector< uint8_t > &identityData = d[Dictionary::arraySubscript(tmp, "s.i$.i", i)];
  207. if (identityData.empty())
  208. return false;
  209. Identity id;
  210. if (id.unmarshal(identityData.data(), (unsigned int)identityData.size()) <= 0)
  211. return false;
  212. const Vector< uint8_t > &locatorData = d[Dictionary::arraySubscript(tmp, "s.i$.l", i)];
  213. if (!locatorData.empty()) {
  214. Locator loc;
  215. if (loc.unmarshal(locatorData.data(), (unsigned int)locatorData.size()) <= 0)
  216. return false;
  217. this->addSubjectIdentity(id, loc);
  218. } else {
  219. this->addSubjectIdentity(id);
  220. }
  221. }
  222. cnt = (unsigned int)d.getUI("s.n$");
  223. for (unsigned int i = 0; i < cnt; ++i) {
  224. const uint64_t nwid = d.getUI(Dictionary::arraySubscript(tmp, "s.n$.i", i));
  225. const Vector< uint8_t > &fingerprintData = d[Dictionary::arraySubscript(tmp, "s.n$.c", i)];
  226. if ((nwid == 0) || (fingerprintData.empty()))
  227. return false;
  228. Fingerprint fp;
  229. if (fp.unmarshal(fingerprintData.data(), (unsigned int)fingerprintData.size()) <= 0)
  230. return false;
  231. this->addSubjectNetwork(nwid, fp);
  232. }
  233. cnt = (unsigned int)d.getUI("s.c$");
  234. for (unsigned int i = 0; i < cnt; ++i) {
  235. const Vector< uint8_t > &serial = d[Dictionary::arraySubscript(tmp, "s.c$", i)];
  236. if (serial.size() != ZT_SHA384_DIGEST_SIZE)
  237. return false;
  238. this->addSubjectCertificate(serial.data());
  239. }
  240. cnt = (unsigned int)d.getUI("s.u$");
  241. for (unsigned int i = 0; i < cnt; ++i)
  242. addSubjectUpdateUrl(d.getS(Dictionary::arraySubscript(tmp, "s.u$", i), tmp, sizeof(tmp)));
  243. d.getS("s.n.sN", this->subject.name.serialNo, sizeof(this->subject.name.serialNo));
  244. d.getS("s.n.cN", this->subject.name.commonName, sizeof(this->subject.name.commonName));
  245. d.getS("s.n.c", this->subject.name.country, sizeof(this->subject.name.country));
  246. d.getS("s.n.o", this->subject.name.organization, sizeof(this->subject.name.organization));
  247. d.getS("s.n.u", this->subject.name.unit, sizeof(this->subject.name.unit));
  248. d.getS("s.n.l", this->subject.name.locality, sizeof(this->subject.name.locality));
  249. d.getS("s.n.p", this->subject.name.province, sizeof(this->subject.name.province));
  250. d.getS("s.n.sA", this->subject.name.streetAddress, sizeof(this->subject.name.streetAddress));
  251. d.getS("s.n.pC", this->subject.name.postalCode, sizeof(this->subject.name.postalCode));
  252. d.getS("s.n.e", this->subject.name.email, sizeof(this->subject.name.email));
  253. d.getS("s.n.ur", this->subject.name.url, sizeof(this->subject.name.url));
  254. d.getS("s.n.h", this->subject.name.host, sizeof(this->subject.name.host));
  255. m_subjectUniqueId = d["s.uI"];
  256. if (!m_subjectUniqueId.empty()) {
  257. this->subject.uniqueId = m_subjectUniqueId.data();
  258. this->subject.uniqueIdSize = (unsigned int)m_subjectUniqueId.size();
  259. }
  260. m_subjectUniqueIdProofSignature = d["s.uS"];
  261. if (!m_subjectUniqueIdProofSignature.empty()) {
  262. this->subject.uniqueIdProofSignature = m_subjectUniqueIdProofSignature.data();
  263. this->subject.uniqueIdProofSignatureSize = (unsigned int)m_subjectUniqueIdProofSignature.size();
  264. }
  265. const Vector< uint8_t > &issuerData = d["i"];
  266. if (!issuerData.empty()) {
  267. Identity id;
  268. if (id.unmarshal(issuerData.data(), (int)issuerData.size()) > 0) {
  269. m_identities.push_back(id);
  270. this->issuer = reinterpret_cast<const Identity *>(&(m_identities.back()));
  271. }
  272. }
  273. d.getS("iN.sN", this->issuerName.serialNo, sizeof(this->issuerName.serialNo));
  274. d.getS("iN.cN", this->issuerName.commonName, sizeof(this->issuerName.commonName));
  275. d.getS("iN.c", this->issuerName.country, sizeof(this->issuerName.country));
  276. d.getS("iN.o", this->issuerName.organization, sizeof(this->issuerName.organization));
  277. d.getS("iN.u", this->issuerName.unit, sizeof(this->issuerName.unit));
  278. d.getS("iN.l", this->issuerName.locality, sizeof(this->issuerName.locality));
  279. d.getS("iN.p", this->issuerName.province, sizeof(this->issuerName.province));
  280. d.getS("iN.sA", this->issuerName.streetAddress, sizeof(this->issuerName.streetAddress));
  281. d.getS("iN.pC", this->issuerName.postalCode, sizeof(this->issuerName.postalCode));
  282. d.getS("iN.e", this->issuerName.email, sizeof(this->issuerName.email));
  283. d.getS("iN.ur", this->issuerName.url, sizeof(this->issuerName.url));
  284. d.getS("iN.h", this->issuerName.host, sizeof(this->issuerName.host));
  285. cnt = (unsigned int)d.getUI("u$");
  286. for (unsigned int i = 0; i < cnt; ++i) {
  287. const char *const url = d.getS(Dictionary::arraySubscript(tmp, "u$", i), tmp2, sizeof(tmp2));
  288. if (url)
  289. addSubjectUpdateUrl(tmp2);
  290. else return false;
  291. }
  292. m_signature = d["si"];
  293. if (!m_signature.empty()) {
  294. this->signature = m_signature.data();
  295. this->signatureSize = (unsigned int)m_signature.size();
  296. }
  297. const Vector< uint8_t > enc(encode(true));
  298. SHA384(this->serialNo, enc.data(), (unsigned int)enc.size());
  299. return true;
  300. }
  301. bool Certificate::sign(const Identity &issuer)
  302. {
  303. Vector< uint8_t > enc(encode(true));
  304. SHA384(this->serialNo, enc.data(), (unsigned int)enc.size());
  305. uint8_t sig[ZT_SIGNATURE_BUFFER_SIZE];
  306. const unsigned int sigSize = issuer.sign(enc.data(), (unsigned int)enc.size(), sig, sizeof(sig));
  307. if (sigSize > 0) {
  308. m_signature.assign(sig, sig + sigSize);
  309. this->signature = m_signature.data();
  310. this->signatureSize = sigSize;
  311. return true;
  312. }
  313. m_signature.clear();
  314. this->signature = nullptr;
  315. this->signatureSize = 0;
  316. return false;
  317. }
  318. ZT_CertificateError Certificate::verify() const
  319. {
  320. try {
  321. if (this->issuer) {
  322. const Vector< uint8_t > enc(encode(true));
  323. if (!reinterpret_cast<const Identity *>(this->issuer)->verify(enc.data(), (unsigned int)enc.size(), this->signature, this->signatureSize))
  324. return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
  325. } else {
  326. return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
  327. }
  328. if (this->subject.uniqueIdProofSignatureSize > 0) {
  329. if (
  330. (this->subject.uniqueIdProofSignatureSize != ZT_ECC384_SIGNATURE_SIZE) ||
  331. (this->subject.uniqueIdSize != (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) ||
  332. (this->subject.uniqueId[0] != ZT_CERTIFICATE_UNIQUE_ID_PUBLIC_KEY_TYPE_NIST_P_384))
  333. return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
  334. Dictionary tmp;
  335. m_encodeSubject(this->subject, tmp, true);
  336. Vector< uint8_t > enc;
  337. tmp.encode(enc);
  338. uint8_t h[ZT_SHA384_DIGEST_SIZE];
  339. SHA384(h, enc.data(), (unsigned int)enc.size());
  340. if (!ECC384ECDSAVerify(this->subject.uniqueId + 1, h, this->subject.uniqueIdProofSignature))
  341. return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
  342. } else if (this->subject.uniqueIdSize > 0) {
  343. return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
  344. }
  345. for (unsigned int i = 0; i < this->subject.identityCount; ++i) {
  346. if (!this->subject.identities[i].identity)
  347. return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
  348. if (!reinterpret_cast<const Identity *>(this->subject.identities[i].identity)->locallyValidate())
  349. return ZT_CERTIFICATE_ERROR_INVALID_IDENTITY;
  350. if (this->subject.identities[i].locator) {
  351. if (!reinterpret_cast<const Locator *>(this->subject.identities[i].locator)->verify(*reinterpret_cast<const Identity *>(this->subject.identities[i].identity)))
  352. return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
  353. }
  354. }
  355. for (unsigned int i = 0; i < this->subject.networkCount; ++i) {
  356. if (!this->subject.networks[i].id)
  357. return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
  358. }
  359. if (this->subject.updateUrlCount) {
  360. if (!this->subject.updateUrls)
  361. return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
  362. for (unsigned int i = 0; i < this->subject.updateUrlCount; ++i) {
  363. if (!this->subject.updateUrls[i])
  364. return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
  365. }
  366. } else if (this->subject.updateUrls) {
  367. return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
  368. }
  369. } catch (...) {}
  370. return ZT_CERTIFICATE_ERROR_NONE;
  371. }
  372. bool Certificate::setSubjectUniqueId(const uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_SIZE_TYPE_NIST_P_384], const uint8_t uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_PRIVATE_KEY_SIZE_TYPE_NIST_P_384])
  373. {
  374. m_subjectUniqueId.assign(uniqueId, uniqueId + ZT_CERTIFICATE_UNIQUE_ID_SIZE_TYPE_NIST_P_384);
  375. this->subject.uniqueId = m_subjectUniqueId.data();
  376. this->subject.uniqueIdSize = ZT_CERTIFICATE_UNIQUE_ID_SIZE_TYPE_NIST_P_384;
  377. Dictionary d;
  378. m_encodeSubject(this->subject, d, true);
  379. Vector< uint8_t > enc;
  380. d.encode(enc);
  381. uint8_t h[ZT_SHA384_DIGEST_SIZE];
  382. SHA384(h, enc.data(), (unsigned int)enc.size());
  383. m_subjectUniqueIdProofSignature.resize(ZT_ECC384_SIGNATURE_SIZE);
  384. ECC384ECDSASign(uniqueIdPrivate, h, m_subjectUniqueIdProofSignature.data());
  385. this->subject.uniqueIdProofSignature = m_subjectUniqueIdProofSignature.data();
  386. this->subject.uniqueIdProofSignatureSize = ZT_ECC384_SIGNATURE_SIZE;
  387. return true;
  388. }
  389. void Certificate::m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d, bool omitUniqueIdProofSignature)
  390. {
  391. char tmp[256];
  392. d.add("s.t", (uint64_t)s.timestamp);
  393. d.add("s.i$", (uint64_t)s.identityCount);
  394. for (unsigned int i = 0; i < s.identityCount; ++i) {
  395. if (s.identities[i].identity)
  396. d.addO(Dictionary::arraySubscript(tmp, "s.i$.i", i), *reinterpret_cast<const Identity *>(s.identities[i].identity));
  397. if (s.identities[i].locator)
  398. d.addO(Dictionary::arraySubscript(tmp, "s.i$.l", i), *reinterpret_cast<const Locator *>(s.identities[i].locator));
  399. }
  400. d.add("s.n$", (uint64_t)s.networkCount);
  401. for (unsigned int i = 0; i < s.networkCount; ++i) {
  402. d.add(Dictionary::arraySubscript(tmp, "s.n$.i", i), s.networks[i].id);
  403. Fingerprint fp(s.networks[i].controller);
  404. d.addO(Dictionary::arraySubscript(tmp, "s.n$.c", i), fp);
  405. }
  406. d.add("s.c$", (uint64_t)s.certificateCount);
  407. for (unsigned int i = 0; i < s.certificateCount; ++i) {
  408. if (s.certificates[i])
  409. d[Dictionary::arraySubscript(tmp, "s.c$", i)].assign(s.certificates[i], s.certificates[i] + ZT_SHA384_DIGEST_SIZE);
  410. }
  411. d.add("s.u$", (uint64_t)s.updateUrlCount);
  412. if (s.updateUrls) {
  413. for (unsigned int i = 0; i < s.updateUrlCount; ++i)
  414. d.add(Dictionary::arraySubscript(tmp, "s.u$", i), s.updateUrls[i]);
  415. }
  416. if (s.name.country[0])
  417. d.add("s.n.c", s.name.country);
  418. if (s.name.organization[0])
  419. d.add("s.n.o", s.name.organization);
  420. if (s.name.unit[0])
  421. d.add("s.n.u", s.name.unit);
  422. if (s.name.locality[0])
  423. d.add("s.n.l", s.name.locality);
  424. if (s.name.province[0])
  425. d.add("s.n.p", s.name.province);
  426. if (s.name.streetAddress[0])
  427. d.add("s.n.sA", s.name.streetAddress);
  428. if (s.name.postalCode[0])
  429. d.add("s.n.pC", s.name.postalCode);
  430. if (s.name.commonName[0])
  431. d.add("s.n.cN", s.name.commonName);
  432. if (s.name.serialNo[0])
  433. d.add("s.n.sN", s.name.serialNo);
  434. if (s.name.email[0])
  435. d.add("s.n.e", s.name.email);
  436. if (s.name.url[0])
  437. d.add("s.n.ur", s.name.url);
  438. if (s.name.host[0])
  439. d.add("s.n.h", s.name.host);
  440. if ((s.uniqueIdSize > 0) && (s.uniqueId != nullptr))
  441. d["s.uI"].assign(s.uniqueId, s.uniqueId + s.uniqueIdSize);
  442. if ((!omitUniqueIdProofSignature) && (s.uniqueIdProofSignatureSize > 0) && (s.uniqueIdProofSignature != nullptr))
  443. d["s.uS"].assign(s.uniqueIdProofSignature, s.uniqueIdProofSignature + s.uniqueIdProofSignatureSize);
  444. }
  445. } // namespace ZeroTier