2013-08-05 9 views

Antwort

5

Ein weiteres Beispiel, das auf der Serverauthentifizierung basiert: TLS mit selbstsignierten Zertifikaten mit Client-Authentifizierung (ich zeige nur die geänderten Teile). Dies ist der Server-Teil:

tlsServerProtocol.accept(new DefaultTlsServer() { 
    protected TlsSignerCredentials getRSASignerCredentials() throws IOException { 
     return tlsSignerCredentials(context); 
    } 
    public void notifyClientCertificate(Certificate clientCertificate) throws IOException { 
     validateCertificate(clientCertificate); 
    } 
    public CertificateRequest getCertificateRequest() { 
     return new CertificateRequest(new short[] { ClientCertificateType.rsa_sign }, new Vector<Object>()); 
    } 
});   

Und dies ist der Client-Teil:

tlsClientProtocol.connect(new DefaultTlsClient() {    
    public TlsAuthentication getAuthentication() throws IOException { 
     return new TlsAuthentication() {      
      public void notifyServerCertificate(Certificate serverCertificate) throws IOException { 
       validateCertificate(serverCertificate); 
      } 
      public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException { 
       return tlsSignerCredentials(context); 
      } 
     }; 
    } 
}); 
10

Dies ist ein sehr einfaches Beispiel, mit Server-Authentifizierung nur und selbst signiertes Zertifikat. Der Code basiert auf BC 1,49, meist leightweight API:

ServerSocket serverSocket = new ServerSocket(SERVER_PORT); 
final KeyPair keyPair = ... 
final Certificate bcCert = new Certificate(new org.spongycastle.asn1.x509.Certificate[] { 
    new X509V3CertificateStrategy().selfSignedCertificateHolder(keyPair).toASN1Structure()}); 
while (true) { 
    Socket socket = serverSocket.accept(); 
    TlsServerProtocol tlsServerProtocol = new TlsServerProtocol(
    socket.getInputStream(), socket.getOutputStream(), secureRandom); 
    tlsServerProtocol.accept(new DefaultTlsServer() { 
     protected TlsSignerCredentials getRSASignerCredentials() throws IOException { 
      return tlsSignerCredentials(context); 
     }    
    });  
    new PrintStream(tlsServerProtocol.getOutputStream()).println("Hello TLS"); 
} 

wo

private TlsSignerCredentials tlsSignerCredentials(TlsContext context) throws IOException { 
    return new DefaultTlsSignerCredentials(context, bcCert, 
      PrivateKeyFactory.createKey(keyPair.getPrivate().getEncoded()));     
} 

Dies ist der Client-Code:

Socket socket = new Socket(<server IP>, SERVER_PORT); 
TlsClientProtocol tlsClientProtocol = new TlsClientProtocol( 
    socket.getInputStream(), socket.getOutputStream()); 
tlsClientProtocol.connect(new DefaultTlsClient() {   
    public TlsAuthentication getAuthentication() throws IOException { 
     return new ServerOnlyTlsAuthentication() {     
      public void notifyServerCertificate(Certificate serverCertificate) throws IOException { 
       validateCertificate(serverCertificate); 
      } 
     }; 
    } 
}); 
String message = new BufferedReader(
    new InputStreamReader(tlsClientProtocol.getInputStream())).readLine(); 

Sie müssen die Eingangs- und Ausgangsstrom verwenden, um von tlsClient/ServerProtocol zum Lesen und Schreiben verschlüsselter Daten (zB tlsClientProtocol.getInputStream()). Andernfalls, wenn Sie z.B. socket.getOutputStream() würden Sie nur unverschlüsselte Daten schreiben.

Wie validateCertificate zu implementieren? Ich verwende selbstsignierte Zertifikate. Das heißt, ich schaue sie einfach im Schlüsselspeicher ohne Zertifikatsketten an. Dies ist, wie ich den Schlüsselspeicher erstellen:

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
keyStore.load(null, password); 
X509Certificate certificate = ...; 
keyStore.setCertificateEntry(alias, certificate); 

Und dies ist die Validierung:

private void validateCertificate(org.spongycastle.crypto.tls.Certificate cert) throws IOException, CertificateException, KeyStoreException { 
    byte[] encoded = cert.getCertificateList()[0].getEncoded(); 
    java.security.cert.Certificate jsCert = 
     CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(encoded)); 
    String alias = keyStore.getCertificateAlias(jsCert); 
    if(alias == null) { 
     throw new IllegalArgumentException("Unknown cert " + jsCert); 
    } 
} 

