EdhocResource.java

/*******************************************************************************
 * Copyright (c) 2020 RISE and others.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * and Eclipse Distribution License v1.0 which accompany this distribution.
 * 
 * The Eclipse Public License is available at
 *    http://www.eclipse.org/legal/epl-v20.html
 * and the Eclipse Distribution License is available at
 *    http://www.eclipse.org/org/documents/edl-v10.html.
 *
 * This class is based on org.eclipse.californium.examples.HelloWorldServer
 * 
 * Contributors:
 *    Marco Tiloca (RISE)
 *    Rikard Höglund (RISE)
 *    
 ******************************************************************************/
package org.eclipse.californium.edhoc;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import org.eclipse.californium.core.CoapResource;
import org.eclipse.californium.core.Utils;
import org.eclipse.californium.core.coap.Response;
import org.eclipse.californium.core.coap.CoAP.ResponseCode;
import org.eclipse.californium.core.server.resources.CoapExchange;
import org.eclipse.californium.cose.AlgorithmID;
import org.eclipse.californium.oscore.OSCoreCtx;
import org.eclipse.californium.oscore.OSException;

import com.upokecenter.cbor.CBORObject;
import com.upokecenter.cbor.CBORType;

/*
 * Definition of the EDHOC Resource
 */
public class EdhocResource extends CoapResource {

	private EdhocEndpointInfo edhocEndpointInfo;
	private Set<CBORObject> ownIdCreds;
	
	private static final boolean debugPrint = true;
	
	public EdhocResource(String resourceIdentifier, EdhocEndpointInfo edhocEndpointInfo, Set<CBORObject> ownIdCreds) {
		
		// set resource identifier
		super(resourceIdentifier);

		// set the information about the EDHOC server hosting this EDHOC resource
		this.edhocEndpointInfo = edhocEndpointInfo;
		
		// set the collection of ID_CRED_X used for an authentication credential associated to this peer
		this.ownIdCreds = ownIdCreds;
		
		// set display name
		getAttributes().setTitle("EDHOC Resource");
	}

