Search in sources :

Example 1 with LargeIntegrityPacket

use of me.retrodaredevil.solarthing.packets.security.LargeIntegrityPacket in project solarthing by wildmountainfarms.

the class SecurityPacketReceiver method receivePacketGroup.

private void receivePacketGroup(StoredPacketGroup storedPacketGroup, TargetPacketGroup packetGroup) {
    LOGGER.debug("Receiving packet group: " + storedPacketGroup.getStoredIdentifier());
    long packetGroupDateMillis = packetGroup.getDateMillis();
    List<? extends Packet> packetGroupPackets = packetGroup.getPackets();
    if (packetGroupPackets.stream().noneMatch(packet -> packet instanceof SecurityPacket && !(packet instanceof AuthNewSenderPacket))) {
        LOGGER.debug("This packet group has no useful SecurityPackets. Ignoring. identifier: " + storedPacketGroup.getStoredIdentifier());
        return;
    }
    if (packetGroupPackets.size() != 1) {
        /*
			In any "millis database" we have the documents inside follow the packet collection format.
			Packet collections can have many packets inside them. When we are dealing with security packets,
			we want to be able to easily refer to a single security packet. Because no one should ever need
			to contain multiple security packets in a given packet collection, we will only process
			packet collections with a single security packet. This allows things like SecurityEventPackets to work nicely,
			and doesn't have any real drawbacks except for some (possible) future use case that we don't know of.
			 */
        LOGGER.warn("This packetGroup targeting us had a packetGroup.size != 1! stored identifier: " + storedPacketGroup.getStoredIdentifier());
        reject(storedPacketGroup, SecurityRejectPacket.Reason.INVALID_DATA, "You cannot have more than one packet (besides source and target)");
        return;
    }
    Packet packet = packetGroupPackets.stream().findFirst().orElseThrow(() -> new AssertionError("size should be 1! This should not fail"));
    if (!(packet instanceof LargeIntegrityPacket)) {
        if (packet instanceof IntegrityPacket) {
            LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "Got an IntegrityPacket! This is no longer supported!");
            reject(storedPacketGroup, SecurityRejectPacket.Reason.LEGACY_REQUEST, "IntegrityPacket is no longer supported");
        } else if (packet instanceof AuthNewSenderPacket) {
            LOGGER.warn("Got an AuthNewSenderPacket. Ignoring.");
            reject(storedPacketGroup, SecurityRejectPacket.Reason.UNKNOWN_ERROR, "Got auth new sender packet");
        } else {
            LOGGER.warn("Unknown packet: " + packet);
            reject(storedPacketGroup, SecurityRejectPacket.Reason.UNKNOWN_ERROR, "Got unknown packet");
        }
        return;
    }
    LargeIntegrityPacket largeIntegrityPacket = (LargeIntegrityPacket) packet;
    String sender = largeIntegrityPacket.getSender();
    final String invalidSenderReason = sender == null ? "sender is null!" : SenderUtil.getInvalidSenderNameReason(sender);
    if (invalidSenderReason != null) {
        LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, invalidSenderReason);
        reject(storedPacketGroup, SecurityRejectPacket.Reason.INVALID_DATA, invalidSenderReason);
        return;
    }
    String encodedHash = decryptData(storedPacketGroup, sender, largeIntegrityPacket.getEncryptedHash(), packetGroupDateMillis);
    if (encodedHash == null) {
        // If encodedHash is null, then decryptData should have already called reject()
        return;
    }
    byte[] decodedHash;
    try {
        decodedHash = Base64Variants.getDefaultVariant().decode(encodedHash);
    } catch (IllegalArgumentException e) {
        LOGGER.error("Not base64 data!", e);
        reject(storedPacketGroup, SecurityRejectPacket.Reason.INVALID_DATA, "Not base64 data!");
        return;
    }
    String payload = largeIntegrityPacket.getPayload();
    byte[] payloadHash = HashUtil.hash(payload);
    if (!Arrays.equals(decodedHash, payloadHash)) {
        LOGGER.warn("Unsuccessfully compared hashes! The data may have been tampered with!");
        reject(storedPacketGroup, SecurityRejectPacket.Reason.DIFFERENT_PAYLOAD, "Unsuccessfully compared hashes");
        return;
    }
    LOGGER.debug("Successfully compared hashes!");
    handleMessage(storedPacketGroup, payload, sender);
}
Also used : Packet(me.retrodaredevil.solarthing.packets.Packet) IntegrityPacket(me.retrodaredevil.solarthing.packets.security.IntegrityPacket) SecurityRejectPacket(me.retrodaredevil.solarthing.commands.event.SecurityRejectPacket) LargeIntegrityPacket(me.retrodaredevil.solarthing.packets.security.LargeIntegrityPacket) InstanceSourcePacket(me.retrodaredevil.solarthing.packets.instance.InstanceSourcePacket) DocumentedPacket(me.retrodaredevil.solarthing.packets.DocumentedPacket) SecurityPacket(me.retrodaredevil.solarthing.packets.security.SecurityPacket) ImmutableSecurityRejectPacket(me.retrodaredevil.solarthing.commands.event.ImmutableSecurityRejectPacket) ImmutableSecurityAcceptPacket(me.retrodaredevil.solarthing.commands.event.ImmutableSecurityAcceptPacket) SecurityAcceptPacket(me.retrodaredevil.solarthing.commands.event.SecurityAcceptPacket) InstancePacket(me.retrodaredevil.solarthing.packets.instance.InstancePacket) AuthNewSenderPacket(me.retrodaredevil.solarthing.packets.security.AuthNewSenderPacket) SecurityEventPacket(me.retrodaredevil.solarthing.commands.event.SecurityEventPacket) SecurityPacket(me.retrodaredevil.solarthing.packets.security.SecurityPacket) AuthNewSenderPacket(me.retrodaredevil.solarthing.packets.security.AuthNewSenderPacket) IntegrityPacket(me.retrodaredevil.solarthing.packets.security.IntegrityPacket) LargeIntegrityPacket(me.retrodaredevil.solarthing.packets.security.LargeIntegrityPacket) LargeIntegrityPacket(me.retrodaredevil.solarthing.packets.security.LargeIntegrityPacket)

