1 package org.bouncycastle.operator.jcajce; 2 3 import java.io.IOException; 4 import java.io.OutputStream; 5 import java.security.GeneralSecurityException; 6 import java.security.PrivateKey; 7 import java.security.Provider; 8 import java.security.SecureRandom; 9 import java.security.Signature; 10 import java.security.SignatureException; 11 import java.security.spec.AlgorithmParameterSpec; 12 import java.security.spec.MGF1ParameterSpec; 13 import java.security.spec.PSSParameterSpec; 14 import java.util.List; 15 16 import org.bouncycastle.asn1.ASN1EncodableVector; 17 import org.bouncycastle.asn1.ASN1Encoding; 18 import org.bouncycastle.asn1.ASN1Integer; 19 import org.bouncycastle.asn1.ASN1Sequence; 20 import org.bouncycastle.asn1.DERBitString; 21 import org.bouncycastle.asn1.DERSequence; 22 import org.bouncycastle.asn1.misc.MiscObjectIdentifiers; 23 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 24 import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; 25 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 26 import org.bouncycastle.jcajce.CompositePrivateKey; 27 import org.bouncycastle.jcajce.io.OutputStreamFactory; 28 import org.bouncycastle.jcajce.spec.CompositeAlgorithmSpec; 29 import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; 30 import org.bouncycastle.jcajce.util.NamedJcaJceHelper; 31 import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; 32 import org.bouncycastle.operator.ContentSigner; 33 import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; 34 import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; 35 import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder; 36 import org.bouncycastle.operator.OperatorCreationException; 37 import org.bouncycastle.operator.RuntimeOperatorException; 38 import org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder; 39 import org.bouncycastle.util.io.TeeOutputStream; 40 41 public class JcaContentSignerBuilder 42 { 43 private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); 44 private SecureRandom random; 45 private String signatureAlgorithm; 46 private AlgorithmIdentifier sigAlgId; 47 private AlgorithmParameterSpec sigAlgSpec; 48 JcaContentSignerBuilder(String signatureAlgorithm)49 public JcaContentSignerBuilder(String signatureAlgorithm) 50 { 51 this.signatureAlgorithm = signatureAlgorithm; 52 this.sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgorithm); 53 this.sigAlgSpec = null; 54 } 55 JcaContentSignerBuilder(String signatureAlgorithm, AlgorithmParameterSpec sigParamSpec)56 public JcaContentSignerBuilder(String signatureAlgorithm, AlgorithmParameterSpec sigParamSpec) 57 { 58 this.signatureAlgorithm = signatureAlgorithm; 59 60 if (sigParamSpec instanceof PSSParameterSpec) 61 { 62 PSSParameterSpec pssSpec = (PSSParameterSpec)sigParamSpec; 63 64 this.sigAlgSpec = pssSpec; 65 this.sigAlgId = new AlgorithmIdentifier( 66 PKCSObjectIdentifiers.id_RSASSA_PSS, createPSSParams(pssSpec)); 67 } 68 else if (sigParamSpec instanceof CompositeAlgorithmSpec) 69 { 70 CompositeAlgorithmSpec compSpec = (CompositeAlgorithmSpec)sigParamSpec; 71 72 this.sigAlgSpec = compSpec; 73 this.sigAlgId = new AlgorithmIdentifier( 74 MiscObjectIdentifiers.id_alg_composite, createCompParams(compSpec)); 75 } 76 else 77 { 78 throw new IllegalArgumentException("unknown sigParamSpec: " 79 + ((sigParamSpec == null) ? "null" : sigParamSpec.getClass().getName())); 80 } 81 } 82 setProvider(Provider provider)83 public JcaContentSignerBuilder setProvider(Provider provider) 84 { 85 this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); 86 87 return this; 88 } 89 setProvider(String providerName)90 public JcaContentSignerBuilder setProvider(String providerName) 91 { 92 this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); 93 94 return this; 95 } 96 setSecureRandom(SecureRandom random)97 public JcaContentSignerBuilder setSecureRandom(SecureRandom random) 98 { 99 this.random = random; 100 101 return this; 102 } 103 build(PrivateKey privateKey)104 public ContentSigner build(PrivateKey privateKey) 105 throws OperatorCreationException 106 { 107 if (privateKey instanceof CompositePrivateKey) 108 { 109 return buildComposite((CompositePrivateKey)privateKey); 110 } 111 112 try 113 { 114 final Signature sig = helper.createSignature(sigAlgId); 115 final AlgorithmIdentifier signatureAlgId = sigAlgId; 116 117 if (random != null) 118 { 119 sig.initSign(privateKey, random); 120 } 121 else 122 { 123 sig.initSign(privateKey); 124 } 125 126 return new ContentSigner() 127 { 128 private OutputStream stream = OutputStreamFactory.createStream(sig); 129 130 public AlgorithmIdentifier getAlgorithmIdentifier() 131 { 132 return signatureAlgId; 133 } 134 135 public OutputStream getOutputStream() 136 { 137 return stream; 138 } 139 140 public byte[] getSignature() 141 { 142 try 143 { 144 return sig.sign(); 145 } 146 catch (SignatureException e) 147 { 148 throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e); 149 } 150 } 151 }; 152 } 153 catch (GeneralSecurityException e) 154 { 155 throw new OperatorCreationException("cannot create signer: " + e.getMessage(), e); 156 } 157 } 158 buildComposite(CompositePrivateKey privateKey)159 private ContentSigner buildComposite(CompositePrivateKey privateKey) 160 throws OperatorCreationException 161 { 162 try 163 { 164 List<PrivateKey> privateKeys = privateKey.getPrivateKeys(); 165 final ASN1Sequence sigAlgIds = ASN1Sequence.getInstance(sigAlgId.getParameters()); 166 final Signature[] sigs = new Signature[sigAlgIds.size()]; 167 168 for (int i = 0; i != sigAlgIds.size(); i++) 169 { 170 sigs[i] = helper.createSignature(AlgorithmIdentifier.getInstance(sigAlgIds.getObjectAt(i))); 171 172 if (random != null) 173 { 174 sigs[i].initSign(privateKeys.get(i), random); 175 } 176 else 177 { 178 sigs[i].initSign(privateKeys.get(i)); 179 } 180 } 181 182 OutputStream sStream = OutputStreamFactory.createStream(sigs[0]); 183 for (int i = 1; i != sigs.length; i++) 184 { 185 sStream = new TeeOutputStream(sStream, OutputStreamFactory.createStream(sigs[i])); 186 } 187 188 final OutputStream sigStream = sStream; 189 190 return new ContentSigner() 191 { 192 OutputStream stream = sigStream; 193 194 public AlgorithmIdentifier getAlgorithmIdentifier() 195 { 196 return sigAlgId; 197 } 198 199 public OutputStream getOutputStream() 200 { 201 return stream; 202 } 203 204 public byte[] getSignature() 205 { 206 try 207 { 208 ASN1EncodableVector sigV = new ASN1EncodableVector(); 209 210 for (int i = 0; i != sigs.length; i++) 211 { 212 sigV.add(new DERBitString(sigs[i].sign())); 213 } 214 215 return new DERSequence(sigV).getEncoded(ASN1Encoding.DER); 216 } 217 catch (IOException e) 218 { 219 throw new RuntimeOperatorException("exception encoding signature: " + e.getMessage(), e); 220 } 221 catch (SignatureException e) 222 { 223 throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e); 224 } 225 } 226 }; 227 } 228 catch (GeneralSecurityException e) 229 { 230 throw new OperatorCreationException("cannot create signer: " + e.getMessage(), e); 231 } 232 } 233 234 private static RSASSAPSSparams createPSSParams(PSSParameterSpec pssSpec) 235 { 236 DigestAlgorithmIdentifierFinder digFinder = new DefaultDigestAlgorithmIdentifierFinder(); 237 AlgorithmIdentifier digId = digFinder.find(pssSpec.getDigestAlgorithm()); 238 AlgorithmIdentifier mgfDig = digFinder.find(((MGF1ParameterSpec)pssSpec.getMGFParameters()).getDigestAlgorithm()); 239 240 return new RSASSAPSSparams( 241 digId, 242 new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, mgfDig), 243 new ASN1Integer(pssSpec.getSaltLength()), 244 new ASN1Integer(pssSpec.getTrailerField())); 245 } 246 247 private static ASN1Sequence createCompParams(CompositeAlgorithmSpec compSpec) 248 { 249 SignatureAlgorithmIdentifierFinder algFinder = new DefaultSignatureAlgorithmIdentifierFinder(); 250 ASN1EncodableVector v = new ASN1EncodableVector(); 251 252 List<String> algorithmNames = compSpec.getAlgorithmNames(); 253 List<AlgorithmParameterSpec> algorithmSpecs = compSpec.getParameterSpecs(); 254 255 for (int i = 0; i != algorithmNames.size(); i++) 256 { 257 AlgorithmParameterSpec sigSpec = algorithmSpecs.get(i); 258 if (sigSpec == null) 259 { 260 v.add(algFinder.find(algorithmNames.get(i))); 261 } 262 else if (sigSpec instanceof PSSParameterSpec) 263 { 264 v.add(createPSSParams((PSSParameterSpec)sigSpec)); 265 } 266 else 267 { 268 throw new IllegalArgumentException("unrecognized parameterSpec"); 269 } 270 } 271 272 return new DERSequence(v); 273 } 274 } 275