Пример #1
0
static uint8_t decryptHandshake(struct Wrapper* wrapper,
                                const uint32_t nonce,
                                struct Message* message,
                                union Headers_CryptoAuth* header)
{
    if (message->length < sizeof(union Headers_CryptoAuth)) {
        Log_debug(wrapper->context->logger, "Dropped runt packet\n");
        return Error_UNDERSIZE_MESSAGE;
    }

    // handshake
    // nextNonce 0: recieving hello.
    // nextNonce 1: recieving key, we sent hello.
    // nextNonce 2: recieving first data packet or duplicate hello.
    // nextNonce 3: recieving first data packet.
    // nextNonce >3: handshake complete

    if (wrapper->nextNonce < 2 && nonce == UINT32_MAX && !wrapper->requireAuth) {
        // Reset without knowing key is allowed until state reaches 2.
        // this is because we don't know that the other end knows our key until we
        // have received a valid packet from them.
        // We can't allow the upper layer to see this message because it's not authenticated.
        if (!knowHerKey(wrapper)) {
            memcpy(wrapper->herPerminentPubKey, header->handshake.publicKey, 32);
        }
        Message_shift(message, -Headers_CryptoAuth_SIZE);
        message->length = 0;
        wrapper->nextNonce = 0;
        wrapper->user = NULL;
        // Send an empty response (to initiate the connection).
        encryptHandshake(message, wrapper);
        return Error_NONE;
    }

    void* user = NULL;
    uint8_t passwordHashStore[32];
    uint8_t* passwordHash = tryAuth(header, passwordHashStore, wrapper, &user);
    if (wrapper->requireAuth && !user) {
        Log_debug(wrapper->context->logger,
                  "Dropping message because auth was not given and is required.\n");
        return Error_AUTHENTICATION;
    }
    if (passwordHash == NULL && header->handshake.auth.challenge.type != 0) {
        Log_debug(wrapper->context->logger,
                  "Dropping message because it contans an authenticator which is unrecognized.\n");
        return Error_AUTHENTICATION;
    }

    // What the nextNonce will become if this packet is valid.
    uint32_t nextNonce;

    // The secret for decrypting this message.
    uint8_t sharedSecret[32];

