1
0
Caleb James DeLisle 7 жил өмнө
parent
commit
719063e184

+ 46 - 37
crypto/CryptoAuth.c

@@ -325,7 +325,7 @@ static void resetIfTimeout(struct CryptoAuth_Session_pvt* session)
     }
 
     uint64_t nowSecs = Time_currentTimeSeconds(session->context->eventBase);
-    if (nowSecs - session->timeOfLastPacket > session->context->pub.resetAfterInactivitySeconds) {
+    if (nowSecs - session->timeOfLastPacket > session->pub.resetAfterInactivitySeconds) {
         cryptoAuthDebug(session, "No traffic in [%d] seconds, resetting connection.",
                   (int) (nowSecs - session->timeOfLastPacket));
 
@@ -524,21 +524,21 @@ static inline void updateTime(struct CryptoAuth_Session_pvt* session, struct Mes
     session->timeOfLastPacket = Time_currentTimeSeconds(session->context->eventBase);
 }
 
-static inline Gcc_USE_RET bool decryptMessage(struct CryptoAuth_Session_pvt* session,
-                                              uint32_t nonce,
-                                              struct Message* content,
-                                              uint8_t secret[32])
+static inline enum CryptoAuth_DecryptErr decryptMessage(struct CryptoAuth_Session_pvt* session,
+                                                        uint32_t nonce,
+                                                        struct Message* content,
+                                                        uint8_t secret[32])
 {
     // Decrypt with authentication and replay prevention.
     if (decrypt(nonce, content, secret, session->isInitiator)) {
         cryptoAuthDebug0(session, "DROP authenticated decryption failed");
-        return false;
+        return CryptoAuth_DecryptErr_DECRYPT;
     }
     if (!ReplayProtector_checkNonce(nonce, &session->pub.replayProtector)) {
         cryptoAuthDebug(session, "DROP nonce checking failed nonce=[%u]", nonce);
-        return false;
+        return CryptoAuth_DecryptErr_REPLAY;
     }
-    return true;
+    return 0;
 }
 
 static bool ip6MatchesKey(uint8_t ip6[16], uint8_t key[32])
@@ -548,14 +548,14 @@ static bool ip6MatchesKey(uint8_t ip6[16], uint8_t key[32])
     return !Bits_memcmp(ip6, calculatedIp6, 16);
 }
 
-static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
-                                        const uint32_t nonce,
-                                        struct Message* message,
-                                        struct CryptoHeader* header)
+static enum CryptoAuth_DecryptErr decryptHandshake(struct CryptoAuth_Session_pvt* session,
+                                                   const uint32_t nonce,
+                                                   struct Message* message,
+                                                   struct CryptoHeader* header)
 {
     if (message->length < CryptoHeader_SIZE) {
         cryptoAuthDebug0(session, "DROP runt");
-        return -1;
+        return CryptoAuth_DecryptErr_RUNT;
     }
 
     // handshake
@@ -568,7 +568,7 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
     Assert_true(knowHerKey(session));
     if (Bits_memcmp(session->pub.herPublicKey, header->publicKey, 32)) {
         cryptoAuthDebug0(session, "DROP a packet with different public key than this session");
-        return -1;
+        return CryptoAuth_DecryptErr_WRONG_PERM_PUBKEY;
     }
 
     Assert_true((session->nextNonce < CryptoAuth_State_RECEIVED_HELLO) ==
@@ -583,17 +583,17 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
             restrictedToip6 = userObj->restrictedToip6;
             if (!ip6MatchesKey(restrictedToip6, session->pub.herPublicKey)) {
                 cryptoAuthDebug0(session, "DROP packet with key not matching restrictedToip6");
-                return -1;
+                return CryptoAuth_DecryptErr_IP_RESTRICTED;
             }
         }
     }
     if (session->requireAuth && !userObj) {
         cryptoAuthDebug0(session, "DROP message because auth was not given");
-        return -1;
+        return CryptoAuth_DecryptErr_AUTH_REQUIRED;
     }
     if (!userObj && header->auth.type != 0) {
         cryptoAuthDebug0(session, "DROP message with unrecognized authenticator");
-        return -1;
+        return CryptoAuth_DecryptErr_UNRECOGNIZED_AUTH;
     }
     // What the nextNonce will become if this packet is valid.
     uint32_t nextNonce;
