SignMessage.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.eclipse.californium.cose;
import java.util.ArrayList;
import java.util.List;
import com.upokecenter.cbor.CBORObject;
import com.upokecenter.cbor.CBORType;
/**
* The SignMessage class is used to implement the COSE_Sign object.
* This provides for a signed object with content and one or more signatures attached.
* The signatures can be either from a single signer or from multiple different signers.
* In the case where only one signature is required and the signer can be implicitly known, {@link Sign1Message} can be used instead.
* There is no way to convert a signed message between the two formats.
* <p>
* Create a SignMessage object for a new message, when processing an existing message use Message.DecodeFromBytes to create a SignMessage object.
* <p>
* Examples can be found at<br>
* <a href="https://github.com/cose-wg/COSE-JAVA/wiki/Sign-Message-Example">Single Signer Example</a> an example of signing and verify a message with a single signature.
* <br><a href="https://github.com/cose-wg/COSE-JAVA/wiki/Multi-Sign-Example">Multiple Signer Example</a> an example of signing and verifying a message which has multiple signatures.
*
* @author jimsch
*/
public class SignMessage extends Message {
protected List<Signer> signerList = new ArrayList<Signer>();
/**
* Create a signed message object for which the leading tag and the content will be included.
*/
public SignMessage() {
messageTag = MessageTag.Sign;
}
/**
* Create a signed message object for which the emission of the leading tag and content is controlled by the parameters.
*
* @param emitTagIn emit leading tag when message is serialized
* @param emitContentIn emit the content as part of the message
*/
public SignMessage(boolean emitTagIn, boolean emitContentIn) {
messageTag = MessageTag.Sign;
emitTag = emitTagIn;
emitContent = emitContentIn;
}
/**
* Internal function used in creating a SignMessage object from a byte string.
*
* @param obj COSE_Sign encoded object.
* @throws CoseException Errors generated by the COSE module
*/
@Override
protected void DecodeFromCBORObject(CBORObject obj) throws CoseException {
if (obj.size() != 4) throw new CoseException("Invalid SignMessage structure");
if (obj.get(0).getType() == CBORType.ByteString) {
rgbProtected = obj.get(0).GetByteString();
if (obj.get(0).GetByteString().length == 0) {
objProtected = CBORObject.NewMap();
}
else {
objProtected = CBORObject.DecodeFromBytes(rgbProtected);
if (objProtected.size() == 0) rgbProtected = new byte[0];
}
}
else throw new CoseException("Invalid SignMessage structure");
if (obj.get(1).getType() == CBORType.Map) {
objUnprotected = obj.get(1);
}
else throw new CoseException("Invalid SignMessage structure");
if (obj.get(2).getType() == CBORType.ByteString) rgbContent = obj.get(2).GetByteString();
else if (!obj.get(2).isNull()) throw new CoseException("Invalid SignMessage structure");
if (obj.get(3).getType() == CBORType.Array) {
for (int i=0; i<obj.get(3).size(); i++) {
Signer signer = new Signer();
signer.DecodeFromCBORObject(obj.get(3).get(i));
signerList.add(signer);
}
}
else throw new CoseException("Invalid SignMessage structure");
}
/**
* Internal function used to create a serialization of a COSE_Sign message
*
* @return CBOR object which can be encoded.
* @throws CoseException Errors generated by the COSE module
*/
@Override
protected CBORObject EncodeCBORObject() throws CoseException {
sign();
CBORObject obj = CBORObject.NewArray();
obj.Add(rgbProtected);
obj.Add(objUnprotected);
if (emitContent) obj.Add(rgbContent);
else obj.Add(null);
CBORObject signers = CBORObject.NewArray();
obj.Add(signers);
for (Signer r : signerList) {
signers.Add(r.EncodeToCBORObject());
}
return obj;
}
/**
* Add a new signer to the message. The details of the signer are provided
* by the Signer object being added.
*
* @param signedBy provides a Signer object containing details for the signer
*/
public void AddSigner(Signer signedBy) {
signerList.add(signedBy);
}
/**
* Return the i-th signer of the message.
*
* @param iSigner - which signer to be returned
* @return Signer object
*/
public Signer getSigner(int iSigner) {
return signerList.get(iSigner);
}
/**
* Return the number of signers on the message
*
* @return number of elements in the signer list
*/
public int getSignerCount() {
return signerList.size();
}
/**
* Return the list of signers on the message
*
* @return a list of all of the Signer objects.
*/
public List<Signer> getSignerList() {
return signerList;
}
/**
* Causes a signature to be created for every signer that does not already have one.
*
* @throws CoseException Errors generated by the COSE module
*/
public void sign() throws CoseException {
if (rgbProtected == null) {
if (objProtected.size() == 0) rgbProtected = new byte[0];
else rgbProtected = objProtected.EncodeToBytes();
}
for (Signer r : signerList) {
r.sign(rgbProtected, rgbContent);
}
ProcessCounterSignatures();
}
/**
* Validate the signature on a message for a specific signer.
* The signer is required to be one of the Signer objects attached to the message.
* The key must be attached to the signer before making this call.
*
* @param signerToUse which signer to validate with
* @return true if the message validates with the signer
* @throws CoseException Errors generated by the COSE module
*/
public boolean validate(Signer signerToUse) throws CoseException {
for (Signer r : signerList) {
if (r == signerToUse) {
return r.validate(rgbProtected, rgbContent);
}
}
throw new CoseException("Signer not found");
}
}