    uint8_t* herPermKey = NULL;
    if (nonce < 2) {
        if (nonce == 0) {
            Log_debug1(wrapper->context->logger,
                       "Received a hello packet, using auth: %d\n",
                       (passwordHash != NULL));
        } else {
            Log_debug(wrapper->context->logger, "Received a repeat hello packet\n");
        }

        // Decrypt message with perminent keys.
        if (!knowHerKey(wrapper) || wrapper->nextNonce == 0) {
            herPermKey = header->handshake.publicKey;
            #ifdef Log_DEBUG
                if (Bits_isZero(header->handshake.publicKey, 32)) {
                    Log_debug(wrapper->context->logger, "Node sent public key of ZERO!\n");
                }
            #endif
        } else {
            herPermKey = wrapper->herPerminentPubKey;
            if (memcmp(header->handshake.publicKey, herPermKey, 32)) {
                Log_debug(wrapper->context->logger, "Packet contains different perminent key.\n");
                return Error_AUTHENTICATION;
            }
        }

        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        herPermKey,
                        passwordHash,
                        wrapper->context->logger);
        nextNonce = 2;
    } else {
        if (nonce == 2) {
            Log_debug(wrapper->context->logger, "Received a key packet\n");
        } else if (nonce == 3) {
            Log_debug(wrapper->context->logger, "Received a repeat key packet\n");
        } else {
            Log_debug1(wrapper->context->logger,
                       "Received a packet of unknown type! nonce=%u\n", nonce);
        }
        if (memcmp(header->handshake.publicKey, wrapper->herPerminentPubKey, 32)) {
            Log_debug(wrapper->context->logger, "Packet contains different perminent key.\n");
            return Error_AUTHENTICATION;
        }
        // We sent the hello, this is a key
        getSharedSecret(sharedSecret,
                        wrapper->secret,
                        wrapper->herPerminentPubKey,
                        passwordHash,
                        wrapper->context->logger);
        nextNonce = 4;
    }

    // Shift it on top of the authenticator before the encrypted public key
    Message_shift(message, 48 - Headers_CryptoAuth_SIZE);

    Log_debug1(wrapper->context->logger, "Message length: %u\n", message->length);
    #ifdef Log_KEYS
        uint8_t sharedSecretHex[65];
        printHexKey(sharedSecretHex, sharedSecret);
        uint8_t nonceHex[49];
        Hex_encode(nonceHex, 49, header->handshake.nonce, 24);
        uint8_t cipherHex[65];
        printHexKey(cipherHex, message->bytes);
        Log_keys3(wrapper->context->logger,
                  "Decrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    #endif

    // Decrypt her temp public key and the message.
    if (decryptRndNonce(header->handshake.nonce, message, sharedSecret) != 0) {
        // just in case
        memset(header, 0, Headers_CryptoAuth_SIZE);
        Log_debug(wrapper->context->logger,
                  "Dropped message because authenticated decryption failed.\n");
        return Error_AUTHENTICATION;
    }

    wrapper->user = user;
    memcpy(wrapper->tempKey, header->handshake.encryptedTempKey, 32);

    #ifdef Log_DEBUG
        assert(!Bits_isZero(header->handshake.encryptedTempKey, 32));
    #endif
    #ifdef Log_KEYS
        uint8_t tempKeyHex[65];
        Hex_encode(tempKeyHex, 65, wrapper->tempKey, 32);
        Log_keys1(wrapper->context->logger,
                  "Unwrapping temp public key:\n"
                  "    %s\n",
                  tempKeyHex);
    #endif

    Message_shift(message, -32);
    wrapper->nextNonce = nextNonce;
    if (nextNonce == 2) {
        wrapper->isInitiator = false;
    }
    if (herPermKey && herPermKey != wrapper->herPerminentPubKey) {
        memcpy(wrapper->herPerminentPubKey, herPermKey, 32);
    }

    // If this is a handshake which was initiated in reverse because we
    // didn't know the other node's key, now send what we were going to send.
    if (wrapper->hasBufferedMessage && message->length == 0) {
        Log_debug(wrapper->context->logger, "Sending buffered message.\n");
        sendMessage(wrapper->bufferedMessage, &wrapper->externalInterface);
        wrapper->hasBufferedMessage = false;
        return Error_NONE;
    } else if (wrapper->hasBufferedMessage) {
        Log_debug(wrapper->context->logger, "There is a buffered message.\n");
    }

    memset(&wrapper->replayProtector, 0, sizeof(struct ReplayProtector));

    setRequiredPadding(wrapper);
    return callReceivedMessage(wrapper, message);
}
Пример #2
0
static uint8_t decryptHandshake(struct CryptoAuth_Wrapper* wrapper,
                                const uint32_t nonce,
                                struct Message* message,
                                union Headers_CryptoAuth* header)
{
    if (message->length < Headers_CryptoAuth_SIZE) {
        cryptoAuthDebug0(wrapper, "DROP runt");
        return Error_UNDERSIZE_MESSAGE;
    }

    // handshake
    // nextNonce 0: recieving hello.
    // nextNonce 1: recieving key, we sent hello.
    // nextNonce 2: recieving first data packet or duplicate hello.
    // nextNonce 3: recieving first data packet.
    // nextNonce >3: handshake complete

    if (knowHerKey(wrapper)) {
        if (Bits_memcmp(wrapper->herPerminentPubKey, header->handshake.publicKey, 32)) {
            cryptoAuthDebug0(wrapper, "DROP a packet with different public key than this session");
            return Error_AUTHENTICATION;
        }
    } else if (!Bits_isZero(wrapper->herIp6, 16)) {
        uint8_t calculatedIp6[16];
        AddressCalc_addressForPublicKey(calculatedIp6, header->handshake.publicKey);
        if (Bits_memcmp(wrapper->herIp6, calculatedIp6, 16)) {
            cryptoAuthDebug0(wrapper, "DROP packet with public key not matching ip6 for session");
            return Error_AUTHENTICATION;
        }
    }

    if (wrapper->nextNonce < 2 && nonce == UINT32_MAX && !wrapper->requireAuth) {
        // Reset without knowing key is allowed until state reaches 2.
        // this is because we don't know that the other end knows our key until we
        // have received a valid packet from them.
        // We can't allow the upper layer to see this message because it's not authenticated.
        if (!knowHerKey(wrapper)) {
            Bits_memcpyConst(wrapper->herPerminentPubKey, header->handshake.publicKey, 32);
        }
        Message_shift(message, -Headers_CryptoAuth_SIZE, NULL);
        message->length = 0;
        reset(wrapper);
        wrapper->user = NULL;
        cryptoAuthDebug0(wrapper, "Got a connect-to-me message, sending a hello");
        // Send an empty response (to initiate the connection).
        encryptHandshake(message, wrapper, 1);
        return Error_NONE;
    }

