Certificate.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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. }
  29. Certificate &Certificate::operator=(const ZT_Certificate &apiCert)
  30. {
  31. clear();
  32. Utils::copy< sizeof(ZT_Certificate) >((ZT_Certificate *)this, &apiCert);
  33. return *this;
  34. }
  35. Certificate &Certificate::operator=(const Certificate &cert)
  36. {
  37. *this = *((const ZT_Certificate *)(&cert));
  38. // Zero these since we must explicitly attach all the objects from
  39. // the other certificate to copy them into our containers.
  40. this->subject.identityCount = 0;
  41. this->subject.networkCount = 0;
  42. this->subject.certificateCount = 0;
  43. this->subject.updateUrlCount = 0;
  44. for (unsigned int i = 0; i < cert.subject.identityCount; ++i) {
  45. if (cert.subject.identities[i].identity) {
  46. if (cert.subject.identities[i].locator)
  47. addSubjectNode(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity), *reinterpret_cast<const Locator *>(cert.subject.identities[i].locator));
  48. else addSubjectNode(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity));
  49. }
  50. }
  51. for (unsigned int i = 0; i < cert.subject.networkCount; ++i) {
  52. if (cert.subject.networks[i].id)
  53. addSubjectNetwork(cert.subject.networks[i].id, cert.subject.networks[i].controller);
  54. }
  55. for (unsigned int i = 0; i < cert.subject.certificateCount; ++i) {
  56. if (cert.subject.certificates[i])
  57. addSubjectCertificate(cert.subject.certificates[i]);
  58. }
  59. if (cert.subject.updateUrls) {
  60. for (unsigned int i = 0; i < cert.subject.updateUrlCount; ++i) {
  61. if (cert.subject.updateUrls[i])
  62. addUpdateUrl(cert.subject.updateUrls[i]);
  63. }
  64. }
  65. if (cert.issuer) {
  66. m_identities.push_back(*reinterpret_cast<const Identity *>(cert.issuer));
  67. this->issuer = &(m_identities.back());
  68. }
  69. return *this;
  70. }
  71. ZT_Certificate_Identity *Certificate::addSubjectNode(const Identity &id)
  72. {
  73. // Enlarge array of ZT_Certificate_Identity structs and set pointer to potentially reallocated array.
  74. m_subjectIdentities.resize(++this->subject.identityCount);
  75. this->subject.identities = m_subjectIdentities.data();
  76. // Store a local copy of the actual identity.
  77. m_identities.push_back(id);
  78. // Set ZT_Certificate_Identity struct fields to point to local copy of identity.
  79. m_subjectIdentities.back().identity = &(m_identities.back());
  80. m_subjectIdentities.back().locator = nullptr;
  81. return &(m_subjectIdentities.back());
  82. }
  83. ZT_Certificate_Identity *Certificate::addSubjectNode(const Identity &id, const Locator &loc)
  84. {
  85. // Add identity as above.
  86. ZT_Certificate_Identity *const n = addSubjectNode(id);
  87. // Store local copy of locator.
  88. m_locators.push_back(loc);
  89. // Set pointer to stored local copy of locator.
  90. n->locator = &(m_locators.back());
  91. return n;
  92. }
  93. ZT_Certificate_Network *Certificate::addSubjectNetwork(const uint64_t id, const ZT_Fingerprint &controller)
  94. {
  95. // Enlarge array of ZT_Certificate_Network and set pointer to potentially reallocated array.
  96. m_subjectNetworks.resize(++this->subject.networkCount);
  97. this->subject.networks = m_subjectNetworks.data();
  98. // Set fields in new ZT_Certificate_Network structure.
  99. m_subjectNetworks.back().id = id;
  100. Utils::copy< sizeof(ZT_Fingerprint) >(&(m_subjectNetworks.back().controller), &controller);
  101. return &(m_subjectNetworks.back());
  102. }
  103. void Certificate::addSubjectCertificate(const uint8_t serialNo[ZT_SHA384_DIGEST_SIZE])
  104. {
  105. // Store local copy of serial in m_serials container.
  106. m_serials.push_back(SHA384Hash(serialNo));
  107. // Enlarge array of uint8_t pointers, set new pointer to local copy of serial, and set
  108. // certificates to point to potentially reallocated array.
  109. m_subjectCertificates.resize(++this->subject.certificateCount);
  110. m_subjectCertificates.back() = m_serials.back().data;
  111. this->subject.certificates = m_subjectCertificates.data();
  112. }
  113. void Certificate::addUpdateUrl(const char *url)
  114. {
  115. // Store local copy of URL.
  116. m_strings.push_back(url);
  117. // Add pointer to local copy to pointer array and update C structure to point to
  118. // potentially reallocated array.
  119. m_updateUrls.push_back(m_strings.back().c_str());
  120. this->subject.updateUrls = m_updateUrls.data();
  121. this->subject.updateUrlCount = (unsigned int)m_updateUrls.size();
  122. }
  123. Vector< uint8_t > Certificate::encode(const bool omitSignature) const
  124. {
  125. char tmp[256];
  126. Vector< uint8_t > enc;
  127. Dictionary d;
  128. // A Dictionary is used to encode certificates as it's a common and extensible
  129. // format. Custom packed formats are used for credentials as these are smaller
  130. // and faster to marshal/unmarshal.
  131. d.add("f", this->flags);
  132. d.add("t", (uint64_t)this->timestamp);
  133. d.add("v0", (uint64_t)this->validity[0]);
  134. d.add("v1", (uint64_t)this->validity[1]);
  135. d.add("mP", (uint64_t)this->maxPathLength);
  136. m_encodeSubject(d, false);
  137. if (this->issuer)
  138. d.addO("i", *reinterpret_cast<const Identity *>(this->issuer));
  139. d.add("iN.c", this->issuerName.country);
  140. d.add("iN.o", this->issuerName.organization);
  141. d.add("iN.u", this->issuerName.unit);
  142. d.add("iN.l", this->issuerName.locality);
  143. d.add("iN.p", this->issuerName.province);
  144. d.add("iN.sA", this->issuerName.streetAddress);
  145. d.add("iN.pC", this->issuerName.postalCode);
  146. d.add("iN.cN", this->issuerName.commonName);
  147. d.add("iN.sN", this->issuerName.serialNo);
  148. d.add("iN.e", this->issuerName.email);
  149. d.add("iN.ur", this->issuerName.url);
  150. if ((!omitSignature) && (this->signatureSize > 0) && (this->signatureSize <= sizeof(this->signature)))
  151. d["si"].assign(this->signature, this->signature + this->signatureSize);
  152. d.encode(enc);
  153. return enc;
  154. }
  155. bool Certificate::decode(const Vector< uint8_t > &data)
  156. {
  157. char tmp[256], tmp2[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1];
  158. clear();
  159. Dictionary d;
  160. if (!d.decode(data.data(), (unsigned int)data.size()))
  161. return false;
  162. this->flags = d.getUI("f");
  163. this->timestamp = (int64_t)d.getUI("t");
  164. this->validity[0] = (int64_t)d.getUI("v0");
  165. this->validity[1] = (int64_t)d.getUI("v1");
  166. this->maxPathLength = (unsigned int)d.getUI("mP");
  167. this->subject.timestamp = (int64_t)d.getUI("s.t");
  168. unsigned int cnt = (unsigned int)d.getUI("s.i$");
  169. for (unsigned int i = 0; i < cnt; ++i) {
  170. const Vector< uint8_t > &identityData = d[Dictionary::arraySubscript(tmp, "s.i$.i", i)];
  171. if (identityData.empty())
  172. return false;
  173. Identity id;
  174. if (id.unmarshal(identityData.data(), (unsigned int)identityData.size()) <= 0)
  175. return false;
  176. const Vector< uint8_t > &locatorData = d[Dictionary::arraySubscript(tmp, "s.i$.l", i)];
  177. if (!locatorData.empty()) {
  178. Locator loc;
  179. if (loc.unmarshal(locatorData.data(), (unsigned int)locatorData.size()) <= 0)
  180. return false;
  181. this->addSubjectNode(id, loc);
  182. } else {
  183. this->addSubjectNode(id);
  184. }
  185. }
  186. cnt = (unsigned int)d.getUI("s.n$");
  187. for (unsigned int i = 0; i < cnt; ++i) {
  188. const uint64_t nwid = d.getUI(Dictionary::arraySubscript(tmp, "s.n$.i", i));
  189. const Vector< uint8_t > &fingerprintData = d[Dictionary::arraySubscript(tmp, "s.n$.c", i)];
  190. if ((nwid == 0) || (fingerprintData.empty()))
  191. return false;
  192. Fingerprint fp;
  193. if (fp.unmarshal(fingerprintData.data(), (unsigned int)fingerprintData.size()) <= 0)
  194. return false;
  195. this->addSubjectNetwork(nwid, fp);
  196. }
  197. cnt = (unsigned int)d.getUI("s.c$");
  198. for (unsigned int i = 0; i < cnt; ++i) {
  199. const Vector< uint8_t > &serial = d[Dictionary::arraySubscript(tmp, "s.c$", i)];
  200. if (serial.size() != ZT_SHA384_DIGEST_SIZE)
  201. return false;
  202. this->addSubjectCertificate(serial.data());
  203. }
  204. d.getS("s.n.sN", this->subject.name.serialNo, sizeof(this->subject.name.serialNo));
  205. d.getS("s.n.cN", this->subject.name.commonName, sizeof(this->subject.name.commonName));
  206. d.getS("s.n.c", this->subject.name.country, sizeof(this->subject.name.country));
  207. d.getS("s.n.o", this->subject.name.organization, sizeof(this->subject.name.organization));
  208. d.getS("s.n.u", this->subject.name.unit, sizeof(this->subject.name.unit));
  209. d.getS("s.n.l", this->subject.name.locality, sizeof(this->subject.name.locality));
  210. d.getS("s.n.p", this->subject.name.province, sizeof(this->subject.name.province));
  211. d.getS("s.n.sA", this->subject.name.streetAddress, sizeof(this->subject.name.streetAddress));
  212. d.getS("s.n.pC", this->subject.name.postalCode, sizeof(this->subject.name.postalCode));
  213. d.getS("s.n.e", this->subject.name.email, sizeof(this->subject.name.email));
  214. d.getS("s.n.ur", this->subject.name.url, sizeof(this->subject.name.url));
  215. const Vector< uint8_t > &issuerData = d["i"];
  216. if (!issuerData.empty()) {
  217. Identity id;
  218. if (id.unmarshal(issuerData.data(), (int)issuerData.size()) > 0) {
  219. m_identities.push_back(id);
  220. this->issuer = reinterpret_cast<const Identity *>(&(m_identities.back()));
  221. }
  222. }
  223. d.getS("iN.sN", this->issuerName.serialNo, sizeof(this->issuerName.serialNo));
  224. d.getS("iN.cN", this->issuerName.commonName, sizeof(this->issuerName.commonName));
  225. d.getS("iN.c", this->issuerName.country, sizeof(this->issuerName.country));
  226. d.getS("iN.o", this->issuerName.organization, sizeof(this->issuerName.organization));
  227. d.getS("iN.u", this->issuerName.unit, sizeof(this->issuerName.unit));
  228. d.getS("iN.l", this->issuerName.locality, sizeof(this->issuerName.locality));
  229. d.getS("iN.p", this->issuerName.province, sizeof(this->issuerName.province));
  230. d.getS("iN.sA", this->issuerName.streetAddress, sizeof(this->issuerName.streetAddress));
  231. d.getS("iN.pC", this->issuerName.postalCode, sizeof(this->issuerName.postalCode));
  232. d.getS("iN.e", this->issuerName.email, sizeof(this->issuerName.email));
  233. d.getS("iN.ur", this->issuerName.url, sizeof(this->issuerName.url));
  234. cnt = (unsigned int)d.getUI("u$");
  235. for (unsigned int i = 0; i < cnt; ++i) {
  236. const char *const url = d.getS(Dictionary::arraySubscript(tmp, "u$", i), tmp2, sizeof(tmp2));
  237. if (url)
  238. addUpdateUrl(tmp2);
  239. else return false;
  240. }
  241. const Vector< uint8_t > &sig = d["si"];
  242. if (sig.size() > sizeof(this->signature))
  243. return false;
  244. Utils::copy(this->signature, sig.data(), (unsigned int)sig.size());
  245. this->signatureSize = (unsigned int)sig.size();
  246. Vector< uint8_t > enc(encode(true));
  247. SHA384(this->serialNo, enc.data(), (unsigned int)enc.size());
  248. return true;
  249. }
  250. bool Certificate::sign(const Identity &issuer)
  251. {
  252. Vector< uint8_t > enc(encode(true));
  253. SHA384(this->serialNo, enc.data(), (unsigned int)enc.size());
  254. return (this->signatureSize = issuer.sign(enc.data(), (unsigned int)enc.size(), this->signature, sizeof(this->signature))) > 0;
  255. }
  256. ZT_CertificateError Certificate::verify() const
  257. {
  258. try {
  259. if (this->issuer) {
  260. const Vector< uint8_t > enc(encode(true));
  261. if (!reinterpret_cast<const Identity *>(this->issuer)->verify(enc.data(), (unsigned int)enc.size(), this->signature, this->signatureSize))
  262. return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
  263. } else {
  264. return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
  265. }
  266. if (this->subject.uniqueIdProofSignatureSize > 0) {
  267. static_assert(ZT_ECC384_SIGNATURE_SIZE <= ZT_CERTIFICATE_MAX_SIGNATURE_SIZE, "overflow");
  268. static_assert((ZT_ECC384_PUBLIC_KEY_SIZE + 1) <= ZT_CERTIFICATE_MAX_UNIQUE_ID_SIZE, "overflow");
  269. if (
  270. (this->subject.uniqueIdProofSignatureSize != ZT_ECC384_SIGNATURE_SIZE) ||
  271. (this->subject.uniqueIdSize != (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) ||
  272. (this->subject.uniqueId[0] != ZT_CERTIFICATE_UNIQUE_ID_PUBLIC_KEY_TYPE_NIST_P_384))
  273. return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
  274. Dictionary tmp;
  275. m_encodeSubject(tmp, true);
  276. Vector< uint8_t > enc;
  277. tmp.encode(enc);
  278. uint8_t h[ZT_SHA384_DIGEST_SIZE];
  279. SHA384(h, enc.data(), (unsigned int)enc.size());
  280. if (!ECC384ECDSAVerify(this->subject.uniqueId + 1, h, this->subject.uniqueIdProofSignature))
  281. return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
  282. } else if (this->subject.uniqueIdSize > ZT_CERTIFICATE_MAX_UNIQUE_ID_SIZE) {
  283. return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
  284. }
  285. for (unsigned int i = 0; i < this->subject.identityCount; ++i) {
  286. if (!this->subject.identities[i].identity)
  287. return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
  288. if (!reinterpret_cast<const Identity *>(this->subject.identities[i].identity)->locallyValidate())
  289. return ZT_CERTIFICATE_ERROR_INVALID_IDENTITY;
  290. if (this->subject.identities[i].locator) {
  291. if (!reinterpret_cast<const Locator *>(this->subject.identities[i].locator)->verify(*reinterpret_cast<const Identity *>(this->subject.identities[i].identity)))
  292. return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
  293. }
  294. }
  295. for (unsigned int i = 0; i < this->subject.networkCount; ++i) {
  296. if (!this->subject.networks[i].id)
  297. return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
  298. }
  299. if (this->subject.updateUrlCount) {
  300. if (!this->subject.updateUrls)
  301. return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
  302. for (unsigned int i = 0; i < this->subject.updateUrlCount; ++i) {
  303. if (!this->subject.updateUrls[i])
  304. return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
  305. }
  306. } else if (this->subject.updateUrls) {
  307. return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
  308. }
  309. } catch (...) {}
  310. return ZT_CERTIFICATE_ERROR_NONE;
  311. }
  312. void Certificate::m_encodeSubject(Dictionary &d, bool omitUniqueIdProofSignature) const
  313. {
  314. char tmp[256];
  315. d.add("s.t", (uint64_t)this->subject.timestamp);
  316. d.add("s.i$", (uint64_t)this->subject.identityCount);
  317. for (unsigned int i = 0; i < this->subject.identityCount; ++i) {
  318. if (this->subject.identities[i].identity)
  319. d.addO(Dictionary::arraySubscript(tmp, "s.i$.i", i), *reinterpret_cast<const Identity *>(this->subject.identities[i].identity));
  320. if (this->subject.identities[i].locator)
  321. d.addO(Dictionary::arraySubscript(tmp, "s.i$.l", i), *reinterpret_cast<const Locator *>(this->subject.identities[i].locator));
  322. }
  323. d.add("s.n$", (uint64_t)this->subject.networkCount);
  324. for (unsigned int i = 0; i < this->subject.networkCount; ++i) {
  325. d.add(Dictionary::arraySubscript(tmp, "s.n$.i", i), this->subject.networks[i].id);
  326. Fingerprint fp(this->subject.networks[i].controller);
  327. d.addO(Dictionary::arraySubscript(tmp, "s.n$.c", i), fp);
  328. }
  329. d.add("s.c$", (uint64_t)this->subject.certificateCount);
  330. for (unsigned int i = 0; i < this->subject.certificateCount; ++i) {
  331. if (this->subject.certificates[i])
  332. d[Dictionary::arraySubscript(tmp, "s.c$", i)].assign(this->subject.certificates[i], this->subject.certificates[i] + ZT_SHA384_DIGEST_SIZE);
  333. }
  334. d.add("s.u$", (uint64_t)this->subject.updateUrlCount);
  335. if (this->subject.updateUrls) {
  336. for (unsigned int i = 0; i < this->subject.updateUrlCount; ++i)
  337. d.add(Dictionary::arraySubscript(tmp, "s.u$", i), this->subject.updateUrls[i]);
  338. }
  339. d.add("s.n.c", this->subject.name.country);
  340. d.add("s.n.o", this->subject.name.organization);
  341. d.add("s.n.u", this->subject.name.unit);
  342. d.add("s.n.l", this->subject.name.locality);
  343. d.add("s.n.p", this->subject.name.province);
  344. d.add("s.n.sA", this->subject.name.streetAddress);
  345. d.add("s.n.pC", this->subject.name.postalCode);
  346. d.add("s.n.cN", this->subject.name.commonName);
  347. d.add("s.n.sN", this->subject.name.serialNo);
  348. d.add("s.n.e", this->subject.name.email);
  349. d.add("s.n.ur", this->subject.name.url);
  350. if ((this->subject.uniqueIdSize > 0) && (this->subject.uniqueIdSize <= ZT_CERTIFICATE_MAX_UNIQUE_ID_SIZE))
  351. d["s.uI"].assign(this->subject.uniqueId, this->subject.uniqueId + this->subject.uniqueIdSize);
  352. if ((!omitUniqueIdProofSignature) && (this->subject.uniqueIdProofSignatureSize > 0) && (this->subject.uniqueIdProofSignatureSize <= ZT_CERTIFICATE_MAX_SIGNATURE_SIZE))
  353. d["s.uS"].assign(this->subject.uniqueIdProofSignature, this->subject.uniqueIdProofSignature + this->subject.uniqueIdProofSignatureSize);
  354. }
  355. } // namespace ZeroTier