Jelajahi Sumber

Certificate API

Adam Ierymenko 5 tahun lalu
induk
melakukan
899f0c9749
7 mengubah file dengan 253 tambahan dan 34 penghapusan
  1. 2 2
      cmd/zerotier/cli/help.go
  2. 117 8
      core/Certificate.cpp
  3. 12 4
      core/Certificate.hpp
  4. 3 3
      core/Tests.cpp
  5. 2 1
      core/Topology.cpp
  6. 114 10
      core/zerotier.h
  7. 3 6
      serviceiocore/GoGlue.cpp

+ 2 - 2
cmd/zerotier/cli/help.go

@@ -81,8 +81,8 @@ Commands:
     verify <identity> <file> <sig>       Verify a signature
   certificate <command> [args]         - Certificate commands
     newid                                Create a new unique subject ID
-    newcsr <settings>                    Create a new CSR (signing request)
-    sign <crl path> <identity path>      Sign a CRL and create a certificate
+    newcsr <settings path>               Create a new CSR (signing request)
+    sign <csr path> <identity path>      Sign a CSR to create a certificate
     verify <certificate>                 Verify a certificate
     show                                 List certificate for current node
     import <certificate> [<trust>]       Import certificate into this node

+ 117 - 8
core/Certificate.cpp

@@ -251,16 +251,16 @@ Vector< uint8_t > Certificate::encode(const bool omitSignature) const
 	return enc;
 }
 
-bool Certificate::decode(const Vector< uint8_t > &data)
+bool Certificate::decode(const void *const data, const unsigned int len)
 {
 	char tmp[256], tmp2[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1];
 
-	m_clear();
-
 	Dictionary d;
-	if (!d.decode(data.data(), (unsigned int)data.size()))
+	if (!d.decode(data, len))
 		return false;
 
+	m_clear();
+
 	this->flags = d.getUI("f");
 	this->timestamp = (int64_t)d.getUI("t");
 	this->validity[0] = (int64_t)d.getUI("v#0");
@@ -384,6 +384,15 @@ bool Certificate::decode(const Vector< uint8_t > &data)
 	return true;
 }
 
+Vector< uint8_t > Certificate::encodeCSR()
+{
+	Vector< uint8_t > enc;
+	Dictionary d;
+	m_encodeSubject(this->subject, d, false);
+	d.encode(enc);
+	return enc;
+}
+
 bool Certificate::sign(const Identity &issuer)
 {
 	Vector< uint8_t > enc(encode(true));
@@ -417,7 +426,7 @@ ZT_CertificateError Certificate::verify() const
 			if (
 				(this->subject.uniqueIdProofSignatureSize != ZT_ECC384_SIGNATURE_SIZE) ||
 				(this->subject.uniqueIdSize != (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) ||
-				(this->subject.uniqueId[0] != ZT_CERTIFICATE_UNIQUE_ID_PUBLIC_KEY_TYPE_NIST_P_384))
+				(this->subject.uniqueId[0] != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384))
 				return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
 			Dictionary tmp;
 			m_encodeSubject(this->subject, tmp, true);
@@ -462,11 +471,11 @@ ZT_CertificateError Certificate::verify() const
 	return ZT_CERTIFICATE_ERROR_NONE;
 }
 
-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])
+bool Certificate::setSubjectUniqueId(const uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE], const uint8_t uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE])
 {
-	m_subjectUniqueId.assign(uniqueId, uniqueId + ZT_CERTIFICATE_UNIQUE_ID_SIZE_TYPE_NIST_P_384);
+	m_subjectUniqueId.assign(uniqueId, uniqueId + ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE);
 	this->subject.uniqueId = m_subjectUniqueId.data();
-	this->subject.uniqueIdSize = ZT_CERTIFICATE_UNIQUE_ID_SIZE_TYPE_NIST_P_384;
+	this->subject.uniqueIdSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE;
 
 	Dictionary d;
 	m_encodeSubject(this->subject, d, true);
@@ -567,3 +576,103 @@ void Certificate::m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d
 }
 
 } // namespace ZeroTier
