Search in sources :

Example 1 with DatagramReader

use of org.eclipse.californium.elements.util.DatagramReader in project californium by eclipse.

the class RequestDecryptor method decrypt.

/**
 * @param db the context database used
 * @param request the request to decrypt
 * @param ctx the OSCore context
 *
 * @return the decrypted request
 *
 * @throws CoapOSException if decryption fails
 */
public static Request decrypt(OSCoreCtxDB db, Request request, OSCoreCtx ctx) throws CoapOSException {
    discardEOptions(request);
    byte[] protectedData = request.getPayload();
    Encrypt0Message enc;
    OptionSet uOptions = request.getOptions();
    try {
        enc = decompression(protectedData, request);
    } catch (OSException e) {
        LOGGER.error(ErrorDescriptions.FAILED_TO_DECODE_COSE);
        throw new CoapOSException(ErrorDescriptions.FAILED_TO_DECODE_COSE, ResponseCode.BAD_OPTION);
    }
    CBORObject kid = enc.findAttribute(HeaderKeys.KID);
    if (kid == null || !kid.getType().equals(CBORType.ByteString)) {
        LOGGER.error(ErrorDescriptions.MISSING_KID);
        throw new CoapOSException(ErrorDescriptions.FAILED_TO_DECODE_COSE, ResponseCode.BAD_OPTION);
    }
    byte[] rid = kid.GetByteString();
    // Retrieve Context ID (kid context)
    CBORObject kidContext = enc.findAttribute(CBORObject.FromObject(10));
    byte[] contextID = null;
    if (kidContext != null) {
        contextID = kidContext.GetByteString();
    }
    // Perform context re-derivation procedure if triggered or ongoing
    try {
        ctx = ContextRederivation.incomingRequest(db, ctx, contextID, rid);
    } catch (OSException e) {
        LOGGER.error(ErrorDescriptions.CONTEXT_REGENERATION_FAILED);
        throw new CoapOSException(ErrorDescriptions.CONTEXT_REGENERATION_FAILED, ResponseCode.BAD_REQUEST);
    }
    if (ctx == null) {
        LOGGER.error(ErrorDescriptions.CONTEXT_NOT_FOUND);
        throw new CoapOSException(ErrorDescriptions.CONTEXT_NOT_FOUND, ResponseCode.UNAUTHORIZED);
    }
    byte[] plaintext;
    try {
        plaintext = decryptAndDecode(enc, request, ctx, null);
    } catch (OSException e) {
        // First check for replay exceptions
        if (e.getMessage().equals(ErrorDescriptions.REPLAY_DETECT)) {
            LOGGER.error(ErrorDescriptions.REPLAY_DETECT);
            throw new CoapOSException(ErrorDescriptions.REPLAY_DETECT, ResponseCode.UNAUTHORIZED);
        }
        // Otherwise return generic error message
        LOGGER.error(ErrorDescriptions.DECRYPTION_FAILED);
        throw new CoapOSException(ErrorDescriptions.DECRYPTION_FAILED, ResponseCode.BAD_REQUEST);
    }
    // Check if parsing of request plaintext succeeds
    try {
        DatagramReader reader = new DatagramReader(new ByteArrayInputStream(plaintext));
        ctx.setCoAPCode(Code.valueOf(reader.read(CoAP.MessageFormat.CODE_BITS)));
        // resets option so eOptions gets priority during parse
        request.setOptions(EMPTY);
        new UdpDataParser().parseOptionsAndPayload(reader, request);
    } catch (Exception e) {
        LOGGER.error(ErrorDescriptions.DECRYPTION_FAILED);
        throw new CoapOSException(ErrorDescriptions.DECRYPTION_FAILED, ResponseCode.BAD_REQUEST);
    }
    OptionSet eOptions = request.getOptions();
    eOptions = OptionJuggle.merge(eOptions, uOptions);
    request.setOptions(eOptions);
    // We need the kid value on layer level
    request.getOptions().setOscore(rid);
    // Associate the Token with the context used
    db.addContext(request.getToken(), ctx);
    // Set information about the OSCORE context used in the endpoint context of this request
    OSCoreEndpointContextInfo.receivingRequest(ctx, request);
    return OptionJuggle.setRealCodeRequest(request, ctx.getCoAPCode());
}
Also used : Encrypt0Message(org.eclipse.californium.cose.Encrypt0Message) UdpDataParser(org.eclipse.californium.core.network.serialization.UdpDataParser) ByteArrayInputStream(java.io.ByteArrayInputStream) DatagramReader(org.eclipse.californium.elements.util.DatagramReader) OptionSet(org.eclipse.californium.core.coap.OptionSet) CBORObject(com.upokecenter.cbor.CBORObject)

