| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 | /* * Copyright (c)2019 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. * * Change Date: 2026-01-01 * * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2.0 of the Apache License. *//****/#ifndef ZT_REVOCATION_HPP#define ZT_REVOCATION_HPP#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdint.h>#include "Constants.hpp"#include "../include/ZeroTierOne.h"#include "Credential.hpp"#include "Address.hpp"#include "C25519.hpp"#include "Utils.hpp"#include "Buffer.hpp"#include "Identity.hpp"/** * Flag: fast propagation via rumor mill algorithm */#define ZT_REVOCATION_FLAG_FAST_PROPAGATE 0x1ULLnamespace ZeroTier {class RuntimeEnvironment;/** * Revocation certificate to instantaneously revoke a COM, capability, or tag */class Revocation : public Credential{public:	static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; }	Revocation() :		_id(0),		_credentialId(0),		_networkId(0),		_threshold(0),		_flags(0),		_target(),		_signedBy(),		_type(Credential::CREDENTIAL_TYPE_NULL)	{		memset(_signature.data,0,sizeof(_signature.data));	}	/**	 * @param i ID (arbitrary for revocations, currently random)	 * @param nwid Network ID	 * @param cid Credential ID being revoked (0 for all or for COMs, which lack IDs)	 * @param thr Revocation time threshold before which credentials will be revoked	 * @param fl Flags	 * @param tgt Target node whose credential(s) are being revoked	 * @param ct Credential type being revoked	 */	Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const int64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) :		_id(i),		_credentialId(cid),		_networkId(nwid),		_threshold(thr),		_flags(fl),		_target(tgt),		_signedBy(),		_type(ct)	{		memset(_signature.data,0,sizeof(_signature.data));	}	inline uint32_t id() const { return _id; }	inline uint32_t credentialId() const { return _credentialId; }	inline uint64_t networkId() const { return _networkId; }	inline int64_t threshold() const { return _threshold; }	inline const Address &target() const { return _target; }	inline const Address &signer() const { return _signedBy; }	inline Credential::Type type() const { return _type; }	inline bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }	/**	 * @param signer Signing identity, must have private key	 * @return True if signature was successful	 */	inline bool sign(const Identity &signer)	{		if (signer.hasPrivate()) {			Buffer<sizeof(Revocation) + 64> tmp;			_signedBy = signer.address();			this->serialize(tmp,true);			_signature = signer.sign(tmp.data(),tmp.size());			return true;		}		return false;	}	/**	 * Verify this revocation's signature	 *	 * @param RR Runtime environment to provide for peer lookup, etc.	 * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call	 * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain	 */	int verify(const RuntimeEnvironment *RR,void *tPtr) const;	template<unsigned int C>	inline void serialize(Buffer<C> &b,const bool forSign = false) const	{		if (forSign) {			b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);		}		b.append((uint32_t)0); // 4 unused bytes, currently set to 0		b.append(_id);		b.append(_networkId);		b.append((uint32_t)0); // 4 unused bytes, currently set to 0		b.append(_credentialId);		b.append(_threshold);		b.append(_flags);		_target.appendTo(b);		_signedBy.appendTo(b);		b.append((uint8_t)_type);		if (!forSign) {			b.append((uint8_t)1); // 1 == Ed25519 signature			b.append((uint16_t)ZT_C25519_SIGNATURE_LEN);			b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);		}		// This is the size of any additional fields, currently 0.		b.append((uint16_t)0);		if (forSign) {			b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);		}	}	template<unsigned int C>	inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)	{		*this = Revocation();		unsigned int p = startAt;		p += 4; // 4 bytes, currently unused		_id = b.template at<uint32_t>(p);		p += 4;		_networkId = b.template at<uint64_t>(p);		p += 8;		p += 4; // 4 bytes, currently unused		_credentialId = b.template at<uint32_t>(p);		p += 4;		_threshold = (int64_t)b.template at<uint64_t>(p);		p += 8;		_flags = b.template at<uint64_t>(p);		p += 8;		_target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);		p += ZT_ADDRESS_LENGTH;		_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);		p += ZT_ADDRESS_LENGTH;		_type = (Credential::Type)b[p++];		if (b[p++] == 1) {			if (b.template at<uint16_t>(p) == ZT_C25519_SIGNATURE_LEN) {				p += 2;				memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);				p += ZT_C25519_SIGNATURE_LEN;			} else {				throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;			}		} else {			p += 2 + b.template at<uint16_t>(p);		}		p += 2 + b.template at<uint16_t>(p);		if (p > b.size()) {			throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;		}		return (p - startAt);	}private:	uint32_t _id;	uint32_t _credentialId;	uint64_t _networkId;	int64_t _threshold;	uint64_t _flags;	Address _target;	Address _signedBy;	Credential::Type _type;	C25519::Signature _signature;};} // namespace ZeroTier#endif
 |