SSL

转载自:http://www.iteye.com/topic/1125183

 

有关SSL的原理和介绍在网上已经有不少,对于Java下使用keytool生成证书,配置SSL通信的教程也非常多。但如果我们不能够亲自动手做一个SSL Sever和SSL Client,可能就永远也不能深入地理解Java环境下,SSL的通信是如何实现的。对SSL中的各种概念的认识也可能会仅限于可以使用的程度。本文通过构造一个简单的SSL Server和SSL Client来讲解Java环境下SSL的通信原理。

首先我们先回顾一下常规的Java Socket编程。在Java下写一个Socket服务器和客户端的例子还是比较简单的。以下是服务端的代码:

Java代码 复制代码 收藏代码
  1. package org.bluedash.tryssl;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.io.PrintWriter;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. publicclass Server extends Thread {
  9. private Socket socket;
  10. public Server(Socket socket) {
  11. this.socket = socket;
  12. }
  13. publicvoid run() {
  14. try {
  15. BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  16. PrintWriter writer = new PrintWriter(socket.getOutputStream());
  17. String data = reader.readLine();
  18. writer.println(data);
  19. writer.close();
  20. socket.close();
  21. } catch (IOException e) {
  22. }
  23. }
  24. publicstaticvoid main(String[] args) throws Exception {
  25. while (true) {
  26. new Server((new ServerSocket(8080)).accept()).start();
  27. }
  28. }
  29. }
package org.bluedash.tryssl;

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

public class Server extends Thread {
	private Socket socket;

	public Server(Socket socket) {
		this.socket = socket;
	}

	public void run() {
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			PrintWriter writer = new PrintWriter(socket.getOutputStream());

			String data = reader.readLine();
			writer.println(data);
			writer.close();
			socket.close();
		} catch (IOException e) {

		}
	}
	
	public static void main(String[] args) throws Exception {
		while (true) {
			new Server((new ServerSocket(8080)).accept()).start();
		}
	}
}



服务端很简单:侦听8080端口,并把客户端发来的字符串返回去。下面是客户端的代码:

Java代码 复制代码 收藏代码
  1. package org.bluedash.tryssl;
  2. import java.io.BufferedReader;
  3. import java.io.InputStreamReader;
  4. import java.io.PrintWriter;
  5. import java.net.Socket;
  6. publicclass Client {
  7. publicstaticvoid main(String[] args) throws Exception {
  8. Socket s = new Socket("localhost", 8080);
  9. PrintWriter writer = new PrintWriter(s.getOutputStream());
  10. BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
  11. writer.println("hello");
  12. writer.flush();
  13. System.out.println(reader.readLine());
  14. s.close();
  15. }
  16. }
package org.bluedash.tryssl;

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

public class Client {

	public static void main(String[] args) throws Exception {

		Socket s = new Socket("localhost", 8080);

		PrintWriter writer = new PrintWriter(s.getOutputStream());
		BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
		writer.println("hello");
		writer.flush();
		System.out.println(reader.readLine());
		s.close();
	}

}



客户端也非常简单:向服务端发起请求,发送一个"hello"字串,然后获得服务端的返回。把服务端运行起来后,执行客户端,我们将得到"hello"的返回。

就是这样一套简单的网络通信的代码,我们来把它改造成使用SSL通信。在SSL通信协议中,我们都知道首先服务端必须有一个数字证书,当客户端连接到服务端时,会得到这个证书,然后客户端会判断这个证书是否是可信的,如果是,则交换信道加密密钥,进行通信。如果不信任这个证书,则连接失败。

因此,我们首先要为服务端生成一个数字证书。Java环境下,数字证书是用keytool生成的,这些证书被存储在store的概念中,就是证书仓库。我们来调用keytool命令为服务端生成数字证书和保存它使用的证书仓库:

Bash代码 复制代码 收藏代码
  1. keytool -genkey -v -alias bluedash-ssl-demo-server -keyalg RSA -keystore ./server_ks -dname "CN=localhost,OU=cn,O=cn,L=cn,ST=cn,C=cn" -storepass server -keypass 123123
keytool -genkey -v -alias bluedash-ssl-demo-server -keyalg RSA -keystore ./server_ks -dname "CN=localhost,OU=cn,O=cn,L=cn,ST=cn,C=cn" -storepass server -keypass 123123



这样,我们就将服务端证书bluedash-ssl-demo-server保存在了server_ksy这个store文件当中。有关keytool的用法在本文中就不再多赘述。执行上面的命令得到如下结果:

Bash代码 复制代码 收藏代码
  1. Generating 1,024 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 90 days
  2. for: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
  3. [Storing ./server_ks]
Generating 1,024 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 90 days
        for: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
[Storing ./server_ks]



然后,改造我们的服务端代码,让服务端使用这个证书,并提供SSL通信:

Java代码 复制代码 收藏代码
  1. package org.bluedash.tryssl;
  2. import java.io.BufferedReader;
  3. import java.io.FileInputStream;
  4. import java.io.IOException;
  5. import java.io.InputStreamReader;
  6. import java.io.PrintWriter;
  7. import java.net.ServerSocket;
  8. import java.net.Socket;
  9. import java.security.KeyStore;
  10. import javax.net.ServerSocketFactory;
  11. import javax.net.ssl.KeyManagerFactory;
  12. import javax.net.ssl.SSLContext;
  13. import javax.net.ssl.SSLServerSocket;
  14. publicclass SSLServer extends Thread {
  15. private Socket socket;
  16. public SSLServer(Socket socket) {
  17. this.socket = socket;
  18. }
  19. publicvoid run() {
  20. try {
  21. BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  22. PrintWriter writer = new PrintWriter(socket.getOutputStream());
  23. String data = reader.readLine();
  24. writer.println(data);
  25. writer.close();
  26. socket.close();
  27. } catch (IOException e) {
  28. }
  29. }
  30. privatestatic String SERVER_KEY_STORE = "/Users/liweinan/projs/ssl/src/main/resources/META-INF/server_ks";
  31. privatestatic String SERVER_KEY_STORE_PASSWORD = "123123";
  32. publicstaticvoid main(String[] args) throws Exception {
  33. System.setProperty("javax.net.ssl.trustStore", SERVER_KEY_STORE);
  34. SSLContext context = SSLContext.getInstance("TLS");
  35. KeyStore ks = KeyStore.getInstance("jceks");
  36. ks.load(new FileInputStream(SERVER_KEY_STORE), null);
  37. KeyManagerFactory kf = KeyManagerFactory.getInstance("SunX509");
  38. kf.init(ks, SERVER_KEY_STORE_PASSWORD.toCharArray());
  39. context.init(kf.getKeyManagers(), null, null);
  40. ServerSocketFactory factory = context.getServerSocketFactory();
  41. ServerSocket _socket = factory.createServerSocket(8443);
  42. ((SSLServerSocket) _socket).setNeedClientAuth(false);
  43. while (true) {
  44. new SSLServer(_socket.accept()).start();
  45. }
  46. }
  47. }
package org.bluedash.tryssl;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;

import javax.net.ServerSocketFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;

public class SSLServer extends Thread {
	private Socket socket;

	public SSLServer(Socket socket) {
		this.socket = socket;
	}

	public void run() {
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			PrintWriter writer = new PrintWriter(socket.getOutputStream());

			String data = reader.readLine();
			writer.println(data);
			writer.close();
			socket.close();
		} catch (IOException e) {

		}
	}

	private static String SERVER_KEY_STORE = "/Users/liweinan/projs/ssl/src/main/resources/META-INF/server_ks";
	private static String SERVER_KEY_STORE_PASSWORD = "123123";

	public static void main(String[] args) throws Exception {
		System.setProperty("javax.net.ssl.trustStore", SERVER_KEY_STORE);
		SSLContext context = SSLContext.getInstance("TLS");
		
		KeyStore ks = KeyStore.getInstance("jceks");
		ks.load(new FileInputStream(SERVER_KEY_STORE), null);
		KeyManagerFactory kf = KeyManagerFactory.getInstance("SunX509");
		kf.init(ks, SERVER_KEY_STORE_PASSWORD.toCharArray());
		
		context.init(kf.getKeyManagers(), null, null);

		ServerSocketFactory factory = context.getServerSocketFactory();
		ServerSocket _socket = factory.createServerSocket(8443);
		((SSLServerSocket) _socket).setNeedClientAuth(false);

		while (true) {
			new SSLServer(_socket.accept()).start();
		}
	}
}



可以看到,服务端的Socket准备设置工作大大增加了,增加的代码的作用主要是将证书导入并进行使用。此外,所使用的Socket变成了SSLServerSocket,另外端口改到了8443(这个不是强制的,仅仅是为了遵守习惯)。另外,最重要的一点,服务端证书里面的CN一定和服务端的域名统一,我们的证书服务的域名是localhost,那么我们的客户端在连接服务端时一定也要用localhost来连接,否则根据SSL协议标准,域名与证书的CN不匹配,说明这个证书是不安全的,通信将无法正常运行。

有了服务端,我们原来的客户端就不能使用了,必须要走SSL协议。由于服务端的证书是我们自己生成的,没有任何受信任机构的签名,所以客户端是无法验证服务端证书的有效性的,通信必然会失败。所以我们需要为客户端创建一个保存所有信任证书的仓库,然后把服务端证书导进这个仓库。这样,当客户端连接服务端时,会发现服务端的证书在自己的信任列表中,就可以正常通信了。

因此现在我们要做的是生成一个客户端的证书仓库,因为keytool不能仅生成一个空白仓库,所以和服务端一样,我们还是生成一个证书加一个仓库(客户端证书加仓库):

Bash代码 复制代码 收藏代码
  1. keytool -genkey -v -alias bluedash-ssl-demo-client -keyalg RSA -keystore ./client_ks -dname "CN=localhost,OU=cn,O=cn,L=cn,ST=cn,C=cn" -storepass client -keypass 456456
