Message.java
/*******************************************************************************
* Original from https://github.com/cose-wg/COSE-JAVA Commit 1a20373
*
* Copyright (c) 2016, Jim Schaad
* Copyright (c) 2018, Ludwig Seitz, RISE SICS
* Copyright (c) 2018, Rikard Höglund, RISE SICS
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* Neither the name of COSE-JAVA nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
* Achim Kraus (Bosch Software Innovations GmbH) - update to cbor 4.0.0
* align with cose 1.0
* commit 629912b94ea80c4c6
******************************************************************************/
package org.eclipse.californium.cose;
import com.upokecenter.cbor.CBORObject;
import com.upokecenter.cbor.CBORType;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.californium.elements.util.StandardCharsets;
/**
* The Message class provides a common class that all of the COSE message classes
* inherit from. It provides the function used for decoding all of the known
* messages.
*
* @author jimsch
*/
public abstract class Message extends Attribute {
/**
* Is the tag identifying the message emitted?
*/
protected boolean emitTag = true;
/**
* Is the content emitted as part of the message?
*/
protected boolean emitContent = true;
/**
* What message tag identifies this message?
*/
protected MessageTag messageTag = MessageTag.Unknown;
/**
* What is the plain text content of the message.
*/
protected byte[] rgbContent = null;
/**
* Decode a COSE message object. This function assumes that the message
* has a leading CBOR tag to identify the message type. If this is not
* true then use {#link DecodeFromBytes(byte[], MessageTag)}.
*
* @param rgbData byte stream to be decoded
* @return the decoded message object
* @throws CoseException on a decode failure
*/
public static Message DecodeFromBytes(byte[] rgbData) throws CoseException {
return DecodeFromBytes(rgbData, MessageTag.Unknown);
}
/**
* Decode a COSE message object. Use a value of {@code MessageTag.Unknown}
* to decode a generic structure with tagging. Use a specific value if
* the tagging is absent or if a known structure is passed in.
*
* @param rgbData byte stream to be decoded
* @param defaultTag assumed message type to be decoded
* @return the decoded message object
* @throws CoseException on a decode failure.
*/
public static Message DecodeFromBytes(byte[] rgbData, MessageTag defaultTag) throws CoseException {
CBORObject messageObject = CBORObject.DecodeFromBytes(rgbData);
if (messageObject.getType() != CBORType.Array) throw new CoseException("Message is not a COSE security Message");
if (messageObject.isTagged()) {
if (messageObject.getTagCount() != 1) throw new CoseException("Malformed message - too many tags");
if (defaultTag == MessageTag.Unknown) {
defaultTag = MessageTag.FromInt(messageObject.getMostInnerTag().ToInt32Unchecked());
}
else if (defaultTag != MessageTag.FromInt(messageObject.getMostInnerTag().ToInt32Unchecked())) {
throw new CoseException("Passed in tag does not match actual tag");
}
}
Message msg;
switch (defaultTag) {
case Unknown: // Unknown
throw new CoseException("Message was not tagged and no default tagging option given");
case Encrypt:
msg = new EncryptMessage();
break;
case Encrypt0:
msg = new Encrypt0Message();
break;
case MAC:
msg = new MACMessage();
break;
case MAC0:
msg = new MAC0Message();
break;
case Sign1:
msg = new Sign1Message();
break;
case Sign:
msg = new SignMessage();
break;
default:
throw new CoseException("Message is not recognized as a COSE security Object");
}
msg.DecodeFromCBORObject(messageObject);
return msg;
}
/**
* Encode the message to a byte array. This function will force cryptographic operations to be executed as needed.
*
* @return byte encoded object
* @throws CoseException Internal COSE Exception
*/
public byte[] EncodeToBytes() throws CoseException {
return EncodeToCBORObject().EncodeToBytes();
}
/**
* Given a CBOR tree, parse the message. This is an abstract function that is implemented for each different supported COSE message.
*
* @param messageObject CBORObject to be converted to a message.
* @throws CoseException Internal COSE Exception
*/
protected abstract void DecodeFromCBORObject(CBORObject messageObject) throws CoseException;
/**
* Encode the COSE message object to a CBORObject tree. This function call will force cryptographic operations to be executed as needed.
* This is an internal function, as such it does not add the tag on the front and is implemented on a per message object.
*
* @return CBORObject representing the message.
* @throws CoseException Internal COSE Exception
*/
protected abstract CBORObject EncodeCBORObject() throws CoseException;
/**
* Encode the COSE message object to a CBORObject tree. This function call will force cryptographic operations to be executed as needed.
*
* @return CBORObject representing the message.
* @throws CoseException Internal COSE Exception
*/
public CBORObject EncodeToCBORObject() throws CoseException {
CBORObject obj;
obj = EncodeCBORObject();
if (emitTag) {
obj = CBORObject.FromObjectAndTag(obj, messageTag.value);
}
return obj;
}
/**
* Return the content bytes of the message
*
* @return bytes of the content
*/
public byte[] GetContent() {
return rgbContent;
}
/**
* Does the message current have content?
*
* @return true if it has content
*/
public boolean HasContent() {
return rgbContent != null;
}
/**
* Set the content bytes of the message. If the message was transmitted with
* detached content, this must be called before doing cryptographic processing on the message.
*
* @param rgbData bytes to set as the content
*/
public void SetContent(byte[] rgbData) {
rgbContent = rgbData;
}
/**
* Set the content bytes as a text string. The string will be encoded using UTF8 into a byte string.
*
* @param strData string to set as the content
*/
public void SetContent(String strData) {
rgbContent = strData.getBytes(StandardCharsets.UTF_8);
}
List<CounterSign> counterSignList = new ArrayList<CounterSign>();
CounterSign1 counterSign1;
public void addCountersignature(CounterSign countersignature) {
counterSignList.add(countersignature);
}
public List<CounterSign> getCountersignerList() {
return counterSignList;
}
public CounterSign1 getCountersign1() {
return counterSign1;
}
public void setCountersign1(CounterSign1 value) {
counterSign1 = value;
}
protected void ProcessCounterSignatures() throws CoseException {
if (!counterSignList.isEmpty()) {
if (counterSignList.size() == 1) {
counterSignList.get(0).sign(rgbProtected, rgbContent);
addAttribute(HeaderKeys.CounterSignature, counterSignList.get(0).EncodeToCBORObject(),
Attribute.UNPROTECTED);
} else {
CBORObject list = CBORObject.NewArray();
for (CounterSign sig : counterSignList) {
sig.sign(rgbProtected, rgbContent);
list.Add(sig.EncodeToCBORObject());
}
addAttribute(HeaderKeys.CounterSignature, list, Attribute.UNPROTECTED);
}
}
if (counterSign1 != null) {
counterSign1.sign(rgbProtected, rgbContent);
addAttribute(HeaderKeys.CounterSignature0, counterSign1.EncodeToCBORObject(), Attribute.UNPROTECTED);
}
}
public boolean validate(CounterSign1 countersignature) throws CoseException {
return countersignature.validate(rgbProtected, rgbContent);
}
public boolean validate(CounterSign countersignature) throws CoseException {
return countersignature.validate(rgbProtected, rgbContent);
}
}