Example 2 with DatagramReader

use of org.eclipse.californium.elements.util.DatagramReader in project californium by eclipse.

the class HelloExtension method readFrom.

/**
 * De-serializes a Client or Server Hello handshake message extension from
 * its binary representation.
 *
 * The TLS spec is unspecific about how a server should handle extensions
 * sent by a client that it does not understand. However,
 * <a href="https://tools.ietf.org/html/rfc7250#section-4.2" target=
 * "_blank"> Section 4.2 of RFC 7250</a> mandates that a server
 * implementation must simply ignore extensions of type
 * <em>client_certificate_type</em> or <em>server_certificate_type</em>, if
 * it does not support these extensions.
 *
 * This (lenient) approach seems feasible for the server to follow in
 * general when a client sends an extension of a type that the server does
 * not know or support (yet).
 *
 * @param reader the serialized extension
 * @return the object representing the extension or {@code null}, if the
 *         extension type is not (yet) known to or supported by Scandium.
 * @throws HandshakeException if the (supported) extension could not be
 *             de-serialized, e.g. due to erroneous encoding etc.
 * @since 3.0 (removed parameter type)
 */
public static HelloExtension readFrom(DatagramReader reader) throws HandshakeException {
    int typeId = reader.read(TYPE_BITS);
    int extensionLength = reader.read(LENGTH_BITS);
    DatagramReader extensionDataReader = reader.createRangeReader(extensionLength);
    ExtensionType type = ExtensionType.getExtensionTypeById(typeId);
    HelloExtension extension = null;
    if (type != null) {
        switch(type) {
            // the currently supported extensions
            case ELLIPTIC_CURVES:
                extension = SupportedEllipticCurvesExtension.fromExtensionDataReader(extensionDataReader);
                break;
            case EC_POINT_FORMATS:
                extension = SupportedPointFormatsExtension.fromExtensionDataReader(extensionDataReader);
                break;
            case SIGNATURE_ALGORITHMS:
                extension = SignatureAlgorithmsExtension.fromExtensionDataReader(extensionDataReader);
                break;
            case CLIENT_CERT_TYPE:
                extension = ClientCertificateTypeExtension.fromExtensionDataReader(extensionDataReader);
                break;
            case SERVER_CERT_TYPE:
                extension = ServerCertificateTypeExtension.fromExtensionDataReader(extensionDataReader);
                break;
            case MAX_FRAGMENT_LENGTH:
                extension = MaxFragmentLengthExtension.fromExtensionDataReader(extensionDataReader);
                break;
            case SERVER_NAME:
                extension = ServerNameExtension.fromExtensionDataReader(extensionDataReader);
                break;
            case RECORD_SIZE_LIMIT:
                extension = RecordSizeLimitExtension.fromExtensionDataReader(extensionDataReader);
                break;
            case EXTENDED_MASTER_SECRET:
                extension = ExtendedMasterSecretExtension.fromExtensionDataReader(extensionDataReader);
                break;
            case CONNECTION_ID:
                extension = ConnectionIdExtension.fromExtensionDataReader(extensionDataReader, type);
                break;
            default:
                if (type.replacement == ExtensionType.CONNECTION_ID) {
                    extension = ConnectionIdExtension.fromExtensionDataReader(extensionDataReader, type);
                }
                break;
        }
    }
    if (extension != null) {
        if (extensionDataReader.bytesAvailable()) {
            byte[] bytesLeft = extensionDataReader.readBytesLeft();
            throw new HandshakeException(String.format("Too many bytes, %d left, hello extension not completely parsed! hello extension type %d", bytesLeft.length, typeId), new AlertMessage(AlertLevel.FATAL, AlertDescription.DECODE_ERROR));
        }
    } else {
        extensionDataReader.close();
    }
    return extension;
}
Also used : DatagramReader(org.eclipse.californium.elements.util.DatagramReader)

Example 3 with DatagramReader

use of org.eclipse.californium.elements.util.DatagramReader in project californium by eclipse.

the class SignatureAlgorithmsExtension method fromExtensionDataReader.

public static SignatureAlgorithmsExtension fromExtensionDataReader(DatagramReader extensionDataReader) {
    List<SignatureAndHashAlgorithm> signatureAndHashAlgorithms = new ArrayList<SignatureAndHashAlgorithm>();
    int listLength = extensionDataReader.read(LIST_LENGTH_BITS);
    DatagramReader rangeReader = extensionDataReader.createRangeReader(listLength);
    while (rangeReader.bytesAvailable()) {
        int hashId = rangeReader.read(HASH_BITS);
        int signatureId = rangeReader.read(SIGNATURE_BITS);
        signatureAndHashAlgorithms.add(new SignatureAndHashAlgorithm(hashId, signatureId));
    }
    signatureAndHashAlgorithms = Collections.unmodifiableList(signatureAndHashAlgorithms);
    return new SignatureAlgorithmsExtension(signatureAndHashAlgorithms);
}
Also used : ArrayList(java.util.ArrayList) DatagramReader(org.eclipse.californium.elements.util.DatagramReader)

