SignatureAssert.java
/*
* Copyright 2017 Emmanuel Bourg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.jsign;
import java.io.IOException;
import java.util.List;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.cms.CMSAttributes;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.util.encoders.Hex;
import static net.jsign.asn1.authenticode.AuthenticodeObjectIdentifiers.*;
import static org.junit.Assert.*;
public class SignatureAssert {
public static void assertTimestamped(String message, CMSSignedData signedData) {
SignerInformation signerInformation = signedData.getSignerInfos().getSigners().iterator().next();
AttributeTable unsignedAttributes = signerInformation.getUnsignedAttributes();
assertNotNull(message + " (missing unauthenticated attributes)", unsignedAttributes);
boolean authenticode = isAuthenticode(signedData.getSignedContentTypeOID());
Attribute authenticodeTimestampAttribute = unsignedAttributes.get(CMSAttributes.counterSignature);
Attribute rfc3161TimestampAttribute = unsignedAttributes.get(authenticode ? SPC_RFC3161_OBJID : PKCSObjectIdentifiers.id_aa_signatureTimeStampToken);
assertTrue(message + " (no counter signature attribute found)", authenticodeTimestampAttribute != null || rfc3161TimestampAttribute != null);
if (authenticodeTimestampAttribute != null) {
assertNotNull(message + " (counter signature attribute value is null)", authenticodeTimestampAttribute.getAttributeValues());
assertTrue(message + " (counter signature attribute value is empty)", authenticodeTimestampAttribute.getAttributeValues().length > 0);
} else {
assertNotNull(message + " (counter signature attribute value is null)", rfc3161TimestampAttribute.getAttributeValues());
assertTrue(message + " (counter signature attribute value is empty)", rfc3161TimestampAttribute.getAttributeValues().length > 0);
}
}
public static void assertNotTimestamped(String message, CMSSignedData signedData) {
SignerInformation signerInformation = signedData.getSignerInfos().getSigners().iterator().next();
AttributeTable unsignedAttributes = signerInformation.getUnsignedAttributes();
if (unsignedAttributes == null) {
return;
}
boolean authenticode = isAuthenticode(signedData.getSignedContentTypeOID());
Attribute authenticodeTimestampAttribute = unsignedAttributes.get(CMSAttributes.counterSignature);
Attribute rfc3161TimestampAttribute = unsignedAttributes.get(authenticode ? SPC_RFC3161_OBJID : PKCSObjectIdentifiers.id_aa_signatureTimeStampToken);
assertTrue(message + " (counter signature attribute found)", authenticodeTimestampAttribute == null && rfc3161TimestampAttribute == null);
}
public static void assertSigned(Signable signable, DigestAlgorithm... algorithms) throws IOException {
List<CMSSignedData> signatures = signable.getSignatures();
assertNotNull("list of signatures null", signatures);
assertEquals("number of signatures", algorithms.length, signatures.size());
for (int i = 0, signaturesSize = signatures.size(); i < signaturesSize; i++) {
CMSSignedData signature = signatures.get(i);
assertNotNull("signature " + i + " is null", signatures.get(0));
// Check the version of the SignedData structure
if (isAuthenticode(signature.getSignedContentTypeOID())) {
assertEquals("Version of signature " + i, 1, signature.getVersion());
}
// Check the signature algorithm
SignerInformation si = signature.getSignerInfos().getSigners().iterator().next();
assertEquals("Digest algorithm of signature " + i, algorithms[i].oid, si.getDigestAlgorithmID().getAlgorithm());
// Check if the signingTime attribute is present
if (isAuthenticode(signature.getSignedContentTypeOID())) {
assertNull("signingTime attribute found in signature " + i, signature.getSignerInfos().iterator().next().getSignedAttributes().get(CMSAttributes.signingTime));
}
}
}
public static void assertNotSigned(Signable signable) throws IOException {
List<CMSSignedData> signatures = signable.getSignatures();
assertNotNull("list of signatures null", signatures);
assertTrue("signature found", signatures.isEmpty());
}
public static void assertUuidEquals(Signable signable, String expected) throws IOException {
ASN1Sequence spcIndirectData = (ASN1Sequence) ((ASN1Sequence) signable.getSignatures().get(0).toASN1Structure().getContent()).getObjectAt(2);
ASN1Sequence spcAttributeTypeAndOptionalValue = (ASN1Sequence) ((ASN1Sequence) ((ASN1TaggedObject) spcIndirectData.getObjectAt(1)).getExplicitBaseObject()).getObjectAt(0);
ASN1Sequence spcSipInfo = (ASN1Sequence) spcAttributeTypeAndOptionalValue.getObjectAt(1);
DEROctetString uuid = (DEROctetString) spcSipInfo.getObjectAt(1);
assertEquals("Authenticode UUID", expected.toUpperCase().replaceAll("-", ""), Hex.toHexString(uuid.getOctets()).toUpperCase());
}
public static void assertSignedAttribute(String message, Signable signable, ASN1ObjectIdentifier oid) throws IOException {
SignerInformation signerInformation = signable.getSignatures().get(0).getSignerInfos().getSigners().iterator().next();
AttributeTable attributes = signerInformation.getSignedAttributes();
assertNotNull(message + " (missing signed attributes)", attributes);
Attribute attribute = attributes.get(oid);
assertNotNull(message + " (missing " + oid + " attribute)", attribute);
}
}