Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I do TLS with BouncyCastle?

Does anybody know about examples of TLS with BouncyCastle? I was surprised by the lack of them on Internet. If there are really none, let's collect them as answers.

like image 786
Jakub Adamek Avatar asked Aug 05 '13 18:08

Jakub Adamek


1 Answers

This is a very basic example, with server-only authentication and self-signed cert. The code is based on BC 1.49, mostly 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"); } 

where

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

This is the 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(); 

You need to use the input and output stream from tlsClient/ServerProtocol to read and write encrypted data (e.g. tlsClientProtocol.getInputStream()). Otherwise, if you used e.g. socket.getOutputStream(), you would just write unencrypted data.

How to implement validateCertificate? I am using self-signed certificates. This means I just look them up in the key-store without any certificate chains. This is how I create the key store:

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

And this is the validation:

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

What is rather confusing, are the three different Certificate classes. You have to convert between them as shown above.

like image 116
Jakub Adamek Avatar answered Sep 19 '22 22:09

Jakub Adamek