View Javadoc

1   package org.apache.commons.openpgp;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements.  See the NOTICE file distributed with
6    * this work for additional information regarding copyright ownership.
7    * The ASF licenses this file to You under the Apache License, Version 2.0
8    * (the "License"); you may not use this file except in compliance with
9    * the License.  You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.security.Security;
23  import java.security.SignatureException;
24  
25  import org.bouncycastle.jce.provider.BouncyCastleProvider;
26  import org.bouncycastle.openpgp.PGPCompressedData;
27  import org.bouncycastle.openpgp.PGPException;
28  import org.bouncycastle.openpgp.PGPObjectFactory;
29  import org.bouncycastle.openpgp.PGPPublicKey;
30  import org.bouncycastle.openpgp.PGPSignature;
31  import org.bouncycastle.openpgp.PGPSignatureList;
32  import org.bouncycastle.openpgp.PGPUtil;
33  import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
34  
35  /**
36   * Bouncy Castle implementation of the OpenPGP signer.
37   * 
38   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
39   */
40  public class BouncyCastleOpenPgpStreamingSignatureVerifier
41      implements OpenPgpStreamingSignatureVerifier
42  {
43      private PGPSignature sig;
44  
45      public BouncyCastleOpenPgpStreamingSignatureVerifier( InputStream signature, KeyRing keyRing )
46          throws OpenPgpException, IOException
47      {
48          init( signature, keyRing );
49      }
50  
51      private void init( InputStream signature, KeyRing keyRing )
52          throws OpenPgpException, IOException
53      {
54          // TODO: better location for this?
55          Security.addProvider( new BouncyCastleProvider() );
56  
57          try
58          {
59              signature = PGPUtil.getDecoderStream( signature );
60  
61              PGPPublicKey key = null;
62              while ( key == null && signature.available() > 0 )
63              {
64                  PGPObjectFactory pgpFact = new PGPObjectFactory( signature );
65  
66                  PGPSignatureList p3;
67  
68                  Object o = pgpFact.nextObject();
69                  if ( o == null )
70                  {
71                      break;
72                  }
73                  
74                  if ( o instanceof PGPCompressedData )
75                  {
76                      PGPCompressedData c1 = (PGPCompressedData) o;
77  
78                      pgpFact = new PGPObjectFactory( c1.getDataStream() );
79  
80                      p3 = (PGPSignatureList) pgpFact.nextObject();
81                  }
82                  else
83                  {
84                      p3 = (PGPSignatureList) o;
85                  }
86  
87                  for ( int i = 0; i < p3.size(); i++ )
88                  {
89                      sig = p3.get( i );
90                      key = keyRing.getPublicKey( sig.getKeyID() );
91                      if ( key != null )
92                      {
93                          break;
94                      }
95                      else
96                      {
97                          // TODO: log them all
98                      }
99                  }
100 
101             }
102 
103             if ( key == null )
104             {
105                 throw new UnknownKeyException( "Unable to find key with key ID '"
106                     + Long.toHexString( sig.getKeyID() ).toUpperCase() + "' in public key ring" );
107             }
108 
109             sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), key);
110         }
111         catch ( PGPException e )
112         {
113             // TODO: more details
114             throw new OpenPgpException( "Error calculating detached signature", e );
115         }
116     }
117 
118     public void update( byte[] buf )
119         throws OpenPgpException
120     {
121         update( buf, 0, buf.length );
122     }
123 
124     public void update( byte[] buf, int offset, int length )
125         throws OpenPgpException
126     {
127         try
128         {
129             sig.update( buf, offset, length );
130         }
131         catch ( SignatureException e )
132         {
133             // TODO: more details
134             throw new OpenPgpException( "Error calculating detached signature", e );
135         }
136     }
137 
138     public SignatureStatus finish()
139         throws OpenPgpException, IOException
140     {
141         try
142         {
143             if ( sig.verify() )
144             {
145                 // TODO: how do we assess trust?
146                 return SignatureStatus.VALID_UNTRUSTED;
147             }
148             else
149             {
150                 return SignatureStatus.INVALID;
151             }
152         }
153         catch ( PGPException e )
154         {
155             // TODO: more details
156             throw new OpenPgpException( "Error calculating detached signature", e );
157         }
158         catch ( SignatureException e )
159         {
160             // TODO: more details
161             throw new OpenPgpException( "Error calculating detached signature", e );
162         }
163     }
164 }