Certificate API

This commit is contained in:
Adam Ierymenko 2020-07-02 22:22:31 -07:00
parent 727aa8e71f
commit 899f0c9749
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
7 changed files with 254 additions and 35 deletions

View file

@ -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

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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";
}

View file

@ -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);
}
}

View file

@ -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
/* ---------------------------------------------------------------------------------------------------------------- */
@ -308,20 +308,26 @@ 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.
*/
#define ZT_CERTIFICATE_UNIQUE_ID_PUBLIC_KEY_TYPE_NIST_P_384 1
/**
* Size of a unique ID of the given key type (with type prefix byte)
*/
#define ZT_CERTIFICATE_UNIQUE_ID_SIZE_TYPE_NIST_P_384 50
#define ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE 50
/**
* Size of the private key corresponding to a unique ID of the given type.
*/
#define ZT_CERTIFICATE_UNIQUE_ID_PRIVATE_KEY_SIZE_TYPE_NIST_P_384 48
#define ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE 48
/**
* Unique ID types supported for certificate subject unique IDs
*/
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

View file

@ -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