pdfbox-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Tilman Hausherr <THaush...@t-online.de>
Subject Re: Verifier digital signatures
Date Tue, 07 Jun 2016 15:28:39 GMT
Here's some code. At this time, it works only properly with 
adbe.pkcs7.detached signatures. I don't know whether it checks advanced 
stuff like certificate chain, revocation lists, etc. But it can detect 
that a file was changed. Enjoy.
Tilman

/*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
  *
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
package org.apache.pdfbox.examples.signature;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Collection;

import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSProcessable;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.util.Store;

/**
  * This will read a document from the filesystem, decrypt it and do 
something with the signature.
  *
  * @author Ben Litchfield
  */
public final class ShowSignature
{
     private static SimpleDateFormat sdf = new 
SimpleDateFormat("dd.MM.yyyy HH:mm:ss");

     private ShowSignature()
     {
     }

     /**
      * This is the entry point for the application.
      *
      * @param args The command-line arguments.
      *
      * @throws IOException If there is an error reading the file.
      * @throws CertificateException
      */
     public static void main(String[] args) throws IOException, 
CertificateException,
NoSuchAlgorithmException, InvalidKeyException,
NoSuchProviderException, SignatureException
     {
         ShowSignature show = new ShowSignature();
         show.showSignature( args );
     }

     private void showSignature(String[] args) throws IOException, 
CertificateException,
NoSuchAlgorithmException, InvalidKeyException,
NoSuchProviderException, SignatureException
     {
         if( args.length != 2 )
         {
             usage();
         }
         else
         {
             String password = args[0];
             String infile = args[1];
             PDDocument document = null;
             try
             {
                 document = PDDocument.load(new File(infile), password);
                 for (PDSignature sig : document.getSignatureDictionaries())
                 {
                     COSDictionary sigDict = sig.getCOSObject();
                     COSString contents = (COSString) 
sigDict.getDictionaryObject(COSName.CONTENTS);

                     // download the signed content, described in 
/ByteRange COSArray:
                     // [offset1 len1 offset2 len2]
                     int[] byteRange = sig.getByteRange();
                     byte[] buf = new byte[byteRange[1] + byteRange[3]];
                     RandomAccessFile raf = new RandomAccessFile(infile, 
"r");
                     raf.seek(byteRange[0]);
                     raf.readFully(buf, byteRange[0], byteRange[1]);
                     raf.seek(byteRange[2]);
                     raf.readFully(buf, byteRange[1], byteRange[3]);
                     raf.close();

                     System.out.println("Signature found");
                     System.out.println("Name:     " + sig.getName());
                     System.out.println("Modified: " + 
sdf.format(sig.getSignDate().getTime()));
                     String subFilter = sig.getSubFilter();
                     if (subFilter != null)
                     {
                         if (subFilter.equals("adbe.pkcs7.detached"))
                         {
                             CMSProcessable signedContent = new 
CMSProcessableByteArray(buf);

                             // inspiration:
                             // http://stackoverflow.com/a/26702631/535646
                             // http://stackoverflow.com/a/9261365/535646
                             CMSSignedData signedData = new 
CMSSignedData(signedContent, contents.getBytes());
                             Store certificatesStore = 
signedData.getCertificates();
                             Collection<SignerInformation> signers = 
signedData.getSignerInfos().getSigners();
                             SignerInformation signerInformation = 
signers.iterator().next();
                             Collection matches = 
certificatesStore.getMatches(signerInformation.getSID());
                             X509CertificateHolder certificateHolder = 
(X509CertificateHolder) matches.iterator().next();
                             X509Certificate certFromSignedData = new 
JcaX509CertificateConverter().getCertificate(certificateHolder);
                             System.out.println("certFromSignedData: " + 
certFromSignedData);
certFromSignedData.checkValidity(sig.getSignDate().getTime());

                             // CMSVerifierCertificateNotValidException 
means that the keystore wasn't valid at signing time
                             if (signerInformation.verify(new 
JcaSimpleSignerInfoVerifierBuilder().build(certFromSignedData)))
                             {
                                 System.out.println("Signature verified");
                             }
                             else
                             {
                                 System.out.println("Signature 
verification failed");
                             }

                             //TODO check certificate chain, revocation 
lists, timestamp...
                         }
                         else if (subFilter.equals("adbe.x509.rsa_sha1"))
                         {
                             // PDFBOX-2693.pdf
                             COSString certString = (COSString) 
sigDict.getDictionaryObject(
                                     COSName.getPDFName("Cert"));
                             byte[] certData = certString.getBytes();
                             CertificateFactory factory = 
CertificateFactory.getInstance("X.509");
                             ByteArrayInputStream certStream = new 
ByteArrayInputStream(certData);
                             Collection<? extends Certificate> certs = 
factory.generateCertificates(certStream);
                             System.out.println("certs=" + certs);

                             //TODO verify signature
                         }
                         else if (subFilter.equals("adbe.pkcs7.sha1"))
                         {
                             // PDFBOX-1452.pdf
                             COSString certString = (COSString) 
sigDict.getDictionaryObject(
                                     COSName.CONTENTS);
                             byte[] certData = certString.getBytes();
                             CertificateFactory factory = 
CertificateFactory.getInstance("X.509");
                             ByteArrayInputStream certStream = new 
ByteArrayInputStream(certData);
                             Collection<? extends Certificate> certs = 
factory.generateCertificates(certStream);
                             System.out.println("certs=" + certs);

                             //TODO verify signature
                         }
                         else
                         {
                             System.err.println("Unknown certificate 
type: " + subFilter);
                         }
                     }
                     else
                     {
                         throw new IOException("Missing subfilter for 
cert dictionary");
                     }
                 }
             }
             catch (CMSException ex)
             {
                 throw new IOException(ex);
             }
             catch (OperatorCreationException ex)
             {
                 throw new IOException(ex);
             }
             finally
             {
                 if (document != null)
                 {
                     document.close();
                 }
             }
         }
     }

     /**
      * This will print a usage message.
      */
     private static void usage()
     {
         System.err.println( "usage: java " + 
ShowSignature.class.getName() +
                             "<password> <inputfile>" );
     }
}


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@pdfbox.apache.org
For additional commands, e-mail: users-help@pdfbox.apache.org


Mime
View raw message