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 }