1package org.bouncycastle.operator.jcajce; 2 3import java.io.IOException; 4import java.io.OutputStream; 5import java.security.GeneralSecurityException; 6import java.security.Provider; 7import java.security.PublicKey; 8import java.security.Signature; 9import java.security.SignatureException; 10import java.security.cert.CertificateEncodingException; 11import java.security.cert.CertificateException; 12import java.security.cert.X509Certificate; 13 14import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 15import org.bouncycastle.cert.X509CertificateHolder; 16import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; 17import org.bouncycastle.jcajce.DefaultJcaJceHelper; 18import org.bouncycastle.jcajce.NamedJcaJceHelper; 19import org.bouncycastle.jcajce.ProviderJcaJceHelper; 20import org.bouncycastle.operator.ContentVerifier; 21import org.bouncycastle.operator.ContentVerifierProvider; 22import org.bouncycastle.operator.OperatorCreationException; 23import org.bouncycastle.operator.OperatorStreamException; 24import org.bouncycastle.operator.RawContentVerifier; 25import org.bouncycastle.operator.RuntimeOperatorException; 26 27public class JcaContentVerifierProviderBuilder 28{ 29 private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); 30 31 public JcaContentVerifierProviderBuilder() 32 { 33 } 34 35 public JcaContentVerifierProviderBuilder setProvider(Provider provider) 36 { 37 this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); 38 39 return this; 40 } 41 42 public JcaContentVerifierProviderBuilder setProvider(String providerName) 43 { 44 this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); 45 46 return this; 47 } 48 49 public ContentVerifierProvider build(X509CertificateHolder certHolder) 50 throws OperatorCreationException, CertificateException 51 { 52 return build(helper.convertCertificate(certHolder)); 53 } 54 55 public ContentVerifierProvider build(final X509Certificate certificate) 56 throws OperatorCreationException 57 { 58 final X509CertificateHolder certHolder; 59 60 try 61 { 62 certHolder = new JcaX509CertificateHolder(certificate); 63 } 64 catch (CertificateEncodingException e) 65 { 66 throw new OperatorCreationException("cannot process certificate: " + e.getMessage(), e); 67 } 68 69 return new ContentVerifierProvider() 70 { 71 private SignatureOutputStream stream; 72 73 public boolean hasAssociatedCertificate() 74 { 75 return true; 76 } 77 78 public X509CertificateHolder getAssociatedCertificate() 79 { 80 return certHolder; 81 } 82 83 public ContentVerifier get(AlgorithmIdentifier algorithm) 84 throws OperatorCreationException 85 { 86 try 87 { 88 Signature sig = helper.createSignature(algorithm); 89 90 sig.initVerify(certificate.getPublicKey()); 91 92 stream = new SignatureOutputStream(sig); 93 } 94 catch (GeneralSecurityException e) 95 { 96 throw new OperatorCreationException("exception on setup: " + e, e); 97 } 98 99 Signature rawSig = createRawSig(algorithm, certificate.getPublicKey()); 100 101 if (rawSig != null) 102 { 103 return new RawSigVerifier(algorithm, stream, rawSig); 104 } 105 else 106 { 107 return new SigVerifier(algorithm, stream); 108 } 109 } 110 }; 111 } 112 113 public ContentVerifierProvider build(final PublicKey publicKey) 114 throws OperatorCreationException 115 { 116 return new ContentVerifierProvider() 117 { 118 public boolean hasAssociatedCertificate() 119 { 120 return false; 121 } 122 123 public X509CertificateHolder getAssociatedCertificate() 124 { 125 return null; 126 } 127 128 public ContentVerifier get(AlgorithmIdentifier algorithm) 129 throws OperatorCreationException 130 { 131 SignatureOutputStream stream = createSignatureStream(algorithm, publicKey); 132 133 Signature rawSig = createRawSig(algorithm, publicKey); 134 135 if (rawSig != null) 136 { 137 return new RawSigVerifier(algorithm, stream, rawSig); 138 } 139 else 140 { 141 return new SigVerifier(algorithm, stream); 142 } 143 } 144 }; 145 } 146 147 private SignatureOutputStream createSignatureStream(AlgorithmIdentifier algorithm, PublicKey publicKey) 148 throws OperatorCreationException 149 { 150 try 151 { 152 Signature sig = helper.createSignature(algorithm); 153 154 sig.initVerify(publicKey); 155 156 return new SignatureOutputStream(sig); 157 } 158 catch (GeneralSecurityException e) 159 { 160 throw new OperatorCreationException("exception on setup: " + e, e); 161 } 162 } 163 164 private Signature createRawSig(AlgorithmIdentifier algorithm, PublicKey publicKey) 165 { 166 Signature rawSig; 167 try 168 { 169 rawSig = helper.createRawSignature(algorithm); 170 171 if (rawSig != null) 172 { 173 rawSig.initVerify(publicKey); 174 } 175 } 176 catch (Exception e) 177 { 178 rawSig = null; 179 } 180 return rawSig; 181 } 182 183 private class SigVerifier 184 implements ContentVerifier 185 { 186 private SignatureOutputStream stream; 187 private AlgorithmIdentifier algorithm; 188 189 SigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream) 190 { 191 this.algorithm = algorithm; 192 this.stream = stream; 193 } 194 195 public AlgorithmIdentifier getAlgorithmIdentifier() 196 { 197 return algorithm; 198 } 199 200 public OutputStream getOutputStream() 201 { 202 if (stream == null) 203 { 204 throw new IllegalStateException("verifier not initialised"); 205 } 206 207 return stream; 208 } 209 210 public boolean verify(byte[] expected) 211 { 212 try 213 { 214 return stream.verify(expected); 215 } 216 catch (SignatureException e) 217 { 218 throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e); 219 } 220 } 221 } 222 223 private class RawSigVerifier 224 extends SigVerifier 225 implements RawContentVerifier 226 { 227 private Signature rawSignature; 228 229 RawSigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream, Signature rawSignature) 230 { 231 super(algorithm, stream); 232 this.rawSignature = rawSignature; 233 } 234 235 public boolean verify(byte[] digest, byte[] expected) 236 { 237 try 238 { 239 rawSignature.update(digest); 240 241 return rawSignature.verify(expected); 242 } 243 catch (SignatureException e) 244 { 245 throw new RuntimeOperatorException("exception obtaining raw signature: " + e.getMessage(), e); 246 } 247 } 248 } 249 250 private class SignatureOutputStream 251 extends OutputStream 252 { 253 private Signature sig; 254 255 SignatureOutputStream(Signature sig) 256 { 257 this.sig = sig; 258 } 259 260 public void write(byte[] bytes, int off, int len) 261 throws IOException 262 { 263 try 264 { 265 sig.update(bytes, off, len); 266 } 267 catch (SignatureException e) 268 { 269 throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e); 270 } 271 } 272 273 public void write(byte[] bytes) 274 throws IOException 275 { 276 try 277 { 278 sig.update(bytes); 279 } 280 catch (SignatureException e) 281 { 282 throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e); 283 } 284 } 285 286 public void write(int b) 287 throws IOException 288 { 289 try 290 { 291 sig.update((byte)b); 292 } 293 catch (SignatureException e) 294 { 295 throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e); 296 } 297 } 298 299 boolean verify(byte[] expected) 300 throws SignatureException 301 { 302 return sig.verify(expected); 303 } 304 } 305}