26

BouncyCastle を使用した TLS の例を知っている人はいますか? インターネット上にそれらがないことに驚きました。本当に無いなら回答として集めましょう。

4

3 に答える 3

15

これは、サーバーのみの認証と自己署名証明書を使用した非常に基本的な例です。コードは BC 1.49 に基づいており、ほとんどが軽量 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");
}

どこ

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

これはクライアント コードです。

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();

暗号化されたデータを読み書きするには、tlsClient/ServerProtocol からの入力ストリームと出力ストリームを使用する必要があります (tlsClientProtocol.getInputStream() など)。それ以外の場合、たとえば socket.getOutputStream() を使用すると、暗号化されていないデータを書き込むだけになります。

検証証明書を実装するには? 自己署名証明書を使用しています。これは、証明書チェーンなしでキーストアでそれらを検索することを意味します。これは私がキーストアを作成する方法です:

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

そして、これは検証です:

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);
    }
}

かなり紛らわしいのは、3 つの異なる Certificate クラスです。上記のように、それらの間で変換する必要があります。

于 2013-08-09T17:25:01.187 に答える
9

シナリオ: 実動サーバーは JDK1.6 を使用しています。ただし、お客様のサーバーは TLS 1.2 でのみ通信するようにアップグレードされています。両方のサーバー間の SSL 通信が切断されています。しかし、JDK6 を 8 (デフォルトで TLS 1.2 をサポートしている) に単純にアップグレードすることはできません。これは、他のライブラリの互換性の問題を引き起こすためです。

次のサンプル コードでは、jdk1.6.0_45 および bcprov-jdk15on-153.jar (Bouncy Castle SIGNED JAR FILES) を使用して、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);
        }
    }
}

サンプル出力は、JDK 6 が一部の SSL 例外ではなく、TLS でサーバー ページを取得できることを示しています。

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>
于 2015-10-14T10:04:21.057 に答える
7

サーバーのみの認証回答の上に構築されたもう1つの例:クライアント認証を使用した自己署名証明書を使用したTLS(変更された部分のみを示しています)。これはサーバー部分です:

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>());
    }
});        

そして、これはクライアント部分です:

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);
            }
        };
    }
});
于 2013-08-08T16:46:36.677 に答える