keytool -genkey -v -alias bluedash-ssl-demo-client -keyalg RSA -keystore ./client_ks -dname "CN=localhost,OU=cn,O=cn,L=cn,ST=cn,C=cn" -storepass client -keypass 456456



结果如下:

Bash代码 复制代码 收藏代码
  1. Generating 1,024 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 90 days
  2. for: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
  3. [Storing ./client_ks]
Generating 1,024 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 90 days
        for: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
[Storing ./client_ks]



接下来,我们要把服务端的证书导出来,并导入到客户端的仓库。第一步是导出服务端的证书:

Bash代码 复制代码 收藏代码
  1. keytool -export -alias bluedash-ssl-demo-server -keystore ./server_ks -file server_key.cer
keytool -export -alias bluedash-ssl-demo-server -keystore ./server_ks -file server_key.cer



执行结果如下:

Bash代码 复制代码 收藏代码
  1. Enter keystore password: server
  2. Certificate stored in file <server_key.cer>
Enter keystore password:  server
Certificate stored in file <server_key.cer>



然后是把导出的证书导入到客户端证书仓库:

Bash代码 复制代码 收藏代码
  1. keytool -import -trustcacerts -alias bluedash-ssl-demo-server -file ./server_key.cer -keystore ./client_ks
keytool -import -trustcacerts -alias bluedash-ssl-demo-server -file ./server_key.cer -keystore ./client_ks



结果如下:

Bash代码 复制代码 收藏代码
  1. Enter keystore password: client
  2. Owner: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
  3. Issuer: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
  4. Serial number: 4c57c7de
  5. Valid from: Tue Aug 0315:40:14 CST 2010 until: Mon Nov 0115:40:14 CST 2010
  6. Certificate fingerprints:
  7. MD5: FC:D4:8B:36:3F:1B:30:EA:6D:63:55:4F:C7:68:3B:0C
  8. SHA1: E1:54:2F:7C:1A:50:F5:74:AA:63:1E:F9:CC:B1:1C:73:AA:34:8A:C4
  9. Signature algorithm name: SHA1withRSA
  10. Version: 3
  11. Trust this certificate? [no]: yes
  12. Certificate was added to keystore
Enter keystore password:  client
Owner: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
Issuer: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
Serial number: 4c57c7de
Valid from: Tue Aug 03 15:40:14 CST 2010 until: Mon Nov 01 15:40:14 CST 2010
Certificate fingerprints:
         MD5:  FC:D4:8B:36:3F:1B:30:EA:6D:63:55:4F:C7:68:3B:0C
         SHA1: E1:54:2F:7C:1A:50:F5:74:AA:63:1E:F9:CC:B1:1C:73:AA:34:8A:C4
         Signature algorithm name: SHA1withRSA
         Version: 3
Trust this certificate? [no]:  yes
Certificate was added to keystore



好,准备工作做完了,我们来撰写客户端的代码:

Java代码 复制代码 收藏代码
  1. package org.bluedash.tryssl;
  2. import java.io.BufferedReader;
  3. import java.io.InputStreamReader;
  4. import java.io.PrintWriter;
  5. import java.net.Socket;
  6. import javax.net.SocketFactory;
  7. import javax.net.ssl.SSLSocketFactory;
  8. publicclass SSLClient {
  9. privatestatic String CLIENT_KEY_STORE = "/Users/liweinan/projs/ssl/src/main/resources/META-INF/client_ks";
  10. publicstaticvoid main(String[] args) throws Exception {
  11. // Set the key store to use for validating the server cert.
  12. System.setProperty("javax.net.ssl.trustStore", CLIENT_KEY_STORE);
  13. System.setProperty("javax.net.debug", "ssl,handshake");
  14. SSLClient client = new SSLClient();
  15. Socket s = client.clientWithoutCert();
  16. PrintWriter writer = new PrintWriter(s.getOutputStream());
  17. BufferedReader reader = new BufferedReader(new InputStreamReader(s
  18. .getInputStream()));
  19. writer.println("hello");
  20. writer.flush();
  21. System.out.println(reader.readLine());
  22. s.close();
  23. }
  24. private Socket clientWithoutCert() throws Exception {
  25. SocketFactory sf = SSLSocketFactory.getDefault();
  26. Socket s = sf.createSocket("localhost", 8443);
  27. return s;
  28. }
  29. }
package org.bluedash.tryssl;

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

import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;

public class SSLClient {

	private static String CLIENT_KEY_STORE = "/Users/liweinan/projs/ssl/src/main/resources/META-INF/client_ks";

	public static void main(String[] args) throws Exception {
		// Set the key store to use for validating the server cert.
		System.setProperty("javax.net.ssl.trustStore", CLIENT_KEY_STORE);
		
		System.setProperty("javax.net.debug", "ssl,handshake");

		SSLClient client = new SSLClient();
		Socket s = client.clientWithoutCert();

		PrintWriter writer = new PrintWriter(s.getOutputStream());
		BufferedReader reader = new BufferedReader(new InputStreamReader(s
				.getInputStream()));
		writer.println("hello");
		writer.flush();
		System.out.println(reader.readLine());
		s.close();
	}

	private Socket clientWithoutCert() throws Exception {
		SocketFactory sf = SSLSocketFactory.getDefault();
		Socket s = sf.createSocket("localhost", 8443);
		return s;
	}
}



可以看到,除了把一些类变成SSL通信类以外,客户端也多出了使用信任证书仓库的代码。以上,我们便完成了SSL单向握手通信。即:客户端验证服务端的证书,服务端不认证客户端的证书。

以上便是Java环境下SSL单向握手的全过程。因为我们在客户端设置了日志输出级别为DEBUG:

Java代码 复制代码 收藏代码
  1. System.setProperty("javax.net.debug", "ssl,handshake");
System.setProperty("javax.net.debug", "ssl,handshake");



因此我们可以看到SSL通信的全过程,这些日志可以帮助我们更具体地了解通过SSL协议建立网络连接时的全过程。

结合日志,我们来看一下SSL双向认证的全过程:



第一步: 客户端发送ClientHello消息,发起SSL连接请求,告诉服务器自己支持的SSL选项(加密方式等)。

Bash代码 复制代码 收藏代码
  1. *** ClientHello, TLSv1
*** ClientHello, TLSv1



第二步: 服务器响应请求,回复ServerHello消息,和客户端确认SSL加密方式:

Bash代码 复制代码 收藏代码
  1. *** ServerHello, TLSv1
*** ServerHello, TLSv1



第三步: 服务端向客户端发布自己的公钥。

第四步: 客户端与服务端的协通沟通完毕,服务端发送ServerHelloDone消息:

Bash代码 复制代码 收藏代码
  1. *** ServerHelloDone
*** ServerHelloDone



第五步: 客户端使用服务端给予的公钥,创建会话用密钥(SSL证书认证完成后,为了提高性能,所有的信息交互就可能会使用对称加密算法),并通过ClientKeyExchange消息发给服务器:

Bash代码 复制代码 收藏代码
  1. *** ClientKeyExchange, RSA PreMasterSecret, TLSv1
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1



第六步: 客户端通知服务器改变加密算法,通过ChangeCipherSpec消息发给服务端:

Bash代码 复制代码 收藏代码
  1. main, WRITE: TLSv1 Change Cipher Spec, length = 1
main, WRITE: TLSv1 Change Cipher Spec, length = 1



第七步: 客户端发送Finished消息,告知服务器请检查加密算法的变更请求:

Bash代码 复制代码 收藏代码
  1. *** Finished
*** Finished



第八步:服务端确认算法变更,返回ChangeCipherSpec消息

Bash代码 复制代码 收藏代码
  1. main, READ: TLSv1 Change Cipher Spec, length = 1
main, READ: TLSv1 Change Cipher Spec, length = 1



第九步:服务端发送Finished消息,加密算法生效:

Bash代码 复制代码 收藏代码
  1. *** Finished
*** Finished



那么如何让服务端也认证客户端的身份,即双向握手呢?其实很简单,在服务端代码中,把这一行:

Java代码 复制代码 收藏代码
  1. ((SSLServerSocket) _socket).setNeedClientAuth(false);
((SSLServerSocket) _socket).setNeedClientAuth(false);



改成:

Java代码 复制代码 收藏代码
  1. ((SSLServerSocket) _socket).setNeedClientAuth(true);
((SSLServerSocket) _socket).setNeedClientAuth(true);



就可以了。但是,同样的道理,现在服务端并没有信任客户端的证书,因为客户端的证书也是自己生成的。所以,对于服务端,需要做同样的工作:把客户端的证书导出来,并导入到服务端的证书仓库:

Bash代码 复制代码 收藏代码
  1. keytool -export -alias bluedash-ssl-demo-client -keystore ./client_ks -file client_key.cer
  2. Enter keystore password: client
  3. Certificate stored in file <client_key.cer>
keytool -export -alias bluedash-ssl-demo-client -keystore ./client_ks -file client_key.cer
Enter keystore password:  client
Certificate stored in file <client_key.cer>



 

Bash代码 复制代码 收藏代码
  1. keytool -import -trustcacerts -alias bluedash-ssl-demo-client -file ./client_key.cer -keystore ./server_ks
  2. Enter keystore password: server
  3. Owner: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
  4. Issuer: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
  5. Serial number: 4c57c80b
  6. Valid from: Tue Aug 0315:40:59 CST 2010 until: Mon Nov 0115:40:59 CST 2010
  7. Certificate fingerprints:
  8. MD5: DB:91:F4:1E:65:D1:81:F2:1E:A6:A3:55:3F:E8:12:79
  9. SHA1: BF:77:56:61:04:DD:95:FC:E5:84:48:5C:BE:60:AF:02:96:A2:E1:E2
  10. Signature algorithm name: SHA1withRSA
  11. Version: 3
  12. Trust this certificate? [no]: yes
  13. Certificate was added to keystore
