001/*
002 * $Id: PdfPKCS7.java 4784 2011-03-15 08:33:00Z blowagie $
003 *
004 * This file is part of the iText (R) project.
005 * Copyright (c) 1998-2011 1T3XT BVBA
006 * Authors: Bruno Lowagie, Paulo Soares, et al.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU Affero General Public License version 3
010 * as published by the Free Software Foundation with the addition of the
011 * following permission added to Section 15 as permitted in Section 7(a):
012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
014 *
015 * This program is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
017 * or FITNESS FOR A PARTICULAR PURPOSE.
018 * See the GNU Affero General Public License for more details.
019 * You should have received a copy of the GNU Affero General Public License
020 * along with this program; if not, see http://www.gnu.org/licenses or write to
021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
022 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
023 * http://itextpdf.com/terms-of-use/
024 *
025 * The interactive user interfaces in modified source and object code versions
026 * of this program must display Appropriate Legal Notices, as required under
027 * Section 5 of the GNU Affero General Public License.
028 *
029 * In accordance with Section 7(b) of the GNU Affero General Public License,
030 * a covered work must retain the producer line in every PDF that is created
031 * or manipulated using iText.
032 *
033 * You can be released from the requirements of the license by purchasing
034 * a commercial license. Buying such a license is mandatory as soon as you
035 * develop commercial activities involving the iText software without
036 * disclosing the source code of your own applications.
037 * These activities include: offering paid services to customers as an ASP,
038 * serving PDFs on the fly in a web application, shipping iText with a closed
039 * source product.
040 *
041 * For more information, please contact iText Software Corp. at this
042 * address: sales@itextpdf.com
043 */
044package com.itextpdf.text.pdf;
045
046import java.io.ByteArrayInputStream;
047import java.io.ByteArrayOutputStream;
048import java.io.File;
049import java.io.FileInputStream;
050import java.io.IOException;
051import java.math.BigInteger;
052import java.security.InvalidKeyException;
053import java.security.KeyStore;
054import java.security.MessageDigest;
055import java.security.NoSuchAlgorithmException;
056import java.security.NoSuchProviderException;
057import java.security.PrivateKey;
058import java.security.Signature;
059import java.security.SignatureException;
060import java.security.cert.CRL;
061import java.security.cert.CRLException;
062import java.security.cert.Certificate;
063import java.security.cert.CertificateException;
064import java.security.cert.CertificateFactory;
065import java.security.cert.CertificateParsingException;
066import java.security.cert.X509CRL;
067import java.security.cert.X509Certificate;
068import java.util.ArrayList;
069import java.util.Arrays;
070import java.util.Calendar;
071import java.util.Collection;
072import java.util.Date;
073import java.util.Enumeration;
074import java.util.GregorianCalendar;
075import java.util.HashMap;
076import java.util.HashSet;
077import java.util.Set;
078
079import org.bouncycastle.asn1.ASN1Encodable;
080import org.bouncycastle.asn1.ASN1EncodableVector;
081import org.bouncycastle.asn1.ASN1InputStream;
082import org.bouncycastle.asn1.ASN1OctetString;
083import org.bouncycastle.asn1.ASN1OutputStream;
084import org.bouncycastle.asn1.ASN1Sequence;
085import org.bouncycastle.asn1.ASN1Set;
086import org.bouncycastle.asn1.ASN1TaggedObject;
087import org.bouncycastle.asn1.DEREnumerated;
088import org.bouncycastle.asn1.DERInteger;
089import org.bouncycastle.asn1.DERNull;
090import org.bouncycastle.asn1.DERObject;
091import org.bouncycastle.asn1.DERObjectIdentifier;
092import org.bouncycastle.asn1.DEROctetString;
093import org.bouncycastle.asn1.DERSequence;
094import org.bouncycastle.asn1.DERSet;
095import org.bouncycastle.asn1.DERString;
096import org.bouncycastle.asn1.DERTaggedObject;
097import org.bouncycastle.asn1.DERUTCTime;
098import org.bouncycastle.asn1.cms.Attribute;
099import org.bouncycastle.asn1.cms.AttributeTable;
100import org.bouncycastle.asn1.cms.ContentInfo;
101import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
102import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
103import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
104import org.bouncycastle.asn1.tsp.MessageImprint;
105import org.bouncycastle.asn1.x509.X509Extensions;
106import org.bouncycastle.jce.X509Principal;
107import org.bouncycastle.jce.provider.X509CertParser;
108import org.bouncycastle.ocsp.BasicOCSPResp;
109import org.bouncycastle.ocsp.CertificateID;
110import org.bouncycastle.ocsp.SingleResp;
111import org.bouncycastle.tsp.TimeStampToken;
112
113import com.itextpdf.text.ExceptionConverter;
114import com.itextpdf.text.error_messages.MessageLocalization;
115
116/**
117 * This class does all the processing related to signing and verifying a PKCS#7
118 * signature.
119 * <p>
120 * It's based in code found at org.bouncycastle.
121 */
122public class PdfPKCS7 {
123
124    private byte sigAttr[];
125    private byte digestAttr[];
126    private int version, signerversion;
127    private Set<String> digestalgos;
128    private Collection<Certificate> certs;
129    private Collection<CRL> crls;
130    private Collection<Certificate> signCerts;
131    private X509Certificate signCert;
132    private byte[] digest;
133    private MessageDigest messageDigest;
134    private String digestAlgorithm, digestEncryptionAlgorithm;
135    private Signature sig;
136    private transient PrivateKey privKey;
137    private byte RSAdata[];
138    private boolean verified;
139    private boolean verifyResult;
140    private byte externalDigest[];
141    private byte externalRSAdata[];
142    private String provider;
143
144    private static final String ID_PKCS7_DATA = "1.2.840.113549.1.7.1";
145    private static final String ID_PKCS7_SIGNED_DATA = "1.2.840.113549.1.7.2";
146    private static final String ID_RSA = "1.2.840.113549.1.1.1";
147    private static final String ID_DSA = "1.2.840.10040.4.1";
148    private static final String ID_CONTENT_TYPE = "1.2.840.113549.1.9.3";
149    private static final String ID_MESSAGE_DIGEST = "1.2.840.113549.1.9.4";
150    private static final String ID_SIGNING_TIME = "1.2.840.113549.1.9.5";
151    private static final String ID_ADBE_REVOCATION = "1.2.840.113583.1.1.8";
152    /**
153     * Holds value of property reason.
154     */
155    private String reason;
156
157    /**
158     * Holds value of property location.
159     */
160    private String location;
161
162    /**
163     * Holds value of property signDate.
164     */
165    private Calendar signDate;
166
167    /**
168     * Holds value of property signName.
169     */
170    private String signName;
171
172    private TimeStampToken timeStampToken;
173
174    private static final HashMap<String, String> digestNames = new HashMap<String, String>();
175    private static final HashMap<String, String> algorithmNames = new HashMap<String, String>();
176    private static final HashMap<String, String> allowedDigests = new HashMap<String, String>();
177
178    static {
179        digestNames.put("1.2.840.113549.2.5", "MD5");
180        digestNames.put("1.2.840.113549.2.2", "MD2");
181        digestNames.put("1.3.14.3.2.26", "SHA1");
182        digestNames.put("2.16.840.1.101.3.4.2.4", "SHA224");
183        digestNames.put("2.16.840.1.101.3.4.2.1", "SHA256");
184        digestNames.put("2.16.840.1.101.3.4.2.2", "SHA384");
185        digestNames.put("2.16.840.1.101.3.4.2.3", "SHA512");
186        digestNames.put("1.3.36.3.2.2", "RIPEMD128");
187        digestNames.put("1.3.36.3.2.1", "RIPEMD160");
188        digestNames.put("1.3.36.3.2.3", "RIPEMD256");
189        digestNames.put("1.2.840.113549.1.1.4", "MD5");
190        digestNames.put("1.2.840.113549.1.1.2", "MD2");
191        digestNames.put("1.2.840.113549.1.1.5", "SHA1");
192        digestNames.put("1.2.840.113549.1.1.14", "SHA224");
193        digestNames.put("1.2.840.113549.1.1.11", "SHA256");
194        digestNames.put("1.2.840.113549.1.1.12", "SHA384");
195        digestNames.put("1.2.840.113549.1.1.13", "SHA512");
196        digestNames.put("1.2.840.113549.2.5", "MD5");
197        digestNames.put("1.2.840.113549.2.2", "MD2");
198        digestNames.put("1.2.840.10040.4.3", "SHA1");
199        digestNames.put("2.16.840.1.101.3.4.3.1", "SHA224");
200        digestNames.put("2.16.840.1.101.3.4.3.2", "SHA256");
201        digestNames.put("2.16.840.1.101.3.4.3.3", "SHA384");
202        digestNames.put("2.16.840.1.101.3.4.3.4", "SHA512");
203        digestNames.put("1.3.36.3.3.1.3", "RIPEMD128");
204        digestNames.put("1.3.36.3.3.1.2", "RIPEMD160");
205        digestNames.put("1.3.36.3.3.1.4", "RIPEMD256");
206
207        algorithmNames.put("1.2.840.113549.1.1.1", "RSA");
208        algorithmNames.put("1.2.840.10040.4.1", "DSA");
209        algorithmNames.put("1.2.840.113549.1.1.2", "RSA");
210        algorithmNames.put("1.2.840.113549.1.1.4", "RSA");
211        algorithmNames.put("1.2.840.113549.1.1.5", "RSA");
212        algorithmNames.put("1.2.840.113549.1.1.14", "RSA");
213        algorithmNames.put("1.2.840.113549.1.1.11", "RSA");
214        algorithmNames.put("1.2.840.113549.1.1.12", "RSA");
215        algorithmNames.put("1.2.840.113549.1.1.13", "RSA");
216        algorithmNames.put("1.2.840.10040.4.3", "DSA");
217        algorithmNames.put("2.16.840.1.101.3.4.3.1", "DSA");
218        algorithmNames.put("2.16.840.1.101.3.4.3.2", "DSA");
219        algorithmNames.put("1.3.36.3.3.1.3", "RSA");
220        algorithmNames.put("1.3.36.3.3.1.2", "RSA");
221        algorithmNames.put("1.3.36.3.3.1.4", "RSA");
222
223        allowedDigests.put("MD5", "1.2.840.113549.2.5");
224        allowedDigests.put("MD2", "1.2.840.113549.2.2");
225        allowedDigests.put("SHA1", "1.3.14.3.2.26");
226        allowedDigests.put("SHA224", "2.16.840.1.101.3.4.2.4");
227        allowedDigests.put("SHA256", "2.16.840.1.101.3.4.2.1");
228        allowedDigests.put("SHA384", "2.16.840.1.101.3.4.2.2");
229        allowedDigests.put("SHA512", "2.16.840.1.101.3.4.2.3");
230        allowedDigests.put("MD-5", "1.2.840.113549.2.5");
231        allowedDigests.put("MD-2", "1.2.840.113549.2.2");
232        allowedDigests.put("SHA-1", "1.3.14.3.2.26");
233        allowedDigests.put("SHA-224", "2.16.840.1.101.3.4.2.4");
234        allowedDigests.put("SHA-256", "2.16.840.1.101.3.4.2.1");
235        allowedDigests.put("SHA-384", "2.16.840.1.101.3.4.2.2");
236        allowedDigests.put("SHA-512", "2.16.840.1.101.3.4.2.3");
237        allowedDigests.put("RIPEMD128", "1.3.36.3.2.2");
238        allowedDigests.put("RIPEMD-128", "1.3.36.3.2.2");
239        allowedDigests.put("RIPEMD160", "1.3.36.3.2.1");
240        allowedDigests.put("RIPEMD-160", "1.3.36.3.2.1");
241        allowedDigests.put("RIPEMD256", "1.3.36.3.2.3");
242        allowedDigests.put("RIPEMD-256", "1.3.36.3.2.3");
243    }
244
245    /**
246     * Gets the digest name for a certain id
247     * @param oid       an id (for instance "1.2.840.113549.2.5")
248     * @return  a digest name (for instance "MD5")
249     * @since   2.1.6
250     */
251    public static String getDigest(String oid) {
252        String ret = digestNames.get(oid);
253        if (ret == null)
254            return oid;
255        else
256            return ret;
257    }
258
259    /**
260     * Gets the algorithm name for a certain id.
261     * @param oid       an id (for instance "1.2.840.113549.1.1.1")
262     * @return  an algorithm name (for instance "RSA")
263     * @since   2.1.6
264     */
265    public static String getAlgorithm(String oid) {
266        String ret = algorithmNames.get(oid);
267        if (ret == null)
268            return oid;
269        else
270            return ret;
271    }
272
273    /**
274     * Gets the timestamp token if there is one.
275     * @return the timestamp token or null
276     * @since   2.1.6
277     */
278    public TimeStampToken getTimeStampToken() {
279        return timeStampToken;
280    }
281
282    /**
283     * Gets the timestamp date
284     * @return  a date
285     * @since   2.1.6
286     */
287    public Calendar getTimeStampDate() {
288        if (timeStampToken == null)
289            return null;
290        Calendar cal = new GregorianCalendar();
291        Date date = timeStampToken.getTimeStampInfo().getGenTime();
292        cal.setTime(date);
293        return cal;
294    }
295
296    /**
297     * Verifies a signature using the sub-filter adbe.x509.rsa_sha1.
298     * @param contentsKey the /Contents key
299     * @param certsKey the /Cert key
300     * @param provider the provider or <code>null</code> for the default provider
301     */
302    @SuppressWarnings("unchecked")
303    public PdfPKCS7(byte[] contentsKey, byte[] certsKey, String provider) {
304        try {
305            this.provider = provider;
306            X509CertParser cr = new X509CertParser();
307            cr.engineInit(new ByteArrayInputStream(certsKey));
308            certs = cr.engineReadAll();
309            signCerts = certs;
310            signCert = (X509Certificate)certs.iterator().next();
311            crls = new ArrayList<CRL>();
312            ASN1InputStream in = new ASN1InputStream(new ByteArrayInputStream(contentsKey));
313            digest = ((DEROctetString)in.readObject()).getOctets();
314            if (provider == null)
315                sig = Signature.getInstance("SHA1withRSA");
316            else
317                sig = Signature.getInstance("SHA1withRSA", provider);
318            sig.initVerify(signCert.getPublicKey());
319        }
320        catch (Exception e) {
321            throw new ExceptionConverter(e);
322        }
323    }
324
325    private BasicOCSPResp basicResp;
326
327    /**
328     * Gets the OCSP basic response if there is one.
329     * @return the OCSP basic response or null
330     * @since   2.1.6
331     */
332    public BasicOCSPResp getOcsp() {
333        return basicResp;
334    }
335
336    private void findCRL(ASN1Sequence seq) throws IOException, CertificateException, CRLException {
337        try {
338            crls = new ArrayList<CRL>();
339            for (int k = 0; k < seq.size(); ++k) {
340                ByteArrayInputStream ar = new ByteArrayInputStream(seq.getObjectAt(k).getDERObject().getDEREncoded());
341                CertificateFactory cf = CertificateFactory.getInstance("X.509");
342                X509CRL crl = (X509CRL)cf.generateCRL(ar);
343                crls.add(crl);
344            }
345        }
346        catch (Exception ex) {
347            // ignore
348        }
349    }
350
351    private void findOcsp(ASN1Sequence seq) throws IOException {
352        basicResp = null;
353        boolean ret = false;
354        while (true) {
355            if (seq.getObjectAt(0) instanceof DERObjectIdentifier
356                && ((DERObjectIdentifier)seq.getObjectAt(0)).getId().equals(OCSPObjectIdentifiers.id_pkix_ocsp_basic.getId())) {
357                break;
358            }
359            ret = true;
360            for (int k = 0; k < seq.size(); ++k) {
361                if (seq.getObjectAt(k) instanceof ASN1Sequence) {
362                    seq = (ASN1Sequence)seq.getObjectAt(0);
363                    ret = false;
364                    break;
365                }
366                if (seq.getObjectAt(k) instanceof ASN1TaggedObject) {
367                    ASN1TaggedObject tag = (ASN1TaggedObject)seq.getObjectAt(k);
368                    if (tag.getObject() instanceof ASN1Sequence) {
369                        seq = (ASN1Sequence)tag.getObject();
370                        ret = false;
371                        break;
372                    }
373                    else
374                        return;
375                }
376            }
377            if (ret)
378                return;
379        }
380        DEROctetString os = (DEROctetString)seq.getObjectAt(1);
381        ASN1InputStream inp = new ASN1InputStream(os.getOctets());
382        BasicOCSPResponse resp = BasicOCSPResponse.getInstance(inp.readObject());
383        basicResp = new BasicOCSPResp(resp);
384    }
385
386    /**
387     * Verifies a signature using the sub-filter adbe.pkcs7.detached or
388     * adbe.pkcs7.sha1.
389     * @param contentsKey the /Contents key
390     * @param provider the provider or <code>null</code> for the default provider
391     */
392    @SuppressWarnings("unchecked")
393    public PdfPKCS7(byte[] contentsKey, String provider) {
394        try {
395            this.provider = provider;
396            ASN1InputStream din = new ASN1InputStream(new ByteArrayInputStream(contentsKey));
397
398            //
399            // Basic checks to make sure it's a PKCS#7 SignedData Object
400            //
401            DERObject pkcs;
402
403            try {
404                pkcs = din.readObject();
405            }
406            catch (IOException e) {
407                throw new IllegalArgumentException(MessageLocalization.getComposedMessage("can.t.decode.pkcs7signeddata.object"));
408            }
409            if (!(pkcs instanceof ASN1Sequence)) {
410                throw new IllegalArgumentException(MessageLocalization.getComposedMessage("not.a.valid.pkcs.7.object.not.a.sequence"));
411            }
412            ASN1Sequence signedData = (ASN1Sequence)pkcs;
413            DERObjectIdentifier objId = (DERObjectIdentifier)signedData.getObjectAt(0);
414            if (!objId.getId().equals(ID_PKCS7_SIGNED_DATA))
415                throw new IllegalArgumentException(MessageLocalization.getComposedMessage("not.a.valid.pkcs.7.object.not.signed.data"));
416            ASN1Sequence content = (ASN1Sequence)((DERTaggedObject)signedData.getObjectAt(1)).getObject();
417            // the positions that we care are:
418            //     0 - version
419            //     1 - digestAlgorithms
420            //     2 - possible ID_PKCS7_DATA
421            //     (the certificates and crls are taken out by other means)
422            //     last - signerInfos
423
424            // the version
425            version = ((DERInteger)content.getObjectAt(0)).getValue().intValue();
426
427            // the digestAlgorithms
428            digestalgos = new HashSet<String>();
429            Enumeration<ASN1Sequence> e = ((ASN1Set)content.getObjectAt(1)).getObjects();
430            while (e.hasMoreElements())
431            {
432                ASN1Sequence s = e.nextElement();
433                DERObjectIdentifier o = (DERObjectIdentifier)s.getObjectAt(0);
434                digestalgos.add(o.getId());
435            }
436
437            // the certificates
438            X509CertParser cr = new X509CertParser();
439            cr.engineInit(new ByteArrayInputStream(contentsKey));
440            certs = cr.engineReadAll();
441
442            // the possible ID_PKCS7_DATA
443            ASN1Sequence rsaData = (ASN1Sequence)content.getObjectAt(2);
444            if (rsaData.size() > 1) {
445                DEROctetString rsaDataContent = (DEROctetString)((DERTaggedObject)rsaData.getObjectAt(1)).getObject();
446                RSAdata = rsaDataContent.getOctets();
447            }
448
449            // the signerInfos
450            int next = 3;
451            while (content.getObjectAt(next) instanceof DERTaggedObject)
452                ++next;
453            ASN1Set signerInfos = (ASN1Set)content.getObjectAt(next);
454            if (signerInfos.size() != 1)
455                throw new IllegalArgumentException(MessageLocalization.getComposedMessage("this.pkcs.7.object.has.multiple.signerinfos.only.one.is.supported.at.this.time"));
456            ASN1Sequence signerInfo = (ASN1Sequence)signerInfos.getObjectAt(0);
457            // the positions that we care are
458            //     0 - version
459            //     1 - the signing certificate issuer and serial number
460            //     2 - the digest algorithm
461            //     3 or 4 - digestEncryptionAlgorithm
462            //     4 or 5 - encryptedDigest
463            signerversion = ((DERInteger)signerInfo.getObjectAt(0)).getValue().intValue();
464            // Get the signing certificate
465            ASN1Sequence issuerAndSerialNumber = (ASN1Sequence)signerInfo.getObjectAt(1);
466            X509Principal issuer = new X509Principal(issuerAndSerialNumber.getObjectAt(0).getDERObject().getEncoded());
467            BigInteger serialNumber = ((DERInteger)issuerAndSerialNumber.getObjectAt(1)).getValue();
468            for (Object element : certs) {
469                X509Certificate cert = (X509Certificate)element;
470                if (issuer.equals(cert.getIssuerDN()) && serialNumber.equals(cert.getSerialNumber())) {
471                    signCert = cert;
472                    break;
473                }
474            }
475            if (signCert == null) {
476                throw new IllegalArgumentException(MessageLocalization.getComposedMessage("can.t.find.signing.certificate.with.serial.1",
477                    issuer.getName() + " / " + serialNumber.toString(16)));
478            }
479            signCertificateChain();
480            digestAlgorithm = ((DERObjectIdentifier)((ASN1Sequence)signerInfo.getObjectAt(2)).getObjectAt(0)).getId();
481            next = 3;
482            if (signerInfo.getObjectAt(next) instanceof ASN1TaggedObject) {
483                ASN1TaggedObject tagsig = (ASN1TaggedObject)signerInfo.getObjectAt(next);
484                ASN1Set sseq = ASN1Set.getInstance(tagsig, false);
485                sigAttr = sseq.getEncoded(ASN1Encodable.DER);
486
487                for (int k = 0; k < sseq.size(); ++k) {
488                    ASN1Sequence seq2 = (ASN1Sequence)sseq.getObjectAt(k);
489                    if (((DERObjectIdentifier)seq2.getObjectAt(0)).getId().equals(ID_MESSAGE_DIGEST)) {
490                        ASN1Set set = (ASN1Set)seq2.getObjectAt(1);
491                        digestAttr = ((DEROctetString)set.getObjectAt(0)).getOctets();
492                    }
493                    else if (((DERObjectIdentifier)seq2.getObjectAt(0)).getId().equals(ID_ADBE_REVOCATION)) {
494                        ASN1Set setout = (ASN1Set)seq2.getObjectAt(1);
495                        ASN1Sequence seqout = (ASN1Sequence)setout.getObjectAt(0);
496                        for (int j = 0; j < seqout.size(); ++j) {
497                            ASN1TaggedObject tg = (ASN1TaggedObject)seqout.getObjectAt(j);
498                            if (tg.getTagNo() == 0) {
499                                ASN1Sequence seqin = (ASN1Sequence)tg.getObject();
500                                findCRL(seqin);
501                            }
502                            if (tg.getTagNo() == 1) {
503                                ASN1Sequence seqin = (ASN1Sequence)tg.getObject();
504                                findOcsp(seqin);
505                            }
506                        }
507                    }
508                }
509                if (digestAttr == null)
510                    throw new IllegalArgumentException(MessageLocalization.getComposedMessage("authenticated.attribute.is.missing.the.digest"));
511                ++next;
512            }
513            digestEncryptionAlgorithm = ((DERObjectIdentifier)((ASN1Sequence)signerInfo.getObjectAt(next++)).getObjectAt(0)).getId();
514            digest = ((DEROctetString)signerInfo.getObjectAt(next++)).getOctets();
515            if (next < signerInfo.size() && signerInfo.getObjectAt(next) instanceof DERTaggedObject) {
516                DERTaggedObject taggedObject = (DERTaggedObject) signerInfo.getObjectAt(next);
517                ASN1Set unat = ASN1Set.getInstance(taggedObject, false);
518                AttributeTable attble = new AttributeTable(unat);
519                Attribute ts = attble.get(PKCSObjectIdentifiers.id_aa_signatureTimeStampToken);
520                if (ts != null && ts.getAttrValues().size() > 0) {
521                    ASN1Set attributeValues = ts.getAttrValues();
522                    ASN1Sequence tokenSequence = ASN1Sequence.getInstance(attributeValues.getObjectAt(0));
523                    ContentInfo contentInfo = new ContentInfo(tokenSequence);
524                    this.timeStampToken = new TimeStampToken(contentInfo);
525                }
526            }
527            if (RSAdata != null || digestAttr != null) {
528                if (provider == null || provider.startsWith("SunPKCS11"))
529                    messageDigest = MessageDigest.getInstance(getHashAlgorithm());
530                else
531                    messageDigest = MessageDigest.getInstance(getHashAlgorithm(), provider);
532            }
533            if (provider == null)
534                sig = Signature.getInstance(getDigestAlgorithm());
535            else
536                sig = Signature.getInstance(getDigestAlgorithm(), provider);
537            sig.initVerify(signCert.getPublicKey());
538        }
539        catch (Exception e) {
540            throw new ExceptionConverter(e);
541        }
542    }
543
544    /**
545     * Generates a signature.
546     * @param privKey the private key
547     * @param certChain the certificate chain
548     * @param crlList the certificate revocation list
549     * @param hashAlgorithm the hash algorithm
550     * @param provider the provider or <code>null</code> for the default provider
551     * @param hasRSAdata <CODE>true</CODE> if the sub-filter is adbe.pkcs7.sha1
552     * @throws InvalidKeyException on error
553     * @throws NoSuchProviderException on error
554     * @throws NoSuchAlgorithmException on error
555     */
556    public PdfPKCS7(PrivateKey privKey, Certificate[] certChain, CRL[] crlList,
557                    String hashAlgorithm, String provider, boolean hasRSAdata)
558      throws InvalidKeyException, NoSuchProviderException,
559      NoSuchAlgorithmException
560    {
561        this.privKey = privKey;
562        this.provider = provider;
563
564        digestAlgorithm = allowedDigests.get(hashAlgorithm.toUpperCase());
565        if (digestAlgorithm == null)
566            throw new NoSuchAlgorithmException(MessageLocalization.getComposedMessage("unknown.hash.algorithm.1", hashAlgorithm));
567
568        version = signerversion = 1;
569        certs = new ArrayList<Certificate>();
570        crls = new ArrayList<CRL>();
571        digestalgos = new HashSet<String>();
572        digestalgos.add(digestAlgorithm);
573
574        //
575        // Copy in the certificates and crls used to sign the private key.
576        //
577        signCert = (X509Certificate)certChain[0];
578        for (Certificate element : certChain) {
579            certs.add(element);
580        }
581
582        if (crlList != null) {
583            for (CRL element : crlList) {
584                crls.add(element);
585            }
586        }
587
588        if (privKey != null) {
589            //
590            // Now we have private key, find out what the digestEncryptionAlgorithm is.
591            //
592            digestEncryptionAlgorithm = privKey.getAlgorithm();
593            if (digestEncryptionAlgorithm.equals("RSA")) {
594                digestEncryptionAlgorithm = ID_RSA;
595            }
596            else if (digestEncryptionAlgorithm.equals("DSA")) {
597                digestEncryptionAlgorithm = ID_DSA;
598            }
599            else {
600                throw new NoSuchAlgorithmException(MessageLocalization.getComposedMessage("unknown.key.algorithm.1", digestEncryptionAlgorithm));
601            }
602        }
603        if (hasRSAdata) {
604            RSAdata = new byte[0];
605            if (provider == null || provider.startsWith("SunPKCS11"))
606                messageDigest = MessageDigest.getInstance(getHashAlgorithm());
607            else
608                messageDigest = MessageDigest.getInstance(getHashAlgorithm(), provider);
609        }
610
611        if (privKey != null) {
612            if (provider == null)
613                sig = Signature.getInstance(getDigestAlgorithm());
614            else
615                sig = Signature.getInstance(getDigestAlgorithm(), provider);
616
617            sig.initSign(privKey);
618        }
619    }
620
621    /**
622     * Update the digest with the specified bytes. This method is used both for signing and verifying
623     * @param buf the data buffer
624     * @param off the offset in the data buffer
625     * @param len the data length
626     * @throws SignatureException on error
627     */
628    public void update(byte[] buf, int off, int len) throws SignatureException {
629        if (RSAdata != null || digestAttr != null)
630            messageDigest.update(buf, off, len);
631        else
632            sig.update(buf, off, len);
633    }
634
635    /**
636     * Verify the digest.
637     * @throws SignatureException on error
638     * @return <CODE>true</CODE> if the signature checks out, <CODE>false</CODE> otherwise
639     */
640    public boolean verify() throws SignatureException {
641        if (verified)
642            return verifyResult;
643        if (sigAttr != null) {
644                final byte [] msgDigestBytes = messageDigest.digest();
645                boolean verifyRSAdata = true;
646            sig.update(sigAttr);
647            if (RSAdata != null)
648                verifyRSAdata = Arrays.equals(msgDigestBytes, RSAdata);
649            verifyResult = Arrays.equals(msgDigestBytes, digestAttr) && sig.verify(digest) && verifyRSAdata;
650        }
651        else {
652            if (RSAdata != null)
653                sig.update(messageDigest.digest());
654            verifyResult = sig.verify(digest);
655        }
656        verified = true;
657        return verifyResult;
658    }
659
660    /**
661     * Checks if the timestamp refers to this document.
662     * @throws java.security.NoSuchAlgorithmException on error
663     * @return true if it checks false otherwise
664     * @since   2.1.6
665     */
666    public boolean verifyTimestampImprint() throws NoSuchAlgorithmException {
667        if (timeStampToken == null)
668            return false;
669        MessageImprint imprint = timeStampToken.getTimeStampInfo().toTSTInfo().getMessageImprint();
670        byte[] md = MessageDigest.getInstance("SHA-1").digest(digest);
671        byte[] imphashed = imprint.getHashedMessage();
672        boolean res = Arrays.equals(md, imphashed);
673        return res;
674    }
675
676    /**
677     * Get all the X.509 certificates associated with this PKCS#7 object in no particular order.
678     * Other certificates, from OCSP for example, will also be included.
679     * @return the X.509 certificates associated with this PKCS#7 object
680     */
681    public Certificate[] getCertificates() {
682        return certs.toArray(new X509Certificate[certs.size()]);
683    }
684
685    /**
686     * Get the X.509 sign certificate chain associated with this PKCS#7 object.
687     * Only the certificates used for the main signature will be returned, with
688     * the signing certificate first.
689     * @return the X.509 certificates associated with this PKCS#7 object
690     * @since   2.1.6
691     */
692    public Certificate[] getSignCertificateChain() {
693        return signCerts.toArray(new X509Certificate[signCerts.size()]);
694    }
695
696    private void signCertificateChain() {
697        ArrayList<Certificate> cc = new ArrayList<Certificate>();
698        cc.add(signCert);
699        ArrayList<Certificate> oc = new ArrayList<Certificate>(certs);
700        for (int k = 0; k < oc.size(); ++k) {
701            if (signCert.equals(oc.get(k))) {
702                oc.remove(k);
703                --k;
704                continue;
705            }
706        }
707        boolean found = true;
708        while (found) {
709            X509Certificate v = (X509Certificate)cc.get(cc.size() - 1);
710            found = false;
711            for (int k = 0; k < oc.size(); ++k) {
712                try {
713                    if (provider == null)
714                        v.verify(((X509Certificate)oc.get(k)).getPublicKey());
715                    else
716                        v.verify(((X509Certificate)oc.get(k)).getPublicKey(), provider);
717                    found = true;
718                    cc.add(oc.get(k));
719                    oc.remove(k);
720                    break;
721                }
722                catch (Exception e) {
723                }
724            }
725        }
726        signCerts = cc;
727    }
728
729    /**
730     * Get the X.509 certificate revocation lists associated with this PKCS#7 object
731     * @return the X.509 certificate revocation lists associated with this PKCS#7 object
732     */
733    public Collection<CRL> getCRLs() {
734        return crls;
735    }
736
737    /**
738     * Get the X.509 certificate actually used to sign the digest.
739     * @return the X.509 certificate actually used to sign the digest
740     */
741    public X509Certificate getSigningCertificate() {
742        return signCert;
743    }
744
745    /**
746     * Get the version of the PKCS#7 object. Always 1
747     * @return the version of the PKCS#7 object. Always 1
748     */
749    public int getVersion() {
750        return version;
751    }
752
753    /**
754     * Get the version of the PKCS#7 "SignerInfo" object. Always 1
755     * @return the version of the PKCS#7 "SignerInfo" object. Always 1
756     */
757    public int getSigningInfoVersion() {
758        return signerversion;
759    }
760
761    /**
762     * Get the algorithm used to calculate the message digest
763     * @return the algorithm used to calculate the message digest
764     */
765    public String getDigestAlgorithm() {
766        String dea = getAlgorithm(digestEncryptionAlgorithm);
767        if (dea == null)
768            dea = digestEncryptionAlgorithm;
769
770        return getHashAlgorithm() + "with" + dea;
771    }
772
773    /**
774     * Returns the algorithm.
775     * @return the digest algorithm
776     */
777    public String getHashAlgorithm() {
778        return getDigest(digestAlgorithm);
779    }
780
781    /**
782     * Loads the default root certificates at &lt;java.home&gt;/lib/security/cacerts
783     * with the default provider.
784     * @return a <CODE>KeyStore</CODE>
785     */
786    public static KeyStore loadCacertsKeyStore() {
787        return loadCacertsKeyStore(null);
788    }
789
790    /**
791     * Loads the default root certificates at &lt;java.home&gt;/lib/security/cacerts.
792     * @param provider the provider or <code>null</code> for the default provider
793     * @return a <CODE>KeyStore</CODE>
794     */
795    public static KeyStore loadCacertsKeyStore(String provider) {
796        File file = new File(System.getProperty("java.home"), "lib");
797        file = new File(file, "security");
798        file = new File(file, "cacerts");
799        FileInputStream fin = null;
800        try {
801            fin = new FileInputStream(file);
802            KeyStore k;
803            if (provider == null)
804                k = KeyStore.getInstance("JKS");
805            else
806                k = KeyStore.getInstance("JKS", provider);
807            k.load(fin, null);
808            return k;
809        }
810        catch (Exception e) {
811            throw new ExceptionConverter(e);
812        }
813        finally {
814            try{if (fin != null) {fin.close();}}catch(Exception ex){}
815        }
816    }
817
818    /**
819     * Verifies a single certificate.
820     * @param cert the certificate to verify
821     * @param crls the certificate revocation list or <CODE>null</CODE>
822     * @param calendar the date or <CODE>null</CODE> for the current date
823     * @return a <CODE>String</CODE> with the error description or <CODE>null</CODE>
824     * if no error
825     */
826    public static String verifyCertificate(X509Certificate cert, Collection<CRL> crls, Calendar calendar) {
827        if (calendar == null)
828            calendar = new GregorianCalendar();
829        if (cert.hasUnsupportedCriticalExtension())
830            return "Has unsupported critical extension";
831        try {
832            cert.checkValidity(calendar.getTime());
833        }
834        catch (Exception e) {
835            return e.getMessage();
836        }
837        if (crls != null) {
838            for (CRL crl : crls) {
839                if (crl.isRevoked(cert))
840                    return "Certificate revoked";
841            }
842        }
843        return null;
844    }
845
846    /**
847     * Verifies a certificate chain against a KeyStore.
848     * @param certs the certificate chain
849     * @param keystore the <CODE>KeyStore</CODE>
850     * @param crls the certificate revocation list or <CODE>null</CODE>
851     * @param calendar the date or <CODE>null</CODE> for the current date
852     * @return <CODE>null</CODE> if the certificate chain could be validated or a
853     * <CODE>Object[]{cert,error}</CODE> where <CODE>cert</CODE> is the
854     * failed certificate and <CODE>error</CODE> is the error message
855     */
856    public static Object[] verifyCertificates(Certificate certs[], KeyStore keystore, Collection<CRL> crls, Calendar calendar) {
857        if (calendar == null)
858            calendar = new GregorianCalendar();
859        for (int k = 0; k < certs.length; ++k) {
860            X509Certificate cert = (X509Certificate)certs[k];
861            String err = verifyCertificate(cert, crls, calendar);
862            if (err != null)
863                return new Object[]{cert, err};
864            try {
865                for (Enumeration<String> aliases = keystore.aliases(); aliases.hasMoreElements();) {
866                    try {
867                        String alias = aliases.nextElement();
868                        if (!keystore.isCertificateEntry(alias))
869                            continue;
870                        X509Certificate certStoreX509 = (X509Certificate)keystore.getCertificate(alias);
871                        if (verifyCertificate(certStoreX509, crls, calendar) != null)
872                            continue;
873                        try {
874                            cert.verify(certStoreX509.getPublicKey());
875                            return null;
876                        }
877                        catch (Exception e) {
878                            continue;
879                        }
880                    }
881                    catch (Exception ex) {
882                    }
883                }
884            }
885            catch (Exception e) {
886            }
887            int j;
888            for (j = 0; j < certs.length; ++j) {
889                if (j == k)
890                    continue;
891                X509Certificate certNext = (X509Certificate)certs[j];
892                try {
893                    cert.verify(certNext.getPublicKey());
894                    break;
895                }
896                catch (Exception e) {
897                }
898            }
899            if (j == certs.length)
900                return new Object[]{cert, "Cannot be verified against the KeyStore or the certificate chain"};
901        }
902        return new Object[]{null, "Invalid state. Possible circular certificate chain"};
903    }
904
905    /**
906     * Verifies an OCSP response against a KeyStore.
907     * @param ocsp the OCSP response
908     * @param keystore the <CODE>KeyStore</CODE>
909     * @param provider the provider or <CODE>null</CODE> to use the BouncyCastle provider
910     * @return <CODE>true</CODE> is a certificate was found
911     * @since   2.1.6
912     */
913    public static boolean verifyOcspCertificates(BasicOCSPResp ocsp, KeyStore keystore, String provider) {
914        if (provider == null)
915            provider = "BC";
916        try {
917            for (Enumeration<String> aliases = keystore.aliases(); aliases.hasMoreElements();) {
918                try {
919                    String alias = aliases.nextElement();
920                    if (!keystore.isCertificateEntry(alias))
921                        continue;
922                    X509Certificate certStoreX509 = (X509Certificate)keystore.getCertificate(alias);
923                    if (ocsp.verify(certStoreX509.getPublicKey(), provider))
924                        return true;
925                }
926                catch (Exception ex) {
927                }
928            }
929        }
930        catch (Exception e) {
931        }
932        return false;
933    }
934
935    /**
936     * Verifies a timestamp against a KeyStore.
937     * @param ts the timestamp
938     * @param keystore the <CODE>KeyStore</CODE>
939     * @param provider the provider or <CODE>null</CODE> to use the BouncyCastle provider
940     * @return <CODE>true</CODE> is a certificate was found
941     * @since   2.1.6
942     */
943    public static boolean verifyTimestampCertificates(TimeStampToken ts, KeyStore keystore, String provider) {
944        if (provider == null)
945            provider = "BC";
946        try {
947            for (Enumeration<String> aliases = keystore.aliases(); aliases.hasMoreElements();) {
948                try {
949                    String alias = aliases.nextElement();
950                    if (!keystore.isCertificateEntry(alias))
951                        continue;
952                    X509Certificate certStoreX509 = (X509Certificate)keystore.getCertificate(alias);
953                    ts.validate(certStoreX509, provider);
954                    return true;
955                }
956                catch (Exception ex) {
957                }
958            }
959        }
960        catch (Exception e) {
961        }
962        return false;
963    }
964
965    /**
966     * Retrieves the OCSP URL from the given certificate.
967     * @param certificate the certificate
968     * @return the URL or null
969     * @throws CertificateParsingException on error
970     * @since   2.1.6
971     */
972    public static String getOCSPURL(X509Certificate certificate) throws CertificateParsingException {
973        try {
974            DERObject obj = getExtensionValue(certificate, X509Extensions.AuthorityInfoAccess.getId());
975            if (obj == null) {
976                return null;
977            }
978
979            ASN1Sequence AccessDescriptions = (ASN1Sequence) obj;
980            for (int i = 0; i < AccessDescriptions.size(); i++) {
981                ASN1Sequence AccessDescription = (ASN1Sequence) AccessDescriptions.getObjectAt(i);
982                if ( AccessDescription.size() != 2 ) {
983                    continue;
984                } else {
985                    if (AccessDescription.getObjectAt(0) instanceof DERObjectIdentifier && ((DERObjectIdentifier)AccessDescription.getObjectAt(0)).getId().equals("1.3.6.1.5.5.7.48.1")) {
986                        String AccessLocation =  getStringFromGeneralName((DERObject)AccessDescription.getObjectAt(1));
987                        if ( AccessLocation == null ) {
988                            return "" ;
989                        } else {
990                            return AccessLocation ;
991                        }
992                    }
993                }
994            }
995        } catch (Exception e)  {
996        }
997        return null;
998    }
999
1000    /**
1001     * Checks if OCSP revocation refers to the document signing certificate.
1002     * @return true if it checks false otherwise
1003     * @since   2.1.6
1004     */
1005    public boolean isRevocationValid() {
1006        if (basicResp == null)
1007            return false;
1008        if (signCerts.size() < 2)
1009            return false;
1010        try {
1011            X509Certificate[] cs = (X509Certificate[])getSignCertificateChain();
1012            SingleResp sr = basicResp.getResponses()[0];
1013            CertificateID cid = sr.getCertID();
1014            X509Certificate sigcer = getSigningCertificate();
1015            X509Certificate isscer = cs[1];
1016            CertificateID tis = new CertificateID(CertificateID.HASH_SHA1, isscer, sigcer.getSerialNumber());
1017            return tis.equals(cid);
1018        }
1019        catch (Exception ex) {
1020        }
1021        return false;
1022    }
1023
1024    private static DERObject getExtensionValue(X509Certificate cert, String oid) throws IOException {
1025        byte[] bytes = cert.getExtensionValue(oid);
1026        if (bytes == null) {
1027            return null;
1028        }
1029        ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(bytes));
1030        ASN1OctetString octs = (ASN1OctetString) aIn.readObject();
1031        aIn = new ASN1InputStream(new ByteArrayInputStream(octs.getOctets()));
1032        return aIn.readObject();
1033    }
1034
1035    private static String getStringFromGeneralName(DERObject names) throws IOException {
1036        DERTaggedObject taggedObject = (DERTaggedObject) names ;
1037        return new String(ASN1OctetString.getInstance(taggedObject, false).getOctets(), "ISO-8859-1");
1038    }
1039
1040    /**
1041     * Get the "issuer" from the TBSCertificate bytes that are passed in
1042     * @param enc a TBSCertificate in a byte array
1043     * @return a DERObject
1044     */
1045    private static DERObject getIssuer(byte[] enc) {
1046        try {
1047            ASN1InputStream in = new ASN1InputStream(new ByteArrayInputStream(enc));
1048            ASN1Sequence seq = (ASN1Sequence)in.readObject();
1049            return (DERObject)seq.getObjectAt(seq.getObjectAt(0) instanceof DERTaggedObject ? 3 : 2);
1050        }
1051        catch (IOException e) {
1052            throw new ExceptionConverter(e);
1053        }
1054    }
1055
1056    /**
1057     * Get the "subject" from the TBSCertificate bytes that are passed in
1058     * @param enc A TBSCertificate in a byte array
1059     * @return a DERObject
1060     */
1061    private static DERObject getSubject(byte[] enc) {
1062        try {
1063            ASN1InputStream in = new ASN1InputStream(new ByteArrayInputStream(enc));
1064            ASN1Sequence seq = (ASN1Sequence)in.readObject();
1065            return (DERObject)seq.getObjectAt(seq.getObjectAt(0) instanceof DERTaggedObject ? 5 : 4);
1066        }
1067        catch (IOException e) {
1068            throw new ExceptionConverter(e);
1069        }
1070    }
1071
1072    /**
1073     * Get the issuer fields from an X509 Certificate
1074     * @param cert an X509Certificate
1075     * @return an X509Name
1076     */
1077    public static X509Name getIssuerFields(X509Certificate cert) {
1078        try {
1079            return new X509Name((ASN1Sequence)getIssuer(cert.getTBSCertificate()));
1080        }
1081        catch (Exception e) {
1082            throw new ExceptionConverter(e);
1083        }
1084    }
1085
1086    /**
1087     * Get the subject fields from an X509 Certificate
1088     * @param cert an X509Certificate
1089     * @return an X509Name
1090     */
1091    public static X509Name getSubjectFields(X509Certificate cert) {
1092        try {
1093            return new X509Name((ASN1Sequence)getSubject(cert.getTBSCertificate()));
1094        }
1095        catch (Exception e) {
1096            throw new ExceptionConverter(e);
1097        }
1098    }
1099
1100    /**
1101     * Gets the bytes for the PKCS#1 object.
1102     * @return a byte array
1103     */
1104    public byte[] getEncodedPKCS1() {
1105        try {
1106            if (externalDigest != null)
1107                digest = externalDigest;
1108            else
1109                digest = sig.sign();
1110            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
1111
1112            ASN1OutputStream dout = new ASN1OutputStream(bOut);
1113            dout.writeObject(new DEROctetString(digest));
1114            dout.close();
1115
1116            return bOut.toByteArray();
1117        }
1118        catch (Exception e) {
1119            throw new ExceptionConverter(e);
1120        }
1121    }
1122
1123    /**
1124     * Sets the digest/signature to an external calculated value.
1125     * @param digest the digest. This is the actual signature
1126     * @param RSAdata the extra data that goes into the data tag in PKCS#7
1127     * @param digestEncryptionAlgorithm the encryption algorithm. It may must be <CODE>null</CODE> if the <CODE>digest</CODE>
1128     * is also <CODE>null</CODE>. If the <CODE>digest</CODE> is not <CODE>null</CODE>
1129     * then it may be "RSA" or "DSA"
1130     */
1131    public void setExternalDigest(byte digest[], byte RSAdata[], String digestEncryptionAlgorithm) {
1132        externalDigest = digest;
1133        externalRSAdata = RSAdata;
1134        if (digestEncryptionAlgorithm != null) {
1135            if (digestEncryptionAlgorithm.equals("RSA")) {
1136                this.digestEncryptionAlgorithm = ID_RSA;
1137            }
1138            else if (digestEncryptionAlgorithm.equals("DSA")) {
1139                this.digestEncryptionAlgorithm = ID_DSA;
1140            }
1141            else
1142                throw new ExceptionConverter(new NoSuchAlgorithmException(MessageLocalization.getComposedMessage("unknown.key.algorithm.1", digestEncryptionAlgorithm)));
1143        }
1144    }
1145
1146    /**
1147     * Gets the bytes for the PKCS7SignedData object.
1148     * @return the bytes for the PKCS7SignedData object
1149     */
1150    public byte[] getEncodedPKCS7() {
1151        return getEncodedPKCS7(null, null, null, null);
1152    }
1153
1154    /**
1155     * Gets the bytes for the PKCS7SignedData object. Optionally the authenticatedAttributes
1156     * in the signerInfo can also be set. If either of the parameters is <CODE>null</CODE>, none will be used.
1157     * @param secondDigest the digest in the authenticatedAttributes
1158     * @param signingTime the signing time in the authenticatedAttributes
1159     * @return the bytes for the PKCS7SignedData object
1160     */
1161    public byte[] getEncodedPKCS7(byte secondDigest[], Calendar signingTime) {
1162        return getEncodedPKCS7(secondDigest, signingTime, null, null);
1163    }
1164
1165    /**
1166     * Gets the bytes for the PKCS7SignedData object. Optionally the authenticatedAttributes
1167     * in the signerInfo can also be set, OR a time-stamp-authority client
1168     * may be provided.
1169     * @param secondDigest the digest in the authenticatedAttributes
1170     * @param signingTime the signing time in the authenticatedAttributes
1171     * @param tsaClient TSAClient - null or an optional time stamp authority client
1172     * @return byte[] the bytes for the PKCS7SignedData object
1173     * @since   2.1.6
1174     */
1175    public byte[] getEncodedPKCS7(byte secondDigest[], Calendar signingTime, TSAClient tsaClient, byte[] ocsp) {
1176        try {
1177            if (externalDigest != null) {
1178                digest = externalDigest;
1179                if (RSAdata != null)
1180                    RSAdata = externalRSAdata;
1181            }
1182            else if (externalRSAdata != null && RSAdata != null) {
1183                RSAdata = externalRSAdata;
1184                sig.update(RSAdata);
1185                digest = sig.sign();
1186            }
1187            else {
1188                if (RSAdata != null) {
1189                    RSAdata = messageDigest.digest();
1190                    sig.update(RSAdata);
1191                }
1192                digest = sig.sign();
1193            }
1194
1195            // Create the set of Hash algorithms
1196            ASN1EncodableVector digestAlgorithms = new ASN1EncodableVector();
1197            for (Object element : digestalgos) {
1198                ASN1EncodableVector algos = new ASN1EncodableVector();
1199                algos.add(new DERObjectIdentifier((String)element));
1200                algos.add(DERNull.INSTANCE);
1201                digestAlgorithms.add(new DERSequence(algos));
1202            }
1203
1204            // Create the contentInfo.
1205            ASN1EncodableVector v = new ASN1EncodableVector();
1206            v.add(new DERObjectIdentifier(ID_PKCS7_DATA));
1207            if (RSAdata != null)
1208                v.add(new DERTaggedObject(0, new DEROctetString(RSAdata)));
1209            DERSequence contentinfo = new DERSequence(v);
1210
1211            // Get all the certificates
1212            //
1213            v = new ASN1EncodableVector();
1214            for (Object element : certs) {
1215                ASN1InputStream tempstream = new ASN1InputStream(new ByteArrayInputStream(((X509Certificate)element).getEncoded()));
1216                v.add(tempstream.readObject());
1217            }
1218
1219            DERSet dercertificates = new DERSet(v);
1220
1221            // Create signerinfo structure.
1222            //
1223            ASN1EncodableVector signerinfo = new ASN1EncodableVector();
1224
1225            // Add the signerInfo version
1226            //
1227            signerinfo.add(new DERInteger(signerversion));
1228
1229            v = new ASN1EncodableVector();
1230            v.add(getIssuer(signCert.getTBSCertificate()));
1231            v.add(new DERInteger(signCert.getSerialNumber()));
1232            signerinfo.add(new DERSequence(v));
1233
1234            // Add the digestAlgorithm
1235            v = new ASN1EncodableVector();
1236            v.add(new DERObjectIdentifier(digestAlgorithm));
1237            v.add(new DERNull());
1238            signerinfo.add(new DERSequence(v));
1239
1240            // add the authenticated attribute if present
1241            if (secondDigest != null && signingTime != null) {
1242                signerinfo.add(new DERTaggedObject(false, 0, getAuthenticatedAttributeSet(secondDigest, signingTime, ocsp)));
1243            }
1244            // Add the digestEncryptionAlgorithm
1245            v = new ASN1EncodableVector();
1246            v.add(new DERObjectIdentifier(digestEncryptionAlgorithm));
1247            v.add(new DERNull());
1248            signerinfo.add(new DERSequence(v));
1249
1250            // Add the digest
1251            signerinfo.add(new DEROctetString(digest));
1252
1253            // When requested, go get and add the timestamp. May throw an exception.
1254            // Added by Martin Brunecky, 07/12/2007 folowing Aiken Sam, 2006-11-15
1255            // Sam found Adobe expects time-stamped SHA1-1 of the encrypted digest
1256            if (tsaClient != null) {
1257                byte[] tsImprint = MessageDigest.getInstance("SHA-1").digest(digest);
1258                byte[] tsToken = tsaClient.getTimeStampToken(this, tsImprint);
1259                if (tsToken != null) {
1260                    ASN1EncodableVector unauthAttributes = buildUnauthenticatedAttributes(tsToken);
1261                    if (unauthAttributes != null) {
1262                        signerinfo.add(new DERTaggedObject(false, 1, new DERSet(unauthAttributes)));
1263                    }
1264                }
1265            }
1266
1267            // Finally build the body out of all the components above
1268            ASN1EncodableVector body = new ASN1EncodableVector();
1269            body.add(new DERInteger(version));
1270            body.add(new DERSet(digestAlgorithms));
1271            body.add(contentinfo);
1272            body.add(new DERTaggedObject(false, 0, dercertificates));
1273
1274            // Only allow one signerInfo
1275            body.add(new DERSet(new DERSequence(signerinfo)));
1276
1277            // Now we have the body, wrap it in it's PKCS7Signed shell
1278            // and return it
1279            //
1280            ASN1EncodableVector whole = new ASN1EncodableVector();
1281            whole.add(new DERObjectIdentifier(ID_PKCS7_SIGNED_DATA));
1282            whole.add(new DERTaggedObject(0, new DERSequence(body)));
1283
1284            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
1285
1286            ASN1OutputStream dout = new ASN1OutputStream(bOut);
1287            dout.writeObject(new DERSequence(whole));
1288            dout.close();
1289
1290            return bOut.toByteArray();
1291        }
1292        catch (Exception e) {
1293            throw new ExceptionConverter(e);
1294        }
1295    }
1296
1297    /**
1298     * Added by Aiken Sam, 2006-11-15, modifed by Martin Brunecky 07/12/2007
1299     * to start with the timeStampToken (signedData 1.2.840.113549.1.7.2).
1300     * Token is the TSA response without response status, which is usually
1301     * handled by the (vendor supplied) TSA request/response interface).
1302     * @param timeStampToken byte[] - time stamp token, DER encoded signedData
1303     * @return ASN1EncodableVector
1304     * @throws IOException
1305     */
1306    private ASN1EncodableVector buildUnauthenticatedAttributes(byte[] timeStampToken)  throws IOException {
1307        if (timeStampToken == null)
1308            return null;
1309
1310        // @todo: move this together with the rest of the defintions
1311        String ID_TIME_STAMP_TOKEN = "1.2.840.113549.1.9.16.2.14"; // RFC 3161 id-aa-timeStampToken
1312
1313        ASN1InputStream tempstream = new ASN1InputStream(new ByteArrayInputStream(timeStampToken));
1314        ASN1EncodableVector unauthAttributes = new ASN1EncodableVector();
1315
1316        ASN1EncodableVector v = new ASN1EncodableVector();
1317        v.add(new DERObjectIdentifier(ID_TIME_STAMP_TOKEN)); // id-aa-timeStampToken
1318        ASN1Sequence seq = (ASN1Sequence) tempstream.readObject();
1319        v.add(new DERSet(seq));
1320
1321        unauthAttributes.add(new DERSequence(v));
1322        return unauthAttributes;
1323     }
1324
1325
1326    /**
1327     * When using authenticatedAttributes the authentication process is different.
1328     * The document digest is generated and put inside the attribute. The signing is done over the DER encoded
1329     * authenticatedAttributes. This method provides that encoding and the parameters must be
1330     * exactly the same as in {@link #getEncodedPKCS7(byte[],Calendar)}.
1331     * <p>
1332     * A simple example:
1333     * <p>
1334     * <pre>
1335     * Calendar cal = Calendar.getInstance();
1336     * PdfPKCS7 pk7 = new PdfPKCS7(key, chain, null, "SHA1", null, false);
1337     * MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
1338     * byte buf[] = new byte[8192];
1339     * int n;
1340     * InputStream inp = sap.getRangeStream();
1341     * while ((n = inp.read(buf)) &gt; 0) {
1342     *    messageDigest.update(buf, 0, n);
1343     * }
1344     * byte hash[] = messageDigest.digest();
1345     * byte sh[] = pk7.getAuthenticatedAttributeBytes(hash, cal);
1346     * pk7.update(sh, 0, sh.length);
1347     * byte sg[] = pk7.getEncodedPKCS7(hash, cal);
1348     * </pre>
1349     * @param secondDigest the content digest
1350     * @param signingTime the signing time
1351     * @return the byte array representation of the authenticatedAttributes ready to be signed
1352     */
1353    public byte[] getAuthenticatedAttributeBytes(byte secondDigest[], Calendar signingTime, byte[] ocsp) {
1354        try {
1355            return getAuthenticatedAttributeSet(secondDigest, signingTime, ocsp).getEncoded(ASN1Encodable.DER);
1356        }
1357        catch (Exception e) {
1358            throw new ExceptionConverter(e);
1359        }
1360    }
1361
1362    private DERSet getAuthenticatedAttributeSet(byte secondDigest[], Calendar signingTime, byte[] ocsp) {
1363        try {
1364            ASN1EncodableVector attribute = new ASN1EncodableVector();
1365            ASN1EncodableVector v = new ASN1EncodableVector();
1366            v.add(new DERObjectIdentifier(ID_CONTENT_TYPE));
1367            v.add(new DERSet(new DERObjectIdentifier(ID_PKCS7_DATA)));
1368            attribute.add(new DERSequence(v));
1369            v = new ASN1EncodableVector();
1370            v.add(new DERObjectIdentifier(ID_SIGNING_TIME));
1371            v.add(new DERSet(new DERUTCTime(signingTime.getTime())));
1372            attribute.add(new DERSequence(v));
1373            v = new ASN1EncodableVector();
1374            v.add(new DERObjectIdentifier(ID_MESSAGE_DIGEST));
1375            v.add(new DERSet(new DEROctetString(secondDigest)));
1376            attribute.add(new DERSequence(v));
1377            if (ocsp != null || !crls.isEmpty()) {
1378                v = new ASN1EncodableVector();
1379                v.add(new DERObjectIdentifier(ID_ADBE_REVOCATION));
1380
1381                ASN1EncodableVector revocationV = new ASN1EncodableVector();
1382
1383                if (!crls.isEmpty()) {
1384                    ASN1EncodableVector v2 = new ASN1EncodableVector();
1385                    for (Object element : crls) {
1386                        ASN1InputStream t = new ASN1InputStream(new ByteArrayInputStream(((X509CRL)element).getEncoded()));
1387                        v2.add(t.readObject());
1388                    }
1389                    revocationV.add(new DERTaggedObject(true, 0, new DERSequence(v2)));
1390                }
1391
1392                if (ocsp != null) {
1393                        DEROctetString doctet = new DEROctetString(ocsp);
1394                        ASN1EncodableVector vo1 = new ASN1EncodableVector();
1395                        ASN1EncodableVector v2 = new ASN1EncodableVector();
1396                        v2.add(OCSPObjectIdentifiers.id_pkix_ocsp_basic);
1397                        v2.add(doctet);
1398                        DEREnumerated den = new DEREnumerated(0);
1399                        ASN1EncodableVector v3 = new ASN1EncodableVector();
1400                        v3.add(den);
1401                        v3.add(new DERTaggedObject(true, 0, new DERSequence(v2)));
1402                        vo1.add(new DERSequence(v3));
1403                        revocationV.add(new DERTaggedObject(true, 1, new DERSequence(vo1)));
1404                }
1405
1406                v.add(new DERSet(new DERSequence(revocationV)));
1407                attribute.add(new DERSequence(v));
1408            }
1409
1410            return new DERSet(attribute);
1411        }
1412        catch (Exception e) {
1413            throw new ExceptionConverter(e);
1414        }
1415    }
1416
1417    /**
1418     * Getter for property reason.
1419     * @return Value of property reason.
1420     */
1421    public String getReason() {
1422        return this.reason;
1423    }
1424
1425    /**
1426     * Setter for property reason.
1427     * @param reason New value of property reason.
1428     */
1429    public void setReason(String reason) {
1430        this.reason = reason;
1431    }
1432
1433    /**
1434     * Getter for property location.
1435     * @return Value of property location.
1436     */
1437    public String getLocation() {
1438        return this.location;
1439    }
1440
1441    /**
1442     * Setter for property location.
1443     * @param location New value of property location.
1444     */
1445    public void setLocation(String location) {
1446        this.location = location;
1447    }
1448
1449    /**
1450     * Getter for property signDate.
1451     * @return Value of property signDate.
1452     */
1453    public Calendar getSignDate() {
1454        return this.signDate;
1455    }
1456
1457    /**
1458     * Setter for property signDate.
1459     * @param signDate New value of property signDate.
1460     */
1461    public void setSignDate(Calendar signDate) {
1462        this.signDate = signDate;
1463    }
1464
1465    /**
1466     * Getter for property sigName.
1467     * @return Value of property sigName.
1468     */
1469    public String getSignName() {
1470        return this.signName;
1471    }
1472
1473    /**
1474     * Setter for property sigName.
1475     * @param signName New value of property sigName.
1476     */
1477    public void setSignName(String signName) {
1478        this.signName = signName;
1479    }
1480
1481    /**
1482     * a class that holds an X509 name
1483     */
1484    public static class X509Name {
1485        /**
1486         * country code - StringType(SIZE(2))
1487         */
1488        public static final DERObjectIdentifier C = new DERObjectIdentifier("2.5.4.6");
1489
1490        /**
1491         * organization - StringType(SIZE(1..64))
1492         */
1493        public static final DERObjectIdentifier O = new DERObjectIdentifier("2.5.4.10");
1494
1495        /**
1496         * organizational unit name - StringType(SIZE(1..64))
1497         */
1498        public static final DERObjectIdentifier OU = new DERObjectIdentifier("2.5.4.11");
1499
1500        /**
1501         * Title
1502         */
1503        public static final DERObjectIdentifier T = new DERObjectIdentifier("2.5.4.12");
1504
1505        /**
1506         * common name - StringType(SIZE(1..64))
1507         */
1508        public static final DERObjectIdentifier CN = new DERObjectIdentifier("2.5.4.3");
1509
1510        /**
1511         * device serial number name - StringType(SIZE(1..64))
1512         */
1513        public static final DERObjectIdentifier SN = new DERObjectIdentifier("2.5.4.5");
1514
1515        /**
1516         * locality name - StringType(SIZE(1..64))
1517         */
1518        public static final DERObjectIdentifier L = new DERObjectIdentifier("2.5.4.7");
1519
1520        /**
1521         * state, or province name - StringType(SIZE(1..64))
1522         */
1523        public static final DERObjectIdentifier ST = new DERObjectIdentifier("2.5.4.8");
1524
1525        /** Naming attribute of type X520name */
1526        public static final DERObjectIdentifier SURNAME = new DERObjectIdentifier("2.5.4.4");
1527        /** Naming attribute of type X520name */
1528        public static final DERObjectIdentifier GIVENNAME = new DERObjectIdentifier("2.5.4.42");
1529        /** Naming attribute of type X520name */
1530        public static final DERObjectIdentifier INITIALS = new DERObjectIdentifier("2.5.4.43");
1531        /** Naming attribute of type X520name */
1532        public static final DERObjectIdentifier GENERATION = new DERObjectIdentifier("2.5.4.44");
1533        /** Naming attribute of type X520name */
1534        public static final DERObjectIdentifier UNIQUE_IDENTIFIER = new DERObjectIdentifier("2.5.4.45");
1535
1536        /**
1537         * Email address (RSA PKCS#9 extension) - IA5String.
1538         * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
1539         */
1540        public static final DERObjectIdentifier EmailAddress = new DERObjectIdentifier("1.2.840.113549.1.9.1");
1541
1542        /**
1543         * email address in Verisign certificates
1544         */
1545        public static final DERObjectIdentifier E = EmailAddress;
1546
1547        /** object identifier */
1548        public static final DERObjectIdentifier DC = new DERObjectIdentifier("0.9.2342.19200300.100.1.25");
1549
1550        /** LDAP User id. */
1551        public static final DERObjectIdentifier UID = new DERObjectIdentifier("0.9.2342.19200300.100.1.1");
1552
1553        /** A HashMap with default symbols */
1554        public static HashMap<DERObjectIdentifier, String> DefaultSymbols = new HashMap<DERObjectIdentifier, String>();
1555
1556        static {
1557            DefaultSymbols.put(C, "C");
1558            DefaultSymbols.put(O, "O");
1559            DefaultSymbols.put(T, "T");
1560            DefaultSymbols.put(OU, "OU");
1561            DefaultSymbols.put(CN, "CN");
1562            DefaultSymbols.put(L, "L");
1563            DefaultSymbols.put(ST, "ST");
1564            DefaultSymbols.put(SN, "SN");
1565            DefaultSymbols.put(EmailAddress, "E");
1566            DefaultSymbols.put(DC, "DC");
1567            DefaultSymbols.put(UID, "UID");
1568            DefaultSymbols.put(SURNAME, "SURNAME");
1569            DefaultSymbols.put(GIVENNAME, "GIVENNAME");
1570            DefaultSymbols.put(INITIALS, "INITIALS");
1571            DefaultSymbols.put(GENERATION, "GENERATION");
1572        }
1573        /** A HashMap with values */
1574        public HashMap<String, ArrayList<String>> values = new HashMap<String, ArrayList<String>>();
1575
1576        /**
1577         * Constructs an X509 name
1578         * @param seq an ASN1 Sequence
1579         */
1580        @SuppressWarnings("unchecked")
1581        public X509Name(ASN1Sequence seq) {
1582            Enumeration<ASN1Set> e = seq.getObjects();
1583
1584            while (e.hasMoreElements()) {
1585                ASN1Set set = e.nextElement();
1586
1587                for (int i = 0; i < set.size(); i++) {
1588                    ASN1Sequence s = (ASN1Sequence)set.getObjectAt(i);
1589                    String id = DefaultSymbols.get(s.getObjectAt(0));
1590                    if (id == null)
1591                        continue;
1592                    ArrayList<String> vs = values.get(id);
1593                    if (vs == null) {
1594                        vs = new ArrayList<String>();
1595                        values.put(id, vs);
1596                    }
1597                    vs.add(((DERString)s.getObjectAt(1)).getString());
1598                }
1599            }
1600        }
1601        /**
1602         * Constructs an X509 name
1603         * @param dirName a directory name
1604         */
1605        public X509Name(String dirName) {
1606            X509NameTokenizer   nTok = new X509NameTokenizer(dirName);
1607
1608            while (nTok.hasMoreTokens()) {
1609                String  token = nTok.nextToken();
1610                int index = token.indexOf('=');
1611
1612                if (index == -1) {
1613                    throw new IllegalArgumentException(MessageLocalization.getComposedMessage("badly.formated.directory.string"));
1614                }
1615
1616                String id = token.substring(0, index).toUpperCase();
1617                String value = token.substring(index + 1);
1618                ArrayList<String> vs = values.get(id);
1619                if (vs == null) {
1620                    vs = new ArrayList<String>();
1621                    values.put(id, vs);
1622                }
1623                vs.add(value);
1624            }
1625
1626        }
1627
1628        public String getField(String name) {
1629            ArrayList<String> vs = values.get(name);
1630            return vs == null ? null : (String)vs.get(0);
1631        }
1632
1633        /**
1634         * gets a field array from the values Hashmap
1635         * @param name
1636         * @return an ArrayList
1637         */
1638        public ArrayList<String> getFieldArray(String name) {
1639            ArrayList<String> vs = values.get(name);
1640            return vs == null ? null : vs;
1641        }
1642
1643        /**
1644         * getter for values
1645         * @return a HashMap with the fields of the X509 name
1646         */
1647        public HashMap<String, ArrayList<String>> getFields() {
1648            return values;
1649        }
1650
1651        /**
1652         * @see java.lang.Object#toString()
1653         */
1654        @Override
1655        public String toString() {
1656            return values.toString();
1657        }
1658    }
1659
1660    /**
1661     * class for breaking up an X500 Name into it's component tokens, ala
1662     * java.util.StringTokenizer. We need this class as some of the
1663     * lightweight Java environment don't support classes like
1664     * StringTokenizer.
1665     */
1666    public static class X509NameTokenizer {
1667        private String          oid;
1668        private int             index;
1669        private StringBuffer    buf = new StringBuffer();
1670
1671        public X509NameTokenizer(
1672        String oid) {
1673            this.oid = oid;
1674            this.index = -1;
1675        }
1676
1677        public boolean hasMoreTokens() {
1678            return index != oid.length();
1679        }
1680
1681        public String nextToken() {
1682            if (index == oid.length()) {
1683                return null;
1684            }
1685
1686            int     end = index + 1;
1687            boolean quoted = false;
1688            boolean escaped = false;
1689
1690            buf.setLength(0);
1691
1692            while (end != oid.length()) {
1693                char    c = oid.charAt(end);
1694
1695                if (c == '"') {
1696                    if (!escaped) {
1697                        quoted = !quoted;
1698                    }
1699                    else {
1700                        buf.append(c);
1701                    }
1702                    escaped = false;
1703                }
1704                else {
1705                    if (escaped || quoted) {
1706                        buf.append(c);
1707                        escaped = false;
1708                    }
1709                    else if (c == '\\') {
1710                        escaped = true;
1711                    }
1712                    else if (c == ',') {
1713                        break;
1714                    }
1715                    else {
1716                        buf.append(c);
1717                    }
1718                }
1719                end++;
1720            }
1721
1722            index = end;
1723            return buf.toString().trim();
1724        }
1725    }
1726}