+
+extern "C" {
+
+int ZT_Certificate_newSubjectUniqueId(
+	enum ZT_CertificateUniqueIdType type,
+	void *uniqueId,
+	int *uniqueIdSize,
+	void *uniqueIdPrivate,
+	int *uniqueIdPrivateSize)
+{
+	switch(type) {
+		case ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384:
+			if ((*uniqueIdSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) || (*uniqueIdPrivateSize < ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE))
+				return ZT_RESULT_ERROR_BAD_PARAMETER;
+			*uniqueIdSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE;
+			*uniqueIdPrivateSize = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE;
+			ZeroTier::Certificate::createSubjectUniqueId(reinterpret_cast<uint8_t *>(uniqueId), reinterpret_cast<uint8_t *>(uniqueIdPrivate));
+			return ZT_RESULT_OK;
+	}
+	return ZT_RESULT_ERROR_BAD_PARAMETER;
+}
+
+int ZT_Certificate_newCSR(
+	const ZT_Certificate_Subject *subject,
+	const void *uniqueId,
+	int uniqueIdSize,
+	const void *uniqueIdPrivate,
+	int uniqueIdPrivateSize,
+	void *csr,
+	int *csrSize)
+{
+	ZeroTier::Certificate c;
+	ZeroTier::Utils::copy< sizeof(ZT_Certificate_Subject) >(&(c.subject), subject);
+	if ((uniqueId) && (uniqueIdSize > 0) && (uniqueIdPrivate) && (uniqueIdPrivateSize > 0)) {
+		if ((reinterpret_cast<const uint8_t *>(uniqueId)[0] != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384) || (uniqueIdSize != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) || (uniqueIdPrivateSize != ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE))
+			return ZT_RESULT_ERROR_BAD_PARAMETER;
+		if (!c.setSubjectUniqueId(reinterpret_cast<const uint8_t *>(uniqueId), reinterpret_cast<const uint8_t *>(uniqueIdPrivate)))
+			return ZT_RESULT_ERROR_INVALID_CREDENTIAL;
+	}
+	ZeroTier::Vector< uint8_t > csrV(c.encodeCSR());
+	if ((int)csrV.size() > *csrSize)
+		return ZT_RESULT_ERROR_BAD_PARAMETER;
+	ZeroTier::Utils::copy(csr, csrV.data(), (unsigned int)csrV.size());
+	*csrSize = (int)csrV.size();
+	return ZT_RESULT_OK;
+}
+
+int ZT_Certificate_sign(
+	const ZT_Certificate *cert,
+	const ZT_Identity *signer,
+	void *signedCert,
+	int *signedCertSize)
+{
+	ZeroTier::Certificate c(*cert);
+	if (!c.sign(*reinterpret_cast<const ZeroTier::Identity *>(signer)))
+		return ZT_RESULT_ERROR_BAD_PARAMETER;
+	ZeroTier::Vector< uint8_t > enc(c.encode());
+	if ((int)enc.size() > *signedCertSize)
+		return ZT_RESULT_ERROR_BAD_PARAMETER;
+	ZeroTier::Utils::copy(signedCert, enc.data(), (unsigned int)enc.size());
+	*signedCertSize = (int)enc.size();
+	return ZT_RESULT_OK;
+}
+
+enum ZT_CertificateError ZT_Certificate_decode(
+	ZT_Certificate **decodedCert,
+	const void *cert,
+	int certSize,
+	int verify)
+{
+	try {
+		if (!decodedCert)
+			return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
+		*decodedCert = nullptr;
+		ZeroTier::Certificate *const c = new ZeroTier::Certificate();
+		if (!c->decode(cert, certSize)) {
+			delete c;
+			return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
+		}
+		if (verify) {
+			ZT_CertificateError err = c->verify();
+			if (err != ZT_CERTIFICATE_ERROR_NONE) {
+				delete c;
+				return err;
+			}
+		}
+		*decodedCert = c;
+		return ZT_CERTIFICATE_ERROR_NONE;
+	} catch ( ... ) {
+		return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
+	}
+}
+
+ZT_SDK_API void ZT_Certificate_delete(ZT_Certificate *cert)
+{
+	if (cert)
+		delete reinterpret_cast<ZeroTier::Certificate *>(cert);
+}
+
+}