@@ -625,7 +625,7 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
         }
         if (!session->isInitiator) {
             cryptoAuthDebug0(session, "DROP a stray key packet");
-            return -1;
+            return CryptoAuth_DecryptErr_STRAY_KEY;
         }
         // We sent the hello, this is a key
         getSharedSecret(sharedSecret,
@@ -659,13 +659,13 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
         // just in case
         Bits_memset(header, 0, CryptoHeader_SIZE);
         cryptoAuthDebug(session, "DROP message with nonce [%d], decryption failed", nonce);
-        return -1;
+        return CryptoAuth_DecryptErr_HANDSHAKE_DECRYPT_FAILED;
     }
 
     if (Bits_isZero(header->encryptedTempKey, 32)) {
         // we need to reject 0 public keys outright because they will be confused with "unknown"
         cryptoAuthDebug0(session, "DROP message with zero as temp public key");
-        return -1;
+        return CryptoAuth_DecryptErr_WISEGUY;
     }
 
     if (Defined(Log_KEYS)) {
@@ -685,7 +685,7 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
         if (!Bits_memcmp(session->herTempPubKey, header->encryptedTempKey, 32)) {
             // possible replay attack or duped packet
             cryptoAuthDebug0(session, "DROP dupe hello packet with same temp key");
-            return -1;
+            return CryptoAuth_DecryptErr_INVALID_PACKET;
         }
     } else if (nonce == Nonce_KEY && session->nextNonce >= CryptoAuth_State_RECEIVED_KEY) {
         // we accept a new key packet and let it change the session since the other end might have
@@ -694,7 +694,7 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
         if (!Bits_memcmp(session->herTempPubKey, header->encryptedTempKey, 32)) {
             Assert_true(!Bits_isZero(session->herTempPubKey, 32));
             cryptoAuthDebug0(session, "DROP dupe key packet with same temp key");
-            return -1;
+            return CryptoAuth_DecryptErr_INVALID_PACKET;
         }
 
     } else if (nonce == Nonce_REPEAT_KEY && session->nextNonce >= CryptoAuth_State_RECEIVED_KEY) {
@@ -702,7 +702,7 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
         if (Bits_memcmp(session->herTempPubKey, header->encryptedTempKey, 32)) {
             Assert_true(!Bits_isZero(session->herTempPubKey, 32));
             cryptoAuthDebug0(session, "DROP repeat key packet with different temp key");
-            return -1;
+            return CryptoAuth_DecryptErr_INVALID_PACKET;
         }
     }
 
@@ -720,7 +720,7 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
             case CryptoAuth_State_RECEIVED_HELLO:
             case CryptoAuth_State_SENT_KEY: {
                 cryptoAuthDebug0(session, "DROP stray key packet");
-                return -1;
+                return CryptoAuth_DecryptErr_STRAY_KEY;
             }
             case CryptoAuth_State_SENT_HELLO: {
                 Bits_memcpy(session->herTempPubKey, header->encryptedTempKey, 32);
@@ -728,8 +728,8 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
             }
             case CryptoAuth_State_RECEIVED_KEY: {
                 if (Bits_memcmp(session->herTempPubKey, header->encryptedTempKey, 32)) {
-                    cryptoAuthDebug0(session, "DROP Stray key packet with different key");
-                    return -1;
+                    cryptoAuthDebug0(session, "DROP key packet with different key");
+                    return CryptoAuth_DecryptErr_INVALID_PACKET;
                 }
                 break;
             }
@@ -791,7 +791,11 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
                 }
                 default: {
                     cryptoAuthDebug0(session, "DROP Incoming repeat hello");
-                    return -1;
+                    // We already know the key which is being used for this hello packet and
+                    // our state has advanced past RECEIVED_HELLO or SENT_KEY or perhaps we
+                    // are the initiator of this session and they're sending us what should
+                    // be a key packet but is marked as hello, it's all invalid.
+                    return CryptoAuth_DecryptErr_INVALID_PACKET;
                 }
             }
         }
