Java 7, HttpClient e il debole algoritmo di firma MD2: Certificates does not conform to algorithm constraints

L’algoritmo di firma RSA-MD2 è ritenuto debole, e viene sconsigliato. Questo è il motivo per cui l’installazione base del jre di Java 7 lo disabilita di default. Questa impostazione è nel file

java.security

che si trova nella cartella JRE_HOME/lib/security

nella riga

jdk.certpath.disabledAlgorithms=MD2

Ma se ci si deve collegare ad un server che espone un certificato firmato in quel modo, si possono avere dei problemi. Ecco la mia storia:

Utilizzando la libreria HttpClient 4.1.2 di Apache, mi sono imbattuto in questa situazione: il codice che esegue una Post sotto ssl funziona se lanciato all’interno dell’ambiente di sviluppo (Eclipse nella fattispecie), ma restituisce un l’errore:

peer not authenticated

se lanciato da riga di comando dal runnable jar generato.

Il codice è il seguente:

HttpClient httpclient = new DefaultHttpClient();
 
    	// creo un TrustManager per considerare tutti i certificati validi, anche se non sono installati sulla macchina		
		X509TrustManager tm = new X509TrustManager() {
    			public java.security.cert.X509Certificate[] getAcceptedIssuers() {
    			return null;
    			}
    			public void checkClientTrusted(
    			java.security.cert.X509Certificate[] certs, String authType) {
    			}
    			public void checkServerTrusted(
    			java.security.cert.X509Certificate[] certs, String authType) {
    			}
		};    	
		try {
	    	// Creo il contesto SSL utilizzando i trust manager creati			
			SSLContext ctx = SSLContext.getInstance("TLS");
			ctx.init(null, new TrustManager[]{tm}, null);
 
			// Creo la connessione https
			SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);			
			ClientConnectionManager ccm = httpclient.getConnectionManager();
			SchemeRegistry sr = ccm.getSchemeRegistry();
			sr.register(new Scheme("https", 443, ssf));
			httpclient = new DefaultHttpClient(ccm, httpclient.getParams());
 
                        HttpPost post = new HttpPost(properties.getXpayAPIurl());
 
                        ...
                        String xml = "..." // Un xml di cui fare il Post     		
               		StringEntity se = new StringEntity(xml);
    		        se.setContentType("application/xml");
 
			post.setEntity(se);
 
			HttpResponse response = httpclient.execute(post);
         	    	HttpEntity entity = response.getEntity();	
	                if (entity != null) {
	         	   repres.setXml(EntityUtils.toString(entity));
          	        }	
                       ...

Per capire il problema ho abilitato il debug ssl a console, impostando le proprietà:

	 	   System.setProperty("javax.net.ssl.debug", "all");
	 	   System.setProperty("javax.net.debug", "all");

L’output del debug ssl termina in questo modo:

main, handling exception: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
main, IOException in getSession():  javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: Certificates does not conform to algorithm constraints

Questo codice funziona da Eclipse perchè Eclipse utilizza un jre (il 6) diverso da quello utilizzato invece dalla riga di comando, che è invece il 7. Commentando la riga indicata nel file indicato, il problema scompare e il cliente considera valido il certificato firmato con questo algoritmo.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>