Example 2 with LargeIntegrityPacket

use of me.retrodaredevil.solarthing.packets.security.LargeIntegrityPacket in project solarthing by wildmountainfarms.

the class AlterManagerAction method isDocumentMadeByUs.

private boolean isDocumentMadeByUs(Instant now, ScheduledCommandData scheduledCommandData, StoredPacketGroup existingDocument) {
    LargeIntegrityPacket largeIntegrityPacket = (LargeIntegrityPacket) existingDocument.getPackets().stream().filter(p -> p instanceof LargeIntegrityPacket).findAny().orElse(null);
    if (largeIntegrityPacket == null) {
        LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "The stored document did not have a LargeIntegrity packet. Someone must be trying to stop a scheduled command!");
        return false;
    }
    String sender = largeIntegrityPacket.getSender();
    if (!commandManager.getSender().equals(sender)) {
        LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "The sender of the large integrity packet we are inspecting is not us (" + commandManager.getSender() + "). It is " + sender + ". Might be a malicious actor, might be a bad setup.");
        return false;
    }
    String encryptedHash = largeIntegrityPacket.getEncryptedHash();
    String data;
    try {
        synchronized (CIPHER) {
            data = Decrypt.decrypt(CIPHER, commandManager.getKeyPair().getPublic(), encryptedHash);
        }
    } catch (InvalidKeyException e) {
        throw new RuntimeException("Should be a valid key!", e);
    } catch (DecryptException e) {
        LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "The document we are inspecting had a large integrity packet with the sender: " + sender + ", but that's us and we couldn't decrypt their payload. Likely a malicious actor", e);
        return false;
    }
    final String[] split = data.split(",", 2);
    LOGGER.debug("decrypted data: " + data);
    if (split.length != 2) {
        LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "split.length: " + split.length + " split: " + Arrays.asList(split));
        return false;
    }
    String hexMillis = split[0];
    // String message = split[1]; We don't care what the message is. We don't even care enough to check if it matches the payload's hash
    long dateMillis;
    try {
        dateMillis = Long.parseLong(hexMillis, 16);
    } catch (NumberFormatException e) {
        LOGGER.error(SolarThingConstants.SUMMARY_MARKER, "Error parsing hex date millis", e);
        return false;
    }
    if (dateMillis < scheduledCommandData.getScheduledTimeMillis()) {
        LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "The dateMillis for this is less than the command's scheduled execution time! This must be a malicious actor!");
        return false;
    }
    if (dateMillis > now.toEpochMilli()) {
        LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "The dateMillis for this is greater than now! This should never ever happen.");
        return false;
    }
    return true;
}
Also used : CommandManager(me.retrodaredevil.solarthing.commands.util.CommandManager) Packet(me.retrodaredevil.solarthing.packets.Packet) Arrays(java.util.Arrays) AlterPacketsProvider(me.retrodaredevil.solarthing.AlterPacketsProvider) LoggerFactory(org.slf4j.LoggerFactory) InstanceTargetPackets(me.retrodaredevil.solarthing.packets.instance.InstanceTargetPackets) VersionedPacket(me.retrodaredevil.solarthing.database.VersionedPacket) LargeIntegrityPacket(me.retrodaredevil.solarthing.packets.security.LargeIntegrityPacket) ActivePeriod(me.retrodaredevil.solarthing.type.alter.flag.ActivePeriod) ImmutableStoredAlterPacket(me.retrodaredevil.solarthing.type.alter.ImmutableStoredAlterPacket) DeleteAlterPacket(me.retrodaredevil.solarthing.commands.packets.open.DeleteAlterPacket) InvalidKeyException(me.retrodaredevil.solarthing.packets.security.crypto.InvalidKeyException) Duration(java.time.Duration) FlagPacket(me.retrodaredevil.solarthing.type.alter.packets.FlagPacket) RequestCommandPacket(me.retrodaredevil.solarthing.commands.packets.open.RequestCommandPacket) DecryptException(me.retrodaredevil.solarthing.packets.security.crypto.DecryptException) Instant(java.time.Instant) IncompatibleUpdateTokenException(me.retrodaredevil.solarthing.database.exception.IncompatibleUpdateTokenException) ZoneId(java.time.ZoneId) Executors(java.util.concurrent.Executors) ExecutionReason(me.retrodaredevil.solarthing.reason.ExecutionReason) List(java.util.List) SolarThingConstants(me.retrodaredevil.solarthing.SolarThingConstants) TimeRange(me.retrodaredevil.solarthing.util.TimeRange) TimeRangeActivePeriod(me.retrodaredevil.solarthing.type.alter.flag.TimeRangeActivePeriod) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) ScheduledCommandPacket(me.retrodaredevil.solarthing.type.alter.packets.ScheduledCommandPacket) OpenSource(me.retrodaredevil.solarthing.type.open.OpenSource) TargetPacketGroup(me.retrodaredevil.solarthing.packets.collection.TargetPacketGroup) Cipher(javax.crypto.Cipher) ArrayList(java.util.ArrayList) RequestFlagPacket(me.retrodaredevil.solarthing.commands.packets.open.RequestFlagPacket) FlagData(me.retrodaredevil.solarthing.type.alter.flag.FlagData) NoSuchPaddingException(javax.crypto.NoSuchPaddingException) OpenSourceExecutionReason(me.retrodaredevil.solarthing.reason.OpenSourceExecutionReason) ScheduleCommandPacket(me.retrodaredevil.solarthing.commands.packets.open.ScheduleCommandPacket) ExecutorService(java.util.concurrent.ExecutorService) SimpleAction(me.retrodaredevil.action.SimpleAction) ScheduledCommandData(me.retrodaredevil.solarthing.type.alter.packets.ScheduledCommandData) Logger(org.slf4j.Logger) PacketCollectionCreator(me.retrodaredevil.solarthing.packets.collection.PacketCollectionCreator) KeyUtil(me.retrodaredevil.solarthing.packets.security.crypto.KeyUtil) SolarThingDatabase(me.retrodaredevil.solarthing.database.SolarThingDatabase) Decrypt(me.retrodaredevil.solarthing.packets.security.crypto.Decrypt) DatabaseCache(me.retrodaredevil.solarthing.database.cache.DatabaseCache) StoredAlterPacket(me.retrodaredevil.solarthing.type.alter.StoredAlterPacket) ImmutableRequestCommandPacket(me.retrodaredevil.solarthing.commands.packets.open.ImmutableRequestCommandPacket) StoredPacketGroup(me.retrodaredevil.solarthing.packets.collection.StoredPacketGroup) SecurityPacketReceiver(me.retrodaredevil.solarthing.program.SecurityPacketReceiver) AlterPacket(me.retrodaredevil.solarthing.type.alter.AlterPacket) UpdateConflictSolarThingDatabaseException(me.retrodaredevil.solarthing.database.exception.UpdateConflictSolarThingDatabaseException) PublicKeyLookUp(me.retrodaredevil.solarthing.packets.security.crypto.PublicKeyLookUp) Collections(java.util.Collections) PacketCollection(me.retrodaredevil.solarthing.packets.collection.PacketCollection) CommandOpenPacket(me.retrodaredevil.solarthing.commands.packets.open.CommandOpenPacket) SolarThingDatabaseException(me.retrodaredevil.solarthing.database.exception.SolarThingDatabaseException) LargeIntegrityPacket(me.retrodaredevil.solarthing.packets.security.LargeIntegrityPacket) InvalidKeyException(me.retrodaredevil.solarthing.packets.security.crypto.InvalidKeyException) DecryptException(me.retrodaredevil.solarthing.packets.security.crypto.DecryptException)

