View Javadoc

1   package es.caib.signatura.impl;
2   
3   import java.io.*;
4   import java.lang.reflect.Constructor;
5   import java.security.InvalidKeyException;
6   import java.security.NoSuchAlgorithmException;
7   import java.security.NoSuchProviderException;
8   import java.security.SignatureException;
9   import java.security.cert.CertificateException;
10  import java.security.cert.CertificateExpiredException;
11  import java.security.cert.CertificateNotYetValidException;
12  import java.security.cert.X509Certificate;
13  import java.util.Collection;
14  import java.util.Iterator;
15  import java.util.List;
16  
17  import es.caib.signatura.api.CertificateVerifyException;
18  import es.caib.signatura.api.ParsedCertificate;
19  import es.caib.signatura.api.SignatureProviderException;
20  import es.caib.signatura.api.SignatureVerifyException;
21  import es.caib.signatura.api.Certificate;
22  
23  public class CertificateImpl implements Certificate {
24  	private X509Certificate[] certificateChain = null;
25  	
26  	/*
27  	 * Constructora de la clase
28  	 */
29  	public CertificateImpl(X509Certificate[] certificateChain){
30  		this.certificateChain = certificateChain;
31  	}
32  	
33  	/**
34  	 * Obtiene el nombre de la entidad certificadora
35  	 * @return nombre de la entidad certificadora
36  	 */
37  	  public String getCertCaName(){
38  		if(certificateChain == null || certificateChain.length == 0){
39  			throw new Error("No se encuentra cadena de certificación.");
40  		}
41  		return certificateChain[certificateChain.length-1].getSubjectX500Principal().getName();
42  	  }
43  
44  	/**
45  	 * Obtiene el nombre del certificado
46  	 * @return nombre del certificado (CommonName)
47  	 */
48  
49  	  public String getCertSubjectCommonName(){
50  		  ParsedCertificate Parsed = this.getParsedCertificate();
51  		  return(Parsed.getName());
52  	  }
53  
54  	/**
55  	 * Obtiene la concatenación del SubjectAlternateName del certificado del usuario en la forma
56  	 * nombre0 = valor, nombre1 = valor, ...
57  	 * @return cadena con el SubjectAlternateName del certificado del usuario
58  	 */
59  
60  	  public String getCertSubjectAlternativeNames(){
61  		  StringBuffer altNameSB = new StringBuffer("");
62  			String altNameString = null;
63  			try {
64  				Collection generalNames = certificateChain[0].getSubjectAlternativeNames();
65  				Iterator itr = generalNames.iterator();
66  				while (itr.hasNext()) {
67  					List list = (List) itr.next();
68  
69  					int tagNo = ((Integer) list.get(0)).intValue();
70  					switch (tagNo) {
71  					case 0:
72  						altNameSB.append("," + "otherName=");
73  						break;
74  
75  					case 1:
76  						altNameSB.append("," + "rfc822Name=");
77  						break;
78  
79  					case 2:
80  						altNameSB.append("," + "dNSName=");
81  						break;
82  
83  					case 3:
84  						altNameSB.append("," + "x400Address=");
85  						break;
86  
87  					case 4:
88  						altNameSB.append("," + "directoryName=");
89  						break;
90  
91  					case 5:
92  						altNameSB.append("," + "ediPartyName=");
93  						break;
94  
95  					case 6:
96  						altNameSB.append("," + "uniformResourceIdentifier=");
97  						break;
98  
99  					case 7:
100 						altNameSB.append("," + "iPAddress=");
101 						break;
102 
103 					case 8:
104 						altNameSB.append("," + "registeredID=");
105 						break;
106 
107 					}
108 					altNameSB.append(list.get(1).toString());
109 
110 					// Quitamos la coma del principio
111 					if (altNameSB.length() > 0) {
112 						altNameString = altNameSB.substring(1, altNameSB.length());
113 					}
114 
115 				}
116 			}
117 
118 			catch (Exception ex) {
119 				return null;
120 			}
121 
122 			return altNameString;
123 	  }
124 
125 
126 	  /**
127 	   * Devuelve el certificado X509 
128 	   * @return X509Certificate
129 	   */  
130 	  public X509Certificate getCert(){
131 		  return certificateChain[0];
132 	  }
133 	  
134 	  /**
135 	   * Devuelve el Seycon Principal a partir del certificado
136 	   * @return SeyconPrincipal
137 	   */  
138 	  public ParsedCertificate getParsedCertificate(){
139 		try {
140 			ClassLoader cl = ClassLoaderFactory.getFactory().getMasterClassLoader();
141 			Class clazz = cl .loadClass( "es.caib.signatura.provider.impl.common.ParsedCertificatImpl" );
142 			Constructor constructor = clazz.getConstructor(new Class[] {certificateChain.getClass(), Boolean.TYPE});
143 			ParsedCertificate parsed = (ParsedCertificate) constructor.newInstance(new Object [] {certificateChain, new Boolean(false)});
144 			return new ParsedCertificateProxy (parsed);
145 		} catch (Exception e) {
146 			throw new RuntimeException(e);
147 		}
148 	  }
149 	  
150 	  /**
151 	   * 
152 	   * Verifica el certificado y su cadena de certificación 
153 	   * @param contentStream flujo de bytes del certificado original
154 	   * @return <code>true</code> si la verificación es correcta y <code>false</code> en caso contrario
155 	   * @throws SignatureProviderException  si no se ha podido acceder a la API del proveedor de firma electrónica
156 	   * @throws IOException  si no se ha podido acceder al fichero o si no se ha podido contactar con
157 	   * el servidor de sello de tiempo
158 	   * @throws SignatureVerifyException  si no se ha podido realizar el proceso de verificación
159 	   */
160 	  	public boolean verify()
161 	            throws IOException, CertificateVerifyException{
162 	  		boolean isValid = true;
163 	  		isValid = isValid && verifyCertificateChain();
164 	  		if(!isValid){
165 	  			/*
166 	  			 * Podría darse el caso que la cadena de certificación estuviera invertida
167 	  			 */
168 	  			invertCertificateChain();
169 	  			isValid = isValid && verifyCertificateChain();
170 	  			if(!isValid){
171 	  				/*
172 	  				 * Si no es válida la cadena de certificación una vez invertida se asume
173 	  				 * que la cadena de certificación original es la válida
174 	  				 */
175 	  				invertCertificateChain();
176 	  			}
177 	  		}
178 	  		return isValid;
179 	  	}
180 	  	
181 	  	/**
182 	  	 * Operación que invierte la cadena de certificación que contiene la clase 
183 	  	 */
184 		private void invertCertificateChain(){
185 			for(int i = 0;i < certificateChain.length / 2;i++){
186 				X509Certificate temporalCertificate = certificateChain[certificateChain.length - 1 - i];
187 				certificateChain[certificateChain.length - 1 - i] = certificateChain[i];
188 				certificateChain[i] = temporalCertificate;
189 			}
190 		}
191 		
192 	  /**
193 	   * 
194 	   * Verifica el certificado y su cadena de certificación 
195 	   * @param contentStream flujo de bytes del certificado original
196 	   * @return <code>true</code> si la verificación es correcta y <code>false</code> en caso contrario
197 	   * @throws SignatureProviderException  si no se ha podido acceder a la API del proveedor de firma electrónica
198 	   * @throws IOException  si no se ha podido acceder al fichero o si no se ha podido contactar con
199 	   * el servidor de sello de tiempo
200 	   * @throws SignatureVerifyException  si no se ha podido realizar el proceso de verificación
201 	   */
202 	  	private boolean verifyCertificateChain()
203 	            throws IOException, CertificateVerifyException{
204 	  		boolean isValid = true;
205 	  		/*
206 	  		 * verificación basada en fechas
207 	  		 */
208 	  		for(int i = 0;i < certificateChain.length && isValid;i++){
209 	  			try {
210 	  				certificateChain[i].checkValidity();
211 	  			} catch (CertificateExpiredException cee) {
212 	  				isValid = false;
213 	  			} catch (CertificateNotYetValidException cve) {
214 	  				isValid = false;
215 	  			}
216 	  		}	  		
217 	  		/*
218 	  		 * verificación de firmas
219 	  		 */
220 	  		for(int i = 0;(i < certificateChain.length - 1) && isValid;i++){	  			
221 	  				try {
222 						certificateChain[i].verify(certificateChain[i + 1].getPublicKey());
223 					} catch (InvalidKeyException e) {
224 						isValid = false;
225 					} catch (CertificateException e) {
226 						isValid = false;
227 					} catch (NoSuchAlgorithmException e) {
228 						throw new CertificateVerifyException(e);
229 					} catch (NoSuchProviderException e) {
230 						throw new CertificateVerifyException(e);
231 					} catch (SignatureException e) {
232 						isValid = false;
233 					}	  			
234 	  		}
235 	  		/*
236 	  		 * verificación mediante Web Services
237 	  		 * En dicha verificación se valida el certificado raiz
238 	  		 */
239 	  		try{
240 	  			isValid = isValid && verifyCertificateWebServices(certificateChain);
241 	  		}catch(Exception e){
242 	  			throw new CertificateVerifyException(e);
243 	  		}
244 	  		return isValid;
245 	  	}
246 	  	
247 	  	/*
248 	  	 * Validación mediante Web Services de la cadena de certificación
249 	  	 */
250 	  	private boolean verifyCertificateWebServices(X509Certificate[] certificateChain)throws CertificateVerifyException{
251 	  		/* TODO: commons-logging*/
252 	  		return true;
253 	  		/*
254 	  		String result = verifyWebServices(certificateChain);
255   			return WSResponseIsAVerifiedMessage(result);
256   			*/
257 	  	}
258 	  	
259 		/*
260 		 * Validación mediante Web Services de la cadena de certificación
261 		 */
262 	  	/*
263 		private String verifyWebServices(X509Certificate[] certificateChain) throws CertificateVerifyException{
264 			String toReturn = new String();
265 			try{
266 				URLClassLoader urlClassLoader = (URLClassLoader)ClassLoaderFactory.getFactory().getMasterClassLoader();
267 				Class c;			
268 				c = urlClassLoader.loadClass("es.caib.signatura.cliente.ValidadorCertificadosEmbedded");						
269 				Constructor constructor = c.getConstructor(new Class [] {});
270 				IValidadorCertificados iValidadorCertificados = (IValidadorCertificados)constructor.newInstance(new Object [] {});
271 				//ValidadorCertificadosEmbedded validadorCertificados = new ValidadorCertificadosEmbedded();
272 				toReturn = iValidadorCertificados.validarCertificadoParaFirma(certificateChain);
273 			} catch (Exception e) {
274 				throw new CertificateVerifyException(e);
275 			}
276 			return toReturn;
277 		}
278 	  	
279 		private boolean WSResponseIsAVerifiedMessage(String result) throws CertificateVerifyException {
280 			String content = new String();
281 			try {
282 				DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
283 				DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
284 				Document document;	    	  
285 				StringBufferInputStream inputStream = new StringBufferInputStream(result);
286 				document = documentBuilder.parse((InputStream)inputStream);	    	  
287 				//Element element = document.getDocumentElement();
288 				try{
289 					NodeList nodeList = document.getElementsByTagName("validado");
290 					Node node = nodeList.item(0);
291 					Element element = (Element) node;
292 					String tagName = element.getTagName();
293 					Node textData = null;
294 					boolean stop = false;
295 					NodeList nodeDataList = element.getChildNodes();				
296 					for(int i = 0;i < nodeDataList.getLength() && !stop;i++){
297 						textData = nodeDataList.item(i);
298 						stop = textData.getNodeType() == org.w3c.dom.Node.TEXT_NODE;						
299 					}
300 					content = ((org.w3c.dom.Text)textData).getData();
301 				}catch(Exception e){
302 					// Para no llevar a malos entendidos
303 					// se da la firma como falsa
304 					// 
305 					return false;
306 				}
307 				if(content == null){
308 					throw new Exception("No content in 'validado' TAG. Response message: " + result);
309 				}
310 			}catch(Exception e){
311 				throw new CertificateVerifyException(e);
312 			}
313 			return content.compareToIgnoreCase("true") == 0;
314 		}
315 	  	*/
316 
317 }