| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 | /* * 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 "../include/ZeroTierOne.h"#include "Address.hpp"#include "Buffer.hpp"#include "Constants.hpp"#include "Credential.hpp"#include "ECC.hpp"#include "Identity.hpp"#include "Utils.hpp"#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>/** * 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_ECC_SIGNATURE_LEN);			b.append(_signature.data, ZT_ECC_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_ECC_SIGNATURE_LEN) {				p += 2;				memcpy(_signature.data, b.field(p, ZT_ECC_SIGNATURE_LEN), ZT_ECC_SIGNATURE_LEN);				p += ZT_ECC_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;	ECC::Signature _signature;};}	// namespace ZeroTier#endif
 |