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());
}
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;
}
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);
}
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());
}
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;
}
}
}
Aggregations