Aggregations

Packet (me.retrodaredevil.solarthing.packets.Packet)2 LargeIntegrityPacket (me.retrodaredevil.solarthing.packets.security.LargeIntegrityPacket)2 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 Duration (java.time.Duration)1 Instant (java.time.Instant)1 ZoneId (java.time.ZoneId)1 ArrayList (java.util.ArrayList)1 Arrays (java.util.Arrays)1 Collections (java.util.Collections)1 List (java.util.List)1 ExecutorService (java.util.concurrent.ExecutorService)1 Executors (java.util.concurrent.Executors)1 Cipher (javax.crypto.Cipher)1 NoSuchPaddingException (javax.crypto.NoSuchPaddingException)1 SimpleAction (me.retrodaredevil.action.SimpleAction)1 AlterPacketsProvider (me.retrodaredevil.solarthing.AlterPacketsProvider)1 SolarThingConstants (me.retrodaredevil.solarthing.SolarThingConstants)1 ImmutableSecurityAcceptPacket (me.retrodaredevil.solarthing.commands.event.ImmutableSecurityAcceptPacket)1 ImmutableSecurityRejectPacket (me.retrodaredevil.solarthing.commands.event.ImmutableSecurityRejectPacket)1 SecurityAcceptPacket (me.retrodaredevil.solarthing.commands.event.SecurityAcceptPacket)1