keytool -import -trustcacerts -alias bluedash-ssl-demo-client -file ./client_key.cer -keystore ./server_ks
Enter keystore password:  server
Owner: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
Issuer: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
Serial number: 4c57c80b
Valid from: Tue Aug 03 15:40:59 CST 2010 until: Mon Nov 01 15:40:59 CST 2010
Certificate fingerprints:
         MD5:  DB:91:F4:1E:65:D1:81:F2:1E:A6:A3:55:3F:E8:12:79
         SHA1: BF:77:56:61:04:DD:95:FC:E5:84:48:5C:BE:60:AF:02:96:A2:E1:E2
         Signature algorithm name: SHA1withRSA
         Version: 3
Trust this certificate? [no]:  yes
Certificate was added to keystore



完成了证书的导入,还要在客户端需要加入一段代码,用于在连接时,客户端向服务端出示自己的证书:

Java代码 复制代码 收藏代码
  1. package org.bluedash.tryssl;
  2. import java.io.BufferedReader;
  3. import java.io.FileInputStream;
  4. import java.io.InputStreamReader;
  5. import java.io.PrintWriter;
  6. import java.net.Socket;
  7. import java.security.KeyStore;
  8. import javax.net.SocketFactory;
  9. import javax.net.ssl.KeyManagerFactory;
  10. import javax.net.ssl.SSLContext;
  11. import javax.net.ssl.SSLSocketFactory;
  12. publicclass SSLClient {
  13. privatestatic String CLIENT_KEY_STORE = "/Users/liweinan/projs/ssl/src/main/resources/META-INF/client_ks";
  14. privatestatic String CLIENT_KEY_STORE_PASSWORD = "456456";
  15. publicstaticvoid main(String[] args) throws Exception {
  16. // Set the key store to use for validating the server cert.
  17. System.setProperty("javax.net.ssl.trustStore", CLIENT_KEY_STORE);
  18. System.setProperty("javax.net.debug", "ssl,handshake");
  19. SSLClient client = new SSLClient();
  20. Socket s = client.clientWithCert();
  21. PrintWriter writer = new PrintWriter(s.getOutputStream());
  22. BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
  23. writer.println("hello");
  24. writer.flush();
  25. System.out.println(reader.readLine());
  26. s.close();
  27. }
  28. private Socket clientWithoutCert() throws Exception {
  29. SocketFactory sf = SSLSocketFactory.getDefault();
  30. Socket s = sf.createSocket("localhost", 8443);
  31. return s;
  32. }
  33. private Socket clientWithCert() throws Exception {
  34. SSLContext context = SSLContext.getInstance("TLS");
  35. KeyStore ks = KeyStore.getInstance("jceks");
  36. ks.load(new FileInputStream(CLIENT_KEY_STORE), null);
  37. KeyManagerFactory kf = KeyManagerFactory.getInstance("SunX509");
  38. kf.init(ks, CLIENT_KEY_STORE_PASSWORD.toCharArray());
  39. context.init(kf.getKeyManagers(), null, null);
  40. SocketFactory factory = context.getSocketFactory();
  41. Socket s = factory.createSocket("localhost", 8443);
  42. return s;
  43. }
  44. }
package org.bluedash.tryssl;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.security.KeyStore;
import javax.net.SocketFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;

public class SSLClient {
	private static String CLIENT_KEY_STORE = "/Users/liweinan/projs/ssl/src/main/resources/META-INF/client_ks";
	private static String CLIENT_KEY_STORE_PASSWORD = "456456";
	
	public static void main(String[] args) throws Exception {
		// Set the key store to use for validating the server cert.
		System.setProperty("javax.net.ssl.trustStore", CLIENT_KEY_STORE);
		System.setProperty("javax.net.debug", "ssl,handshake");
		SSLClient client = new SSLClient();
		Socket s = client.clientWithCert();
		
		PrintWriter writer = new PrintWriter(s.getOutputStream());
		BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
		writer.println("hello");
		writer.flush();
		System.out.println(reader.readLine());
		s.close();
	}

	private Socket clientWithoutCert() throws Exception {
		SocketFactory sf = SSLSocketFactory.getDefault();
		Socket s = sf.createSocket("localhost", 8443);
		return s;
	}

	private Socket clientWithCert() throws Exception {
		SSLContext context = SSLContext.getInstance("TLS");
		KeyStore ks = KeyStore.getInstance("jceks");
		
		ks.load(new FileInputStream(CLIENT_KEY_STORE), null);
		KeyManagerFactory kf = KeyManagerFactory.getInstance("SunX509");
		kf.init(ks, CLIENT_KEY_STORE_PASSWORD.toCharArray());
		context.init(kf.getKeyManagers(), null, null);
		
		SocketFactory factory = context.getSocketFactory();
		Socket s = factory.createSocket("localhost", 8443);
		return s;
	}
}



通过比对单向认证的日志输出,我们可以发现双向认证时,多出了服务端认证客户端证书的步骤:

Bash代码 复制代码 收藏代码
  1. *** CertificateRequest
  2. Cert Types: RSA, DSS
  3. Cert Authorities:
  4. <CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn>
  5. <CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn>
  6. *** ServerHelloDone
*** CertificateRequest
Cert Types: RSA, DSS
Cert Authorities:
<CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn>
<CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn>
*** ServerHelloDone



 

Bash代码 复制代码 收藏代码
  1. *** CertificateVerify
  2. main, WRITE: TLSv1 Handshake, length = 134
  3. main, WRITE: TLSv1 Change Cipher Spec, length = 1
*** CertificateVerify
main, WRITE: TLSv1 Handshake, length = 134
main, WRITE: TLSv1 Change Cipher Spec, length = 1



在 @*** ServerHelloDone@ 之前,服务端向客户端发起了需要证书的请求 @*** CertificateRequest@ 。

在客户端向服务端发出 @Change Cipher Spec@ 请求之前,多了一步客户端证书认证的过程 @*** CertificateVerify@ 。

客户端与服务端互相认证证书的情景,可参考下图:



参考资料:

fn1. Tomcat双向SSL认证的配置 - http://www.javaeedev.com/blog/article.jspx?articleId=ff808081198fb524011993a9bb7a029a

fn2. Understanding SSL - http://developerspoint.wordpress.com/2008/06/21/understanding-ssl/

fn3. Change Cipher Spec Protocol - http://www.pierobon.org/ssl/ch2/ccs.htm

fn4. SSL & TLS Essentials: Securing the Web - http://www.amazon.com/SSL-TLS-Essentials-Securing-Web/dp/0471383546/ref=sr_1_1?ie=UTF8&s=books&qid=1280891641&sr=8-1

