diff options
Diffstat (limited to 'node/CertificateOfMembership.hpp')
-rw-r--r-- | node/CertificateOfMembership.hpp | 150 |
1 files changed, 139 insertions, 11 deletions
diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 7ae60ba1..8f73f9e2 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -50,10 +50,8 @@ namespace ZeroTier { * These contain an id, a value, and a maximum delta. * * The ID is arbitrary and should be assigned using a scheme that makes - * every ID globally unique. ID 0 is reserved for the always-present - * validity timestamp and range, and ID 1 is reserved for the always-present - * network ID. IDs less than 65536 are reserved for future global - * assignment. + * every ID globally unique. IDs beneath 65536 are reserved for global + * assignment by ZeroTier Networks. * * The value's meaning is ID-specific and isn't important here. What's * important is the value and the third member of the tuple: the maximum @@ -83,22 +81,108 @@ public: }; /** - * Reserved COM IDs + * Reserved qualifier IDs * * IDs below 65536 should be considered reserved for future global * assignment here. + * + * Addition of new required fields requires that code in hasRequiredFields + * be updated as well. */ enum ReservedId { - COM_RESERVED_ID_TIMESTAMP = 0, // timestamp, max delta defines cert life - COM_RESERVED_ID_NETWORK_ID = 1 // network ID, max delta always 0 + /** + * Timestamp of certificate issue in milliseconds since epoch + * + * maxDelta here defines certificate lifetime, and certs are lazily + * pushed to other peers on a net with a frequency of 1/2 this time. + */ + COM_RESERVED_ID_TIMESTAMP = 0, + + /** + * Network ID for which certificate was issued + * + * maxDelta here is zero, since this must match. + */ + COM_RESERVED_ID_NETWORK_ID = 1, + + /** + * ZeroTier address to whom certificate was issued + * + * maxDelta will be 0xffffffffffffffff here since it's permitted to differ + * from peers obviously. + */ + COM_RESERVED_ID_ISSUED_TO = 2 }; + /** + * Create an empty certificate + */ CertificateOfMembership() { memset(_signature.data,0,_signature.size()); } + + /** + * Create from required fields common to all networks + * + * @param timestamp Timestamp of cert + * @param timestampMaxDelta Maximum variation between timestamps on this net + * @param nwid Network ID + * @param issuedTo Certificate recipient + */ + CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo) + { + _qualifiers.push_back(_Qualifier(COM_RESERVED_ID_TIMESTAMP,timestamp,timestampMaxDelta)); + _qualifiers.push_back(_Qualifier(COM_RESERVED_ID_NETWORK_ID,nwid,0)); + _qualifiers.push_back(_Qualifier(COM_RESERVED_ID_ISSUED_TO,issuedTo.toInt(),0xffffffffffffffffULL)); + memset(_signature.data,0,_signature.size()); + } + + /** + * Create from string-serialized data + * + * @param s String-serialized COM + */ CertificateOfMembership(const char *s) { fromString(s); } + + /** + * Create from string-serialized data + * + * @param s String-serialized COM + */ CertificateOfMembership(const std::string &s) { fromString(s.c_str()); } /** + * Create from binary-serialized COM in buffer + * + * @param b Buffer to deserialize from + * @param startAt Position to start in buffer + */ + template<unsigned int C> + CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0) + throw(std::out_of_range,std::invalid_argument) + { + deserialize(b,startAt); + } + + /** + * Check for presence of all required fields common to all networks + * + * @return True if all required fields are present + */ + inline bool hasRequiredFields() const + throw() + { + if (_qualifiers.size() < 3) + return false; + if (_qualifiers[0].id != COM_RESERVED_ID_TIMESTAMP) + return false; + if (_qualifiers[1].id != COM_RESERVED_ID_NETWORK_ID) + return false; + if (_qualifiers[2].id != COM_RESERVED_ID_ISSUED_TO) + return false; + return true; + } + + /** * @return Maximum delta for mandatory timestamp field or 0 if field missing */ inline uint64_t timestampMaxDelta() const @@ -112,6 +196,45 @@ public: } /** + * @return Timestamp for this cert in ms since epoch (according to netconf's clock) + */ + inline Address timestamp() const + throw() + { + for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) { + if (q->id == COM_RESERVED_ID_TIMESTAMP) + return Address(q->value); + } + return Address(); + } + + /** + * @return Address to which this cert was issued + */ + inline Address issuedTo() const + throw() + { + for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) { + if (q->id == COM_RESERVED_ID_ISSUED_TO) + return Address(q->value); + } + return Address(); + } + + /** + * @return Network ID for which this cert was issued + */ + inline uint64_t networkId() const + throw() + { + for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) { + if (q->id == COM_RESERVED_ID_NETWORK_ID) + return q->value; + } + return 0ULL; + } + + /** * Add or update a qualifier in this certificate * * Any signature is invalidated and signedBy is set to null. @@ -186,7 +309,7 @@ public: throw(std::out_of_range) { b.append((unsigned char)COM_UINT64_ED25519); - b.append((uint32_t)_qualifiers.size()); + b.append((uint16_t)_qualifiers.size()); for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) { b.append(q->id); b.append(q->value); @@ -209,10 +332,15 @@ public: if (b[p++] != COM_UINT64_ED25519) throw std::invalid_argument("unknown certificate of membership type"); - unsigned int numq = b.template at<uint32_t>(p); p += sizeof(uint32_t); + unsigned int numq = b.template at<uint16_t>(p); p += sizeof(uint16_t); + uint64_t lastId = 0; for(unsigned int i=0;i<numq;++i) { + uint64_t tmp = b.template at<uint64_t>(p); + if (tmp < lastId) + throw std::invalid_argument("certificate qualifiers are not sorted"); + else lastId = tmp; _qualifiers.push_back(_Qualifier( - b.template at<uint64_t>(p), + tmp, b.template at<uint64_t>(p + 8), b.template at<uint64_t>(p + 16) )); @@ -247,8 +375,8 @@ private: inline bool operator<(const _Qualifier &q) const throw() { return (id < q.id); } // for sort }; - std::vector<_Qualifier> _qualifiers; // sorted by id and unique Address _signedBy; + std::vector<_Qualifier> _qualifiers; // sorted by id and unique C25519::Signature _signature; }; |