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