Example 4 with DatagramReader

use of org.eclipse.californium.elements.util.DatagramReader in project californium by eclipse.

the class DataParser method parseMessage.

/**
 * Parses a byte array into a CoAP Message.
 *
 * @param msg the byte array to parse.
 * @return the message.
 * @throws MessageFormatException if the array cannot be parsed into a
 *             message.
 */
public final Message parseMessage(final byte[] msg) {
    String errorMsg = "illegal message code";
    DatagramReader reader = new DatagramReader(msg);
    MessageHeader header = parseHeader(reader);
    try {
        Message message = null;
        if (CoAP.isRequest(header.getCode())) {
            message = parseMessage(reader, header, new Request(CoAP.Code.valueOf(header.getCode())));
        } else if (CoAP.isResponse(header.getCode())) {
            message = parseMessage(reader, header, new Response(CoAP.ResponseCode.valueOf(header.getCode())));
        } else if (CoAP.isEmptyMessage(header.getCode())) {
            message = parseMessage(reader, header, new EmptyMessage(header.getType()));
        }
        // Set the message's bytes and return the message
        if (message != null) {
            message.setBytes(msg);
            return message;
        }
    } catch (CoAPMessageFormatException e) {
        throw e;
    } catch (MessageFormatException e) {
        /**
         * use message to add CoAP message specific information
         */
        errorMsg = e.getMessage();
    }
    throw new CoAPMessageFormatException(errorMsg, header.getToken(), header.getMID(), header.getCode(), CoAP.Type.CON == header.getType());
}
Also used : Response(org.eclipse.californium.core.coap.Response) CoAPMessageFormatException(org.eclipse.californium.core.coap.CoAPMessageFormatException) MessageFormatException(org.eclipse.californium.core.coap.MessageFormatException) EmptyMessage(org.eclipse.californium.core.coap.EmptyMessage) Message(org.eclipse.californium.core.coap.Message) CoAPMessageFormatException(org.eclipse.californium.core.coap.CoAPMessageFormatException) Request(org.eclipse.californium.core.coap.Request) DatagramReader(org.eclipse.californium.elements.util.DatagramReader) EmptyMessage(org.eclipse.californium.core.coap.EmptyMessage)

Example 5 with DatagramReader

use of org.eclipse.californium.elements.util.DatagramReader in project californium by eclipse.

the class DTLSConnector method processDatagram.

/**
 * Process received datagram.
 *
 * Potentially called by multiple threads.
 *
 * @param packet received message
 * @param router router address, {@code null}, if no router is used.
 * @since 2.5
 */
