001 package org.apache.commons.openpgp;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one or more
005 * contributor license agreements. See the NOTICE file distributed with
006 * this work for additional information regarding copyright ownership.
007 * The ASF licenses this file to You under the Apache License, Version 2.0
008 * (the "License"); you may not use this file except in compliance with
009 * the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020 import java.io.IOException;
021 import java.io.InputStream;
022 import java.security.Security;
023 import java.security.SignatureException;
024
025 import org.bouncycastle.jce.provider.BouncyCastleProvider;
026 import org.bouncycastle.openpgp.PGPCompressedData;
027 import org.bouncycastle.openpgp.PGPException;
028 import org.bouncycastle.openpgp.PGPObjectFactory;
029 import org.bouncycastle.openpgp.PGPPublicKey;
030 import org.bouncycastle.openpgp.PGPSignature;
031 import org.bouncycastle.openpgp.PGPSignatureList;
032 import org.bouncycastle.openpgp.PGPUtil;
033 import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
034
035 /**
036 * Bouncy Castle implementation of the OpenPGP signer.
037 *
038 * @author <a href="mailto:brett@apache.org">Brett Porter</a>
039 */
040 public class BouncyCastleOpenPgpStreamingSignatureVerifier
041 implements OpenPgpStreamingSignatureVerifier
042 {
043 private PGPSignature sig;
044
045 public BouncyCastleOpenPgpStreamingSignatureVerifier( InputStream signature, KeyRing keyRing )
046 throws OpenPgpException, IOException
047 {
048 init( signature, keyRing );
049 }
050
051 private void init( InputStream signature, KeyRing keyRing )
052 throws OpenPgpException, IOException
053 {
054 // TODO: better location for this?
055 Security.addProvider( new BouncyCastleProvider() );
056
057 try
058 {
059 signature = PGPUtil.getDecoderStream( signature );
060
061 PGPPublicKey key = null;
062 while ( key == null && signature.available() > 0 )
063 {
064 PGPObjectFactory pgpFact = new PGPObjectFactory( signature );
065
066 PGPSignatureList p3;
067
068 Object o = pgpFact.nextObject();
069 if ( o == null )
070 {
071 break;
072 }
073
074 if ( o instanceof PGPCompressedData )
075 {
076 PGPCompressedData c1 = (PGPCompressedData) o;
077
078 pgpFact = new PGPObjectFactory( c1.getDataStream() );
079
080 p3 = (PGPSignatureList) pgpFact.nextObject();
081 }
082 else
083 {
084 p3 = (PGPSignatureList) o;
085 }
086
087 for ( int i = 0; i < p3.size(); i++ )
088 {
089 sig = p3.get( i );
090 key = keyRing.getPublicKey( sig.getKeyID() );
091 if ( key != null )
092 {
093 break;
094 }
095 else
096 {
097 // TODO: log them all
098 }
099 }
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 }