/* Copyright© 2024 TP-Link Systems Inc. * file brief SSL APIs for mbedtls details author Wang Shiqin version 1.0.0 date 16Sep19 warning history \arg */ #if defined(INCLUDE_SSL) && defined(INCLUDE_SSL_MBEDTLS) //#define SSL_DEBUG_TIME #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/time.h> #include “ssl_backend.h” #include “ssl_mbedtls.h” #include <mbedtls/debug.h> #ifdef INCLUDE_IMDA static int g_ciphersuite[7] = { 0x2F, /* TLS_RSA_WITH_AES_128_CBC_SHA / 0x35, / TLS_RSA_WITH_AES_256_CBC_SHA / 0xC02F, / TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 / 0xC014, / TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA / 0xC013, / TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA / 0, 0 }; #elif defined(INCLUDE_CIPHER_LIST) static int g_ciphersuite[5] = { 0xC030, / TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 / 0xC02B, / TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 / 0xC0AD, / TLS_ECDHE_ECDSA_WITH_AES_256_CCM / 0xC0AC, / TLS_ECDHE_ECDSA_WITH_AES_128_CCM / 0 }; #else static int g_ciphersuite[7] = { 0x2F, / TLS_RSA_WITH_AES_128_CBC_SHA / 0x35, / TLS_RSA_WITH_AES_256_CBC_SHA / 0x0A, / TLS_RSA_WITH_3DES_EDE_CBC_SHA / 0xC02F, / TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 / 0xC014, / TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA / 0xC013, / TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA */ 0 }; #endif static int g_accept_timeout = 5000; /* 5s / static int g_read_timeout = 5000; / 5s / static int g_write_timeout = 5000; / 5s */ void set_debug_level(int level) { ssl_log(SSL_ERROR, “mbedtls_debug_set_threshold %d”, level); mbedtls_debug_set_threshold(level); } void tls_init_lib(void) { ssl_loglevel_init(); } void tls_free_lib(void) { } void tls_clear_error(void) { } int tls_ctx_server_new(struct tls_root_ctx *ctx) { ssl_log(SSL_DEBUG, “enter %s”, FUNCTION); if (NULL == ctx) return -1; ctx->ca_chain = (mbedtls_x509_crt*)malloc(sizeof(mbedtls_x509_crt)); if (NULL == ctx->ca_chain) goto error; ctx->crt_chain = (mbedtls_x509_crt*)malloc(sizeof(mbedtls_x509_crt)); if (NULL == ctx->crt_chain) goto error; ctx->priv_key = (mbedtls_pk_context*)malloc(sizeof(mbedtls_pk_context)); if (NULL == ctx->priv_key) goto error; mbedtls_x509_crt_init(ctx->ca_chain); mbedtls_x509_crt_init(ctx->crt_chain); mbedtls_pk_init(ctx->priv_key); ctx->endpoint = MBEDTLS_SSL_IS_SERVER; ctx->initialised = 1; return 0; error: ssl_log(SSL_ERROR, “tls_ctx_server_new failed”); if (ctx->ca_chain) free(ctx->ca_chain); if (ctx->crt_chain) free(ctx->crt_chain); if (ctx->priv_key) free(ctx->priv_key); ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return -1; } int tls_ctx_client_new(struct tls_root_ctx *ctx) { ssl_log(SSL_DEBUG, “enter %s”, FUNCTION); if (NULL == ctx) return -1; ctx->ca_chain = (mbedtls_x509_crt*)malloc(sizeof(mbedtls_x509_crt)); if (NULL == ctx->ca_chain) goto error; ctx->crt_chain = (mbedtls_x509_crt*)malloc(sizeof(mbedtls_x509_crt)); if (NULL == ctx->crt_chain) goto error; ctx->priv_key = (mbedtls_pk_context*)malloc(sizeof(mbedtls_pk_context)); if (NULL == ctx->priv_key) goto error; mbedtls_x509_crt_init(ctx->ca_chain); mbedtls_x509_crt_init(ctx->crt_chain); mbedtls_pk_init(ctx->priv_key); ctx->verify_time = 0; ctx->verify_cn = NULL; ctx->endpoint = MBEDTLS_SSL_IS_CLIENT; ctx->initialised = 1; return 0; error: ssl_log(SSL_ERROR, “tls_ctx_client_new failed”); if (ctx->ca_chain) free(ctx->ca_chain); if (ctx->crt_chain) free(ctx->crt_chain); if (ctx->priv_key) free(ctx->priv_key); ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return -1; } void tls_ctx_free(struct tls_root_ctx *ctx) { if (ctx) { mbedtls_pk_free(ctx->priv_key); if (ctx->priv_key) { free(ctx->priv_key); } mbedtls_x509_crt_free(ctx->ca_chain); if (ctx->ca_chain) { free(ctx->ca_chain); } mbedtls_x509_crt_free(ctx->crt_chain); if (ctx->crt_chain) { free(ctx->crt_chain); } ctx->verify_time = 0; ctx->verify_cn = NULL; ctx->initialised = 0; free(ctx); ctx = NULL; } } int tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags) { return 0; } static int verify_callback( void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags ) { char buf[1024]; ((void) data); ssl_log(SSL_ERROR, "Verify requested for (Depth %d):", depth); mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt); ssl_log(SSL_ERROR, "%s", buf); if ((*flags) == 0) { ssl_log(SSL_ERROR, "This certificate has no flags"); } else { mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", *flags); ssl_log(SSL_ERROR, "%s\n", buf); } return 0; } int tls_ctx_verify_cloud(struct tls_root_ctx *ctx, char *cert_file, int verify_time, char *cn) { ssl_log(SSL_DEBUG, “enter %s”, FUNCTION); if (NULL == ctx || NULL == cert_file) return -1; if (NULL == ctx->crt_chain || mbedtls_x509_crt_parse_file(ctx->crt_chain, cert_file) != 0) { ssl_log(SSL_ERROR, "load cer file error"); return -1; } ctx->verify_time = verify_time; ctx->verify_cn = cn; ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return 0; } int tls_ctx_verify_ca_buf(struct tls_root_ctx *ctx, const void *cert_buf, size_t len) { int ret = 0; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == cert_buf || NULL == ctx || NULL == ctx->crt_chain) return -1; ssl_log(SSL_DEBUG, "buf len: %d %d", len, strlen(cert_buf)); if ((ret = mbedtls_x509_crt_parse(ctx->crt_chain, cert_buf, len)) != 0) { ssl_log(SSL_ERROR, "mbedtls_x509_crt_parse fail. ret=%d", ret); return -1; } ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return 0; } int tls_ctx_verify_init(struct tls_root_ctx *ctx, int depth, char *ca_path, void *ud) { ssl_log(SSL_DEBUG, “enter %s”, FUNCTION); if (NULL == ctx || NULL == ca_path) return -1; if (NULL == ctx->ca_chain || mbedtls_x509_crt_parse_file(ctx->ca_chain, ca_path) != 0) { ssl_log(SSL_ERROR, "mbedtls_x509_crt_parse_file fail."); return -1; } ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return 0; } int tls_ctx_check_key(struct tls_root_ctx *ctx, char *cert_file, char *key_file, void *passwd) { int status; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == ctx || NULL == cert_file || NULL == key_file || NULL == ctx->crt_chain) return -1; if ((status = mbedtls_x509_crt_parse_file(ctx->crt_chain, cert_file)) != 0) { ssl_log(SSL_ERROR, "mbedtls_x509_crt_parse_file fail. ret=%d", status); return -1; } if (NULL == ctx->priv_key) return -1; status = mbedtls_pk_parse_keyfile(ctx->priv_key, key_file, NULL); if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status) { status = mbedtls_pk_parse_keyfile(ctx->priv_key, key_file, (const char*)passwd); } if (0 != status) { ssl_log(SSL_ERROR, "Cannot load private key file %s", key_file); return -1; } if (mbedtls_pk_check_pair(&ctx->crt_chain->pk, ctx->priv_key) != 0) { ssl_log(SSL_ERROR, "Private key does not match the certificate"); return -1; } ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return 0; } static void tp_debug(void *ctx, int level, const char *file, int line, const char *str) { const char *p, *basename; /* Extract basename from file */ for (p = basename = file; *p != '\0'; p++) if (*p == '/' || *p == '\\') basename = p + 1; fprintf((FILE *)ctx, "%s:%04d: |%d| %s", basename, line, level, str); fflush((FILE *)ctx); } static void ssl_init_debug_level(void) { int level = 1; FILE *f = NULL; char line[5] = {0}; f = fopen("/var/mbedtls/dbg", "r"); if (f == NULL || fgets(line, sizeof(line), f) == NULL || sscanf(line, "%d", &level) != 1) { level = 0; } if (f != NULL) fclose(f); set_debug_level(level); } static void ssl_init_timeout(void) { int accept_timeout = 5000; int read_timeout = 5000; int write_timeout = 5000; FILE *f = NULL; char line[32] = {0}; f = fopen("/var/mbedtls/timeout", "r"); if (f == NULL || fgets(line, sizeof(line), f) == NULL || sscanf(line, "%d %d %d", &accept_timeout, &read_timeout, &write_timeout) != 3) { if (f != NULL) fclose(f); return; } if (f != NULL) fclose(f); g_accept_timeout = accept_timeout; g_read_timeout = read_timeout; g_write_timeout = write_timeout; ssl_log(SSL_ERROR, "g_accept_timeout: %d, g_read_timeout: %d, g_write_timeout: %d\n", g_accept_timeout, g_read_timeout, g_write_timeout); } static void ssl_init_hs_dbg_level(void) { int level = 1; FILE *f = NULL; char line[5] = {0}; f = fopen("/var/mbedtls/hs", "r"); if (f == NULL || fgets(line, sizeof(line), f) == NULL || sscanf(line, "%d", &level) != 1) { level = 0; } if (f != NULL) fclose(f); set_debug_level(level); } static void ssl_init_stream(struct tp_stream *stream) { stream->buf[0] = ‘\0’; stream->cur = stream->buf; stream->end = stream->buf; } static inline void buf_free_entry(struct buf_entry *entry) { if (NULL != entry) { //printf(“-free %p\n”, entry); free(entry->data); free(entry); } } static void buf_free_entries(struct write_buf *buf) { while (buf->first_block) { struct buf_entry *cur_block = buf->first_block; buf->first_block = cur_block->next_block; buf_free_entry(cur_block); } buf->last_block = NULL; buf->cur_block = NULL; buf->data_len = 0; } static struct buf_entry* buf_create_entry(void) { struct buf_entry *entry = (struct buf_entry *)malloc(sizeof(struct buf_entry)); if (NULL == entry) return NULL; entry->data = (char *)malloc(TP_BUF_ENTRY_LEN); if (NULL == entry->data) { free(entry); return NULL; } entry->used_len = 0; entry->free_len = TP_BUF_ENTRY_LEN; entry->next_block = NULL; //printf("+create %p\n", entry); return entry; } static int buf_write_data_1block(struct write_buf *buf, char *in, size_t len) { struct buf_entry *cur_block = buf->cur_block; if (len > TP_BUF_ENTRY_LEN) { return -1; } if (NULL == cur_block) { cur_block = buf_create_entry(); if (NULL == cur_block) return -1; cur_block->next_block = NULL; if (NULL == buf->first_block) { buf->first_block = cur_block; } if (NULL != buf->last_block) { buf->last_block->next_block = cur_block; } buf->last_block = buf->cur_block = cur_block; } else { if (cur_block->free_len < len) { cur_block= cur_block->next_block; if (NULL == cur_block) { cur_block = buf_create_entry(); if (NULL == cur_block) return -1; cur_block->next_block = NULL; buf->last_block->next_block = cur_block; buf->last_block = buf->cur_block = cur_block; } else { if (cur_block->free_len != TP_BUF_ENTRY_LEN || cur_block->used_len > 0) { ssl_log(SSL_ERROR, "free_len: %d, used_len: %d\n", cur_block->free_len, cur_block->used_len); return -1; } buf->cur_block = cur_block; } } } //printf("cur_block: %p\n", cur_block); if (cur_block->free_len < len) { ssl_log(SSL_ERROR, "free_len: %d, len: %d\n", cur_block->free_len, len); return -1; } if (cur_block->used_len + len > TP_BUF_ENTRY_LEN) { ssl_log(SSL_ERROR, "used_len: %d, len: %d\n", cur_block->used_len, len); return -1; } memcpy(cur_block->data + cur_block->used_len, in, len); cur_block->used_len += len; cur_block->free_len -= len; buf->data_len += len; return len; } static int buf_write_data(struct write_buf *buf, char *in, size_t len) { int ret; size_t write_len = 0; size_t left_len = len; while (left_len > 0) { ret = (left_len < TP_BUF_ENTRY_LEN) ? left_len : TP_BUF_ENTRY_LEN; ret = buf_write_data_1block(buf, in + write_len, ret); if (ret <= 0) return -1; write_len += ret; left_len -= ret; } return write_len; } static int buf_read_data(struct write_buf *buf, char *out, size_t len) { size_t read_len = 0; struct buf_entry *cur_block = buf->first_block; while (cur_block) { if (cur_block->used_len == 0) return read_len; if (len - read_len < cur_block->used_len) return read_len; memcpy(out + read_len, cur_block->data, cur_block->used_len); read_len += cur_block->used_len; cur_block = cur_block->next_block; } return read_len; } static size_t buf_get_data_len(struct write_buf *buf) { return buf->data_len; } static void buf_reinit(struct write_buf *buf) { if (NULL == buf) return; struct buf_entry *cur_block = buf->first_block; while (cur_block) { cur_block->free_len = TP_BUF_ENTRY_LEN; cur_block->used_len = 0; cur_block = cur_block->next_block; } buf->cur_block = buf->first_block; buf->data_len = 0; } #if 0 static void buf_info(struct write_buf *buf) { struct buf_entry *cur_block; printf("%d (%p %p %p)\n", buf->data_len, buf->first_block, buf->cur_block, buf->last_block); cur_block = buf->first_block; while (cur_block) { printf("%p: %d %d\n", cur_block, cur_block->free_len, cur_block->used_len); cur_block = cur_block->next_block; } } #endif static long long get_time_ms() { struct timeval tv; if (0 != gettimeofday(&tv, NULL)) { return 0; } return ((long long)tv.tv_sec * 1000 + (long long)tv.tv_usec / 1000); } #ifdef INCLUDE_HTTP_SSL_MIN_TLS1_2 int ssl_init(struct tp_ssl *ssl, const struct tls_root_ctx *ssl_ctx, int is_server, int is_cwmp) #else int ssl_init(struct tp_ssl *ssl, const struct tls_root_ctx ssl_ctx, int is_server) #endif / INCLUDE_HTTP_SSL_MIN_TLS1_2 */ { int ret = -1; const char *pers = “tp_ssl”; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == ssl || NULL == ssl_ctx) return -1; memset(ssl, 0, sizeof(struct tp_ssl)); ssl_init_debug_level(); ssl_init_timeout(); mbedtls_ctr_drbg_init(&ssl->ctr_drbg); mbedtls_entropy_init(&ssl->entropy); if ((ret = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg, mbedtls_entropy_func, &ssl->entropy, (const unsigned char *) pers, strlen(pers))) != 0) { ssl_log(SSL_ERROR, "mbedtls_ctr_drbg_seed returned %d\n", ret ); goto exit; } /* Initialise SSL config */ mbedtls_ssl_config_init(&ssl->ssl_config); if ((ret = mbedtls_ssl_config_defaults(&ssl->ssl_config, ssl_ctx->endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { ssl_log(SSL_ERROR, "mbedtls_ssl_config_defaults returned %d\n", ret ); goto exit; } mbedtls_ssl_conf_rng(&ssl->ssl_config, mbedtls_ctr_drbg_random, &ssl->ctr_drbg); mbedtls_ssl_conf_dbg(&ssl->ssl_config, tp_debug, stdout); mbedtls_ssl_cache_init(&ssl->cache); mbedtls_ssl_conf_session_cache(&ssl->ssl_config, &ssl->cache, mbedtls_ssl_cache_get, mbedtls_ssl_cache_set); mbedtls_ssl_conf_ciphersuites(&ssl->ssl_config, g_ciphersuite); mbedtls_ssl_conf_ca_chain(&ssl->ssl_config, ssl_ctx->ca_chain, NULL); if ((ret = mbedtls_ssl_conf_own_cert(&ssl->ssl_config, ssl_ctx->crt_chain, ssl_ctx->priv_key)) != 0) { ssl_log(SSL_ERROR, "mbedtls_ssl_conf_own_cert returned %d\n", ret ); goto exit; } if (!is_server) { mbedtls_ssl_conf_verify(&ssl->ssl_config, verify_callback, NULL); mbedtls_ssl_conf_authmode(&ssl->ssl_config, MBEDTLS_SSL_VERIFY_OPTIONAL); } #ifdef INCLUDE_IMDA mbedtls_ssl_conf_min_version(&ssl->ssl_config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); #else #ifdef INCLUDE_HTTP_SSL_MIN_TLS1_2 if (1 != is_cwmp) { mbedtls_ssl_conf_min_version(&ssl->ssl_config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); } else #endif /* INCLUDE_HTTP_SSL_MIN_TLS1_2 / { mbedtls_ssl_conf_min_version(&ssl->ssl_config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1); } #endif / INCLUDE_IMDA */ mbedtls_ssl_conf_max_version(&ssl->ssl_config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); /* Initialise SSL context */ ssl->ctx = (mbedtls_ssl_context*)malloc(sizeof(mbedtls_ssl_context)); if (NULL == ssl->ctx) goto exit; mbedtls_ssl_init(ssl->ctx); if (mbedtls_ssl_setup(ssl->ctx, &ssl->ssl_config) != 0) { ssl_log(SSL_ERROR, "mbedtls_ssl_setup failed"); return -1; } if (is_server) { ssl->endpoint = MBEDTLS_SSL_IS_SERVER; } else { if (ssl_ctx->verify_cn) { mbedtls_ssl_set_hostname(ssl->ctx, ssl_ctx->verify_cn); ssl->verify_cn = 1; } if (ssl_ctx->verify_time) { ssl->verify_time = 1; } ssl->endpoint = MBEDTLS_SSL_IS_CLIENT; } ssl_init_stream(&ssl->stream); ret = 0; exit: ssl_log(SSL_DEBUG, "leave %s ret=%d", __FUNCTION__, ret); return ret; } void ssl_free(struct tp_ssl *ssl) { if (ssl) { if (ssl->ctx) { mbedtls_ssl_free(ssl->ctx); free(ssl->ctx); } mbedtls_ssl_config_free(&ssl->ssl_config); mbedtls_ctr_drbg_free(&ssl->ctr_drbg); mbedtls_entropy_free(&ssl->entropy); mbedtls_ssl_cache_free(&ssl->cache); if (ssl->endpoint == MBEDTLS_SSL_IS_SERVER) { mbedtls_net_free(&ssl->client_fd); } if (ssl->endpoint == MBEDTLS_SSL_IS_CLIENT) { mbedtls_net_free(&ssl->server_fd); } buf_free_entries(&ssl->out); ssl->verify_cn = 0; ssl->verify_time = 0; free(ssl); ssl = NULL; } } void ssl_shutdown(struct tp_ssl *ssl) { int ret; if (NULL == ssl || NULL == ssl->ctx) return; do { ssl_log(SSL_DEBUG, "=========================================================== ->\n"); ret = mbedtls_ssl_close_notify(ssl->ctx); ssl_log(SSL_DEBUG, "=========================================================== <-\n"); } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE); } int ssl_reset(struct tp_ssl *ssl, const struct tls_root_ctx *ssl_ctx) { if (NULL == ssl || NULL == ssl->ctx) return -1; //mbedtls_ssl_session_reset(ssl->ctx); if (ssl->endpoint == MBEDTLS_SSL_IS_SERVER) { ssl_log(SSL_DEBUG, "close %d", ssl->client_fd.fd); mbedtls_net_free(&ssl->client_fd); } if (ssl->endpoint == MBEDTLS_SSL_IS_CLIENT) { ssl_log(SSL_DEBUG, "close %d", ssl->server_fd.fd); mbedtls_net_free(&ssl->server_fd); } ssl_init_stream(&ssl->stream); //buf_reinit(&ssl->out); buf_free_entries(&ssl->out); /* free the out buffer, not just reinit */ return 0; } #if defined (INCLUDE_DYNDNS_HTTPS) || defined(INCLUDE_NOIPDNS_HTTPS) int ssl_connect(struct tp_ssl *ssl, int sockfd, int timeout, int needTrustedCA) #else int ssl_connect(struct tp_ssl ssl, int sockfd, int timeout) #endif / INCLUDE_DYNDNS_HTTPS || INCLUDE_NOIPDNS_HTTPS */ { int ret; unsigned int flags; long long time_remain = (long long)timeout; long long time_begin = 0; long long time_spend = 0; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == ssl || NULL == ssl->ctx) { return -1; } mbedtls_net_init(&ssl->server_fd); ssl_log(SSL_DEBUG, "mbedtls_ssl_set_bio"); ssl->server_fd.fd = sockfd; //mbedtls_ssl_set_bio(ssl->ctx, &ssl->server_fd, mbedtls_net_send, mbedtls_net_recv, NULL); mbedtls_ssl_conf_read_timeout(&ssl->ssl_config, timeout); mbedtls_ssl_set_bio(ssl->ctx, &ssl->server_fd, mbedtls_net_send, NULL, mbedtls_net_recv_timeout); ssl_log(SSL_DEBUG, "mbedtls_ssl_handshake"); ssl_init_hs_dbg_level(); while((ret = mbedtls_ssl_handshake(ssl->ctx)) != 0) { if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { ssl_log(SSL_ERROR, "mbedtls_ssl_handshake returned -0x%x", -ret); return -1; } time_begin = get_time_ms(); time_remain -= time_spend; ssl_log(SSL_ERROR, "==> time_remain: %llu ms time_spend: %llu ms", time_remain, time_spend); if (time_remain < 0) { ssl_log(SSL_ERROR, "==> mbedtls_ssl_handshake timeout %d ms", timeout); return -1; } fd_set fds; FD_ZERO(&fds); FD_SET(sockfd, &fds); struct timeval tv; tv.tv_sec = (long)(time_remain / 1000); tv.tv_usec = (long)(time_remain % 1000) * 1000; switch (ret) { case MBEDTLS_ERR_SSL_WANT_READ: select(sockfd +1, &fds, NULL, NULL, &tv); break; case MBEDTLS_ERR_SSL_WANT_WRITE: select(sockfd +1, NULL, &fds, NULL, &tv); break; default: ssl_log(SSL_ERROR, "mbedtls_ssl_handshake returned -0x%x", -ret); return -1; } time_spend = get_time_ms() - time_begin; } ssl_init_debug_level(); ssl_log(SSL_DEBUG, "mbedtls_ssl_get_verify_result"); if ((flags = mbedtls_ssl_get_verify_result(ssl->ctx)) != 0) { char vrfy_buf[512]; ssl_log(SSL_ERROR, "mbedtls_ssl_get_verify_result failed"); mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags); ssl_log(SSL_ERROR, "%s", vrfy_buf); ssl_log(SSL_ERROR, "verify flags: 0x%x", flags); if ((ssl->verify_time && (MBEDTLS_X509_BADCERT_EXPIRED & flags)) || (ssl->verify_cn && (MBEDTLS_X509_BADCERT_CN_MISMATCH & flags)) || (MBEDTLS_X509_BADCERT_REVOKED & flags) || (MBEDTLS_X509_BADCERT_BAD_MD & flags)) { return -1; } #if defined (INCLUDE_DYNDNS_HTTPS) || defined(INCLUDE_NOIPDNS_HTTPS) if (needTrustedCA && (MBEDTLS_X509_BADCERT_NOT_TRUSTED & flags)) { return -1; } #endif /* INCLUDE_DYNDNS_HTTPS || INCLUDE_NOIPDNS_HTTPS */ } ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return 0; } int ssl_accept(struct tp_ssl *ssl, int sockfd) { int ret; long long time_remain = (long long)g_accept_timeout; long long time_begin = 0; long long time_spend = 0; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == ssl || NULL == ssl->ctx) { return -1; } mbedtls_net_init(&ssl->client_fd); mbedtls_ssl_session_reset(ssl->ctx); ssl->client_fd.fd = sockfd; mbedtls_ssl_conf_read_timeout(&ssl->ssl_config, time_remain); mbedtls_ssl_set_bio(ssl->ctx, &ssl->client_fd, mbedtls_net_send, NULL, mbedtls_net_recv_timeout); #ifdef SSL_DEBUG_TIME struct timeval time_s; struct timeval time_e; int time = 0; gettimeofday(&time_s, NULL); #endif ssl_init_hs_dbg_level(); while((ret = mbedtls_ssl_handshake(ssl->ctx)) != 0) { if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { ssl_log(SSL_ERROR, “mbedtls_ssl_handshake returned -0x%x”, -ret); return -1; } time_begin = get_time_ms(); time_remain -= time_spend; ssl_log(SSL_ERROR, "==> time_remain: %llu ms time_spend: %llu ms", time_remain, time_spend); if (time_remain < 0) { ssl_log(SSL_ERROR, "==> mbedtls_ssl_handshake timeout %d ms", g_accept_timeout); return -1; } fd_set fds; FD_ZERO(&fds); FD_SET(sockfd, &fds); struct timeval tv; tv.tv_sec = (long)(time_remain / 1000); tv.tv_usec = (long)(time_remain % 1000) * 1000; switch (ret) { case MBEDTLS_ERR_SSL_WANT_READ: select(sockfd +1, &fds, NULL, NULL, &tv); break; case MBEDTLS_ERR_SSL_WANT_WRITE: select(sockfd +1, NULL, &fds, NULL, &tv); break; default: ssl_log(SSL_ERROR, "mbedtls_ssl_handshake returned -0x%x", -ret); return -1; } time_spend = get_time_ms() - time_begin; } ssl_init_debug_level(); #ifdef SSL_DEBUG_TIME gettimeofday(&time_e, NULL); time = ((time_e.tv_sec - time_s.tv_sec) * 1000000 + time_e.tv_usec - time_s.tv_usec); printf(“<<<<< ssl handshake: %d us %d >>>>>\n”, time, sockfd); #endif ssl_log(SSL_DEBUG, "[ Protocol is %s ]\n[ Ciphersuite is %s ]", mbedtls_ssl_get_version(ssl->ctx), mbedtls_ssl_get_ciphersuite(ssl->ctx)); ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return 0; } int ssl_read(struct tp_ssl *ssl, void *buf, int len) { int ret; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == ssl || NULL == ssl->ctx || NULL == buf) { return -1; } long long time_out = (long long)g_read_timeout; long long time_begin = get_time_ms(); do { ret = mbedtls_ssl_read(ssl->ctx, buf, len); if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { if (get_time_ms() - time_begin > time_out) { ssl_log(SSL_ERROR, "mbedtls_ssl_read timeout: %llu ms", time_out); return -1; } else { usleep(20 * 1000); continue; } } if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { ssl_log(SSL_ERROR, "MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY"); break; } if(ret == MBEDTLS_ERR_NET_CONN_RESET) { ssl_log(SSL_ERROR, "MBEDTLS_ERR_NET_CONN_RESET"); break; } if(ret <= 0) { ssl_log(SSL_ERROR, "mbedtls_ssl_read returned %d", ret); break; } if (ret > 0) { ssl_log(SSL_DEBUG, "read buf: len=%d [\n%s\n] ", len, (char*)buf); break; } }while (1); ssl_log(SSL_DEBUG, "leave %s ret=%d", __FUNCTION__, ret); //printf("++++++ ssl_read %d %d ++++++\n", len, ret); return ret; } int ssl_write(struct tp_ssl *ssl, void *buf, int len) { int ret = 0; int written = 0; int frags = 0; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == ssl || NULL == ssl->ctx || NULL == buf) { return -1; } for (written = 0, frags = 0; written < len; written += ret, frags++) { long long time_out = (long long)g_write_timeout; long long time_begin = get_time_ms(); while ((ret = mbedtls_ssl_write(ssl->ctx, buf + written, len - written)) <= 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { ssl_log(SSL_ERROR, "mbedtls_ssl_write returned %d", ret); return ret; } if (get_time_ms() - time_begin > time_out) { ssl_log(SSL_ERROR, "mbedtls_ssl_write timeout: %llu ms", time_out); return -1; } else { usleep(20 * 1000); continue; } } } ssl_log(SSL_DEBUG, "leave %s ret=%d", __FUNCTION__, ret); //printf("frags=%d\n", frags); return written; } int bio_printf(struct tp_ssl *ssl, const char *format, …) { va_list args; int ret; char buf[1024] = {0}; va_start(args, format); ret = vsnprintf(buf, 1024, format, args); va_end(args); //printf("++++++ bio_printf %d ++++++\n", ret); //printf("++ %s", buf); return bio_write(ssl, buf, ret); } int bio_write(struct tp_ssl *ssl, void *buf, int len) { //printf(“++++++ bio_write %d ++++++\n”, len); if (NULL == ssl || NULL == buf) return -1; return buf_write_data(&ssl->out, buf, len); } int bio_flush(struct tp_ssl *ssl) { int ret; int len; char *buf; if (NULL == ssl) return -1; len = buf_get_data_len(&ssl->out); if (0 == len) return 0; buf = (char *)malloc(len); if (NULL == buf) return -1; ret = buf_read_data(&ssl->out, buf, len); if (ret != len) { free(buf); return -1; } //buf_info(&ssl->out); ret = ssl_write(ssl, buf, len); if (ret != len) { ssl_log(SSL_ERROR, "ssl_write len=%d ret=%d\n", len, ret); } free(buf); buf_reinit(&ssl->out); //buf_info(&ssl->out); ssl_log(SSL_DEBUG, "++++++ bio_flush %d ++++++\n", len); return ret; } int bio_read(struct tp_ssl *ssl, void *buf, int len) { int ret = 0; if (NULL == ssl || NULL == buf) return -1; struct tp_stream *stream = &ssl->stream; if ((stream->end - stream->cur) == 0) return 0; if (len <= (stream->end - stream->cur)) { memcpy(buf, stream->cur, len); ret = len; } else { memcpy(buf, stream->cur, (stream->end - stream->cur)); ret = (stream->end - stream->cur); } stream->cur += ret; //printf("++++++ bio_read %d ++++++\n", len); return ret; } int bio_gets(struct tp_ssl *ssl, void *buf, int len) { int ret = 0; char *index = (char *)buf; if (NULL == ssl || NULL == buf) return -1; struct tp_stream *stream = &ssl->stream; //printf("++++++ bio_gets %d ++++++\n", len); while(--len) { if (stream->cur < stream->end) { if ((*index = *stream->cur++) == '\n') { if (index > (char *)buf && *(index - 1) == '\r') { index++; break; } } index++; } else { len++; stream->cur = stream->buf; ret = ssl_read(ssl, stream->buf, TP_STREAM_LEN); if (ret == 0) { ssl_log(SSL_ERROR, "ssl_read returned %d", ret); return 0; } if (ret < 0) { ssl_log(SSL_ERROR, "ssl_read returned %d", ret); return -1; } stream->buf[ret] = '\0'; stream->end = stream->cur + ret; continue; } } if (index > (char *)buf) { *index = '\0'; //printf("-- %s", (char *)buf); ssl_log(SSL_DEBUG, "bio_gets: %s", (char *)buf); return (index - (char *)buf); } ssl_log(SSL_DEBUG, "bio_gets: \n%s", (char *)buf); return ret; } int gen_rand_bytes(unsigned char *buf, size_t len) { int ret; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_init( &ctr_drbg ); mbedtls_entropy_init( &entropy ); if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)"RANDOM_GEN", 10)) != 0) { ssl_log(SSL_ERROR, "failed in mbedtls_ctr_drbg_seed: %d", ret); goto exit; } mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_OFF); if ((ret = mbedtls_ctr_drbg_random(&ctr_drbg, buf, len)) != 0) { ssl_log(SSL_ERROR, "failed in mbedtls_ctr_drbg_random: %d", ret); goto exit; } ret = 0; exit: mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); return ret; } unsigned long long gen_rand_num(int predicable) { int i; unsigned char buf[8]; unsigned long long rand = 0; if (gen_rand_bytes(buf, 8) != 0) { return 0; } for (i = 0; i < 8; i++) { rand = (rand << 8) | buf[i]; } ssl_log(SSL_DEBUG, "gen rand: %llx\n", rand); return rand; } #if 0 #define DEV_RANDOM_THRESHOLD 32 static int dev_random_entropy_poll( void *data, unsigned char *output, size_t len, size_t *olen ) { FILE *file; size_t ret, left = len; unsigned char *p = output; ((void) data); ssl_log(SSL_DEBUG, "enter %s\n", __FUNCTION__); *olen = 0; file = fopen( "/dev/random", "rb" ); if (file == NULL) return (MBEDTLS_ERR_ENTROPY_SOURCE_FAILED); while (left > 0) { /* /dev/random can return much less than requested. If so, try again */ ret = fread(p, 1, left, file); if (ret == 0 && ferror( file)) { fclose (file); return (MBEDTLS_ERR_ENTROPY_SOURCE_FAILED); } p += ret; left -= ret; sleep(1); printf("ret=%d left=%d\n", ret, left); } fclose(file); *olen = len; ssl_log(SSL_DEBUG, "leave %s\n", __FUNCTION__); return 0; } #endif int gen_pkey(pkey_t **pkey, unsigned int bits) { int ret = -1; mbedtls_pk_context *key; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; const char *pers = "gen_key"; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == pkey) return -1; key = (mbedtls_pk_context*)malloc(sizeof(mbedtls_pk_context)); if (NULL == key) return -1; mbedtls_pk_init(key); mbedtls_ctr_drbg_init(&ctr_drbg); mbedtls_entropy_init(&entropy); #if 0 if ((ret = mbedtls_entropy_add_source(&entropy, dev_random_entropy_poll, NULL, DEV_RANDOM_THRESHOLD, MBEDTLS_ENTROPY_SOURCE_STRONG)) != 0) { ssl_log(SSL_ERROR, “mbedtls_entropy_add_source returned -0x%04x”, -ret); goto exit; } ssl_log(SSL_DEBUG, “mbedtls_entropy_add_source done”); #endif if ((ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen(pers))) != 0) { ssl_log(SSL_ERROR, "mbedtls_ctr_drbg_seed returned -0x%04x", -ret ); goto exit; } ssl_log(SSL_DEBUG, "mbedtls_ctr_drbg_seed done"); if ((ret = mbedtls_pk_setup(key, mbedtls_pk_info_from_type((mbedtls_pk_type_t)MBEDTLS_PK_RSA))) != 0) { ssl_log(SSL_ERROR, "mbedtls_pk_setup returned -0x%04x", -ret ); goto exit; } ssl_log(SSL_DEBUG, "mbedtls_pk_setup done"); ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(*key), mbedtls_ctr_drbg_random, &ctr_drbg, bits, 65537); if(ret != 0) { ssl_log(SSL_ERROR, "mbedtls_rsa_gen_key returned -0x%04x", -ret ); goto exit; } ssl_log(SSL_DEBUG, "mbedtls_rsa_gen_key done"); ret = 0; *pkey = key; exit: if (ret != 0) mbedtls_pk_free(key); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return ret; } static int print_pkey(pkey_t *key) { int ret = -1; mbedtls_mpi N, P, Q, D, E, DP, DQ, QP; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); mbedtls_mpi_init(&N); mbedtls_mpi_init(&P); mbedtls_mpi_init(&Q); mbedtls_mpi_init(&D); mbedtls_mpi_init(&E); mbedtls_mpi_init(&DP); mbedtls_mpi_init(&DQ); mbedtls_mpi_init(&QP); if (mbedtls_pk_get_type(key) == MBEDTLS_PK_RSA) { mbedtls_rsa_context *rsa = mbedtls_pk_rsa(*key); if ((ret = mbedtls_rsa_export(rsa, &N, &P, &Q, &D, &E)) != 0 || (ret = mbedtls_rsa_export_crt(rsa, &DP, &DQ, &QP)) != 0) { ssl_log(SSL_ERROR, "could not export RSA parameters"); goto exit; } mbedtls_mpi_write_file("N: ", &N, 16, NULL); mbedtls_mpi_write_file("E: ", &E, 16, NULL); mbedtls_mpi_write_file("D: ", &D, 16, NULL); mbedtls_mpi_write_file("P: ", &P, 16, NULL); mbedtls_mpi_write_file("Q: ", &Q, 16, NULL); mbedtls_mpi_write_file("DP: ", &DP, 16, NULL); mbedtls_mpi_write_file("DQ: ", &DQ, 16, NULL); mbedtls_mpi_write_file("QP: ", &QP, 16, NULL); } else { ssl_log(SSL_ERROR, "error pk type."); goto exit; } ret = 0; exit: mbedtls_mpi_free(&N); mbedtls_mpi_free(&P); mbedtls_mpi_free(&Q); mbedtls_mpi_free(&D); mbedtls_mpi_free(&E); mbedtls_mpi_free(&DP); mbedtls_mpi_free(&DQ); mbedtls_mpi_free(&QP); ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return ret; } int write_private_key(pkey_t *key, const char *output_file) { int ret; FILE *f = NULL; unsigned char *output_buf = NULL; size_t len = 0; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == key || NULL == output_file) return -1; print_pkey(key); output_buf = (unsigned char *)malloc(16000); if (NULL == output_buf) return -1; memset(output_buf, 0, 16000); if((ret = mbedtls_pk_write_key_pem(key, output_buf, 16000)) != 0) { ssl_log(SSL_ERROR, "mbedtls_pk_write_key_pem returned -0x%04x", -ret ); goto exit; } len = strlen((char *)output_buf); if((f = fopen(output_file, "wb")) == NULL) { ssl_log(SSL_ERROR, "open %s fail.", output_file); goto exit; } if(fwrite(output_buf, 1, len, f) != len) { ssl_log(SSL_ERROR, "fwrite fail."); goto exit; } ret = 0; exit: if (f) fclose(f); if (output_buf) free(output_buf); ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return ret; } void free_pkey(pkey_t *key) { if (key) { mbedtls_pk_free(key); free(key); key = NULL; } } static int gen_cert(unsigned char *buf, size_t size, int self_sign, int is_ca, x509_cert_t *issuer_cert, pkey_t *issuer_key, pkey_t *subject_key, char *subject_name, char *issuer_name, const char *not_before, const char *not_after, int pathlen, const char *san) { int ret = 0; mbedtls_x509write_cert crt; mbedtls_mpi serial; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; char ca_subject_name[256]; pkey_t *set_subject_key, *set_issuer_key; char *set_subject_name, *set_issuer_name; int max_pathlen = pathlen; const char *pers = "tp-link app"; unsigned long long serial_num; char serial_str[20] = {0}; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == buf || NULL == issuer_key) return -1; set_subject_key = subject_key; set_issuer_key = issuer_key; set_subject_name = subject_name; set_issuer_name = issuer_name; mbedtls_x509write_crt_init(&crt); mbedtls_mpi_init(&serial); mbedtls_ctr_drbg_init(&ctr_drbg); mbedtls_entropy_init(&entropy); if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen(pers))) != 0) { ssl_log(SSL_ERROR, "mbedtls_ctr_drbg_seed fail."); goto exit; } serial_num = gen_rand_num(0); snprintf(serial_str, 20, "%llx", serial_num); if ((ret = mbedtls_mpi_read_string(&serial, 16, serial_str)) != 0) { ssl_log(SSL_ERROR, "mbedtls_mpi_read_string fail."); goto exit; } if(!self_sign) { if (NULL == issuer_cert) { ssl_log(SSL_ERROR, "issuer_cert should not be NULL."); goto exit; } ret = mbedtls_x509_dn_gets(ca_subject_name, sizeof(ca_subject_name), &issuer_cert->subject); if( ret < 0 ) { ssl_log(SSL_ERROR, "mbedtls_x509_dn_gets fail."); goto exit; } set_issuer_name = ca_subject_name; if (NULL == subject_key) { ssl_log(SSL_ERROR, "subject_key and issuer_key should not be NULL."); goto exit; } } if (issuer_cert) { if (mbedtls_pk_check_pair(&issuer_cert->pk, issuer_key) != 0) { ssl_log(SSL_ERROR, "issuer_key does not match issuer certificate."); goto exit; } } if (self_sign) { set_subject_name = set_issuer_name; set_subject_key = set_issuer_key; } mbedtls_x509write_crt_set_subject_key(&crt, set_subject_key); mbedtls_x509write_crt_set_issuer_key(&crt, set_issuer_key); if ((ret = mbedtls_x509write_crt_set_subject_name(&crt, set_subject_name)) != 0) { ssl_log(SSL_ERROR, "mbedtls_x509write_crt_set_subject_name " "returned -0x%04x", -ret); goto exit; } if ((ret = mbedtls_x509write_crt_set_issuer_name(&crt, set_issuer_name)) != 0) { ssl_log(SSL_ERROR, "mbedtls_x509write_crt_set_issuer_name " "returned -0x%04x", -ret); goto exit; } mbedtls_x509write_crt_set_version(&crt, 2); mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256); if ((ret = mbedtls_x509write_crt_set_serial(&crt, &serial)) != 0) { ssl_log(SSL_ERROR, "mbedtls_x509write_crt_set_serial " "returned -0x%04x", -ret); goto exit; } if ((ret = mbedtls_x509write_crt_set_validity(&crt, not_before, not_after)) != 0) { ssl_log(SSL_ERROR, "mbedtls_x509write_crt_set_validity " "returned -0x%04x", -ret); goto exit; } if (is_ca) { max_pathlen = 0; } if ((ret = mbedtls_x509write_crt_set_basic_constraints(&crt, is_ca, max_pathlen)) != 0) { ssl_log(SSL_ERROR, "mbedtls_x509write_crt_set_basic_constraints " "returned -0x%04x", -ret); goto exit; } if ((ret = mbedtls_x509write_crt_set_subject_key_identifier(&crt)) != 0) { ssl_log(SSL_ERROR, "mbedtls_x509write_crt_set_subject_key_identifier " "returned -0x%04x", -ret); goto exit; } if ((ret = mbedtls_x509write_crt_set_authority_key_identifier(&crt)) != 0) { ssl_log(SSL_ERROR, "mbedtls_x509write_crt_set_authority_key_identifier " "returned -0x%04x", -ret); goto exit; } if (!is_ca && san) { // set san ssl_log(SSL_DEBUG, "san: %s", san); ret = mbedtls_x509write_crt_set_subject_alt_name(&crt, (const unsigned char *)san, strlen(san)); //char *san_tmp = "DNS:tplinkmodem.net,DNS:192.168.1.1,IP:192.168.1.1"; //ret = mbedtls_x509write_crt_set_subject_alt_name(&crt, (const unsigned char *)san_tmp, strlen(san_tmp)); if (ret != 0) { ssl_log(SSL_ERROR, "mbedtls_x509write_crt_set_subject_alt_name " "returned -0x%04x", -ret); goto exit; } } if ((ret = mbedtls_x509write_crt_pem(&crt, buf, size, mbedtls_ctr_drbg_random, &ctr_drbg)) < 0) { ssl_log(SSL_ERROR, "mbedtls_x509write_crt_pem " "returned -0x%04x", -ret); goto exit; } ret = 0; exit: mbedtls_x509write_crt_free(&crt); mbedtls_mpi_free(&serial); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return ret; } int gen_ca_cert_file(const char *cert_file, pkey_t *pkey, const char *org, const char *orgUnit) { int ret = -1; FILE *f = NULL; unsigned char *output_buf = NULL; char issuer_name[256] = {0}; size_t len = 0; const char *not_before = “20010101000000”; const char *not_after = “20371231235959”; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == cert_file || NULL == pkey || NULL == org || NULL == orgUnit) return -1; output_buf = (unsigned char *)malloc(4096); if (NULL == output_buf) return -1; snprintf(issuer_name, 256, "CN=%s,O=%s,OU=%s", "TP-Link SOHO Router CA", org, orgUnit); memset(output_buf, 0, 4096); if (gen_cert(output_buf, 4096, 1, 1, NULL, pkey, NULL, NULL, issuer_name, not_before, not_after, 0, NULL) != 0) { ssl_log(SSL_ERROR, "gen_cert fail."); ret = -1; goto exit; } len = strlen((char *)output_buf); f = fopen(cert_file, "w"); if (f == NULL) { ssl_log(SSL_ERROR, "open %s fail.", cert_file); ret = -1; goto exit; } if (fwrite(output_buf, 1, len, f) != len) { ssl_log(SSL_ERROR, "fwrite fail."); ret = -1; goto exit; } ret = 0; exit: if (f) fclose(f); if (output_buf) free(output_buf); ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return ret; } int gen_ca_cert_buf(void *cert_buf, size_t len, pkey_t *pkey, const char *org, const char *orgUnit) { char issuer_name[256] = {0}; const char *not_before = “20010101000000”; const char *not_after = “20371231235959”; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); snprintf(issuer_name, 256, "CN=%s,O=%s,OU=%s", "TP-Link SOHO Router CA", org, orgUnit); if (gen_cert(cert_buf, len, 1, 1, NULL, pkey, NULL, NULL, issuer_name, not_before, not_after, 0, NULL) != 0) { ssl_log(SSL_ERROR, "gen_cert fail."); return -1; } ssl_log(SSL_DEBUG, "cert buf: \n%s\n", (char *)cert_buf); ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return 0; } int gen_server_cert_file(const char *cert_file, pkey_t *pkey, x509_cert_t *issuer_cert, pkey_t *issuer_key, const char *cn, char *san) { FILE *f; unsigned char output_buf[4096]; char subject_name[256] = {0}; size_t len = 0; char not_before[20] = {0}; char not_after[20] = {0}; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); snprintf(subject_name, 256, "CN=%s", cn); snprintf(not_before, 20, "%04d%02d%02d%02d%02d%02d", issuer_cert->valid_from.year, issuer_cert->valid_from.mon, issuer_cert->valid_from.day, issuer_cert->valid_from.hour, issuer_cert->valid_from.min, issuer_cert->valid_from.sec ); snprintf(not_after, 20, "%04d%02d%02d%02d%02d%02d", issuer_cert->valid_to.year, issuer_cert->valid_to.mon, issuer_cert->valid_to.day, issuer_cert->valid_to.hour, issuer_cert->valid_to.min, issuer_cert->valid_to.sec ); memset(output_buf, 0, 4096); if (gen_cert(output_buf, 4096, 0, 0, issuer_cert, issuer_key, pkey, subject_name, NULL, not_before, not_after, 1, san) != 0) { ssl_log(SSL_ERROR, "gen_cert fail."); return -1; } len = strlen((char *)output_buf); if ((f = fopen(cert_file, "w")) == NULL) { ssl_log(SSL_ERROR, "open %s fail.", cert_file); return -1; } if (fwrite(output_buf, 1, len, f) != len) { ssl_log(SSL_ERROR, "fwrite fail."); fclose(f); return -1; } fclose(f); ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return 0; } void free_cert(x509_cert_t *cert) { if (cert) { mbedtls_x509_crt_free(cert); free(cert); cert = NULL; } } int load_cert_from_file(const char *cert_file, x509_cert_t **cert) { int ret = 0; x509_cert_t *tmp = NULL; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == cert_file || NULL == cert) return -1; if (access(cert_file, 0) != 0) { ssl_log(SSL_ERROR, "File %s is not exist.", cert_file); return -1; } tmp = (x509_cert_t *)malloc(sizeof(x509_cert_t)); if (NULL == tmp) return -1; mbedtls_x509_crt_init(tmp); if ((ret = mbedtls_x509_crt_parse_file(tmp, cert_file)) != 0) { ssl_log(SSL_ERROR, "mbedtls_x509_crt_parse_file fail. ret=%d", ret); free(tmp); return -1; } *cert = tmp; ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return 0; } int load_pkey_from_file(const char *key_file, pkey_t **pkey) { int ret = 0; pkey_t *tmp = NULL; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == key_file || NULL == pkey) return -1; if (access(key_file, 0) != 0) { ssl_log(SSL_ERROR, "File %s is not exist.", key_file); return -1; } tmp = (pkey_t *)malloc(sizeof(pkey_t)); if (NULL == tmp) return -1; mbedtls_pk_init(tmp); if ((ret = mbedtls_pk_parse_keyfile(tmp, key_file, NULL)) != 0) { ssl_log(SSL_ERROR, "mbedtls_pk_parse_keyfile fail. ret=%d", ret); free(tmp); return -1; } *pkey = tmp; ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return 0; } int load_cert_from_buf(const void *cert_buf, size_t len, x509_cert_t **cert) { int ret = 0; x509_cert_t *tmp = NULL; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == cert_buf || NULL == cert) return -1; tmp = (x509_cert_t *)malloc(sizeof(x509_cert_t)); if (NULL == tmp) return -1; ssl_log(SSL_DEBUG, "cert buf: \n%s\n", (char *)cert_buf); mbedtls_x509_crt_init(tmp); ssl_log(SSL_DEBUG, "buf len: %d %d", len, strlen(cert_buf)); if ((ret = mbedtls_x509_crt_parse(tmp, cert_buf, len)) != 0) { ssl_log(SSL_ERROR, "mbedtls_x509_crt_parse fail. ret=%d", ret); free(tmp); return -1; } *cert = tmp; ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return 0; } int load_pkey_from_buf(const void *key_buf, size_t len, pkey_t **pkey) { int ret = 0; pkey_t *tmp = NULL; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == key_buf || NULL == pkey) return -1; tmp = (pkey_t *)malloc(sizeof(pkey_t)); if (NULL == tmp) return -1; ssl_log(SSL_DEBUG, "key buf: \n%s\n", (char *)key_buf); mbedtls_pk_init(tmp); ssl_log(SSL_DEBUG, "buf len: %d %d", len, strlen(key_buf)); if (mbedtls_pk_parse_key(tmp, key_buf, len, NULL, 0) != 0) { ssl_log(SSL_ERROR, "mbedtls_pk_parse_key fail. ret=%d", ret); free(tmp); return -1; } *pkey = tmp; ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return 0; } int write_cert_to_buf(x509_cert_t *cert, void *cert_buf, size_t len) { return -1; } int write_pkey_to_buf(pkey_t *pkey, void *key_buf, size_t len) { int ret = 0; ssl_log(SSL_DEBUG, "enter %s", __FUNCTION__); if (NULL == pkey || NULL == key_buf) return -1; if ((ret = mbedtls_pk_write_key_pem(pkey, key_buf, len)) != 0) { ssl_log(SSL_ERROR, "mbedtls_pk_write_key_pem failed. ret=%d", ret); return -1; } ssl_log(SSL_DEBUG, "key buf: \n%s\n", (char *)key_buf); ssl_log(SSL_DEBUG, "leave %s", __FUNCTION__); return 0; } #endif /* INCLUDE_SSL && INCLUDE_SSL_MBEDTLS */整理代码缩进,空格等格式问题
最新发布
10-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值