protected void processDatagram(DatagramPacket packet, InetSocketAddress router) {
    InetSocketAddress peerAddress = (InetSocketAddress) packet.getSocketAddress();
    if (MDC_SUPPORT) {
        MDC.put("PEER", StringUtil.toString(peerAddress));
    }
    if (health != null) {
        health.receivingRecord(false);
    }
    long timestamp = ClockUtil.nanoRealtime();
    if (peerAddress.getPort() == 0) {
        // RFC 768
        // Source Port is an optional field, when meaningful, it indicates
        // the port of the sending process, and may be assumed to be the
        // port to which a reply should be addressed in the absence of any
        // other information. If not used, a value of zero is inserted.
        DROP_LOGGER.trace("Discarding record with {} bytes from [{}] without source-port", packet.getLength(), StringUtil.toLog(peerAddress));
        if (health != null) {
            health.receivingRecord(true);
        }
        return;
    }
    if (datagramFilter != null) {
        if (!datagramFilter.onReceiving(packet)) {
            DROP_LOGGER.trace("Filter out packet with {} bytes from [{}]", packet.getLength(), StringUtil.toLog(peerAddress));
            if (health != null) {
                health.receivingRecord(true);
            }
            return;
        }
    }
    DatagramReader reader = new DatagramReader(packet.getData(), packet.getOffset(), packet.getLength());
    List<Record> records = Record.fromReader(reader, connectionIdGenerator, timestamp);
    LOGGER.trace("Received {} DTLS records from {} using a {} byte datagram buffer", records.size(), StringUtil.toLog(peerAddress), inboundDatagramBufferSize);
    if (records.isEmpty()) {
        DROP_LOGGER.trace("Discarding malicious record with {} bytes from [{}]", packet.getLength(), StringUtil.toLog(peerAddress));
        if (health != null) {
            health.receivingRecord(true);
        }
        return;
    }
    if (!running.get()) {
        DROP_LOGGER.trace("Discarding {} records, startting with {} from [{}] on shutdown", records.size(), records.get(0).getType(), StringUtil.toLog(peerAddress));
        LOGGER.debug("Execution shutdown while processing incoming records from peer: {}", StringUtil.toLog(peerAddress));
        if (health != null) {
            health.receivingRecord(true);
        }
        return;
    }
    final Record firstRecord = records.get(0);
    if (records.size() == 1 && firstRecord.isNewClientHello()) {
        firstRecord.setAddress(peerAddress, router);
        if (dtlsRole == DtlsRole.CLIENT_ONLY) {
            DROP_LOGGER.trace("client-only, discarding {} CLIENT_HELLO from [{}]!", records.size(), StringUtil.toLog(peerAddress));
            if (health != null) {
                health.receivingRecord(true);
            }
            return;
        }
        executeInbound(getExecutorService(), peerAddress, new Runnable() {

            @Override
            public void run() {
                if (MDC_SUPPORT) {
                    MDC.put("PEER", StringUtil.toString(firstRecord.getPeerAddress()));
                }
                processNewClientHello(firstRecord);
                if (MDC_SUPPORT) {
                    MDC.clear();
                }
                pendingInboundJobsCountdown.incrementAndGet();
            }
        });
        return;
    }
    final ConnectionId connectionId = firstRecord.getConnectionId();
    final Connection connection = getConnection(peerAddress, connectionId, false);
    if (connection == null) {
        if (health != null) {
            health.receivingRecord(true);
        }
        if (connectionId == null) {
            DROP_LOGGER.trace("Discarding {} records from [{}] received without existing connection", records.size(), StringUtil.toLog(peerAddress));
        } else {
            DROP_LOGGER.trace("Discarding {} records from [{},{}] received without existing connection", records.size(), StringUtil.toLog(peerAddress), connectionId);
        }
        return;
    }
    SerialExecutor serialExecutor = connection.getExecutor();
    for (final Record record : records) {
        record.setAddress(peerAddress, router);
        try {
            if (!executeInbound(serialExecutor, peerAddress, new Runnable() {

                @Override
                public void run() {
                    try {
                        if (running.get()) {
                            processRecord(record, connection);
                        }
                    } finally {
                        pendingInboundJobsCountdown.incrementAndGet();
                    }
                }
            })) {
                break;
            }
        } catch (RuntimeException e) {
            LOGGER.warn("Unexpected error occurred while processing record [type: {}, peer: {}]", record.getType(), StringUtil.toLog(peerAddress), e);
            terminateConnectionWithInternalError(connection);
            break;
        }
    }
}
Also used : ConnectionId(org.eclipse.californium.scandium.dtls.ConnectionId) SerialExecutor(org.eclipse.californium.elements.util.SerialExecutor) InetSocketAddress(java.net.InetSocketAddress) Connection(org.eclipse.californium.scandium.dtls.Connection) Record(org.eclipse.californium.scandium.dtls.Record) DatagramReader(org.eclipse.californium.elements.util.DatagramReader)

Aggregations

DatagramReader (org.eclipse.californium.elements.util.DatagramReader)32 DatagramWriter (org.eclipse.californium.elements.util.DatagramWriter)7 ArrayList (java.util.ArrayList)5 Test (org.junit.Test)5 GeneralSecurityException (java.security.GeneralSecurityException)3 CBORObject (com.upokecenter.cbor.CBORObject)2 ByteArrayInputStream (java.io.ByteArrayInputStream)2 DatagramPacket (java.net.DatagramPacket)2 InetSocketAddress (java.net.InetSocketAddress)2 OptionSet (org.eclipse.californium.core.coap.OptionSet)2 UdpDataParser (org.eclipse.californium.core.network.serialization.UdpDataParser)2 Encrypt0Message (org.eclipse.californium.cose.Encrypt0Message)2 SerialExecutor (org.eclipse.californium.elements.util.SerialExecutor)2 Connection (org.eclipse.californium.scandium.dtls.Connection)2 ConnectionId (org.eclipse.californium.scandium.dtls.ConnectionId)2 IOException (java.io.IOException)1 Certificate (java.security.cert.Certificate)1 CertificateFactory (java.security.cert.CertificateFactory)1 X509Certificate (java.security.cert.X509Certificate)1 X500Principal (javax.security.auth.x500.X500Principal)1