1 package es.caib.signatura.impl;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.File;
5 import java.io.FileInputStream;
6 import java.io.FileNotFoundException;
7 import java.io.FileWriter;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.io.OutputStream;
11 import java.io.PrintWriter;
12 import java.lang.reflect.Constructor;
13 import java.net.URL;
14 import java.security.Provider;
15 import java.security.Security;
16 import java.util.Collection;
17 import java.util.Date;
18 import java.util.LinkedHashMap;
19 import java.util.Map;
20 import java.util.Properties;
21 import java.util.StringTokenizer;
22 import java.util.Vector;
23 import java.util.Iterator;
24
25 import es.caib.signatura.api.SMIMEParser;
26 import es.caib.signatura.api.Signature;
27 import es.caib.signatura.api.SignatureCertNotFoundException;
28 import es.caib.signatura.api.SignatureException;
29 import es.caib.signatura.api.SignaturePrivKeyException;
30 import es.caib.signatura.api.SignatureProviderException;
31 import es.caib.signatura.api.SignatureTimestampException;
32 import es.caib.signatura.api.SignatureVerifyException;
33 import es.caib.signatura.api.Signer;
34 import es.caib.signatura.api.SignerFactory;
35 import es.caib.signatura.api.ParsedCertificate;
36
37 import java.security.DigestInputStream;
38 import java.security.MessageDigest;
39 import java.security.NoSuchAlgorithmException;
40 import java.security.NoSuchProviderException;
41 import java.security.cert.X509Certificate;
42
43 public class CAIBSigner implements Signer {
44 private static LinkedHashMap realSigners = null;
45 private SignaturaProperties properties = null;
46 private static ClassLoaderFactory factory;
47 private static Object lock = new Object();
48
49 private SignerProviderInterface getSigner (String certificateName, String contentType) throws SignatureCertNotFoundException
50 {
51
52 boolean recognized = properties.needsRecognizedCertificate(contentType);
53 Iterator signersIterator = realSigners.values().iterator();
54 while (signersIterator.hasNext())
55 {
56 SignerProviderInterface s = (SignerProviderInterface) signersIterator.next();
57 String[] certs;
58 try {
59 certs = s.getCertList(recognized);
60 for (int j = 0; j < certs.length; j ++)
61 {
62 if (certs [ j ] .equals(certificateName))
63 return s;
64 }
65 } catch (SignatureCertNotFoundException e) {
66 } catch (SignaturePrivKeyException e) {
67 }
68 }
69 throw new SignatureCertNotFoundException ();
70 }
71
72 public String[] getCertList(String contentType)
73 throws SignatureCertNotFoundException, SignaturePrivKeyException {
74 synchronized (lock) {
75 Vector v = new Vector ();
76 Collection signersCollection = realSigners.values();
77 if(signersCollection != null){
78 Iterator signersIterator = signersCollection.iterator();
79 if(signersIterator != null){
80 while (signersIterator.hasNext())
81 {
82 SignerProviderInterface s = (SignerProviderInterface) signersIterator.next();
83 String certs[];
84 boolean recognized = properties.needsRecognizedCertificate(contentType);
85 try {
86 certs = s.getCertList(recognized);
87 for (int j = 0 ; j < certs.length; j++)
88 {
89 if (!v.contains(certs[j]))
90 v.add (certs[j]);
91 }
92 } catch (SignatureCertNotFoundException e) {
93
94
95 } catch (SignaturePrivKeyException e) {
96 e.printStackTrace();
97 }catch(Throwable e){
98 System.err.println ("CANNOT LOAD on signature provider "+s.getClass().getName());
99 e.printStackTrace();
100 }
101 }
102 }
103 }
104 return (String[]) v.toArray(new String[v.size()]);
105 }
106 }
107
108 public Signature sign(String fileName, String certificateName,
109 String password, String contentType) throws IOException,
110 SignatureException {
111 return sign (new FileInputStream (fileName), certificateName, password, contentType);
112 }
113
114 public Signature sign(InputStream contentStream, String certificateName,
115 String password, String contentType) throws IOException,
116 SignatureException {
117 synchronized (lock){
118 boolean recognized = properties.needsRecognizedCertificate(contentType);
119 boolean timeStamp = properties.needsTimeStamp(contentType);
120 boolean rawSign = properties.needsRawSignature(contentType);
121 SignerProviderInterface signer = getSigner (certificateName, contentType);
122
123 if( SigDebug.isActive() ) SigDebug.write( "Comprovacio password null." );
124 if( password == null ) {
125 if( SigDebug.isActive() ) SigDebug.write( "Posem el password a cadena buida." );
126 password = "";
127 }
128 if( SigDebug.isActive() ) {
129 SigDebug.write( "CAIBSigned.sign: password " + (password.length() == 0? "es" : "no es") + " buit." );
130 }
131 return signer.sign(contentStream, certificateName, password, contentType, recognized, timeStamp, rawSign);
132 }
133 }
134
135 public Signature sign(URL url, String certificateName, String password, String contentType)
136 throws IOException, SignatureException
137 {
138 return sign (url.openStream(), certificateName, password, contentType);
139 }
140
141
142 public void signPDF(InputStream contentStream, OutputStream signedStream,
143 String certificateName, String password, String contentType, String url, int position)
144 throws IOException, SignatureException {
145 synchronized (lock){
146 boolean recognized = properties.needsRecognizedCertificate(contentType);
147 SignerProviderInterface signer = getSigner (certificateName, contentType);
148
149 if( SigDebug.isActive() ) SigDebug.write( "Comprovacio password null." );
150 if( password == null ) {
151 if( SigDebug.isActive() ) SigDebug.write( "Posem el password a cadena buida." );
152 password = "";
153 }
154 if( SigDebug.isActive() ) {
155 SigDebug.write( "CAIBSigned.sign: password " + (password.length() == 0? "es" : "no es") + " buit." );
156 }
157 signer.signPDF(contentStream, signedStream, certificateName, password, contentType, recognized, url, position);
158 }
159 }
160
161 public OutputStream signPDF(InputStream contentStream,
162 String certificateName, String password, String contentType, String url, int position)
163 throws IOException, SignatureException {
164 OutputStream out = new ByteArrayOutputStream();
165 signPDF(contentStream, out, certificateName, password, contentType, url, position);
166 return out;
167 }
168
169
170
171
172 public boolean verify(InputStream contentStream, Signature signatureData)
173 throws SignatureProviderException, IOException, SignatureVerifyException
174 {
175 try{
176 boolean isVerified = false;
177 isVerified = signatureData.verify(contentStream);
178 return isVerified;
179 } catch(SignatureVerifyException e){
180 throw e;
181 } catch(Exception e){
182 throw new SignatureVerifyException(e);
183 }
184 }
185
186 public boolean verifyAPosterioriTimeStamp(InputStream contentStream, Signature signatureData)
187 throws SignatureProviderException, IOException, SignatureVerifyException
188 {
189 boolean isVerified = false;
190 try{
191 isVerified = signatureData.verifyAPosterioriTimestamp(contentStream);
192 }catch(SignatureVerifyException e){
193 throw e;
194 } catch(Exception e){
195 throw new SignatureVerifyException(e);
196 }
197 return isVerified;
198 }
199
200 public boolean verify(String fileName, Signature signatureData)
201 throws FileNotFoundException, SignatureProviderException, IOException, SignatureVerifyException
202 {
203 return verify( new FileInputStream(fileName) ,signatureData);
204 }
205
206 public boolean verify(URL url, Signature signatureData)
207 throws SignatureProviderException, IOException, SignatureVerifyException
208 {
209 return verify( url.openStream() ,signatureData);
210 }
211
212
213
214
215
216 public boolean verifyAPosterioriTimeStamp(String fileName, Signature signatureData)
217 throws FileNotFoundException, SignatureProviderException, IOException, SignatureVerifyException
218 {
219 return verifyAPosterioriTimeStamp(new FileInputStream(fileName), signatureData);
220 }
221
222 public boolean verifyAPosterioriTimeStamp(URL url, Signature signatureData)
223 throws SignatureProviderException, IOException, SignatureVerifyException
224 {
225 return verifyAPosterioriTimeStamp(url.openStream(), signatureData);
226 }
227
228
229
230
231
232
233 public void generateSMIME(InputStream document, Signature signature,
234 OutputStream smime) throws IOException {
235 SMIMEGenerator smimeGenerator;
236 try {
237 Class c = factory.getMasterClassLoader().loadClass("es.caib.signatura.provider.impl.common.SMIMEGeneratorImpl");
238 smimeGenerator = (SMIMEGenerator)c.newInstance();
239 }
240 catch(Exception e){
241 throw new RuntimeException (e);
242 }
243
244 InputStream in = smimeGenerator.generateSMIME(document,signature);
245
246 byte b []= new byte [8192];
247 int read;
248 while ( (read = in.read(b)) > 0)
249 {
250 smime.write(b, 0, read);
251 }
252 in.close();
253 }
254
255
256
257 public void generateSMIMEParalell(InputStream document, Signature[] signatures, OutputStream smime) throws IOException, SignatureException {
258
259 try {
260
261 Class c = factory.getMasterClassLoader().loadClass("es.caib.signatura.provider.impl.common.GeneradorSMIMEParaleloImpl");
262 GeneradorSMIMEParalelo generadorSMIMEParalelo = (GeneradorSMIMEParalelo)c.newInstance();
263 SMIMEInputStream in = generadorSMIMEParalelo.generarSMIMEParalelo(document,signatures);
264
265 byte b[] = new byte[8192];
266 int read;
267 while ( (read=in.read(b) ) > 0) {
268 smime.write(b,0,read);
269 }
270 in.close();
271
272 }catch (IOException iox) {
273 throw iox;
274 }catch (Exception e) {
275 throw new SignatureException(e.getMessage());
276 }
277 }
278
279
280
281 public Date getCurrentDate(String certificateName, String password,
282 String contentType) throws SignatureTimestampException,
283 SignatureException, IOException {
284 if( password == null ) password = "";
285 if( SigDebug.isActive() ) {
286 SigDebug.write( "CAIBSigned.getCurrentDate: password " + (password.length() == 0? "es" : "no es") + " buit." );
287 }
288 boolean recognized = properties.needsRecognizedCertificate(contentType);
289
290 return getSigner(certificateName, contentType).getCurrentDate(certificateName, password, recognized);
291 }
292
293 public CAIBSigner () throws FileNotFoundException {
294 this(null);
295 }
296
297 public CAIBSigner (Map signerConfiguration) throws FileNotFoundException
298 {
299
300 CAIBSecurityManager.register();
301
302 if (factory == null) {
303 factory = ClassLoaderFactory.getFactory ();
304 realSigners = new LinkedHashMap ();
305 }
306
307
308 try{
309 if(Security.getProvider("BC") == null){
310 ClassLoader c = factory.getFactory().getMasterClassLoader();
311 Provider p = (Provider) factory.getFactory().getMasterClassLoader().loadClass("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance();
312 Security.addProvider(p);
313 }
314 }catch(Exception e){
315 throw new RuntimeException (e);
316 }
317
318
319 try {
320 if (signerConfiguration == null) {
321 properties = new SignaturaProperties();
322 }
323 else {
324 properties = new SignaturaProperties(signerConfiguration);
325 }
326 } catch (Exception e1) {
327 throw new RuntimeException (e1);
328 }
329
330
331
332
333 if( SigDebug.getLevel() == SigDebug.DEBUG_LEVEL_NONE ) {
334 SigDebug.setLevel( properties.getProperty("debugLevel") );
335 }
336
337 if(System.getProperty("es.caib.provider.unactive")==null || System.getProperty("es.caib.provider.unactive").indexOf("tradise")==-1){
338
339 try {
340 addTradiseSigner( "tradise");
341 SigDebug.write( "[DBG] ACTIVAT TRADISE." );
342 } catch (FileNotFoundException e) {
343
344 }catch (Exception e) {
345 e.printStackTrace();
346 }
347
348 File dirDev = new File (factory.getLibraryDir(), "tradise-dev");
349 if (dirDev.isDirectory())
350 {
351 try {
352 addTradiseSigner( "tradise-dev");
353 SigDebug.write( "[DBG] ACTIVAT TRADISE TEST." );
354 } catch (Exception e) {
355 e.printStackTrace();
356 }
357 }
358 }
359
360
361
362 if(System.getProperty("es.caib.provider.unactive")==null || System.getProperty("es.caib.provider.unactive").indexOf("PKCS11")==-1){
363 String drivers []= properties.getPKCS11Drivers();
364 for (int i = 0; i < drivers.length; i++)
365 {
366 addPKCS11Signer(drivers[i]);
367 SigDebug.write( "[DBG] ACTIVAT PKCS11 "+drivers[i]+"." );
368 }
369 }
370
371
372 if(System.getProperty("es.caib.provider.unactive")==null || System.getProperty("es.caib.provider.unactive").indexOf("MSCRYPTOAPI")==-1){
373 try{
374 addMscryptoapiSigner();
375 SigDebug.write( "[DBG] ACTIVAT MSCRYPTOAPI." );
376 }
377 catch (Exception e){
378 e.printStackTrace();
379 }
380 }
381
382 if(System.getProperty("es.caib.provider.unactive")==null || System.getProperty("es.caib.provider.unactive").indexOf("BC")==-1){
383 try {
384 addBcCryptoApiSigner();
385 SigDebug.write( "[DBG] ACTIVAT BC." );
386 } catch (Exception e) {
387 if(e instanceof FileNotFoundException && System.getProperty("caib-crypto-keystore")==null){
388 SigDebug.write( "[DBG] El usuario no tiene keystore por defecto para el BcCryptoApiSigner." );
389 }else{
390 e.printStackTrace();
391 }
392 }
393 }
394 }
395
396 private void addPKCS11Signer (String libraryName)
397 {
398 File f = new File (libraryName);
399 if ( f.isAbsolute())
400 {
401 String name = f.getName();
402 if (realSigners.get(name) == null)
403 {
404 addPKCS11Signer (name, f);
405 }
406 } else {
407 if (realSigners.get(libraryName) == null)
408 {
409 String path = System.getProperty("java.library.path");
410 StringTokenizer tokenizer = new StringTokenizer (path, File.pathSeparator);
411 while (tokenizer.hasMoreTokens())
412 {
413 File next = new File( tokenizer.nextToken() );
414 f = new File (next, libraryName);
415 if (addPKCS11Signer (libraryName, f))
416 return;
417 f = new File (next, libraryName+".dll") ;
418 if (addPKCS11Signer (libraryName, f))
419 return;
420 }
421 }
422 }
423 }
424
425 private boolean addPKCS11Signer(String libraryName, File f) {
426 if (f.canRead())
427 {
428 String providerName = properties.getPKCS11DriversDescription(libraryName);
429 try {
430 File cfg = File.createTempFile(libraryName, "pkcs11.cfg");
431 PrintWriter writer = new PrintWriter (new FileWriter (cfg));
432 writer.println("name="+libraryName);
433 writer.println("library="+f.getAbsolutePath());
434 writer.close();
435 cfg.deleteOnExit();
436 Class c = factory.getMasterClassLoader().loadClass("es.caib.signatura.provider.impl.pkcs11.PKCS11Signer");
437 Constructor constructor = c.getConstructor(new Class [] {String.class,String.class});
438 realSigners.put(libraryName, constructor.newInstance(new Object [] {cfg.getAbsolutePath(),providerName}));
439 return true;
440 } catch (Throwable e) {
441
442 return false;
443 }
444 }
445 else
446 return false;
447 }
448
449 private void addTradiseSigner (String name) throws ClassNotFoundException, InstantiationException, IllegalAccessException, FileNotFoundException
450 {
451
452 if (realSigners.get(name) == null)
453 {
454 ClassLoader loader = factory.getClassLoader(name);
455 Class c = loader.loadClass("es.caib.signatura.provider.impl.tradise.TradiseSigner");
456 realSigners.put(name, c.newInstance());
457 }
458
459 }
460
461 public String getAPIVersion()
462 {
463 try {
464 InputStream inputStream = CAIBSigner.class.getResourceAsStream("version.properties");
465 if (inputStream==null)
466 {
467 throw new FileNotFoundException();
468 }
469 Properties tempProperties = new Properties();
470 tempProperties.load(inputStream);
471
472 inputStream.close();
473 return tempProperties.getProperty("Version");
474 } catch (FileNotFoundException e) {
475 throw new RuntimeException (e);
476 } catch (IOException e) {
477 throw new RuntimeException (e);
478 }
479 }
480
481 private void addBcCryptoApiSigner() throws ClassNotFoundException, InstantiationException, IllegalAccessException
482 {
483 Class c = factory.getMasterClassLoader().loadClass("es.caib.signatura.provider.impl.bccryptoapi.BcCryptoApiSigner");
484 realSigners.put("bccryptoapi", c.newInstance());
485 if ( SigDebug.isActive() ) SigDebug.write("CAIBSigner: addBcCryptoApiSigner: Cargados los certificados del keystore");
486 }
487
488
489
490
491
492
493
494 private void addMscryptoapiSigner ()
495 {
496 try{
497 String libraryName = System.getProperty("java.home")+"\\lib\\signaturacaib\\mscryptofunctions.dll";
498 if( SigDebug.isActive() ) SigDebug.write("CAIBSigner: addMscryptoapiSigner: Path mscryptofunctions = " + libraryName);
499 File f = new File (libraryName);
500 if (f.canRead()){
501 Class c = factory.getMasterClassLoader().loadClass("es.caib.signatura.provider.impl.mscryptoapi.MscryptoapiSigner");
502 realSigners.put("mscryptoapi", c.newInstance());
503 if( SigDebug.isActive() ) SigDebug.write("CAIBSigner: addMscryptoapiSigner: Cargada mscryptofunctions.dll");
504 return;
505 }
506
507 } catch(Exception e) {
508 e.printStackTrace();
509 System.out.println("No se puede cargar la biblioteca mscryptofunctions.dll");
510 return;
511 }
512 }
513
514
515
516 public SMIMEParser getSMIMEParser(InputStream smime) throws InstantiationException, IllegalAccessException, IOException, SignatureException {
517 return new SMIMEParserProxy(smime);
518 }
519
520 public ParsedCertificate parseCertificate(X509Certificate certificate) {
521 try {
522 Class c = factory.getMasterClassLoader().loadClass("es.caib.signatura.provider.impl.common.ParsedCertificateImpl");
523 Constructor constructor = c.getConstructor(new Class [] {X509Certificate[].class, boolean.class});
524
525
526 return (ParsedCertificate) constructor.newInstance(new Object [] {new X509Certificate[] {certificate}, new Boolean(false)});
527 } catch (Exception e) {
528 throw new RuntimeException(e);
529 }
530 }
531
532 }
533
534