Was eher verwirrend ist, sind die drei verschiedenen Zertifikatsklassen. Sie müssen zwischen ihnen wie oben gezeigt konvertieren.

6

Szenario: Unser Produktionsserver verwendet JDK1.6. Der Kundenserver wird jedoch aktualisiert, um nur in TLS 1.2 zu kommunizieren. SSL Die Kommunikation zwischen beiden Servern ist unterbrochen. Aber wir können JDK6 nicht einfach auf 8 upgraden (standardmäßig wird TLS 1.2 unterstützt), da dies zu Kompatibilitätsproblemen anderer Bibliotheken führt.

Der folgende Beispielcode verwendet jdk1.6.0_45 und bcprov-jdk15on-153.jar (Bouncy Castle signierte JAR-Dateien) zum Herstellen einer Verbindung zu einem beliebigen Server mit TLS.

import java.io.IOException; 
import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.net.Socket; 

import org.bouncycastle.crypto.tls.CertificateRequest; 
import org.bouncycastle.crypto.tls.DefaultTlsClient; 
import org.bouncycastle.crypto.tls.TlsAuthentication; 
import org.bouncycastle.crypto.tls.TlsClientProtocol; 
import org.bouncycastle.crypto.tls.TlsCredentials; 

public class TestHttpClient { 
    // Reference: http://boredwookie.net/index.php/blog/how-to-use-bouncy-castle-lightweight-api-s-tlsclient/ 
    //   bcprov-jdk15on-153.tar\src\org\bouncycastle\crypto\tls\test\TlsClientTest.java 
    public static void main(String[] args) throws Exception { 
     java.security.SecureRandom secureRandom = new java.security.SecureRandom(); 
     Socket socket = new Socket(java.net.InetAddress.getByName("www.google.com"), 443); 
     TlsClientProtocol protocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(),secureRandom); 
     DefaultTlsClient client = new DefaultTlsClient() { 
      public TlsAuthentication getAuthentication() throws IOException { 
       TlsAuthentication auth = new TlsAuthentication() { 
        // Capture the server certificate information! 
        public void notifyServerCertificate(org.bouncycastle.crypto.tls.Certificate serverCertificate) throws IOException { 
        } 

        public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException { 
         return null; 
        } 
       }; 
       return auth; 
      } 
     }; 
     protocol.connect(client); 

     java.io.OutputStream output = protocol.getOutputStream(); 
     output.write("GET/HTTP/1.1\r\n".getBytes("UTF-8")); 
     output.write("Host: www.google.com\r\n".getBytes("UTF-8")); 
     output.write("Connection: close\r\n".getBytes("UTF-8")); // So the server will close socket immediately. 
     output.write("\r\n".getBytes("UTF-8")); // HTTP1.1 requirement: last line must be empty line. 
     output.flush(); 

     java.io.InputStream input = protocol.getInputStream(); 
     BufferedReader reader = new BufferedReader(new InputStreamReader(input)); 
     String line; 
     while ((line = reader.readLine()) != null) 
     { 
      System.out.println(line); 
     } 
    } 
} 

Beispielausgabe zeigt, dass JDK 6 die Server-Seite in TLS erhalten können, anstatt einige SSL Ausnahme:

HTTP/1.1 302 Found 
Cache-Control: private 
Content-Type: text/html; charset=UTF-8 
Location: https://www.google.com.sg/?gfe_rd=cr&ei=WRgeVovGEOTH8Afcx4XYAw 
Content-Length: 263 
Date: Wed, 14 Oct 2015 08:54:49 GMT 
Server: GFE/2.0 
Alternate-Protocol: 443:quic,p=1 
Alt-Svc: quic="www.google.com:443"; p="1"; ma=600,quic=":443"; p="1"; ma=600 
Connection: close 

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"> 
<TITLE>302 Moved</TITLE></HEAD><BODY> 
<H1>302 Moved</H1> 
The document has moved 
<A HREF="https://www.google.com.sg/?gfe_rd=cr&amp;ei=WRgeVovGEOTH8Afcx4XYAw">here</A>. 
</BODY></HTML> 
+0

ich mit Java stecke 5 und versuchen, diese Arbeit durch BouncyCastle zu bekommen, aber der Code gibt Exception für eine andere URL: "Interner TLS-Fehler, dies könnte ein Angriff sein", irgendeine Idee, wie man es löst? – Saky