1e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrompackage org.bouncycastle.cms;
2e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
3e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport java.io.IOException;
4e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport java.io.OutputStream;
5e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport java.util.ArrayList;
6e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport java.util.Enumeration;
7e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport java.util.Iterator;
8e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport java.util.List;
9e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
10e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.ASN1Encodable;
11e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.ASN1EncodableVector;
12e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.ASN1Encoding;
13e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.ASN1ObjectIdentifier;
14e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.ASN1OctetString;
15e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.ASN1Primitive;
16e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.ASN1Set;
1770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstromimport org.bouncycastle.asn1.DERNull;
18e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.DERSet;
19e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.cms.Attribute;
20e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.cms.AttributeTable;
21e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.cms.CMSAttributes;
22e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
23e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.cms.SignerIdentifier;
24e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.cms.SignerInfo;
25e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.cms.Time;
26e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.x509.AlgorithmIdentifier;
27e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.asn1.x509.DigestInfo;
28e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.cert.X509CertificateHolder;
29e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.operator.ContentVerifier;
30e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.operator.DigestCalculator;
31e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.operator.OperatorCreationException;
32e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.operator.RawContentVerifier;
33e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstromimport org.bouncycastle.util.Arrays;
3470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstromimport org.bouncycastle.util.io.TeeOutputStream;
35e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
36e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom/**
37e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom * an expanded SignerInfo block from a CMS Signed message
38e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom */
39e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrompublic class SignerInformation
40e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom{
41e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private SignerId                sid;
42e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private SignerInfo              info;
43e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private AlgorithmIdentifier     digestAlgorithm;
44e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private AlgorithmIdentifier     encryptionAlgorithm;
45e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private final ASN1Set           signedAttributeSet;
46e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private final ASN1Set           unsignedAttributeSet;
47e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private CMSProcessable          content;
48e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private byte[]                  signature;
49e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private ASN1ObjectIdentifier    contentType;
50e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private byte[]                  resultDigest;
51e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
52e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    // Derived
53e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private AttributeTable          signedAttributeValues;
54e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private AttributeTable          unsignedAttributeValues;
55e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private boolean                 isCounterSignature;
56e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
57e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    SignerInformation(
58e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        SignerInfo          info,
59e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        ASN1ObjectIdentifier contentType,
60e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        CMSProcessable      content,
61e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        byte[]              resultDigest)
62e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
63e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        this.info = info;
64e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        this.contentType = contentType;
65e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        this.isCounterSignature = contentType == null;
66e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
67e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        SignerIdentifier   s = info.getSID();
68e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
69e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        if (s.isTagged())
70e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
71e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            ASN1OctetString octs = ASN1OctetString.getInstance(s.getId());
72e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
73e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            sid = new SignerId(octs.getOctets());
74e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
75e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        else
76e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
77e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            IssuerAndSerialNumber   iAnds = IssuerAndSerialNumber.getInstance(s.getId());
78e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
79e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            sid = new SignerId(iAnds.getName(), iAnds.getSerialNumber().getValue());
80e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
81e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
82e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        this.digestAlgorithm = info.getDigestAlgorithm();
83e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        this.signedAttributeSet = info.getAuthenticatedAttributes();
84e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        this.unsignedAttributeSet = info.getUnauthenticatedAttributes();
85e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        this.encryptionAlgorithm = info.getDigestEncryptionAlgorithm();
86e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        this.signature = info.getEncryptedDigest().getOctets();
87e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
88e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        this.content = content;
89e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        this.resultDigest = resultDigest;
90e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
91e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
92e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public boolean isCounterSignature()
93e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
94e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return isCounterSignature;
95e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
96e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
97e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public ASN1ObjectIdentifier getContentType()
98e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
99e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return this.contentType;
100e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
101e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
102e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private byte[] encodeObj(
103e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        ASN1Encodable    obj)
104e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        throws IOException
105e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
106e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        if (obj != null)
107e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
108e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            return obj.toASN1Primitive().getEncoded();
109e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
110e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
111e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return null;
112e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
113e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
114e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public SignerId getSID()
115e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
116e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return sid;
117e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
118e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
119e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
120e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * return the version number for this objects underlying SignerInfo structure.
121e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
122e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public int getVersion()
123e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
124e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return info.getVersion().getValue().intValue();
125e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
126e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
127e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public AlgorithmIdentifier getDigestAlgorithmID()
128e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
129e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return digestAlgorithm;
130e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
131e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
132e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
133e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * return the object identifier for the signature.
134e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
135e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public String getDigestAlgOID()
136e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
13770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        return digestAlgorithm.getAlgorithm().getId();
138e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
139e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
140e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
141e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * return the signature parameters, or null if there aren't any.
142e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
143e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public byte[] getDigestAlgParams()
144e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
145e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        try
146e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
147e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            return encodeObj(digestAlgorithm.getParameters());
148e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
149e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        catch (Exception e)
150e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
151e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            throw new RuntimeException("exception getting digest parameters " + e);
152e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
153e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
154e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
155e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
156e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * return the content digest that was calculated during verification.
157e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
158e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public byte[] getContentDigest()
159e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
160e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        if (resultDigest == null)
161e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
162e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            throw new IllegalStateException("method can only be called after verify.");
163e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
164e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
1655db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        return Arrays.clone(resultDigest);
166e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
167e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
168e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
169e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * return the object identifier for the signature.
170e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
171e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public String getEncryptionAlgOID()
172e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
17370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        return encryptionAlgorithm.getAlgorithm().getId();
174e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
175e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
176e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
177e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * return the signature/encryption algorithm parameters, or null if
178e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * there aren't any.
179e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
180e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public byte[] getEncryptionAlgParams()
181e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
182e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        try
183e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
184e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            return encodeObj(encryptionAlgorithm.getParameters());
185e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
186e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        catch (Exception e)
187e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
188e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            throw new RuntimeException("exception getting encryption parameters " + e);
189e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
190e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
191e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
192e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
193e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * return a table of the signed attributes - indexed by
194e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * the OID of the attribute.
195e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
196e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public AttributeTable getSignedAttributes()
197e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
198e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        if (signedAttributeSet != null && signedAttributeValues == null)
199e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
200e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            signedAttributeValues = new AttributeTable(signedAttributeSet);
201e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
202e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
203e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return signedAttributeValues;
204e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
205e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
206e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
207e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * return a table of the unsigned attributes indexed by
208e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * the OID of the attribute.
209e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
210e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public AttributeTable getUnsignedAttributes()
211e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
212e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        if (unsignedAttributeSet != null && unsignedAttributeValues == null)
213e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
214e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            unsignedAttributeValues = new AttributeTable(unsignedAttributeSet);
215e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
216e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
217e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return unsignedAttributeValues;
218e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
219e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
220e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
221e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * return the encoded signature
222e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
223e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public byte[] getSignature()
224e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
2255db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        return Arrays.clone(signature);
226e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
227e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
228e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
229e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * Return a SignerInformationStore containing the counter signatures attached to this
230e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * signer. If no counter signatures are present an empty store is returned.
231e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
232e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public SignerInformationStore getCounterSignatures()
233e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
234e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        // TODO There are several checks implied by the RFC3852 comments that are missing
235e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
236e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        /*
237e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        The countersignature attribute MUST be an unsigned attribute; it MUST
238e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        NOT be a signed attribute, an authenticated attribute, an
239e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        unauthenticated attribute, or an unprotected attribute.
240e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        */
241e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        AttributeTable unsignedAttributeTable = getUnsignedAttributes();
242e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        if (unsignedAttributeTable == null)
243e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
244e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            return new SignerInformationStore(new ArrayList(0));
245e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
246e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
247e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        List counterSignatures = new ArrayList();
248e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
249e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        /*
250e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        The UnsignedAttributes syntax is defined as a SET OF Attributes.  The
251e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        UnsignedAttributes in a signerInfo may include multiple instances of
252e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        the countersignature attribute.
253e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        */
254e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        ASN1EncodableVector allCSAttrs = unsignedAttributeTable.getAll(CMSAttributes.counterSignature);
255e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
256e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        for (int i = 0; i < allCSAttrs.size(); ++i)
257e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
258e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            Attribute counterSignatureAttribute = (Attribute)allCSAttrs.get(i);
259e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
260e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            /*
261e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            A countersignature attribute can have multiple attribute values.  The
262e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            syntax is defined as a SET OF AttributeValue, and there MUST be one
263e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            or more instances of AttributeValue present.
264e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            */
265e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            ASN1Set values = counterSignatureAttribute.getAttrValues();
266e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            if (values.size() < 1)
267e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            {
268e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                // TODO Throw an appropriate exception?
269e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            }
270e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
271e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            for (Enumeration en = values.getObjects(); en.hasMoreElements();)
272e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            {
273e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                /*
274e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                Countersignature values have the same meaning as SignerInfo values
275e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                for ordinary signatures, except that:
276e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
277e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                   1. The signedAttributes field MUST NOT contain a content-type
278e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                      attribute; there is no content type for countersignatures.
279e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
280e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                   2. The signedAttributes field MUST contain a message-digest
281e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                      attribute if it contains any other attributes.
282e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
283e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                   3. The input to the message-digesting process is the contents
284e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                      octets of the DER encoding of the signatureValue field of the
285e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                      SignerInfo value with which the attribute is associated.
286e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                */
287e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                SignerInfo si = SignerInfo.getInstance(en.nextElement());
288e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
289e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                counterSignatures.add(new SignerInformation(si, null, new CMSProcessableByteArray(getSignature()), null));
290e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            }
291e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
292e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
293e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return new SignerInformationStore(counterSignatures);
294e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
295e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
296e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
297e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * return the DER encoding of the signed attributes.
298e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * @throws IOException if an encoding error occurs.
299e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
300e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public byte[] getEncodedSignedAttributes()
301e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        throws IOException
302e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
303e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        if (signedAttributeSet != null)
304e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
305e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            return signedAttributeSet.getEncoded();
306e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
307e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
308e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return null;
309e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
310e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
311e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private boolean doVerify(
312e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        SignerInformationVerifier verifier)
313e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        throws CMSException
314e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
315e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        String          encName = CMSSignedHelper.INSTANCE.getEncryptionAlgName(this.getEncryptionAlgOID());
31670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        ContentVerifier contentVerifier;
317e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
318e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        try
319e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
32070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            contentVerifier = verifier.getContentVerifier(encryptionAlgorithm, info.getDigestAlgorithm());
32170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
32270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        catch (OperatorCreationException e)
32370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
32470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            throw new CMSException("can't create content verifier: " + e.getMessage(), e);
32570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
32670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
32770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        try
32870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
32970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            OutputStream sigOut = contentVerifier.getOutputStream();
33070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
331e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            if (resultDigest == null)
332e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            {
333e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                DigestCalculator calc = verifier.getDigestCalculator(this.getDigestAlgorithmID());
334e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                if (content != null)
335e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                {
336e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    OutputStream      digOut = calc.getOutputStream();
337e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
33870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    if (signedAttributeSet == null)
33970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    {
34070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                        if (contentVerifier instanceof RawContentVerifier)
34170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                        {
34270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                            content.write(digOut);
34370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                        }
34470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                        else
34570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                        {
34670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                            OutputStream cOut = new TeeOutputStream(digOut, sigOut);
34770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
34870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                            content.write(cOut);
34970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
35070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                            cOut.close();
35170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                        }
35270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    }
35370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    else
35470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    {
35570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                        content.write(digOut);
35670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                        sigOut.write(this.getEncodedSignedAttributes());
35770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    }
358e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
359e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    digOut.close();
360e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                }
36170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                else if (signedAttributeSet != null)
36270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                {
36370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    sigOut.write(this.getEncodedSignedAttributes());
36470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                }
36570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                else
366e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                {
367e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    // TODO Get rid of this exception and just treat content==null as empty not missing?
368e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    throw new CMSException("data not encapsulated in signature - use detached constructor.");
369e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                }
370e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
371e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                resultDigest = calc.getDigest();
372e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            }
37370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            else
37470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
37570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                if (signedAttributeSet == null)
37670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                {
37770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    if (content != null)
37870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    {
37970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                        content.write(sigOut);
38070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    }
38170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                }
38270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                else
38370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                {
38470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    sigOut.write(this.getEncodedSignedAttributes());
38570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                }
38670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
38770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
38870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            sigOut.close();
389e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
390e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        catch (IOException e)
391e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
392e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            throw new CMSException("can't process mime object to create signature.", e);
393e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
394e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        catch (OperatorCreationException e)
395e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
396e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            throw new CMSException("can't create digest calculator: " + e.getMessage(), e);
397e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
398e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
399e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        // RFC 3852 11.1 Check the content-type attribute is correct
400e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
401e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            ASN1Primitive validContentType = getSingleValuedSignedAttribute(
402e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                CMSAttributes.contentType, "content-type");
403e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            if (validContentType == null)
404e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            {
405e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                if (!isCounterSignature && signedAttributeSet != null)
406e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                {
407e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    throw new CMSException("The content-type attribute type MUST be present whenever signed attributes are present in signed-data");
408e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                }
409e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            }
410e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            else
411e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            {
412e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                if (isCounterSignature)
413e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                {
414e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    throw new CMSException("[For counter signatures,] the signedAttributes field MUST NOT contain a content-type attribute");
415e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                }
416e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
41770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                if (!(validContentType instanceof ASN1ObjectIdentifier))
418e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                {
419e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    throw new CMSException("content-type attribute value not of ASN.1 type 'OBJECT IDENTIFIER'");
420e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                }
421e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
42270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                ASN1ObjectIdentifier signedContentType = (ASN1ObjectIdentifier)validContentType;
423e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
424e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                if (!signedContentType.equals(contentType))
425e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                {
426e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    throw new CMSException("content-type attribute value does not match eContentType");
427e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                }
428e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            }
429e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
430e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
431e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        // RFC 3852 11.2 Check the message-digest attribute is correct
432e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
433e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            ASN1Primitive validMessageDigest = getSingleValuedSignedAttribute(
434e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                CMSAttributes.messageDigest, "message-digest");
435e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            if (validMessageDigest == null)
436e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            {
437e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                if (signedAttributeSet != null)
438e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                {
439e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    throw new CMSException("the message-digest signed attribute type MUST be present when there are any signed attributes present");
440e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                }
441e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            }
442e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            else
443e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            {
444e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                if (!(validMessageDigest instanceof ASN1OctetString))
445e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                {
446e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    throw new CMSException("message-digest attribute value not of ASN.1 type 'OCTET STRING'");
447e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                }
448e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
449e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                ASN1OctetString signedMessageDigest = (ASN1OctetString)validMessageDigest;
450e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
451e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                if (!Arrays.constantTimeAreEqual(resultDigest, signedMessageDigest.getOctets()))
452e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                {
453e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    throw new CMSSignerDigestMismatchException("message-digest attribute value does not match calculated value");
454e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                }
455e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            }
456e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
457e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
458e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        // RFC 3852 11.4 Validate countersignature attribute(s)
459e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
460e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            AttributeTable signedAttrTable = this.getSignedAttributes();
461e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            if (signedAttrTable != null
462e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                && signedAttrTable.getAll(CMSAttributes.counterSignature).size() > 0)
463e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            {
464e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                throw new CMSException("A countersignature attribute MUST NOT be a signed attribute");
465e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            }
466e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
467e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            AttributeTable unsignedAttrTable = this.getUnsignedAttributes();
468e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            if (unsignedAttrTable != null)
469e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            {
470e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                ASN1EncodableVector csAttrs = unsignedAttrTable.getAll(CMSAttributes.counterSignature);
471e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                for (int i = 0; i < csAttrs.size(); ++i)
472e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                {
473e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    Attribute csAttr = (Attribute)csAttrs.get(i);
474e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    if (csAttr.getAttrValues().size() < 1)
475e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    {
476e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                        throw new CMSException("A countersignature attribute MUST contain at least one AttributeValue");
477e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    }
478e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
479e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    // Note: We don't recursively validate the countersignature value
480e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                }
481e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            }
482e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
483e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
484e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        try
485e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
48670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            if (signedAttributeSet == null && resultDigest != null)
487e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            {
48870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                if (contentVerifier instanceof RawContentVerifier)
489e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                {
49070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    RawContentVerifier rawVerifier = (RawContentVerifier)contentVerifier;
491e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
49270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    if (encName.equals("RSA"))
49370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    {
49470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                        DigestInfo digInfo = new DigestInfo(new AlgorithmIdentifier(digestAlgorithm.getAlgorithm(), DERNull.INSTANCE), resultDigest);
495e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
49670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                        return rawVerifier.verify(digInfo.getEncoded(ASN1Encoding.DER), this.getSignature());
497e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    }
498e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
49970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    return rawVerifier.verify(resultDigest, this.getSignature());
500e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                }
501e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            }
502e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
503e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            return contentVerifier.verify(this.getSignature());
504e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
505e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        catch (IOException e)
506e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
507e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            throw new CMSException("can't process mime object to create signature.", e);
508e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
509e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
510e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
511e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
512e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * Verify that the given verifier can successfully verify the signature on
513e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * this SignerInformation object.
514e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     *
515e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * @param verifier a suitably configured SignerInformationVerifier.
516e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * @return true if the signer information is verified, false otherwise.
517e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * @throws org.bouncycastle.cms.CMSVerifierCertificateNotValidException if the provider has an associated certificate and the certificate is not valid at the time given as the SignerInfo's signing time.
518e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * @throws org.bouncycastle.cms.CMSException if the verifier is unable to create a ContentVerifiers or DigestCalculators.
519e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
520e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public boolean verify(SignerInformationVerifier verifier)
521e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        throws CMSException
522e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
523e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        Time signingTime = getSigningTime();   // has to be validated if present.
524e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
525e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        if (verifier.hasAssociatedCertificate())
526e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
527e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            if (signingTime != null)
528e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            {
529e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                X509CertificateHolder dcv = verifier.getAssociatedCertificate();
530e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
531e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                if (!dcv.isValidOn(signingTime.getDate()))
532e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                {
533e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    throw new CMSVerifierCertificateNotValidException("verifier not valid at signingTime");
534e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                }
535e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            }
536e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
537e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
538e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return doVerify(verifier);
539e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
540e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
541e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
542e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * Return the underlying ASN.1 object defining this SignerInformation object.
543e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     *
544e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * @return a SignerInfo.
545e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
546e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public SignerInfo toASN1Structure()
547e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
548e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return info;
549e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
550e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
551e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private ASN1Primitive getSingleValuedSignedAttribute(
552e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        ASN1ObjectIdentifier attrOID, String printableName)
553e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        throws CMSException
554e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
555e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        AttributeTable unsignedAttrTable = this.getUnsignedAttributes();
556e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        if (unsignedAttrTable != null
557e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            && unsignedAttrTable.getAll(attrOID).size() > 0)
558e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
559e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            throw new CMSException("The " + printableName
560e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                + " attribute MUST NOT be an unsigned attribute");
561e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
562e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
563e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        AttributeTable signedAttrTable = this.getSignedAttributes();
564e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        if (signedAttrTable == null)
565e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
566e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            return null;
567e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
568e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
569e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        ASN1EncodableVector v = signedAttrTable.getAll(attrOID);
570e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        switch (v.size())
571e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
572e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            case 0:
573e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                return null;
574e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            case 1:
575e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            {
576e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                Attribute t = (Attribute)v.get(0);
577e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                ASN1Set attrValues = t.getAttrValues();
578e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                if (attrValues.size() != 1)
579e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                {
580e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    throw new CMSException("A " + printableName
581e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                        + " attribute MUST have a single attribute value");
582e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                }
583e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
584e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                return attrValues.getObjectAt(0).toASN1Primitive();
585e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            }
586e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            default:
587e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                throw new CMSException("The SignedAttributes in a signerInfo MUST NOT include multiple instances of the "
588e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    + printableName + " attribute");
589e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
590e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
591e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
592e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    private Time getSigningTime() throws CMSException
593e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
594e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        ASN1Primitive validSigningTime = getSingleValuedSignedAttribute(
595e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            CMSAttributes.signingTime, "signing-time");
596e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
597e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        if (validSigningTime == null)
598e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
599e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            return null;
600e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
601e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
602e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        try
603e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
604e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            return Time.getInstance(validSigningTime);
605e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
606e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        catch (IllegalArgumentException e)
607e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
608e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            throw new CMSException("signing-time attribute value not a valid 'Time' structure");
609e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
610e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
611e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
612e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
613e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * Return a signer information object with the passed in unsigned
614e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * attributes replacing the ones that are current associated with
615e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * the object passed in.
616e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     *
617e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * @param signerInformation the signerInfo to be used as the basis.
618e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * @param unsignedAttributes the unsigned attributes to add.
619e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * @return a copy of the original SignerInformationObject with the changed attributes.
620e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
621e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public static SignerInformation replaceUnsignedAttributes(
622e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        SignerInformation   signerInformation,
623e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        AttributeTable      unsignedAttributes)
624e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
625e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        SignerInfo  sInfo = signerInformation.info;
626e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        ASN1Set     unsignedAttr = null;
627e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
628e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        if (unsignedAttributes != null)
629e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
630e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            unsignedAttr = new DERSet(unsignedAttributes.toASN1EncodableVector());
631e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
632e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
633e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return new SignerInformation(
634e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                new SignerInfo(sInfo.getSID(), sInfo.getDigestAlgorithm(),
635e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    sInfo.getAuthenticatedAttributes(), sInfo.getDigestEncryptionAlgorithm(), sInfo.getEncryptedDigest(), unsignedAttr),
636e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    signerInformation.contentType, signerInformation.content, null);
637e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
638e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
639e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    /**
640e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * Return a signer information object with passed in SignerInformationStore representing counter
641e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * signatures attached as an unsigned attribute.
642e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     *
643e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * @param signerInformation the signerInfo to be used as the basis.
644e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * @param counterSigners signer info objects carrying counter signature.
645e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     * @return a copy of the original SignerInformationObject with the changed attributes.
646e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom     */
647e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    public static SignerInformation addCounterSigners(
648e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        SignerInformation        signerInformation,
649e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        SignerInformationStore   counterSigners)
650e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    {
651e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        // TODO Perform checks from RFC 3852 11.4
652e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
653e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        SignerInfo          sInfo = signerInformation.info;
654e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        AttributeTable      unsignedAttr = signerInformation.getUnsignedAttributes();
655e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        ASN1EncodableVector v;
656e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
657e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        if (unsignedAttr != null)
658e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
659e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            v = unsignedAttr.toASN1EncodableVector();
660e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
661e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        else
662e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
663e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom            v = new ASN1EncodableVector();
664e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
665e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
666e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        ASN1EncodableVector sigs = new ASN1EncodableVector();
667e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
668e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        for (Iterator it = counterSigners.getSigners().iterator(); it.hasNext();)
669e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        {
67070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            sigs.add(((SignerInformation)it.next()).toASN1Structure());
671e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        }
672e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
673e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        v.add(new Attribute(CMSAttributes.counterSignature, new DERSet(sigs)));
674e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom
675e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom        return new SignerInformation(
676e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                new SignerInfo(sInfo.getSID(), sInfo.getDigestAlgorithm(),
677e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    sInfo.getAuthenticatedAttributes(), sInfo.getDigestEncryptionAlgorithm(), sInfo.getEncryptedDigest(), new DERSet(v)),
678e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom                    signerInformation.contentType, signerInformation.content, null);
679e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom    }
680e6bf3e8dfa2804891a82075cb469b736321b4827Brian Carlstrom}
681