+ 12 - 4
core/Certificate.hpp

@@ -129,9 +129,17 @@ public:
 	 * Decode this certificate from marshaled bytes.
 	 *
 	 * @param data Marshalled certificate
+	 * @param len Length of marshalled certificate
 	 * @return True if input is valid and was unmarshalled (signature is NOT checked)
 	 */
-	bool decode(const Vector< uint8_t > &data);
+	bool decode(const void *data, unsigned int len);
+
+	/**
+	 * Encode only the subject portion of this certificate as a CSR
+	 *
+	 * @return Encoded CSR
+	 */
+	Vector< uint8_t > encodeCSR();
 
 	/**
 	 * Sign this certificate (and also fill in serialNo).
@@ -160,7 +168,7 @@ public:
 	 * @param uniqueIdPrivate Private key associated with unique ID to prove ownership of it
 	 * @return True if successful
 	 */
-	bool 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]);
+	bool setSubjectUniqueId(const uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE], const uint8_t uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE]);
 
 	/**
 	 * Create a subject unique ID and corresponding private key required for use
@@ -168,9 +176,9 @@ public:
 	 * @param uniqueId Buffer to receive unique ID
 	 * @param uniqueIdPrivate Buffer to receive private key
 	 */
-	static ZT_INLINE void createSubjectUniqueId(uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_SIZE_TYPE_NIST_P_384], uint8_t uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_PRIVATE_KEY_SIZE_TYPE_NIST_P_384])
+	static ZT_INLINE void createSubjectUniqueId(uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE], uint8_t uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE])
 	{
-		uniqueId[0] = ZT_CERTIFICATE_UNIQUE_ID_PUBLIC_KEY_TYPE_NIST_P_384;
+		uniqueId[0] = ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384;
 		ECC384GenerateKey(uniqueId + 1, uniqueIdPrivate);
 	}
 

+ 3 - 3
core/Tests.cpp

@@ -1107,9 +1107,9 @@ extern "C" const char *ZTT_crypto()
 			ZT_T_PRINTF("OK" ZT_EOL_S);
 
 			ZT_T_PRINTF("  Create subject unique ID... ");
-			uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_SIZE_TYPE_NIST_P_384], uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_PRIVATE_KEY_SIZE_TYPE_NIST_P_384];
+			uint8_t uniqueId[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE], uniqueIdPrivate[ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE];
 			Certificate::createSubjectUniqueId(uniqueId, uniqueIdPrivate);
-			Utils::b32e(uniqueId, ZT_CERTIFICATE_UNIQUE_ID_SIZE_TYPE_NIST_P_384, tmp, sizeof(tmp));
+			Utils::b32e(uniqueId, ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE, tmp, sizeof(tmp));
 			ZT_T_PRINTF("OK %s" ZT_EOL_S, tmp);
 
 			ZT_T_PRINTF("  Create and sign certificate... ");
@@ -1148,7 +1148,7 @@ extern "C" const char *ZTT_crypto()
 
 			ZT_T_PRINTF("  Test certificate decode from marshaled format... ");
 			SharedPtr<Certificate> cert2(new Certificate());
-			if (!cert2->decode(enc)) {
+			if (!cert2->decode(enc.data(), (unsigned int)enc.size())) {
 				ZT_T_PRINTF("FAILED (decode)" ZT_EOL_S);
 				return "Certificate decode";
 			}

+ 2 - 1
core/Topology.cpp

@@ -34,7 +34,8 @@ Topology::Topology(const RuntimeEnvironment *renv, void *tPtr, const int64_t now
 			if (serialNo.size() == ZT_SHA384_DIGEST_SIZE) {
 				Utils::copy< 48 >(id, serialNo.data());
 				Certificate cert;
-				if (cert.decode(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_CERT, id)))
+				Vector< uint8_t > enc(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_CERT, id));
+				if (cert.decode(enc.data(), (unsigned int)enc.size()))
 					addCertificate(tPtr, cert, now, (unsigned int)d.getUI(Dictionary::arraySubscript(tmp, "c$.lt", idx)), false, false, false);
 			}
 		}

+ 114 - 10
core/zerotier.h