@@ -811,7 +815,8 @@ static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
 }
 
 /** @return 0 on success, -1 otherwise. */
-int CryptoAuth_decrypt(struct CryptoAuth_Session* sessionPub, struct Message* msg)
+enum CryptoAuth_DecryptErr CryptoAuth_decrypt(struct CryptoAuth_Session* sessionPub,
+                                              struct Message* msg)
 {
     struct CryptoAuth_Session_pvt* session =
         Identity_check((struct CryptoAuth_Session_pvt*) sessionPub);
@@ -819,7 +824,7 @@ int CryptoAuth_decrypt(struct CryptoAuth_Session* sessionPub, struct Message* ms
 
     if (msg->length < 20) {
         cryptoAuthDebug0(session, "DROP runt");
-        return -1;
+        return CryptoAuth_DecryptErr_RUNT;
     }
     Assert_true(msg->padding >= 12 || "need at least 12 bytes of padding in incoming message");
     Assert_true(!((uintptr_t)msg->bytes % 4) || !"alignment fault");
@@ -834,7 +839,7 @@ int CryptoAuth_decrypt(struct CryptoAuth_Session* sessionPub, struct Message* ms
             if (session->nextNonce < CryptoAuth_State_SENT_KEY) {
                 // This is impossible because we have not exchanged hello and key messages.
                 cryptoAuthDebug0(session, "DROP Received a run message to an un-setup session");
-                return -1;
+                return CryptoAuth_DecryptErr_NO_SESSION;
             }
             cryptoAuthDebug(session, "Trying final handshake step, nonce=%u\n", nonce);
             uint8_t secret[32];
@@ -846,7 +851,8 @@ int CryptoAuth_decrypt(struct CryptoAuth_Session* sessionPub, struct Message* ms
                             NULL,
                             session->context->logger);
 
-            if (decryptMessage(session, nonce, msg, secret)) {
+            enum CryptoAuth_DecryptErr ret = decryptMessage(session, nonce, msg, secret);
+            if (!ret) {
                 cryptoAuthDebug0(session, "Final handshake step succeeded");
                 Bits_memcpy(session->sharedSecret, secret, 32);
 
@@ -857,7 +863,7 @@ int CryptoAuth_decrypt(struct CryptoAuth_Session* sessionPub, struct Message* ms
                 return 0;
             }
             cryptoAuthDebug0(session, "DROP Final handshake step failed");
-            return -1;
+            return ret;
         }
 
         Message_shift(msg, 4, NULL);
@@ -865,12 +871,14 @@ int CryptoAuth_decrypt(struct CryptoAuth_Session* sessionPub, struct Message* ms
 
     } else if (nonce >= Nonce_FIRST_TRAFFIC_PACKET) {
         Assert_ifParanoid(!Bits_isZero(session->sharedSecret, 32));
-        if (decryptMessage(session, nonce, msg, session->sharedSecret)) {
+        enum CryptoAuth_DecryptErr ret = decryptMessage(session, nonce, msg, session->sharedSecret);
+        if (!ret) {
             updateTime(session, msg);
             return 0;
         } else {
-            cryptoAuthDebug0(session, "DROP Failed to decrypt message");
-            return -1;
+            cryptoAuthDebug(session, "DROP Failed to [%s] message",
+                ((ret == CryptoAuth_DecryptErr_REPLAY) ? "replay check" : "decrypt"));
+            return ret;
         }
     } else if (nonce <= Nonce_REPEAT_HELLO) {
         cryptoAuthDebug(session, "hello packet during established session nonce=[%d]", nonce);
@@ -878,7 +886,7 @@ int CryptoAuth_decrypt(struct CryptoAuth_Session* sessionPub, struct Message* ms
         return decryptHandshake(session, nonce, msg, header);
     } else {
         cryptoAuthDebug(session, "DROP key packet during established session nonce=[%d]", nonce);
-        return -1;
+        return CryptoAuth_DecryptErr_KEY_PKT_ESTABLISHED_SESSION;
     }
     Assert_failure("unreachable");
 }
@@ -896,7 +904,6 @@ struct CryptoAuth* CryptoAuth_new(struct Allocator* allocator,
     ca->allocator = allocator;
     ca->eventBase = eventBase;
     ca->logger = logger;
-    ca->pub.resetAfterInactivitySeconds = CryptoAuth_DEFAULT_RESET_AFTER_INACTIVITY_SECONDS;
     ca->rand = rand;
 
     if (privateKey != NULL) {
@@ -1024,6 +1031,8 @@ struct CryptoAuth_Session* CryptoAuth_newSession(struct CryptoAuth* ca,
     session->timeOfLastPacket = Time_currentTimeSeconds(context->eventBase);
     session->alloc = alloc;
 
+    session->pub.resetAfterInactivitySeconds = CryptoAuth_DEFAULT_RESET_AFTER_INACTIVITY_SECONDS;
+
     Assert_true(herPublicKey);
     Bits_memcpy(session->pub.herPublicKey, herPublicKey, 32);
     uint8_t calculatedIp6[16];

+ 56 - 8
crypto/CryptoAuth.h

@@ -34,12 +34,6 @@ Linker_require("crypto/CryptoAuth.c");
 struct CryptoAuth
 {
     uint8_t publicKey[32];
-
-    /**
-     * After this number of seconds of inactivity,
-     * a connection will be reset to prevent them hanging in a bad state.
-     */
-    uint32_t resetAfterInactivitySeconds;
 };
 
 struct CryptoAuth_Session
@@ -55,6 +49,12 @@ struct CryptoAuth_Session
      * any packet avertizing a key which doesn't hash to this will be dropped.
      */
     uint8_t herIp6[16];
+
+    /**
+     * After this number of seconds of inactivity,
+     * a connection will be reset to prevent them hanging in a bad state.
+     */
+    uint32_t resetAfterInactivitySeconds;
 };
 
 /**
@@ -144,8 +144,56 @@ struct CryptoAuth_Session* CryptoAuth_newSession(struct CryptoAuth* ca,
 /** @return 0 on success, -1 otherwise. */
 int CryptoAuth_encrypt(struct CryptoAuth_Session* session, struct Message* msg);
 
-/** @return 0 on success, -1 otherwise. */
-int CryptoAuth_decrypt(struct CryptoAuth_Session* session, struct Message* msg);
+enum CryptoAuth_DecryptErr {
+    CryptoAuth_DecryptErr_NONE = 0,
+
+    // Packet too short
+    CryptoAuth_DecryptErr_RUNT = 1,
+
+    // Received a run message to an un-setup session
+    CryptoAuth_DecryptErr_NO_SESSION = 2,
+
+    CryptoAuth_DecryptErr_FINAL_SHAKE_FAIL = 3,
+
+    CryptoAuth_DecryptErr_FAILED_DECRYPT_RUN_MSG = 4,
+
+    CryptoAuth_DecryptErr_KEY_PKT_ESTABLISHED_SESSION = 5,
+
+    CryptoAuth_DecryptErr_WRONG_PERM_PUBKEY = 6,
+
+    // Only specific IPv6 can connect to this CA session and the request has the wrong one.
+    CryptoAuth_DecryptErr_IP_RESTRICTED = 7,
+
+    // Authentication is required and is missing.
+    CryptoAuth_DecryptErr_AUTH_REQUIRED = 8,
+
+    // Basically this means the login name doesn't exist, beware of giving this information up.
+    CryptoAuth_DecryptErr_UNRECOGNIZED_AUTH = 9,
+
+    // Key packet and we are not in a state to accept a key packet
+    CryptoAuth_DecryptErr_STRAY_KEY = 10,
+
+    CryptoAuth_DecryptErr_HANDSHAKE_DECRYPT_FAILED = 11,
+
+    // Set zero as the temporary public key
+    CryptoAuth_DecryptErr_WISEGUY = 12,
+
+    // Duplicate hello or key packet (same temp key and not a repeat-packet type)
+    // Or repeat key packet with different key than what is known
+    // Or a repeat hello packet for which we already know the temp key (meaning it is associated
+    // with an existing session) when we are not in a state to accept a repeat hello.
+    CryptoAuth_DecryptErr_INVALID_PACKET = 13,
+
+    // Replay checker could not validate this packet
+    CryptoAuth_DecryptErr_REPLAY = 14,
+
+    // Authenticated decryption failed
+    CryptoAuth_DecryptErr_DECRYPT = 15
+};
+
+// returns 0 if everything if ok, otherwise an encryption error.
+// If there is an error, the content of the message MIGHT already be decrypted !
+enum CryptoAuth_DecryptErr CryptoAuth_decrypt(struct CryptoAuth_Session* sess, struct Message* msg);
 
 /**
  * Choose the authentication credentials to use.

+ 3 - 3
dht/dhtcore/NodeStore.c

@@ -453,10 +453,10 @@ static bool findBestParent(struct Node_Two* node, struct NodeStore_pvt* store)
             }
         }
     } while (ret);
-    uint64_t time1 = Time_currentTimeMilliseconds(store->eventBase);
-    if ((int64_t)(time1 - time0) > 1) {
+    uint64_t time1 = Time_hrtime(store->eventBase);
+    if ((int64_t)(time1 - time0) > 1000000) {
         Log_warn(store->logger, "\n\nfindBestParent() took [%lld] ms\n\n",
-            (long long) (time1 - time0));
+            (long long) ((time1 - time0) / 1000000));
     }
     return true;
 }

+ 55 - 13
net/SessionManager.c

@@ -22,6 +22,7 @@
 #include "util/Defined.h"
 #include "wire/RouteHeader.h"
 #include "util/events/Timeout.h"
+#include "util/Checksum.h"
 
 /** Handle numbers 0-3 are reserved for CryptoAuth nonces. */
 #define MIN_FIRST_HANDLE 4
@@ -237,6 +238,29 @@ static Iface_DEFUN ctrlFrame(struct Message* msg, struct SessionManager_pvt* sm)
     return Iface_next(&sm->pub.insideIf, msg);
 }
 
+static Iface_DEFUN failedDecrypt(struct Message* msg,
+                                 uint64_t label_be,
+                                 struct SessionManager_pvt* sm)
+{
+    Message_push32(msg, Error_AUTHENTICATION, NULL);
+    Message_push16(msg, Control_ERROR, NULL);
+    Message_push16(msg, 0, NULL);
+    uint16_t csum = Checksum_engine(msg->bytes, msg->length);
+    Message_pop16(msg, NULL);
+    Message_push16(msg, csum, NULL);
+
+    Message_push32(msg, 0xffffffff, NULL);
+
+    struct SwitchHeader sh;
+    Bits_memset(&sh, 0, SwitchHeader_SIZE);
+    SwitchHeader_setSuppressErrors(&sh, true);
+    SwitchHeader_setVersion(&sh, SwitchHeader_CURRENT_VERSION);
+    sh.label_be = label_be;
+    Message_push(msg, &sh, SwitchHeader_SIZE, NULL);
+
+    return Iface_next(&sm->pub.switchIf, msg);
+}
+
 static Iface_DEFUN incomingFromSwitchIf(struct Message* msg, struct Iface* iface)
 {
     struct SessionManager_pvt* sm =
@@ -263,6 +287,13 @@ static Iface_DEFUN incomingFromSwitchIf(struct Message* msg, struct Iface* iface
         Message_shift(msg, SwitchHeader_SIZE, NULL);
         return ctrlFrame(msg, sm);
     }
+
+    // This is for handling error situations and being able to send back some kind of a message.
+    uint8_t firstSixteen[16];
+    uint32_t length0 = msg->length;
+    Assert_true(msg->length >= 16);
+    Bits_memcpy(firstSixteen, msg->bytes, 16);
+
     if (nonceOrHandle > 3) {
         // > 3 it's a handle.
         session = sessionForHandle(nonceOrHandle, sm);
@@ -296,20 +327,30 @@ static Iface_DEFUN incomingFromSwitchIf(struct Message* msg, struct Iface* iface
         debugHandlesAndLabel(sm->log, session, label, "new session nonce[%d]", nonceOrHandle);
     }
 
-    if (CryptoAuth_decrypt(session->pub.caSession, msg)) {
+    bool currentMessageSetup = (nonceOrHandle <= 3);
+
+    enum CryptoAuth_DecryptErr ret = CryptoAuth_decrypt(session->pub.caSession, msg);
+    if (ret) {
         debugHandlesAndLabel(sm->log, session,
                              Endian_bigEndianToHost64(switchHeader->label_be),
                              "DROP Failed decrypting message NoH[%d] state[%s]",
                              nonceOrHandle,
                              CryptoAuth_stateString(CryptoAuth_getState(session->pub.caSession)));
-        return NULL;
+        Message_shift(msg, (length0 - msg->length) + 24, NULL);
+        msg->length = 0;
+        Message_push32(msg, CryptoAuth_getState(session->pub.caSession), NULL);
+        Message_push32(msg, ret, NULL);
+        Message_push(msg, firstSixteen, 16, NULL);
+        Message_shift(msg, -SwitchHeader_SIZE, NULL);
+        Assert_true(msg->bytes == (uint8_t*)switchHeader);
+        uint64_t label_be = switchHeader->label_be;
+        switchHeader->label_be = Bits_bitReverse64(switchHeader->label_be);
+        return failedDecrypt(msg, label_be, sm);
     }
 
     session->pub.timeOfLastIn = Time_currentTimeMilliseconds(sm->eventBase);
     session->pub.bytesIn += msg->length;
 
-    bool currentMessageSetup = (nonceOrHandle <= 3);
-
     if (currentMessageSetup) {
         session->pub.sendHandle = Message_pop32(msg, NULL);
     }
@@ -382,6 +423,16 @@ static void checkTimedOutSessions(struct SessionManager_pvt* sm)
     for (int i = 0; i < (int)sm->ifaceMap.count; i++) {
         struct SessionManager_Session_pvt* sess = sm->ifaceMap.values[i];
         int64_t now = Time_currentTimeMilliseconds(sm->eventBase);
+
+        // Check if the session is timed out...
+        if (now - sess->pub.timeOfLastIn > sm->pub.sessionTimeoutMilliseconds) {
+            debugSession0(sm->log, sess, "ended");
+            sendSession(sess, sess->pub.sendSwitchLabel, 0xffffffff, PFChan_Core_SESSION_ENDED);
+            Map_OfSessionsByIp6_remove(i, &sm->ifaceMap);
+            Allocator_free(sess->alloc);
+            i--;
+        }
+
         if (now - sess->pub.timeOfLastOut >= sm->pub.sessionIdleAfterMilliseconds &&
             now - sess->pub.timeOfLastIn >= sm->pub.sessionIdleAfterMilliseconds)
         {
@@ -396,15 +447,6 @@ static void checkTimedOutSessions(struct SessionManager_pvt* sm)
             searchTriggered = true;
             continue;
         }
-
-        // Session is in idle state or doesn't need a search right now, check if it's timed out.
-        if (now - sess->pub.timeOfLastIn > sm->pub.sessionTimeoutMilliseconds) {
-            debugSession0(sm->log, sess, "ended");
-            sendSession(sess, sess->pub.sendSwitchLabel, 0xffffffff, PFChan_Core_SESSION_ENDED);
-            Map_OfSessionsByIp6_remove(i, &sm->ifaceMap);
-            Allocator_free(sess->alloc);
-            i--;
-        }
     }
 }
 

+ 2 - 1
wire/Control.h

@@ -22,7 +22,8 @@
 /**
  * Type two, error.
  */
-#define Control_ERROR_be Endian_hostToBigEndian16(2)
+#define Control_ERROR 2
+#define Control_ERROR_be Endian_hostToBigEndian16(Control_ERROR)
 #define Control_Error_HEADER_SIZE 4
 #define Control_Error_MIN_SIZE (Control_Error_HEADER_SIZE + SwitchHeader_SIZE + 4)
 #define Control_Error_MAX_SIZE 256