    String* user = NULL;
    uint8_t passwordHashStore[32];
    uint8_t* passwordHash = tryAuth(header, passwordHashStore, wrapper, &user);
    if (wrapper->requireAuth && !user) {
        cryptoAuthDebug0(wrapper, "DROP message because auth was not given");
        return Error_AUTHENTICATION;
    }
    if (passwordHash == NULL && header->handshake.auth.challenge.type != 0) {
        cryptoAuthDebug0(wrapper, "DROP message with unrecognized authenticator");
        return Error_AUTHENTICATION;
    }

    // What the nextNonce will become if this packet is valid.
    uint32_t nextNonce;

    // The secret for decrypting this message.
    uint8_t sharedSecret[32];

    uint8_t* herPermKey = NULL;
    if (nonce < 2) {
        if (nonce == 0) {
            cryptoAuthDebug(wrapper, "Received a hello packet, using auth: %d",
                            (passwordHash != NULL));
        } else {
            cryptoAuthDebug0(wrapper, "Received a repeat hello packet");
        }

        // Decrypt message with perminent keys.
        if (!knowHerKey(wrapper) || wrapper->nextNonce == 0) {
            herPermKey = header->handshake.publicKey;
            #ifdef Log_DEBUG
                if (Bits_isZero(header->handshake.publicKey, 32)) {
                    cryptoAuthDebug0(wrapper, "Node sent public key of ZERO!");
                }
            #endif
        } else {
            herPermKey = wrapper->herPerminentPubKey;
            if (Bits_memcmp(header->handshake.publicKey, herPermKey, 32)) {
                cryptoAuthDebug0(wrapper, "DROP packet contains different perminent key");
                return Error_AUTHENTICATION;
            }
        }

        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        herPermKey,
                        passwordHash,
                        wrapper->context->logger);
        nextNonce = 2;
    } else {
        if (nonce == 2) {
            cryptoAuthDebug0(wrapper, "Received a key packet");
        } else if (nonce == 3) {
            cryptoAuthDebug0(wrapper, "Received a repeat key packet");
        } else {
            cryptoAuthDebug(wrapper, "Received a packet of unknown type! nonce=%u", nonce);
        }
        if (Bits_memcmp(header->handshake.publicKey, wrapper->herPerminentPubKey, 32)) {
            cryptoAuthDebug0(wrapper, "DROP packet contains different perminent key");
            return Error_AUTHENTICATION;
        }
        if (!wrapper->isInitiator) {
            cryptoAuthDebug0(wrapper, "DROP a stray key packet");
            return Error_AUTHENTICATION;
        }
        // We sent the hello, this is a key
        getSharedSecret(sharedSecret,
                        wrapper->ourTempPrivKey,
                        wrapper->herPerminentPubKey,
                        passwordHash,
                        wrapper->context->logger);
        nextNonce = 4;
    }

    // Shift it on top of the authenticator before the encrypted public key
    Message_shift(message, 48 - Headers_CryptoAuth_SIZE, NULL);

    #ifdef Log_KEYS
        uint8_t sharedSecretHex[65];
        printHexKey(sharedSecretHex, sharedSecret);
        uint8_t nonceHex[49];
        Hex_encode(nonceHex, 49, header->handshake.nonce, 24);
        uint8_t cipherHex[65];
        printHexKey(cipherHex, message->bytes);
        Log_keys(wrapper->context->logger,
                  "Decrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    #endif

    // Decrypt her temp public key and the message.
    if (decryptRndNonce(header->handshake.nonce, message, sharedSecret) != 0) {
        // just in case
        Bits_memset(header, 0, Headers_CryptoAuth_SIZE);
        cryptoAuthDebug(wrapper, "DROP message with nonce [%d], decryption failed", nonce);
        return Error_AUTHENTICATION;
    }

    Assert_ifParanoid(!Bits_isZero(header->handshake.encryptedTempKey, 32));

    #ifdef Log_KEYS
        uint8_t tempKeyHex[65];
        Hex_encode(tempKeyHex, 65, header->handshake.encryptedTempKey, 32);
        Log_keys(wrapper->context->logger,
                  "Unwrapping temp public key:\n"
                  "    %s\n",
                  tempKeyHex);
    #endif

    Message_shift(message, -32, NULL);

    // Post-decryption checking
    if (nonce == 0) {
        // A new hello packet
        if (!Bits_memcmp(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            // possible replay attack or duped packet
            cryptoAuthDebug0(wrapper, "DROP dupe hello packet with same temp key");
            return Error_AUTHENTICATION;
        }
    } else if (nonce == 2 && wrapper->nextNonce >= 4) {
        // we accept a new key packet and let it change the session since the other end might have
        // killed off the session while it was in the midst of setting up.
        if (!Bits_memcmp(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            Assert_true(!Bits_isZero(wrapper->herTempPubKey, 32));
            cryptoAuthDebug0(wrapper, "DROP dupe key packet with same temp key");
            return Error_AUTHENTICATION;
        }

    } else if (nonce == 3 && wrapper->nextNonce >= 4) {
        // Got a repeat key packet, make sure the temp key is the same as the one we know.
        if (Bits_memcmp(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            Assert_true(!Bits_isZero(wrapper->herTempPubKey, 32));
            cryptoAuthDebug0(wrapper, "DROP repeat key packet with different temp key");
            return Error_AUTHENTICATION;
        }
    }

    // If Alice sent a hello packet then Bob sent a hello packet and they crossed on the wire,
    // somebody has to yield and the other has to stand firm otherwise they will either deadlock
    // each believing their hello packet is superior or they will livelock, each switching to the
    // other's session and never synchronizing.
    // In this event whoever has the lower permanent public key wins.

    // If we receive a (possibly repeat) key packet
    if (nextNonce == 4) {
        if (wrapper->nextNonce <= 4) {
            // and have not yet begun sending "run" data
            Assert_true(wrapper->nextNonce <= nextNonce);
            wrapper->nextNonce = nextNonce;

            wrapper->user = user;
            Bits_memcpyConst(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32);
        } else {
            // It's a (possibly repeat) key packet and we have begun sending run data.
            // We will change the shared secret to the one specified in the new key packet but
            // intentionally avoid de-incrementing the nonce just in case
            getSharedSecret(wrapper->sharedSecret,
                            wrapper->ourTempPrivKey,
                            header->handshake.encryptedTempKey,
                            NULL,
                            wrapper->context->logger);
            cryptoAuthDebug0(wrapper, "New key packet but we are already sending data");
        }

    } else if (nextNonce == 2 && (!wrapper->isInitiator || wrapper->established)) {
        // This is a hello packet and we are either in ESTABLISHED state or we are
        // not the initiator of the connection.
        // If the case is that we are in ESTABLISHED state, the other side tore down the session
        // and we have not so lets tear it down.
        // If we are not in ESTABLISHED state then we don't allow resetting of the session unless
        // they are the sender of the hello packet or their permanent public key is lower.
        // this is a tie-breaker in case hello packets cross on the wire.
        if (wrapper->established) {
            reset(wrapper);
        }
        // We got a (possibly repeat) hello packet and we have not sent any hello packet,
        // new session.
        if (wrapper->nextNonce == 3 && nextNonce == 2) {
            // We sent a key packet so the next packet is a repeat key but we got another hello
            // We'll just keep steaming along sending repeat key packets
            nextNonce = 3;
        }

        Assert_true(wrapper->nextNonce <= nextNonce);
        wrapper->nextNonce = nextNonce;
        wrapper->user = user;
        Bits_memcpyConst(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32);

    } else if (nextNonce == 2
        && Bits_memcmp(header->handshake.publicKey, wrapper->context->pub.publicKey, 32) < 0)
    {
        // It's a hello and we are the initiator but their permant public key is numerically lower
        // than ours, this is so that in the event of two hello packets crossing on the wire, the
        // nodes will agree on who is the initiator.
        cryptoAuthDebug0(wrapper, "Incoming hello from node with lower key, resetting");
        reset(wrapper);

        Assert_true(wrapper->nextNonce <= nextNonce);
        wrapper->nextNonce = nextNonce;
        wrapper->user = user;
        Bits_memcpyConst(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32);

    } else {
        cryptoAuthDebug0(wrapper, "Incoming hello from node with higher key, not resetting");
    }

    if (herPermKey && herPermKey != wrapper->herPerminentPubKey) {
        Bits_memcpyConst(wrapper->herPerminentPubKey, herPermKey, 32);
    }

    // If this is a handshake which was initiated in reverse because we
    // didn't know the other node's key, now send what we were going to send.

    if (wrapper->bufferedMessage) {
        // This can only happen when we have received a (maybe repeat) hello packet.
        Assert_true(wrapper->nextNonce == 2);

        struct Message* bm = wrapper->bufferedMessage;
        wrapper->bufferedMessage = NULL;
        cryptoAuthDebug0(wrapper, "Sending buffered message");
        sendMessage(bm, &wrapper->externalInterface);
        Allocator_free(bm->alloc);
    }

    if (message->length == 0 && Headers_isSetupPacket(&header->handshake.auth)) {
        return Error_NONE;
    }

    Bits_memset(&wrapper->replayProtector, 0, sizeof(struct ReplayProtector));

    setRequiredPadding(wrapper);
    return callReceivedMessage(wrapper, message);
}