View Javadoc

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  		//TODO:check nulll
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  	//						System.err.println ("Provider "+s.getClass().getName());
94  	//						e.printStackTrace();
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 	 * Función principal de verificación de firma
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 	 * Funcions de verificacio a posteriori.
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 	 * Altres funcions.
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 		//TODO: check nulls
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 		// Si ningu no ha posat el nivell primer, posem el que hi hagi al fitxer
332 		// de properties, sino, deixem el que hi ha.
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 					//quan no est� instal.lat
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 		//SigDebug.write( "[DBG] Desactivat API microsoft per provar PKCS11." );
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 		//Jesus Reyes. Carga de MscryptoapiSigners
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 //				e.printStackTrace ();
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 	 * Añade mscryptoapi como proveedor de firma de la CAIB. Sólo se hace si se puede cargar la biblioteca dinámica mscryptofunctions.dll,
491 	 * que debe estar en el directorio JAVA_HOME\lib\signaturacaib\ del PC con windows del usuario
492 	 * @author Jesus Reyes (3digits)
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 		  // El ParsedCertificateImp que retornem, sempre estará com si
525 		  // no estigués en un dispositiu segur.
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