In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article will explain in detail about Java secure socket programming and the analysis of best practices in the use of keytool. The content of the article is of high quality, so the editor shares it for you as a reference. I hope you will have some understanding of the relevant knowledge after reading this article.
Overview
Using Java's JSSE (Java Secure Socket Extension) technology, we can easily write secure socket programs. For an introduction to JSSE, you can refer to the JSSE guide provided by the Oracle website. In the process of programming, we need to apply the digital certificate to the code. Usually in formal product development, we can pay a certain fee and apply to formal certification bodies, such as Verisign, Geotrust, Thawte and so on.
If it is just for experimental purposes, we can also use the keytool tool that comes with Java to make certificates. Keytool is a key and certificate management tool. The generated keys or certificates are stored in files in jks (Java Key Store) format. For purposes, files in jks format are often used to:
1) Certificate library for storing asymmetric key pairs and digital certificates
2) the truststore that stores the list of trust certificates.
Note: the keytool command line parameters that come with different versions of Java may vary slightly. Compared to Java6, the keytool tool in Java7 has the following changes:
The-export option was renamed to-exportcert
The-genkey option was renamed to-genkeypair
The-import option was renamed to-importcert
-keyclone option is deprecated
-identitydb option is deprecated
-selfcert option is deprecated
The following will take keytool in Java7 as an example to illustrate common usage.
Using keytool to make certificate store and trust library
Generate asymmetric keys and self-issued certificates
Command: keytool-genkeypair-alias TEST_ROOT-keystore test_root.jks
Explanation: generate a pair of keys and a self-signed certificate, where the private key and certificate are stored in the test_root.jks file under the alias TEST_ROOT.
Note: when using the above command, the command line will interact with the need to manually fill in the password, CN, OU and other information. You can also specify these parameters directly on the command line, as detailed in the keytool usage help listed in Resources.
Generate a certificate request file
Command: keytool-certreq-file test_server.csr-alias TEST_SERVER-keystore test_server.jks
Explanation: export the public key aliased as TEST_SERVER and some personal information from the test_server.jks file as a certificate request file.
Issue a certificate
Command: keytool-gencert-infile test_server.csr-outfile test_server.cer-alias TEST_ROOT-keystore TEST_ROOT.jks
Explanation: use the private key alias TEST_ROOT to issue a certificate for test_server.csr and save it to the test_server.cer file.
Export a certificate from a jks file
Command: keytool-exportcert-alias TEST_ROOT-file test_root.cer-keystore test_root.jks
Explanation: export a certificate aliased as TEST_ROOT from the test_root.jks file and store it in the test_root.cer file.
Import the trust certificate to the jks file
Command: keytool-importcert-alias TEST_ROOT-file test_root.cer-keystore TEST_SERVER.jks
Explanation: import the certificate test_root.cer into TEST_SERVER.jks with the alias TEST_ROOT.
Note: the target jks file here does not contain the specified alias, and the import entry will be saved in the form of a trustedCertEntry trust certificate.
Import issued certificate to jks file (update certificate)
Command: keytool-importcert-alias TEST_SERVER-file test_server.cer-keystore TEST_SERVER.jks
Explanation: update the certificate test_server.cer to the TEST_SERVER.jks file where the alias TEST_SERVER already exists
Note: the command here is exactly the same in form as the above command to import the trust certificate, but has a different effect.
1. The target jks file here should contain the specified alias so that the keytool tool will understand the command to update the certificate and save it in the form of PrivateKeyEntry.
two。 Before updating the issued certificate, be sure to import the corresponding CA certificate into the jks file, otherwise you will get an error "keytool error: java.lang.Exception: unable to establish chain from reply".
Print certificate content
Command: keytool-printcert-v-file test_server.cer
Explanation: print out the contents of the certificate test_server.cer
Note: you can also use the parameter-sslserver ip:port to print out the contents of a certificate provided by a sslserver directly from the network. For details, see the keytool usage help listed in Resources.
Display the contents of the jks file
Command: keytool-list-v-keystore test_server.jks
Explanation: displays all entries stored in test_server.jks
Note: the password for the jks file will be required here, and all entry information can be displayed if you do not enter it, but it will prompt that "the integrity of the information stored in the KeyStore has not been verified!"
Delete entries from the jks file
Command: keytool-delete-alias TEST_ROOT-keystore test_server.jks
Explanation: delete an entry aliased as TEST_ROOT from test_server.jks
The programming method of secure socket
Using Java to write secure sockets programs, you can follow certain methods, as shown in figure 1, showing the relationship between the relevant classes. Among them, Keystore, KeyManagerFactory, TrustManagerFactory and SSLContext can be called "engine class". If you specify specific parameters (such as protocols, algorithms, etc.), you can produce object instances that meet our requirements and are used for programming.
Figure 1. The relationship between related classes
(note: the picture is quoted from "Java ™Secure Socket Extension (JSSE) Reference Guide")
The steps of programming can be simply summarized as follows:
1. Use the Keystore class to load certificate store or truststore files
two。 Use KeyManagerFactory and Keystore instances loaded with certificate stores to generate an array of KeyManager instances
3. Use TrustManagerFactory and Keystore instances loaded with the truststore to generate an array of TrustManager instances
4. Use SSLContext to initialize the KeyManager instance array and the TrustManager instance array to set up the communication environment.
5. Use SSLSocket or SSLServerSocket generated by SSLContext for communication.
Before writing a specific program, we need to use the previous knowledge of the keytool tool to prepare the following jks file:
1. Test_root.jks: this file contains the self-issued certificate, which is used as a CA to issue the certificate.
2. Test_server_cert.jks: this file contains a certificate signed by CA, which is used on the server side of SSL/TSL communication.
3. Test_server_trust.jks: the certificate of the trusted client is stored in this file, which is used on the server side of SSL/TSL communication
4. Test_client_cert.jks: this file contains a certificate signed by CA, which is used by clients of SSL/TSL communication
5. Test_client_trust.jks: this file contains the certificate of the trust server, which is used for the client of SSL/TSL communication.
Suppose the password for each jks file is set to "Testpassw0rd" and is stored under the "D:" disk.
Specify certificate store and trust base through system properties
This way of writing is simple and straightforward, and you can specify the jks file needed for communication by passing parameters to JVM, or by using the System.setProperty () method in your code.
Server program
To run the program shown in listing 1, add the following virtual machine parameters to the command line to specify the certificate store and password to be used by the server program:
-Djavax.net.ssl.keyStore= "D:/test_server_cert.jks"
-Djavax.net.ssl.keyStorePassword= "Testpassw0rd"
Note the setNeedClientAuth (false) in the program, indicating that there is no need to authenticate the client. If it is set to true, we also need to specify the truststore and password here:
-Djavax.net.ssl.trustStore= "D:/test_server_trust.jks"
-Djavax.net.ssl.trustStorePassword= "Testpassw0rd"
Listing 1. Simple SSL communication server program
Import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocket; public class Simple_SSLServerSocket {/ / defines the listening port number private final static int LISTEN_PORT=54321; public static void main (String args []) throws IOException {SSLServerSocket serverSocket=null; SSLSocket clientSocket=null / / get socket factory instance SSLServerSocketFactory ssf= (SSLServerSocketFactory) SSLServerSocketFactory.getDefault () by default; try {serverSocket= (SSLServerSocket) ssf.createServerSocket (LISTEN_PORT); / / set serverSocket.setNeedClientAuth (false) without client authentication; System.out.println ("SSLServer is listening on" + LISTEN_PORT+ "port") / / Loop listener port, if a client is connected, a new thread will be opened to communicate with it while (true) {/ / accept a new client connection clientSocket= (SSLSocket) serverSocket.accept (); ClientConnection clientConnection=new ClientConnection (clientSocket); / / start a new thread Thread clientThread=new Thread (clientConnection) System.out.println ("Client" + clientThread.getId () + "is connected"); clientThread.run ();} catch (IOException ioExp) {ioExp.printStackTrace ();} catch (Exception e) {e.printStackTrace ();} finally {serverSocket.close ();}} class ClientConnection implements Runnable {private Socket clientSocket=null Public ClientConnection (SSLSocket sslsocket) {clientSocket=sslsocket;} public void run () {BufferedReader reader=null; / / print out try {reader=new BufferedReader (new InputStreamReader (clientSocket.getInputStream (); while (true) {String line=reader.readLine (); if (line==null) {System.out.println ("Communication end.") Break;} System.out.println ("Receive message:" + line);} reader.close (); clientSocket.close ();} catch (IOException ioExp) {ioExp.printStackTrace ();} catch (Exception e) {e.printStackTrace ();}
Client program
Corresponding to the server program shown in listing 1, listing 2 is the client program, which needs to add the following virtual machine parameters to the command line to specify the truststore and password:
-Djavax.net.ssl.trustStore= "D:/test_client_trust.jks"
-Djavax.net.ssl.trustStorePassword= "Testpassw0rd"
If the server program setNeedClientAuth (true) requires that the client be authenticated, we also need to specify the certificate store and password:
-Djavax.net.ssl.keyStore= "D:/test_client_cert.jks"
-Djavax.net.ssl.keyStorePassword= "Testpassw0rd"
Listing 2. Simple SSL communication client program
Import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Writer; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; public class Simple_SSLSocket {/ / defines the server name and port number to connect to private static final int DEFAULT_PORT=54321; private static final String DEFAULT_HOST= "localhost"; public static void main (String args []) {SSLSocket socket=null / / obtain the factory instance SSLSocketFactory sf= (SSLSocketFactory) SSLSocketFactory.getDefault () by default; try {/ / connect the port of the server to complete the handshake process socket= (SSLSocket) sf.createSocket (DEFAULT_HOST, DEFAULT_PORT); socket.startHandshake (); System.out.println ("Connected to" + DEFAULT_HOST+ ":" + DEFAULT_PORT+ "!") / / enter the text BufferedReader reader=new BufferedReader (new InputStreamReader (System.in)); Writer writer=new OutputStreamWriter (socket.getOutputStream ()) to be sent to the server from the console; / / you can send the message boolean done=false; while (! done) {System.out.print ("Send Message:"); String line=reader.readLine () repeatedly to the server. If {writer.write (line+ "\ n"); writer.flush ();} else {done=true;}} socket.close ();} catch (Exception e) {System.out.println ("Connection failed:" + e); try {socket.close () } catch (IOException ioe) {} socket=null;}
Specify certificate store and trust base through SSLContext
As described earlier, the method of specifying certificate library and trust library through system parameters is easy to use, but the disadvantage is obvious, the whole program environment has to use the same jks file. If there are different SSL/TSL communications in the program, you need to use different jks files. What should I do?
You can use SSLContext to specify the jks file, just replace the code snippet in listing 3 with the "SSLServerSocketFactory ssf" generation in listing 1; replace the code snippet in listing 4 with the "SSLSocketFactory sf" generation in listing 2, and then make some code adjustments.
(note: in fact, when you use SSLSocketFactory.getDefault () or SSLServerSocketFactory.getDefault () to create a socket, the default context is already used inside the program, and its parameters are specified through the system property.)
Listing 3. SSLContext designated certificate library
/ / related jks file and its password definition private final static String CERT_STORE= "D:/test_server_cert.jks"; private final static String CERT_STORE_PASSWORD= "Testpassw0rd"; / / load jks file FileInputStream f_certStore=new FileInputStream (CERT_STORE); KeyStore ks=KeyStore.getInstance ("jks"); ks.load (f_certStore, CERT_STORE_PASSWORD.toCharArray ()); f_certStore.close () / / create and initialize certificate store factory String alg=KeyManagerFactory.getDefaultAlgorithm (); KeyManagerFactory kmFact=KeyManagerFactory.getInstance (alg); kmFact.init (ks, CERT_STORE_PASSWORD.toCharArray ()); KeyManager [] kms=kmFact.getKeyManagers (); / / create and initialize SSLContext instance SSLContext context=SSLContext.getInstance ("SSL"); context.init (kms, null, null); SSLServerSocketFactory ssf= (SSLServerSocketFactory) context.getServerSocketFactory ()
Listing 4. SSLContext designated truststore
/ / related jks file and its password definition private final static String TRUST_STORE= "D:/test_client_trust.jks"; private final static String TRUST_STORE_PASSWORD= "Testpassw0rd"; / / load jks file FileInputStream f_trustStore=new FileInputStream (TRUST_STORE); KeyStore ks=KeyStore.getInstance ("jks"); ks.load (f_trustStore, TRUST_STORE_PASSWORD.toCharArray ()); f_trustStore.close () / / create and initialize truststore factory String alg=TrustManagerFactory.getDefaultAlgorithm (); TrustManagerFactory tmFact=TrustManagerFactory.getInstance (alg); tmFact.init (ks); TrustManager [] tms=tmFact.getTrustManagers (); / / create and initialize SSLContext instance SSLContext context=SSLContext.getInstance ("SSL"); context.init (null, tms, null); SSLSocketFactory sf=context.getSocketFactory ()
Of course, if you want to use both the certificate store and the trust store on the server side or the client side, you can use the code in listing 3 and listing 4 in the same place as context.init ().
It is important to note that if the first KeyManager [] parameter of context.init () is null, the certificate is not provided; if the second TrustManager [] parameter is null, the truststore provided by the system by default is found (for example, lib/security/cacerts under the JRE installation directory).
Use the X509 Certificate Trust Manager
The X509TrustManager interface extends the TrustManager interface. Using the TrustManager interface, we can already customize the truststore in the program, but if the other party's certificate is not in the truststore, the communication will fail directly.
If you want to customize some behavior of the truststore (for example, checking the other party's certificate and doing some handling for exceptions), we can use the X509TrustManager interface to implement our own method.
As shown in listing 5, assuming we want to use X509TrustManager in the client program, we can do something in the checkServerTrusted () function and do some of our own processing if we detect a server-side certificate exception. CheckClientTrusted () is used by the server to detect the certificate of the client.
Replace the code in listing 5 with the generation of TrustManager [] tms in listing 4, and make some adjustments to the code.
Listing 5. Use of X509TrustManager
/ / generate truststore TrustManager [] tms=new TrustManager [] {new MyTrustManager ()} using custom MyTrustManager;... …… Class MyTrustManager implements X509TrustManager {/ / related jks files and their password definitions private final static String TRUST_STORE= "D:/test_client_trust.jks"; private final static String TRUST_STORE_PASSWORD= "Testpassw0rd"; X509TrustManager xtm; public MyTrustManager () throws Exception {/ / load jks file KeyStore ks = KeyStore.getInstance ("JKS"); ks.load (new FileInputStream (TRUST_STORE), TRUST_STORE_PASSWORD.toCharArray ()) TrustManagerFactory tmf = TrustManagerFactory.getInstance ("SunX509", "SunJSSE"); tmf.init (ks); TrustManager [] tms = tmf.getTrustManagers (); / / filter out the trust certificate for (int I = 0; I < tms.length; iTunes +) {if (tms [I] instanceof X509TrustManager) {xtm = (X509TrustManager) tms [I]; return } / / public void checkClientTrusted (X509Certificate [] chain, String authType) throws CertificateException {} / / client verification server certificate interface public void checkServerTrusted (X509Certificate [] chain, String authType) throws CertificateException {try {xtm.checkServerTrusted (chain, authType);} catch (CertificateException excep) {System.out.println (excep.getMessage ()) Throw excep;}} / / get acceptable publisher public X509Certificate [] getAcceptedIssuers () {/ / return xtm.getAcceptedIssuers (); return null;}}
Note:
1. When the server code setNeedClientAuth (False), after the client-side MyTrustManager implements X509TrustManager, if the implementation of the checkServerTrusted () method is empty, the client will accept by default no matter what certificate the server uses; if you want to check the server-side certificate, you also need to catch the exception and handle it, as in the code snippet in listing 5.
The 2.getAcceptedIssuers () method usually does not require a concrete implementation, but when the server asks to verify the identity of the client, that is, setNeedClientAuth (True), the server also needs to implement X509TrustManager, and the getAcceptedIssuers () method is implemented as the annotated part of the code in listing 5.
Debug SSL/TSL program
Turn on the debug switch to observe the communication log
Figure 2 depicts the handshake process of SSL/TSL communication. In the actual writing of the program, may encounter problems in these links, resulting in unable to communicate, troubleshooting is often difficult to start. At this time, we can turn on the handshake log switch of SSL/TSL communication and observe it.
Figure 2.SSL communication protocol handshake process
(note: the picture is quoted from "Java ™Secure Socket Extension (JSSE) Reference Guide")
The way to turn on the log switch is also to add virtual machine parameters from the command line by setting system properties:
-Djavax.net.debug=ssl,handshake
Of course, you can also use the System.setProperty () method to turn on the switch in your code.
After turning on the log switch, you can search for keywords such as "ClientHello" and "ServerHello", or "*" (three asterisks and a space)-this is the beginning of log printing for each step of the handshake phase. Locate the problem by reading the log. For more detailed switch information, see the "Debugging Utilities" section in the JSSE guide:
Select the Cipher Suites of the communication
Sometimes in order to do experiments, we will choose a specific CipherSuites, we can use SSLServerSocket or SSLSocket's getEnabledCipherSuites () to observe all the default supported cipher suite information, and then use setEnabledCipherSuites () to set it.
Listing 6 shows the code to filter out all anonymous cipher suites from the server.
Listing 6. Filter all anonymous cipher suites
String enabled [] = serverSocket.getEnabledCipherSuites (); Set filter = new LinkedHashSet (); for (int I = 0; I < enabled.length; iTunes +) {if (enabled [I] .indexOf ("anon")
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.