@@ -38,7 +38,7 @@ extern "C" {
 
 /* This symbol may be defined to anything we need to put in front of API function prototypes. */
 #ifndef ZT_SDK_API
-#define ZT_SDK_API
+#define ZT_SDK_API extern
 #endif
 
 /* ---------------------------------------------------------------------------------------------------------------- */
@@ -309,19 +309,25 @@ typedef struct
 #define ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ZEROTIER_ROOT_SET 0x0002U
 
 /**
- * Public key type for NIST P-384 public keys used as subject unique IDs.
+ * Size of a unique ID of the given key type (with type prefix byte)
  */
-#define ZT_CERTIFICATE_UNIQUE_ID_PUBLIC_KEY_TYPE_NIST_P_384 1
+#define ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE 50
 
 /**
- * Size of a unique ID of the given key type (with type prefix byte)
+ * Size of the private key corresponding to a unique ID of the given type.
  */
-#define ZT_CERTIFICATE_UNIQUE_ID_SIZE_TYPE_NIST_P_384 50
+#define ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE 48
 
 /**
- * Size of the private key corresponding to a unique ID of the given type.
+ * Unique ID types supported for certificate subject unique IDs
  */
-#define ZT_CERTIFICATE_UNIQUE_ID_PRIVATE_KEY_SIZE_TYPE_NIST_P_384 48
+enum ZT_CertificateUniqueIdType
+{
+	/**
+	 * Public key type for NIST P-384 public keys used as subject unique IDs.
+	 */
+	ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384 = 1
+};
 
 /**
  * Errors returned by functions that verify or handle certificates.
@@ -2620,7 +2626,10 @@ ZT_SDK_API ZT_Locator *ZT_Locator_fromString(const char *str);
  * @param bufSize Size of buffer in bytes (needs to be at least 2048 bytes in size)
  * @return Number of bytes stored to buf or -1 on error such as buffer too small
  */
-ZT_SDK_API int ZT_Locator_marshal(const ZT_Locator *loc,void *buf,unsigned int bufSize);
+ZT_SDK_API int ZT_Locator_marshal(
+	const ZT_Locator *loc,
+	void *buf,
+	unsigned int bufSize);
 
 /**
  * Get this locator in string format
@@ -2669,7 +2678,9 @@ ZT_SDK_API unsigned int ZT_Locator_endpointCount(const ZT_Locator *loc);
  * @param ep Endpoint number from 0 to 1 - endpointCount()
  * @return Endpoint or NULL if out of bounds
  */
-ZT_SDK_API const ZT_Endpoint *ZT_Locator_endpoint(const ZT_Locator *loc,const unsigned int ep);
+ZT_SDK_API const ZT_Endpoint *ZT_Locator_endpoint(
+	const ZT_Locator *loc,
+	const unsigned int ep);
 
 /**
  * Verify this locator's signature
@@ -2677,7 +2688,9 @@ ZT_SDK_API const ZT_Endpoint *ZT_Locator_endpoint(const ZT_Locator *loc,const un
  * @param signer Signing identity
  * @return Non-zero if locator is valid
  */
-ZT_SDK_API int ZT_Locator_verify(const ZT_Locator *loc,const ZT_Identity *signer);
+ZT_SDK_API int ZT_Locator_verify(
+	const ZT_Locator *loc,
+	const ZT_Identity *signer);
 
 /**
  * Delete a locator
@@ -2704,6 +2717,97 @@ ZT_SDK_API void ZT_version(
 
 /* ---------------------------------------------------------------------------------------------------------------- */
 
+/**
+ * Create a new certificate subject unique ID and private key
+ *
+ * A unique ID is really a public/private key pair.
+ *
+ * @param type Unique ID type (key pair algorithm)
+ * @param uniqueId Unique ID buffer
+ * @param uniqueIdSize Value/result: size of buffer
+ * @param uniqueIdPrivate Unique ID private key buffer
+ * @param uniqueIdPrivateSize Value/result: size of buffer
+ * @return OK (0) or error
+ */
+ZT_SDK_API int ZT_Certificate_newSubjectUniqueId(
+	enum ZT_CertificateUniqueIdType type,
+	void *uniqueId,
+	int *uniqueIdSize,
+	void *uniqueIdPrivate,
+	int *uniqueIdPrivateSize);
+
+/**
+ * Create a new certificate signing request (CSR)
+ *
+ * A CSR is effectively just an encoded certificate subject.
+ * If both uniqueId and uniqueIdPrivate are specified, the subject
+ * will be signed with a unique ID. Otherwise these fields are not
+ * set. If a unique ID and unique ID signature are present in the
+ * supplied subject, these will be ignored.
+ *
+ * @param subject Subject filled in with fields for CSR
+ * @param uniqueId Unique ID or NULL if none
+ * @param uniqueIdSize Size of unique ID
+ * @param uniqueIdPrivate Unique ID private key or NULL if none
+ * @param uniqueIdPrivateSize Size of unique ID private key
+ * @param csr Buffer to hold CSR (recommended size: 16384 bytes)
+ * @param csrSize Value/result: size of buffer
+ * @return OK (0) or error
+ */
+ZT_SDK_API int ZT_Certificate_newCSR(
+	const ZT_Certificate_Subject *subject,
+	const void *uniqueId,
+	int uniqueIdSize,
+	const void *uniqueIdPrivate,
+	int uniqueIdPrivateSize,
+	void *csr,
+	int *csrSize);
+
+/**
+ * Sign a CSR to generate a complete certificate
+ *
+ * @param cert Certificate to sign
+ * @param signer Signer identity (must contain secret key)
+ * @param signedCert Signed certificate buffer (recommended size: 16384 bytes)
+ * @param signedCertSize Value/result: size of buffer
+ * @return OK (0) or error
+ */
+ZT_SDK_API int ZT_Certificate_sign(
+	const ZT_Certificate *cert,
+	const ZT_Identity *signer,
+	void *signedCert,
+	int *signedCertSize);
+
+/**
+ * Decode a certificate or CSR
+ *
+ * A CSR is just the encoded subject part of a certificate. Decoding a CSR
+ * results in a certificate whose subject is filled in but nothing else.
+ *
+ * If no error occurs and the pointer at decodedCert is set to non-NULL,
+ * the returned certificate must be freed with ZT_Certificate_delete().
+ *
+ * @param decodedCert Result parameter: target pointer is set to certificate
+ * @param cert Certificate or CSR data
+ * @param certSize Size of data
+ * @param verify If non-zero, verify signatures and structure
+ * @return Certificate error, if any
+ */
+ZT_SDK_API enum ZT_CertificateError ZT_Certificate_decode(
+	ZT_Certificate **decodedCert,
+	const void *cert,
+	int certSize,
+	int verify);
+
+/**
+ * Free a certificate created with ZT_Certificate_decode()
+ *
+ * @param cert Certificate to free
+ */
+ZT_SDK_API void ZT_Certificate_delete(ZT_Certificate *cert);
+
+/* ---------------------------------------------------------------------------------------------------------------- */
+
 #ifdef __cplusplus
 }
 #endif

+ 3 - 6
serviceiocore/GoGlue.cpp

@@ -11,7 +11,9 @@
  */
 /****/
 
+#ifndef _WIN32_WINNT
 #define _WIN32_WINNT 0x06010000
+#endif
 
 #include "GoGlue.h"
 
@@ -22,11 +24,11 @@
 #include "../core/MAC.hpp"
 #include "../core/Address.hpp"
 #include "../core/Containers.hpp"
+#include "../core/Certificate.hpp"
 #include "../osdep/OSUtils.hpp"
 #include "../osdep/EthernetTap.hpp"
 
 #ifndef __WINDOWS__
-
 #include <unistd.h>
 #include <sys/socket.h>
 #include <sys/un.h>
@@ -35,16 +37,11 @@
 #include <ifaddrs.h>
 #include <net/if.h>
 #include <netinet/in.h>
-
 #ifdef __BSD__
-
 #include <netinet6/in6_var.h>
-
 #endif
-
 #include <arpa/inet.h>
 #include <errno.h>
-
 #ifdef __LINUX__
 #ifndef IPV6_DONTFRAG
 #define IPV6_DONTFRAG 62