From 6ccbc9791369440bef65a136c7c30ae3a33b8534 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 29 Oct 2015 15:58:12 +0100 Subject: [PortScan] Try to verify remote certificate --- .../org/openslx/taskmanager/tasks/PortScan.java | 87 ++++++++++++++++++---- 1 file changed, 73 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/main/java/org/openslx/taskmanager/tasks/PortScan.java b/src/main/java/org/openslx/taskmanager/tasks/PortScan.java index b525df6..edc9e36 100644 --- a/src/main/java/org/openslx/taskmanager/tasks/PortScan.java +++ b/src/main/java/org/openslx/taskmanager/tasks/PortScan.java @@ -1,16 +1,22 @@ package org.openslx.taskmanager.tasks; +import java.io.File; +import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.io.FileUtils; import org.openslx.satserver.util.Exec; import org.openslx.taskmanager.api.AbstractTask; @@ -22,9 +28,15 @@ public class PortScan extends AbstractTask private String host; @Expose private int[] ports; + @Expose + private String certificate; private Output status = new Output(); + private String certFile = null; + + private static final Pattern verifyPattern = Pattern.compile( "^\\s*verify return code:\\s+(\\d+)(\\D|$)", Pattern.CASE_INSENSITIVE );; + @Override protected boolean initTask() { @@ -44,13 +56,29 @@ public class PortScan extends AbstractTask @Override protected boolean execute() { - ExecutorService tp = Executors.newFixedThreadPool( ports.length > 6 ? 6 : ports.length ); + // Create usable cert file if possible + File tmpFile = null; + if ( certificate == null || certificate.isEmpty() || certificate.equals( "default" ) ) { + certFile = CreateLdapConfig.DEFAULT_CA_BUNDLE; + } else { + try { + tmpFile = File.createTempFile( "bwlp-", ".pem" ); + FileUtils.writeStringToFile( tmpFile, certificate, StandardCharsets.UTF_8 ); + } catch ( IOException e ) { + status.addMessage( "Error creating temporary file for certificate: " + e.getMessage() ); + return false; + } + certFile = tmpFile.getAbsolutePath(); + } + // Execute scan in parallel (4 tasks) to speed things up + ExecutorService tp = Executors.newFixedThreadPool( ports.length > 4 ? 4 : ports.length ); + final List results = new ArrayList<>(); for ( final int port : ports ) { tp.submit( new Callable() { @Override public Object call() throws Exception { - status.ports.add( testPort( port ) ); + results.add( testPort( port ) ); return null; } } ); @@ -61,6 +89,10 @@ public class PortScan extends AbstractTask } catch ( InterruptedException e ) { // ... } + if ( tmpFile != null ) { + tmpFile.delete(); + } + status.ports = results; return true; } @@ -69,34 +101,55 @@ public class PortScan extends AbstractTask boolean open = false; final AtomicReference fingerprint = new AtomicReference<>(); final AtomicReference notAfter = new AtomicReference<>(); - final StringBuffer sb = new StringBuffer(); + final AtomicInteger verifyResult = new AtomicInteger( -1 ); + final StringBuffer messages = new StringBuffer(); + final StringBuffer certList = new StringBuffer(); try { Socket sock = new Socket(); sock.connect( new InetSocketAddress( this.host, port ), 1200 ); open = true; - sb.append( "Found open port " + port ); + messages.append( "Found open port " + port ); sock.close(); } catch ( Exception e ) { if ( !open ) { - sb.append( "Found closed port " + port ); + messages.append( "Found closed port " + port ); } } if ( open ) { String str = this.host.replaceAll( "[^a-zA-Z0-9\\.\\-_]", "" ) + ":" + port; // Is open, see if it is running SSL - Exec.syncAt( 2, new Exec.ExecCallback() { + Exec.syncAt( 4, new Exec.ExecCallback() { + private boolean inCert = false; @Override public void processStdOut( String line ) { if ( line.startsWith( "notAfter=" ) ) { notAfter.set( line.substring( 9 ) ); - sb.append( "\nCertificate valid until " + notAfter.get() ); + messages.append( "\nCertificate valid until " + notAfter.get() ); } if ( line.startsWith( "SHA1 Fingerprint=" ) ) { fingerprint.set( line.substring( 17 ) ); - sb.append( "\nCertificate fingerprint: " + fingerprint.get() ); + messages.append( "\nCertificate fingerprint: " + fingerprint.get() ); + } + if ( !inCert && line.equals( "-----BEGIN CERTIFICATE-----" ) ) { + inCert = true; + } + if ( inCert ) { + if ( line.equals( "-----END CERTIFICATE-----" ) ) { + inCert = false; + } + certList.append( line ); + certList.append( '\n' ); + } + Matcher m; + if ( verifyResult.get() == -1 && null != ( m = verifyPattern.matcher( line ) ) && m.find() ) { + try { + verifyResult.set( Integer.parseInt( m.group( 1 ) ) ); + } catch ( Exception e ) { + } + messages.append( "\nVerify result: " + verifyResult.get() ); } } @@ -107,11 +160,12 @@ public class PortScan extends AbstractTask } }, "/", "/bin/sh", "-c", - "openssl s_client -showcerts -connect " + str + " /dev/null " + "openssl s_client -CAfile '" + certFile + "' -showcerts -connect " + str + " /dev/null; " + + "openssl s_client -connect " + str + " /dev/null " + " | openssl x509 -noout -enddate -fingerprint -sha1 2>&1" ); } - status.addMessage( sb.toString() ); - return new Result( port, open, fingerprint.get(), notAfter.get() ); + status.addMessage( messages.toString() ); + return new Result( port, open, fingerprint.get(), notAfter.get(), verifyResult.get(), certList.toString() ); } /** @@ -120,7 +174,8 @@ public class PortScan extends AbstractTask private static class Output { protected String messages = null; - protected List ports = Collections.synchronizedList( new ArrayList() ); + @SuppressWarnings( "unused" ) + protected List ports = null; private void addMessage( String str ) { @@ -139,13 +194,17 @@ public class PortScan extends AbstractTask protected final boolean open; protected final String certFingerprint; protected final String notAfter; + protected final int verifyResult; + protected final String certificateChain; - public Result( int port, boolean open, String fingerprint, String notAfter ) + public Result( int port, boolean open, String fingerprint, String notAfter, int verifyResult, String certificateChain ) { this.port = port; this.open = open; this.certFingerprint = fingerprint; this.notAfter = notAfter; + this.verifyResult = verifyResult; + this.certificateChain = certificateChain; } } -- cgit v1.2.3-55-g7522