	@Override
	public void handleGET(CoapExchange exchange) {

		// respond to the request
		exchange.respond("Send me a POST request to run EDHOC!");
	}
	
	
	@Override
	public void handlePOST(CoapExchange exchange) {
		
		byte[] nextMessage = new byte[] {};
				
		URI edhocResourceUri = null;
		try {
			edhocResourceUri = new URI(exchange.advanced().getRequest().getURI());
		} catch (URISyntaxException e1) {
			String responseString = new String("Error when parsing the request target URI");
			System.err.println(responseString);
			
			nextMessage = responseString.getBytes(Constants.charset);
			Response genericErrorResponse = new Response(ResponseCode.INTERNAL_SERVER_ERROR);
			genericErrorResponse.setPayload(nextMessage);
			exchange.respond(genericErrorResponse);
			return;
		}
		
		// Retrieve the application profile to use
		String path = edhocResourceUri.getPath();
		AppProfile appProfile = edhocEndpointInfo.getAppProfiles().get(path);
		
		// Error when retrieving the application profile for this EDHOC resource
		if (appProfile == null) {
			String responseString = new String("Error when retrieving the application profile");
			System.err.println(responseString);
			
			nextMessage = responseString.getBytes(Constants.charset);
			Response genericErrorResponse = new Response(ResponseCode.INTERNAL_SERVER_ERROR);
			genericErrorResponse.setPayload(nextMessage);
			exchange.respond(genericErrorResponse);
			return;
			
		}
		
		byte[] message = exchange.getRequestPayload();
		
		boolean hasContentFormat = exchange.getRequestOptions().hasContentFormat();
		int contentFormat = exchange.getRequestOptions().getContentFormat();
		
		if ( (message == null && !hasContentFormat) ||
			 (message != null && hasContentFormat && contentFormat != Constants.APPLICATION_CID_EDHOC_CBOR_SEQ &&
			  contentFormat != Constants.APPLICATION_EDHOC_CBOR_SEQ) ) {
			// The server can start acting as Initiator and send an EDHOC Message 1 as a CoAP response
			processTriggerRequest(exchange, appProfile);
			return;
		}
		
		if ( message == null ||
			(message != null && hasContentFormat && contentFormat != Constants.APPLICATION_CID_EDHOC_CBOR_SEQ) ) {
			String responseString = new String("Error when receiving a request to the EDHOC resource"
					+ "An EDHOC message must be included in a request either without content-format "
					+ "or with content-format application/cid-edhoc+cbor-seq");
			System.err.println(responseString);
			
			nextMessage = responseString.getBytes(Constants.charset);
			Response genericErrorResponse = new Response(ResponseCode.BAD_REQUEST);
			genericErrorResponse.setPayload(nextMessage);
			exchange.respond(genericErrorResponse);
			return;
		}

		int messageType = MessageProcessor.messageType(message, true, edhocEndpointInfo.getEdhocSessions(), null);
		
		// Invalid EDHOC message type
		if (messageType == -1) {
			String responseString = new String("Invalid EDHOC message type");
			System.err.println(responseString);
			
			nextMessage = responseString.getBytes(Constants.charset);
			Response genericErrorResponse = new Response(ResponseCode.BAD_REQUEST);
			genericErrorResponse.setPayload(nextMessage);
			exchange.respond(genericErrorResponse);
			return;
			
		}
		
		List<CBORObject> processingResult = new ArrayList<CBORObject>();

		
		// The received message is an actual EDHOC message
		
		String typeName = "";
		switch (messageType) {
			case Constants.EDHOC_ERROR_MESSAGE:
				typeName = new String("EDHOC Error Message");
				break;
			case Constants.EDHOC_MESSAGE_1:
			case Constants.EDHOC_MESSAGE_2:
			case Constants.EDHOC_MESSAGE_3:
			case Constants.EDHOC_MESSAGE_4:
				typeName = new String("EDHOC Message " + messageType);
				break;		
		}
		System.out.println("Determined EDHOC message type: " + typeName + "\n");
		
        // Since the incoming EDHOC message is transported as a CoAP request,
		// it is prepended by C_X, which does not have to be printed
		List<CBORObject> trimmedSequence = new ArrayList<CBORObject>();
		CBORObject[] objectListRequest = CBORObject.DecodeSequenceFromBytes(message);
		for (int i = 1; i < objectListRequest.length; i++) {
			trimmedSequence.add(objectListRequest[i]);
		}
		byte[] messageToPrint = Util.buildCBORSequence(trimmedSequence);
		Util.nicePrint(typeName, messageToPrint);

		
		/* Start handling EDHOC Message 1 */
		
		if (messageType == Constants.EDHOC_MESSAGE_1) {
			
			SideProcessor sideProcessor = new SideProcessor(edhocEndpointInfo.getTrustModel(),
															edhocEndpointInfo.getPeerCredentials(),
															edhocEndpointInfo.getEadProductionInput());
			
			processingResult = MessageProcessor.readMessage1(message, true,
															 edhocEndpointInfo.getSupportedCipherSuites(),
															 edhocEndpointInfo.getSupportedEADs(),
															 appProfile, sideProcessor);

			if (processingResult.get(0) == null || processingResult.get(0).getType() != CBORType.ByteString) {
				String responseString = new String("Internal error when processing EDHOC Message 1");
				System.err.println(responseString);
				
				nextMessage = responseString.getBytes(Constants.charset);
				Response genericErrorResponse = new Response(ResponseCode.INTERNAL_SERVER_ERROR);
				genericErrorResponse.setPayload(nextMessage);
				exchange.respond(genericErrorResponse);
				return;
			}
			
			EdhocSession session = null;
			int responseType = -1;
			
			// A non-zero length response payload would be an EDHOC Error Message
			nextMessage = processingResult.get(0).GetByteString();
			
			// Prepare EDHOC Message 2
			if (nextMessage.length == 0) {

				session = MessageProcessor.createSessionAsResponder(message, true,
																	edhocEndpointInfo.getKeyPairs(),
																    edhocEndpointInfo.getIdCreds(),
																    edhocEndpointInfo.getCreds(),
																    edhocEndpointInfo.getSupportedCipherSuites(),
																    edhocEndpointInfo.getSupportedEADs(),
																    edhocEndpointInfo.getUsedConnectionIds(),
																    appProfile, edhocEndpointInfo.getTrustModel(),
																    edhocEndpointInfo.getOscoreDb());
				
				// Provide the side processor object with the just created EDHOC session.
				// A reference to the sideProcessor is also going to be stored in the EDHOC session.
				sideProcessor.setEdhocSession(session);
				
				// Compute the EDHOC Message 2
				nextMessage = MessageProcessor.writeMessage2(session);

				byte[] connectionIdentifier = session.getConnectionId();
				
				// Deallocate the assigned Connection Identifier for this peer
				if (nextMessage == null || session.getCurrentStep() != Constants.EDHOC_BEFORE_M2) {
					Util.releaseConnectionId(connectionIdentifier, edhocEndpointInfo.getUsedConnectionIds(), session.getOscoreDb());
					session.deleteTemporaryMaterial();
					session = null;
					
					String responseString = new String("Inconsistent state before sending EDHOC Message 2");
					System.err.println(responseString);
					nextMessage = responseString.getBytes(Constants.charset);
					Response genericErrorResponse = new Response(ResponseCode.INTERNAL_SERVER_ERROR);
					genericErrorResponse.setPayload(nextMessage);
					exchange.respond(genericErrorResponse);
					return;
				}
				
				// Add the new session to the list of existing EDHOC sessions
				session.setCurrentStep(Constants.EDHOC_AFTER_M2);
				CBORObject connectionIdentifierCbor = CBORObject.FromObject(connectionIdentifier);
				edhocEndpointInfo.getEdhocSessions().put(connectionIdentifierCbor, session);
				
			}
			
			byte[] connectionIdentifier = null;
			if (session != null) {
				connectionIdentifier = session.getConnectionId();
			}
			
			responseType = MessageProcessor.messageType(nextMessage, false,
														edhocEndpointInfo.getEdhocSessions(), connectionIdentifier);
			
			if (responseType != Constants.EDHOC_MESSAGE_2 && responseType != Constants.EDHOC_ERROR_MESSAGE) {
				nextMessage = null;
			}
			
			if (nextMessage != null) {
				
				ResponseCode responseCode = ResponseCode.CHANGED;
				
				if (responseType == Constants.EDHOC_ERROR_MESSAGE) {
					int responseCodeValue = processingResult.get(1).AsInt32();
					responseCode = ResponseCode.valueOf(responseCodeValue);
				}

				Response myResponse = new Response(responseCode);
				myResponse.getOptions().setContentFormat(Constants.APPLICATION_EDHOC_CBOR_SEQ);
				myResponse.setPayload(nextMessage);
				
				String myString = (responseType == Constants.EDHOC_MESSAGE_2) ? "EDHOC Message 2" : "EDHOC Error Message";
				System.out.println("Response type: " + myString + "\n");
				
				if (responseType == Constants.EDHOC_MESSAGE_2) {
			        System.out.println("Sent EDHOC Message 2\n");
				}
				if (responseType == Constants.EDHOC_ERROR_MESSAGE) {
				    
					if (session != null) {
						// The reading of EDHOC Message 1 was successful, but the writing of EDHOC Message 2 was not
						
						// The session was created, but not added to the list of EDHOC sessions
						Util.releaseConnectionId(session.getConnectionId(),
								                 edhocEndpointInfo.getUsedConnectionIds(),
								                 session.getOscoreDb());
						session.deleteTemporaryMaterial();
						session = null;
					}
					
			        System.out.println("Sent EDHOC Error Message\n");
			        if (debugPrint) {
			        	Util.nicePrint("EDHOC Error Message", nextMessage);
			        }
				}
				
				if (responseType == Constants.EDHOC_MESSAGE_2) {
					session.setCurrentStep(Constants.EDHOC_SENT_M2);
				}
				
				exchange.respond(myResponse);
				return;
			}
			else {
				Util.purgeSession(session, session.getConnectionId(),
								  edhocEndpointInfo.getEdhocSessions(),
								  edhocEndpointInfo.getUsedConnectionIds());
				
				String responseString = new String("Inconsistent state after processing EDHOC Message 2");
				System.err.println(responseString);
				nextMessage = responseString.getBytes(Constants.charset);
				Response genericErrorResponse = new Response(ResponseCode.INTERNAL_SERVER_ERROR);
				genericErrorResponse.setPayload(nextMessage);
				exchange.respond(genericErrorResponse);
				
				return;
			}
			
		}
		/* End handling EDHOC Message 1 */
		
		
		/* Start handling EDHOC Message 2 */
		
		if (messageType == Constants.EDHOC_MESSAGE_2) {
			
			System.out.println("Handler for processing EDHOC Message 2");
			
			// Do nothing
			
		}
		
		
		/* Start handling EDHOC Message 3 */
		
		if (messageType == Constants.EDHOC_MESSAGE_3) {
			
			processingResult = MessageProcessor.readMessage3(message, true, null,
															 edhocEndpointInfo.getEdhocSessions(),
															 edhocEndpointInfo.getPeerPublicKeys(),
															 edhocEndpointInfo.getPeerCredentials(),
															 edhocEndpointInfo.getUsedConnectionIds());
			
			if (processingResult.get(0) == null || processingResult.get(0).getType() != CBORType.ByteString) {
				System.err.println("Internal error when processing EDHOC Message 3");
				return;
			}
			
			EdhocSession mySession = null;
			
			// A non-zero length response payload would be an EDHOC Error Message
			nextMessage = processingResult.get(0).GetByteString();
			
			// The EDHOC protocol has successfully completed
			if (nextMessage.length == 0) {
				
				CBORObject cR = processingResult.get(1);
				mySession = edhocEndpointInfo.getEdhocSessions().get(cR);
				
				if (mySession == null) {
					System.err.println("Inconsistent state before sending EDHOC Message 3");
					return;
				}
				if (mySession.getCurrentStep() != Constants.EDHOC_AFTER_M3) {
						System.err.println("Inconsistent state after sending EDHOC Message 3");							
						Util.purgeSession(mySession, mySession.getConnectionId(),
										  edhocEndpointInfo.getEdhocSessions(),
										  edhocEndpointInfo.getUsedConnectionIds());
						return;
				}
				
				if (mySession.getApplicationProfile().getUsedForOSCORE() == true) {
			        /* Invoke the EDHOC-Exporter to produce OSCORE input material */
			        byte[] masterSecret = EdhocSession.getMasterSecretOSCORE(mySession);
			        byte[] masterSalt = EdhocSession.getMasterSaltOSCORE(mySession);
			        if (debugPrint) {
			        	Util.nicePrint("OSCORE Master Secret", masterSecret);
			        	Util.nicePrint("OSCORE Master Salt", masterSalt);
			        }
			        
			        /* Setup the OSCORE Security Context */
			        
			        // The Sender ID of this peer is the EDHOC connection identifier of the other peer
			        byte[] senderId = mySession.getPeerConnectionId();
			        
			        // The Recipient ID of this peer is the EDHOC connection identifier of this peer
			        byte[] recipientId = mySession.getConnectionId();
			        
			        if (Arrays.equals(senderId, recipientId)) {
						System.err.println("Error: the Sender ID coincides with the Recipient ID " +
											Utils.toHexString(senderId));
						Util.purgeSession(mySession, mySession.getConnectionId(),
										  edhocEndpointInfo.getEdhocSessions(),
										  edhocEndpointInfo.getUsedConnectionIds());
						return;
			        }
			        
			        int selectedCipherSuite = mySession.getSelectedCipherSuite();
			        AlgorithmID alg = EdhocSession.getAppAEAD(selectedCipherSuite);
			        AlgorithmID hkdf = EdhocSession.getAppHkdf(selectedCipherSuite);
			        
			        OSCoreCtx ctx = null;
			        try {
						ctx = new OSCoreCtx(masterSecret, false, alg, senderId, 
											recipientId, hkdf, edhocEndpointInfo.getOscoreReplayWindow(),
											masterSalt, null, edhocEndpointInfo.getOscoreMaxUnfragmentedSize());
						
					} catch (OSException e) {
						System.err.println("Error when deriving the OSCORE Security Context " + e.getMessage());						
						Util.purgeSession(mySession, mySession.getConnectionId(),
										  edhocEndpointInfo.getEdhocSessions(),
										  edhocEndpointInfo.getUsedConnectionIds());
						return;
					}
			        
			        try {
			        	edhocEndpointInfo.getOscoreDb().addContext(edhocEndpointInfo.getUri(), ctx);
					} catch (OSException e) {
						System.err.println("Error when adding the OSCORE Security Context to the context database " + e.getMessage());							
						Util.purgeSession(mySession, mySession.getConnectionId(),
										  edhocEndpointInfo.getEdhocSessions(),
										  edhocEndpointInfo.getUsedConnectionIds());
						return;
					}
		        
				}
		        
		        // Prepare the response to send back
		        Response myResponse = new Response(ResponseCode.CHANGED);
		        
		        if (mySession.getApplicationProfile().getUseMessage4() == false) {
			        // Just send an empty response back
		        	
		        	// Uncomment to have the response as a confirmable Separate Response
		        	// myResponse.setConfirmable(true);
		        	
					myResponse.setPayload(nextMessage);
					exchange.respond(myResponse);
					return;
					
			        /*
			        // Alternative sending an empty ACK instead
			        if (exchange.advanced().getRequest().isConfirmable())
			        	exchange.accept();
			        */
					
		        }
		        else {
		        	// message_4 has to be sent to the Initiator
		        	
					// Compute the EDHOC Message 4
					byte[] connectionIdentifierResponder = mySession.getConnectionId();
					nextMessage = MessageProcessor.writeMessage4(mySession);
					
					// Deallocate the assigned Connection Identifier for this peer
					if (nextMessage == null || mySession.getCurrentStep() != Constants.EDHOC_AFTER_M4) {
						System.err.println("Inconsistent state before sending EDHOC Message 4");
						Util.purgeSession(mySession, connectionIdentifierResponder,
										  edhocEndpointInfo.getEdhocSessions(),
										  edhocEndpointInfo.getUsedConnectionIds());
						return;
					}
					
					int responseType = MessageProcessor.messageType(nextMessage, false,
																	edhocEndpointInfo.getEdhocSessions(),
																	connectionIdentifierResponder);

					if (responseType == Constants.EDHOC_MESSAGE_4 || responseType == Constants.EDHOC_ERROR_MESSAGE) {
						
						myResponse.getOptions().setContentFormat(Constants.APPLICATION_EDHOC_CBOR_SEQ);
						myResponse.setConfirmable(true);
						myResponse.setPayload(nextMessage);
						
						String myString = (responseType == Constants.EDHOC_MESSAGE_4) ?
								                             "EDHOC Message 4" : "EDHOC Error Message";
						System.out.println("Response type: " + myString + "\n");
						
						if (responseType == Constants.EDHOC_MESSAGE_4) {

					        mySession.setCurrentStep(Constants.EDHOC_SENT_M4);
							exchange.respond(myResponse);
					        
					        System.out.println("Sent EDHOC Message 4\n");
					        
						}
						
						if (responseType == Constants.EDHOC_ERROR_MESSAGE) {
					        
							int responseCodeValue = processingResult.get(1).AsInt32();
							ResponseCode responseCode = ResponseCode.valueOf(responseCodeValue);
					        sendErrorMessage(exchange, nextMessage, appProfile, responseCode);
					        
					        Util.purgeSession(mySession, connectionIdentifierResponder,
							        		  edhocEndpointInfo.getEdhocSessions(),
							        		  edhocEndpointInfo.getUsedConnectionIds());
					        
					        System.out.println("Sent EDHOC Error Message\n");
					        if (debugPrint) {
					        	Util.nicePrint("EDHOC Error Message", nextMessage);
					        }
					        
						}
						return;
					}
					else {
						System.err.println("Inconsistent state before sending EDHOC Message 4");
						Util.purgeSession(mySession, connectionIdentifierResponder,
										  edhocEndpointInfo.getEdhocSessions(),
										  edhocEndpointInfo.getUsedConnectionIds());
						return;
					}
					
				}
					
			}
			// An EDHOC error message has to be returned in response to EDHOC message_3
			// The session has been possibly purged while attempting to process message_3
			else {				
				int responseCodeValue = processingResult.get(1).AsInt32();
				ResponseCode responseCode = ResponseCode.valueOf(responseCodeValue);
				sendErrorMessage(exchange, nextMessage, appProfile, responseCode);
			}
			
			return;
			
		}
		
		
		/* Start handling EDHOC Error Message */
		if (messageType == Constants.EDHOC_ERROR_MESSAGE) {
            
        	CBORObject[] objectList = MessageProcessor.readErrorMessage(message, null, edhocEndpointInfo.getEdhocSessions());
        	
        	if (objectList != null) {
        	
	        	// The first element is always C_X.
	        	CBORObject cX = objectList[0];
	        	byte[] connectionIdentifier = MessageProcessor.decodeIdentifier(cX);
	        	
	    		if (connectionIdentifier == null) {
	    			System.err.println("Malformed or invalid connection identifier in EDHOC Error Message");
	    			return;
	    		}
	        	
	        	// Retrieve ERR_CODE
	        	int errorCode = objectList[1].AsInt32();
	        	System.out.println("ERR_CODE: " + errorCode + "\n");
	        	
	        	// Retrieve ERR_INFO
	    		if (errorCode == Constants.ERR_CODE_SUCCESS) {
	    			System.out.println("Success\n");
	    		}
	    		else if (errorCode == Constants.ERR_CODE_UNSPECIFIED_ERROR) {
		        	String errMsg = objectList[2].toString();
		        	System.out.println("ERR_INFO: " + errMsg + "\n");
	    		}
	    		else if (errorCode == Constants.ERR_CODE_WRONG_SELECTED_CIPHER_SUITE) {
	    			CBORObject suitesR = objectList[2];
					if (suitesR.getType() == CBORType.Integer) {
			        	System.out.println("SUITES_R: " + suitesR.AsInt32() + "\n");
					}
					else if (suitesR.getType() == CBORType.Array) {
						System.out.print("SUITES_R: [ " );
						for (int i = 0; i < suitesR.size(); i++) {
							System.out.print(suitesR.get(i).AsInt32() + " " );
						}
						System.out.println("]\n");
					}
	    		}
	        	
	        	// The following simply deletes the EDHOC session. However, if the server was the Initiator 
	        	// and the EDHOC Error Message is a reply to an EDHOC Message 1, it would be fine to prepare a new
	        	// EDHOC Message 1 right away, keeping the same Connection Identifier C_I and this same session.
	        	// In fact, the session is marked as "used", hence new ephemeral keys would be generated when
	        	// preparing a new EDHOC Message 1. 
	        	
	    		CBORObject connectionIdentifierCbor = CBORObject.FromObject(connectionIdentifier);
	        	EdhocSession mySession = edhocEndpointInfo.getEdhocSessions().get(connectionIdentifierCbor);
	    		if (mySession == null) {
	    			System.err.println("EDHOC session to delete not found");
	    			return;
	    		}
	    		
	        	Util.purgeSession(mySession, connectionIdentifier,
	        					  edhocEndpointInfo.getEdhocSessions(),
	        					  edhocEndpointInfo.getUsedConnectionIds());
	        	
	        	// Just send an empty response back
	        	Response myResponse = new Response(ResponseCode.CHANGED);
	        	nextMessage = new byte[] {};
	        	
	        	// Uncomment to have the response as a confirmable Separate Response
	        	// myResponse.setConfirmable(true);
	        	
	        	myResponse.setPayload(nextMessage);
	        	exchange.respond(myResponse);
	        	
	        	/*
	        	// Alternative sending an empty ACK instead
		        if (exchange.advanced().getRequest().isConfirmable()) {
		        	exchange.accept();
		        }
		        */
        	
			}
        	
    		return;
			
		}
		

	}
	
	private void sendErrorMessage(CoapExchange exchange, byte[] nextMessage,
			                      AppProfile appProfile, ResponseCode responseCode) {
		
		int responseType = MessageProcessor.messageType(nextMessage, false, edhocEndpointInfo.getEdhocSessions(), null);
		
		if (responseType != Constants.EDHOC_ERROR_MESSAGE) {
			System.err.println("Inconsistent state before sending EDHOC Error Message");	
			return;
		}
		
		Response myResponse = new Response(responseCode);
		myResponse.getOptions().setContentFormat(Constants.APPLICATION_EDHOC_CBOR_SEQ);
		myResponse.setPayload(nextMessage);
		
		Util.nicePrint("EDHOC Error Message", nextMessage);
		
		exchange.respond(myResponse);
		
	}
	
	/*
	 * Process a "trigger request" targeting the EDHOC resource
	 */
	private void processTriggerRequest(CoapExchange request, AppProfile appProfile) {
		// Do nothing
		System.out.println("Entered processTriggerRequest()");
		
		// Here the server can start acting as Initiator and send an EDHOC Message 1 as a CoAP response
	}
	
}