• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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