From e94518590de48e2718539f98b87e2f617fa02f75 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 14 May 2015 17:41:05 -0700 Subject: First stab of PFS design work with PKC security -- may not implement in 1.0.3 but stubbing out. --- node/Packet.cpp | 1 + node/Packet.hpp | 114 +++++++++++++++++++++++++++++++++++++++++--------------- node/Utils.cpp | 9 +++++ 3 files changed, 94 insertions(+), 30 deletions(-) (limited to 'node') diff --git a/node/Packet.cpp b/node/Packet.cpp index f72f64b2..a81873ff 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -50,6 +50,7 @@ const char *Packet::verbString(Verb v) case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH"; case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER"; case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME"; + case VERB_SET_EPHEMERAL_KEY: return "SET_EPHEMERAL_KEY"; } return "(unknown)"; } diff --git a/node/Packet.hpp b/node/Packet.hpp index 76f84996..efe58c78 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -98,6 +98,17 @@ */ #define ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 1 +/** + * Cipher suite: PFS negotiated ephemeral cipher suite and authentication + * + * This message is encrypted with the latest negotiated ephemeral (PFS) + * key pair and cipher suite. If authentication fails, VERB_SET_EPHEMERAL_KEY + * may be sent to renegotiate ephemeral keys. To prevent attacks, this + * attempted renegotiation should be limited to some sane rate such as + * once per second. + */ +#define ZT_PROTO_CIPHER_SUITE__EPHEMERAL 7 + /** * DEPRECATED payload encrypted flag, will be removed for re-use soon. * @@ -114,13 +125,6 @@ */ #define ZT_PROTO_FLAG_FRAGMENTED 0x40 -/** - * Flag indicating encryption with a PFS session key - * - * Not used yet -- for future PFS session re-keying support. - */ -#define ZT_PROTO_FLAG_PFS_SESSION 0x20 - /** * Verb flag indicating payload is compressed with LZ4 */ @@ -186,6 +190,17 @@ #define ZT_PROTO_DEST_ADDRESS_TYPE_IPV4 4 #define ZT_PROTO_DEST_ADDRESS_TYPE_IPV6 6 +// Ephemeral key record flags +#define ZT_PROTO_EPHEMERAL_KEY_FLAG_FIPS 0x01 + +// Ephemeral key record symmetric cipher types +#define ZT_PROTO_EPHEMERAL_KEY_SYMMETRIC_CIPHER_SALSA2012_POLY1305 0x01 +#define ZT_PROTO_EPHEMERAL_KEY_SYMMETRIC_CIPHER_AES256_GCM 0x02 + +// Ephemeral key record public key types +#define ZT_PROTO_EPHEMERAL_KEY_PK_C25519 0x01 +#define ZT_PROTO_EPHEMERAL_KEY_PK_NISTP256 0x02 + // Field incides for parsing verbs ------------------------------------------- // Some verbs have variable-length fields. Those aren't fully defined here @@ -298,8 +313,8 @@ namespace ZeroTier { * * Packets smaller than 28 bytes are invalid and silently discarded. * - * The flags/cipher/hops bit field is: FFFCCHHH where C is a 2-bit cipher - * selection allowing up to 4 cipher suites, F is outside-envelope flags, + * The flags/cipher/hops bit field is: FFCCCHHH where C is a 3-bit cipher + * selection allowing up to 7 cipher suites, F is outside-envelope flags, * and H is hop count. * * The three-bit hop count is the only part of a packet that is mutable in @@ -752,7 +767,59 @@ public: * <[6] multicast group MAC> * <[4] 32-bit multicast group ADI> */ - VERB_MULTICAST_FRAME = 14 + VERB_MULTICAST_FRAME = 14, + + /* Ephemeral (PFS) key push: + * <[8] 64-bit PFS key set ID sender holds for recipient (0==none)> + * <[8] 64-bit PFS key set ID of this key set> + * [... begin PFS key record ...] + * <[1] flags> + * <[1] symmetric cipher ID> + * <[1] public key type ID> + * <[2] public key length in bytes> + * <[2] identity signature length in bytes (0 for none)> + * <[...] public key> + * <[...] signature of sender's ZT identity with public key> + * [... additional records may follow up to max packet length ...] + * + * This message is sent to negotiate an ephemeral key. If the recipient's + * current key pair for the sender does not match the one the sender + * claims to have on file, it must respond with its own SET_EPHEMERAL_KEY. + * + * PFS key IDs are random and must not be zero, since zero indicates that + * the sender does not have an ephemeral key on file for the recipient. + * + * For each public key, the sender may sign its ZeroTier identity (public + * portion only) using the associated digital signature algorithm. This + * permits the extension of FIPS-compliant cryptographic algorithms to + * cover verification of the identity for full FIPS compliant mode. For + * non-FIPS mode, this is optional. If no signature is included the + * signature length field must be zero. + * + * One or more records may be sent. If multiple records are present, + * the first record with common symmetric cipher, public key type, + * and relevant flags must be used. + * + * Flags (all unspecified flags must be zero): + * 0x01 - FIPS mode, only use record if FIPS compliant crypto in use + * + * Symmetric cipher IDs: + * 0x01 - Salsa20/12 with Poly1305 authentication (ZT default) + * 0x02 - AES256-GCM combined crypto and authentication + * + * Public key types: + * 0x01 - Curve25519 ECDH with SHA-512 KDF, Ed25519 signatures + * 0x02 - NIST P-256 ECDH with SHA-512 KDF, ECDSA signatures + * + * Once both peers have a PFS key, they will attempt to send PFS key + * encrypted messages with the PFS flag set using the negotiated + * cipher/auth type. + * + * Note: most of these features such as FIPS and other cipher suites are + * not implemented yet. They're just specified in the protocol for future + * use to support e.g. FIPS requirements. + */ + VERB_SET_EPHEMERAL_KEY = 15 }; /** @@ -824,7 +891,7 @@ public: Buffer(ZT_PROTO_MIN_PACKET_LENGTH) { Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops + (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops } /** @@ -873,7 +940,7 @@ public: Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); setDestination(dest); setSource(source); - (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops + (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops setVerb(v); } @@ -884,34 +951,21 @@ public: * technically different but otherwise identical copies of the same * packet. */ - inline void newInitializationVector() - { - Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - } + inline void newInitializationVector() { Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); } /** * Set this packet's destination * * @param dest ZeroTier address of destination */ - inline void setDestination(const Address &dest) - { - unsigned char *d = field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH); - for(unsigned int i=0;i> 3); + return (((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x38) >> 3); } /** @@ -983,7 +1037,7 @@ public: inline void setCipher(unsigned int c) { unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS]; - b = (b & 0xe7) | (unsigned char)((c << 3) & 0x18); // bits: FFFCCHHH + b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH // DEPRECATED "encrypted" flag -- used by pre-1.0.3 peers if (c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) b |= ZT_PROTO_FLAG_ENCRYPTED; diff --git a/node/Utils.cpp b/node/Utils.cpp index 3380b324..9630e6b3 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -49,6 +49,7 @@ #include "Utils.hpp" #include "Mutex.hpp" +#include "Salsa20.hpp" namespace ZeroTier { @@ -152,6 +153,7 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes) static HCRYPTPROV cryptProvider = NULL; static Mutex globalLock; + static Salsa20 s20; Mutex::Lock _l(globalLock); @@ -161,12 +163,19 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes) exit(1); return; } + char s20key[32]; + if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(s20key),(BYTE *)s20key)) { + fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n"); + exit(1); + } + s20.init(s20key,256,s20key,8); } if (!CryptGenRandom(cryptProvider,(DWORD)bytes,(BYTE *)buf)) { fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n"); exit(1); } + s20.encrypt(buf,buf,bytes); #else // not __WINDOWS__ -- cgit v1.2.3 From d0e0f5dd126d37a27a43cc00ed351ed1289c203c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 15 May 2015 08:48:53 -0700 Subject: Basic OpenBSD compile fixes -- still need to update BSDEthernetTap, will do that later. Should be able to re-use FreeBSD port for OpenBSD, but we will see. --- Makefile | 4 +++- include/ZeroTierOne.h | 2 ++ node/Constants.hpp | 2 +- node/Utils.hpp | 4 ++-- service/OneService.cpp | 4 ++++ 5 files changed, 12 insertions(+), 4 deletions(-) (limited to 'node') diff --git a/Makefile b/Makefile index bc094260..5a5f6605 100644 --- a/Makefile +++ b/Makefile @@ -13,4 +13,6 @@ endif ifeq ($(OSTYPE),FreeBSD) include make-freebsd.mk endif - +ifeq ($(OSTYPE),OpenBSD) + include make-freebsd.mk +endif diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index ecc2edef..dd7ccfa1 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -43,6 +43,8 @@ #else /* not Windows */ #include #include +#include +#include #endif /* Windows or not */ #ifdef __cplusplus diff --git a/node/Constants.hpp b/node/Constants.hpp index 10c48c20..3bda685d 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -60,7 +60,7 @@ #include #endif -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__OpenBSD__) #ifndef __UNIX_LIKE__ #define __UNIX_LIKE__ #endif diff --git a/node/Utils.hpp b/node/Utils.hpp index 585c7f5b..bdd673a9 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -331,7 +331,7 @@ public: throw() { #if __BYTE_ORDER == __LITTLE_ENDIAN -#ifdef __GNUC__ +#if defined(__GNUC__) && (!defined(__OpenBSD__)) return __builtin_bswap64(n); #else return ( @@ -361,7 +361,7 @@ public: throw() { #if __BYTE_ORDER == __LITTLE_ENDIAN -#ifdef __GNUC__ +#if defined(__GNUC__) && !defined(__OpenBSD__) return __builtin_bswap64(n); #else return ( diff --git a/service/OneService.cpp b/service/OneService.cpp index 56b1d979..dd919474 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -70,6 +70,10 @@ namespace ZeroTier { typedef LinuxEthernetTap EthernetTap; } #include "../osdep/WindowsEthernetTap.hpp" namespace ZeroTier { typedef WindowsEthernetTap EthernetTap; } #endif +#ifdef __BSD__ +#include "../osdep/BSDEthernetTap.hpp" +namespace ZeroTier { typedef BSDEthernetTap EthernetTap; } +#endif // Sanity limits for HTTP #define ZT_MAX_HTTP_MESSAGE_SIZE (1024 * 1024 * 8) -- cgit v1.2.3 From 0bdd56ebd6711f851ae228d5a1e4c298dae5dc59 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 15 May 2015 09:04:39 -0700 Subject: A few revisions to PFS design. --- node/Packet.hpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'node') diff --git a/node/Packet.hpp b/node/Packet.hpp index efe58c78..2dfb75e4 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -777,9 +777,7 @@ public: * <[1] symmetric cipher ID> * <[1] public key type ID> * <[2] public key length in bytes> - * <[2] identity signature length in bytes (0 for none)> * <[...] public key> - * <[...] signature of sender's ZT identity with public key> * [... additional records may follow up to max packet length ...] * * This message is sent to negotiate an ephemeral key. If the recipient's @@ -789,13 +787,6 @@ public: * PFS key IDs are random and must not be zero, since zero indicates that * the sender does not have an ephemeral key on file for the recipient. * - * For each public key, the sender may sign its ZeroTier identity (public - * portion only) using the associated digital signature algorithm. This - * permits the extension of FIPS-compliant cryptographic algorithms to - * cover verification of the identity for full FIPS compliant mode. For - * non-FIPS mode, this is optional. If no signature is included the - * signature length field must be zero. - * * One or more records may be sent. If multiple records are present, * the first record with common symmetric cipher, public key type, * and relevant flags must be used. @@ -808,8 +799,8 @@ public: * 0x02 - AES256-GCM combined crypto and authentication * * Public key types: - * 0x01 - Curve25519 ECDH with SHA-512 KDF, Ed25519 signatures - * 0x02 - NIST P-256 ECDH with SHA-512 KDF, ECDSA signatures + * 0x01 - Curve25519 ECDH with SHA-512 KDF + * 0x02 - NIST P-256 ECDH with SHA-512 KDF * * Once both peers have a PFS key, they will attempt to send PFS key * encrypted messages with the PFS flag set using the negotiated @@ -818,6 +809,10 @@ public: * Note: most of these features such as FIPS and other cipher suites are * not implemented yet. They're just specified in the protocol for future * use to support e.g. FIPS requirements. + * + * OK response payload: + * <[8] PFS key set ID of received key set> + * <[1] index in record list of chosen key record> */ VERB_SET_EPHEMERAL_KEY = 15 }; -- cgit v1.2.3