Android原生网络库HttpURLConnection分析——HTTPS部分

一、前言

在《Android原生网络库分析——HTTP部分》一文中分析完了HTTP部分,当然其中也包含了网络库中绝大部分共有的基础部分。这一篇中只侧重于HTTPS协议部分,相关基础只会一笔带过,不了解HTTP基础的同学可以先看看前文中的HTTP部分。

应该有不少小伙伴对HTTPS中所涉及到的证书,签名,RSA加密,SSL/TLS等名词是熟悉的陌生人。没关系,通过对Android原生网络库的分析,我们不仅要了解这些名词的意义,还要知道它们是如何应用的。
原则还是不变,还是以网络连接、通信与断开为线索进行分析。

二、HTTPS连接

1.openConnection()打开连接

OpenHttpsURLConnection.jpg

在详细分析之前,需要再看一个类图结构,以了解 Http们 与 Https们的关系。


HttpsUrlConnectionImpl.jpg

从类图可以看到,HttpsUrlConnectionImpl的继承树里包含了HttpUrlConnection,也就是说HttpUrlConnection中的基本功能都是共用的,可能你会觉得这是废话。而有一个关键点在于其还有一个子类HttpUrlConnectionDelegate,这个子类又继承了HttpUrlConnectionImpl,而它的继承树里也有HttpUrlConnection,看起来似乎有点乱了。其实不然,HttpsUrlConnection以及HttpUrlConnection都是抽象类,它们封装了各自协议里最基础接口以及功能。而HttpsUrlConnectionImpl及HttpUrlConnectionImpl是各自协议的具体实现者,并且在HttpsUrlConnectionImpl中的代理类HttpUrlConnectionDelegate其实就指向了HttpUrlConnectionImpl的实例对象,这也体现了Https只需要关心 TLS/SSL 层的事情就可以了,其他与Http相关的事情还是由Http们来完成即可。

好像绕了点,那简单点说就是HttpsUrlConnectionImpl继承HttpUrlConnection是为了代码的复用,而HttpsUrlConnectionImpl包含HttpUrlConnectionImpl的实例对象则是功能复用。

理清了Https们与Http们的关系后就可以后面的流程分析了。从时序图来看,openConnection()最终就是创建了一个HttpsUrlConnectionImpl的实现来返回给调用者。而当HttpsUrlConnectionImpl被创建时,它同时创建好HttpUrlConnectionImpl的代理类。有一点需要关注的是,系统如何判断的协议是否为Https的,看如下代码,其实很简单,在setupStreamHandler()中确定Handler的时候确定的。

void setupStreamHandler() {
            ...... // 省略部分代码
423
424        // Fall back to a built-in stream handler if the user didn't supply one
425        if (protocol.equals("file")) {
426            streamHandler = new FileHandler();
427        } else if (protocol.equals("ftp")) {
428            streamHandler = new FtpHandler();
429        } else if (protocol.equals("http")) {
430            streamHandler = new HttpHandler();
431        } else if (protocol.equals("https")) {
432            streamHandler = new HttpsHandler();
433        } else if (protocol.equals("jar")) {
434            streamHandler = new JarHandler();
435        }
436        if (streamHandler != null) {
437            streamHandlers.put(protocol, streamHandler);
438        }
439    }

在创建HttpsUrlConnectionImpl实例的过程中,在其父类HttpsUrlConnection中创建了两个重要的类,一个是HostnameVerifier,用于握手时验证主机名的,另一个是SSLSockoetFactory的实例,用于创建SSLSocket的。

protected HttpsURLConnection(URL url) {
178        super(url);
179        hostnameVerifier = defaultHostnameVerifier;
180        sslSocketFactory = defaultSSLSocketFactory;
181    }

先来看SSLSockoetFactory吧。sslSocketFactory被设置成了默认defaultSSLSocketFactory,当然,其也允许用户自己指定SSLSockoetFactory,比如自签名的证书就可以自己设置。再来看看defaultSSLSocketFactory的初始化。

private static SSLSocketFactory defaultSSLSocketFactory = (SSLSocketFactory) SSLSocketFactory
111            .getDefault();

继续看SSLSocketFactory#getDefault()

/**
38     * Returns the default {@code SSLSocketFactory} instance. The default is
39     * defined by the security property {@code 'ssl.SocketFactory.provider'}.
40     *
41     * @return the default ssl socket factory instance.
42     */
43    public static synchronized SocketFactory getDefault() {
44        if (defaultSocketFactory != null) { // 单例类的实现
45            return defaultSocketFactory;
46        }
            // Security类所提供的以“ssl.SocketFactory.provider”为属性key的类
47        if (defaultName == null) {
48            defaultName = Security.getProperty("ssl.SocketFactory.provider");
49            if (defaultName != null) {
50                ClassLoader cl = Thread.currentThread().getContextClassLoader();
51                if (cl == null) {
52                    cl = ClassLoader.getSystemClassLoader();
53                }
54                try {
55                    final Class<?> sfc = Class.forName(defaultName, true, cl);
56                    defaultSocketFactory = (SocketFactory) sfc.newInstance();
57                } catch (Exception e) {
58                    System.logE("Problem creating " + defaultName, e);
59                }
60            }
61        }
62        // 默认SSLConext返回的对象实例
63        if (defaultSocketFactory == null) {
64            SSLContext context;
65            try {
66                context = SSLContext.getDefault();
67            } catch (NoSuchAlgorithmException e) {
68                context = null;
69            }
70            if (context != null) {
71                defaultSocketFactory = context.getSocketFactory();
72            }
73        }
            // 直接new一个DefaultSSLSocketFactory,但表明其未安装。
74        if (defaultSocketFactory == null) {
75            // Use internal implementation
76            defaultSocketFactory = new DefaultSSLSocketFactory("No SSLSocketFactory installed");
77        }
78        return defaultSocketFactory;
79    }

从实现上来看会从三个方面的其中之一。
(1)通过Security获取。与之配套的有一个属性文件/libcore/luni/src/main/java/java/security/security.properties,其记录了key=ssl.SocketFactory.provider所对应的类名。可以说是OpenSSLSocketFactoryImpl,其所在的包为org.apache.harmony.xnet.provider.jsse。哦哟,看来是移植的OpenSSL实现咯,要越陷越深了吗。先认识到这里,后面会再见面的。

# For regular SSLSockets, we have two implementations:
ssl.SocketFactory.provider=org.apache.harmony.xnet.provider.jsse.OpenSSLSocketFactoryImpl
#ssl.SocketFactory.provider=org.apache.harmony.xnet.provider.jsse.SSLSocketFactoryImpl

(2)通过SSLConext来获取

    public final SSLSocketFactory getSocketFactory() {
228        return spiImpl.engineGetSocketFactory();
229    }

其中spiImpl是SSLContextSpi所定义的,SSLContextSpi是一个抽象类,其具体实现类是SSLContextImpl,其在engineGetSocketFactory方法返回的是SSLServerSocketFactoryImpl的实例。其包也是org.apache.harmony.xnet.provider.jsse。恩,其实就是上面属性文件中被注释掉的那个。
(3)在(1)和(2)都没有结果时,就直接返回默认的类DefaultSSLSocketFactory的实例了。

2.getOutputStream()

相较于HTTP的getOutputStream(),这一部分多了个TLS/SSL的握手部分,然后再加上这里涉及到了另外三方开源库OpenSSL的实现,这里至少需要分成三部分来讲解。为了讲解不过于复杂,先来看前两部分:


HttpsGetOutputStream.jpg

(1)Http的连接

前面的1-14步所完成的工作就是HTTP的TCP三步握手,从而使客户端与服务器之间建立起通信连接。这一点和HTTP的相同,因此,这里只做简单的回顾。首先创建的是HttpsUrlConnectionImpl,这里设定了默认的端口号为443。然后就是设定http的相关协议请求行,请求头参数等,最后通过HttpEngine#sendRequest()将请求发出去,
看过《Android原生网络库分析——HTTP部分》的同学应该还记得,经过HttpConnection#connect()方法并创建好HttpConnection实例后其实就建立起TCP的连接了。

(2)发起Https的握手请求

Https用于连接的帮助类为HttpsEngines,在其connect()方法里还进一步调用了自身的makeSslConnection()方法,这个方法是私有的也是https特有的,由这里开始发起Https的握手协议。

/**
451         * Attempt to make an https connection. Returns true if a
452         * connection was reused, false otherwise.
453         *
454         * @param tlsTolerant If true, assume server can handle common
455         * TLS extensions and SSL deflate compression. If false, use
456         * an SSL3 only fallback mode without compression.
457         */
458        private boolean makeSslConnection(boolean tlsTolerant) throws IOException {
459            // make an SSL Tunnel on the first message pair of each SSL + proxy connection
460            if (connection == null) {
461                connection = openSocketConnection();
462                if (connection.getAddress().getProxy() != null) {
463                    makeTunnel(policy, connection, getRequestHeaders());
464                }
465            }
466
467            // if super.makeConnection returned a connection from the
468            // pool, sslSocket needs to be initialized here. If it is
469            // a new connection, it will be initialized by
470            // getSecureSocket below.
               // 这里第一次获取时会返回 null
471            sslSocket = connection.getSecureSocketIfConnected();
472
473            // we already have an SSL connection,
474            if (sslSocket != null) {
475                return true;
476            }
477            // 带着前面定义好的 SSLSocketFactory 进一步设置 sslSocket,这里应该是 OpenSSLSocketFactoryImpl 
478            connection.setupSecureSocket(enclosing.getSSLSocketFactory(), tlsTolerant);
479            return false;
480        }

这里进一步调用 HttpConnection#setupSecureSocket()。

/**
186     * Create an {@code SSLSocket} and perform the SSL handshake
187     * (performing certificate validation.
188     *
189     * @param sslSocketFactory Source of new {@code SSLSocket} instances.
190     * @param tlsTolerant If true, assume server can handle common
191     * TLS extensions and SSL deflate compression. If false, use
192     * an SSL3 only fallback mode without compression.
193     */
194    public void setupSecureSocket(SSLSocketFactory sslSocketFactory, boolean tlsTolerant)
195            throws IOException {
196        // create the wrapper over connected socket
           // 创建 SslSocket,其应该为 OpenSSLSocketImpl 的实例
197        unverifiedSocket = (SSLSocket) sslSocketFactory.createSocket(socket,
198                address.uriHost, address.uriPort, true /* autoClose */);
199        // tlsTolerant mimics Chrome's behavior
200        if (tlsTolerant && unverifiedSocket instanceof OpenSSLSocketImpl) {
201            OpenSSLSocketImpl openSslSocket = (OpenSSLSocketImpl) unverifiedSocket;
202            openSslSocket.setUseSessionTickets(true);
203            openSslSocket.setHostname(address.uriHost);
204            // use SSLSocketFactory default enabled protocols
205        } else {
206            unverifiedSocket.setEnabledProtocols(new String [] { "SSLv3" });
207        }
208        // force handshake, which can throw
           // 这里会发起https的握手
209        unverifiedSocket.startHandshake();
210    }

在这个方法创建了 SslSocket 的创建以及通过其发起了Https的握手。这里已经开始涉及到Native层的操作了,也就是OpenSSL相关的操作。后面的东西会涉及到Native的东西,所以需要点c/c++的基础语法,一点点就好。
其实前面已经多次提到OpenSSL了,它是一个TLS/SSL的实现,其代码托管在Giithub上,有兴趣的可以做更深入的了解。在后面的三步握手实现里也会讲到其里面的部分实现。这里还是要继续分析关于创建SslScoket以及发起Https握手前的细节。

a.创建SslSocket以及ssl的上下文指针

SslSocket的是OpenSSLSocketImpl的实例,而sslSocketFactory是OpenSSLSocketFactoryImpl的实现。createSocket有多个版本,根据上面的代码,调用的版本如下。

public Socket createSocket(Socket s, String host, int port, boolean autoClose)
93            throws IOException {
94        return new OpenSSLSocketImplWrapper(s,
95                                            host,
96                                            port,
97                                            autoClose,
98                                            (SSLParametersImpl) sslParameters.clone());
99    }

OpenSSLSocketImplWrapper是个包装类,其继承自OpenSSLSocketImpl,它的构造函数也是有多个版本的。

protected OpenSSLSocketImpl(Socket socket, String host, int port,
160            boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
161        this.socket = socket;
162        this.wrappedHost = host;
163        this.wrappedPort = port;
164        this.autoClose = autoClose;
165        init(sslParameters);
166
167        // this.timeout is not set intentionally.
168        // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout
169        // to wrapped socket
170    }
171

在创建OpenSSLSocketImpl时,除了socket,host,port这些基本参数,还有一个用于SSL的参数sslParameters,其所属类为SSLParametersImpl。在OpenSSLSocketFactoryImpl构造时通过调用SSLParametersImpl#getDefault()对其进行了初始化。

protected static SSLParametersImpl getDefault() throws KeyManagementException {
144        SSLParametersImpl result = defaultParameters;
145        if (result == null) {
146            // single-check idiom
147            defaultParameters = result = new SSLParametersImpl(null,
148                                                               null,
149                                                               null,
150                                                               new ClientSessionContext(),
151                                                               new ServerSessionContext());
152        }
153        return (SSLParametersImpl) result.clone();
154    }

其创建了用于会话的上下文,且包含了client与server的。这里只以Android客户端来分析,那就只关注ClientSessionContext即可。


public class ClientSessionContext extends AbstractSessionContext {
...
}

abstract class AbstractSessionContext implements SSLSessionContext {
40
41    volatile int maximumSize;
42    volatile int timeout;
43
44    final long sslCtxNativePointer = NativeCrypto.SSL_CTX_new();

ClientSessionContext继承自AbstractSessionContext,而在AbstractSessionContext初始化时就会初始化Native层的上下文指针,且最终把值赋给上层Java的整型变量sslCtxNativePointer。我们把这一过程可以叫做SSL的上下文创建。

那就来看看SSL_CTX_new()的实现。这里必须要补充一下的是NativeCrypto.java的 jni 层对应的文件是 /libcore/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp。SSL_CTX_new()函数在其里面的实现如下:

/*
5998 * public static native int SSL_CTX_new();
5999 */
6000static jlong NativeCrypto_SSL_CTX_new(JNIEnv* env, jclass) {
            // 创建上下文
6001    Unique_SSL_CTX sslCtx(SSL_CTX_new(SSLv23_method()));
6002    if (sslCtx.get() == NULL) {
6003        throwExceptionIfNecessary(env, "SSL_CTX_new");
6004        return 0;
6005    }
            // 设置上下文选项
6006    SSL_CTX_set_options(sslCtx.get(),
6007                        SSL_OP_ALL
6008                        // Note: We explicitly do not allow SSLv2 to be used.
6009                        | SSL_OP_NO_SSLv2
6010                        // We also disable session tickets for better compatibility b/2682876
6011                        | SSL_OP_NO_TICKET
6012                        // We also disable compression for better compatibility b/2710492 b/2710497
6013                        | SSL_OP_NO_COMPRESSION
6014                        // Because dhGenerateParameters uses DSA_generate_parameters_ex
6015                        | SSL_OP_SINGLE_DH_USE
6016                        // Because ecGenerateParameters uses a fixed named curve
6017                        | SSL_OP_SINGLE_ECDH_USE);
6018
6019    int mode = SSL_CTX_get_mode(sslCtx.get());
6020    /*
6021     * Turn on "partial write" mode. This means that SSL_write() will
6022     * behave like Posix write() and possibly return after only
6023     * writing a partial buffer. Note: The alternative, perhaps
6024     * surprisingly, is not that SSL_write() always does full writes
6025     * but that it will force you to retry write calls having
6026     * preserved the full state of the original call. (This is icky
6027     * and undesirable.)
6028     */
6029    mode |= SSL_MODE_ENABLE_PARTIAL_WRITE;
6030
6031    // Reuse empty buffers within the SSL_CTX to save memory
6032    mode |= SSL_MODE_RELEASE_BUFFERS;
6033    // 设置模式
6034    SSL_CTX_set_mode(sslCtx.get(), mode);
6035    // 设置一系列的 callback
6036    SSL_CTX_set_cert_verify_callback(sslCtx.get(), cert_verify_callback, NULL);
6037    SSL_CTX_set_info_callback(sslCtx.get(), info_callback);
6038    SSL_CTX_set_client_cert_cb(sslCtx.get(), client_cert_cb);
6039    SSL_CTX_set_tmp_rsa_callback(sslCtx.get(), tmp_rsa_callback);
6040    SSL_CTX_set_tmp_dh_callback(sslCtx.get(), tmp_dh_callback);
6041    SSL_CTX_set_tmp_ecdh_callback(sslCtx.get(), tmp_ecdh_callback);
6042
6043    JNI_TRACE("NativeCrypto_SSL_CTX_new => %p", sslCtx.get());
6044    return (jlong) sslCtx.release();
6045}

这里又调用了另一个SSL_CTX_new()函数,它的实现在 ssl_lib.c 文件中,其将创建用于会话的上下文指针 SSL_CTX*,其是typedef定义,即ssl_ctx_st。而这里还要注意其传入参数为SSLv23_method(),这是一个函数指针,其返回值是SSL_METHOD,而SSL_METHOD其是结构体 ssl_method_st,其定义如下。

/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
409struct ssl_method_st
410 {
411 int version;
412 int (*ssl_new)(SSL *s);
413 void (*ssl_clear)(SSL *s);
414 void (*ssl_free)(SSL *s);
415 int (*ssl_accept)(SSL *s);
416 int (*ssl_connect)(SSL *s);
417 int (*ssl_read)(SSL *s,void *buf,int len);
418 int (*ssl_peek)(SSL *s,void *buf,int len);
419 int (*ssl_write)(SSL *s,const void *buf,int len);
420 int (*ssl_shutdown)(SSL *s);
421 int (*ssl_renegotiate)(SSL *s);
422 int (*ssl_renegotiate_check)(SSL *s);
423 long (*ssl_get_message)(SSL *s, int st1, int stn, int mt, long
424     max, int *ok);
425 int (*ssl_read_bytes)(SSL *s, int type, unsigned char *buf, int len,
426     int peek);
427 int (*ssl_write_bytes)(SSL *s, int type, const void *buf_, int len);
428 int (*ssl_dispatch_alert)(SSL *s);
429 long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg);
430 long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg);
431 const SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr);
432 int (*put_cipher_by_char)(const SSL_CIPHER *cipher,unsigned char *ptr);
433 int (*ssl_pending)(const SSL *s);
434 int (*num_ciphers)(void);
435 const SSL_CIPHER *(*get_cipher)(unsigned ncipher);
436 const struct ssl_method_st *(*get_ssl_method)(int version);
437 long (*get_timeout)(void);
438 struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */
439 int (*ssl_version)(void);
440 long (*ssl_callback_ctrl)(SSL *s, int cb_id, void (*fp)(void));
441 long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)(void));
442 };

上面的定义比较长,只作了解即可,在后面的过程中会慢慢熟悉的。当然,其实从这个定义其上可以看到 TLS/SSL 连接或者认证的一些影子了。
而对于SSLv23_method()本身来说,既然是一个函数指针,那么一定有其实现的地方。

IMPLEMENT_ssl23_meth_func(SSLv23_method,
89          ssl23_accept,
90          ssl23_connect,
91          ssl23_get_method)

由一个宏来实现的,这是 C 语言的惯用技巧。还是来看看吧。

#define IMPLEMENT_ssl23_meth_func(func_name, s_accept, s_connect, s_get_meth) \
702const SSL_METHOD *func_name(void)  \
703 { \
704 static const SSL_METHOD func_name##_data= { \
705 TLS1_2_VERSION, \
706 tls1_new, \
707 tls1_clear, \
708 tls1_free, \
709 s_accept, \
710 s_connect, \
711 ssl23_read, \
712 ssl23_peek, \
713 ssl23_write, \
714 ssl_undefined_function, \
715 ssl_undefined_function, \
716 ssl_ok, \
717 ssl3_get_message, \
718 ssl3_read_bytes, \
719 ssl3_write_bytes, \
720 ssl3_dispatch_alert, \
721 ssl3_ctrl, \
722 ssl3_ctx_ctrl, \
723 ssl23_get_cipher_by_char, \
724 ssl23_put_cipher_by_char, \
725 ssl_undefined_const_function, \
726 ssl23_num_ciphers, \
727 ssl23_get_cipher, \
728 s_get_meth, \
729 ssl23_default_timeout, \
730 &ssl3_undef_enc_method, \
731 ssl_undefined_void_function, \
732 ssl3_callback_ctrl, \
733 ssl3_ctx_callback_ctrl, \
734 }; \
735 return &func_name##_data; \
736 }

也就是说最终定义了一个类型为ssl_method_st的 SSLv23_method_data 的变量,它的每一项参数也将赋值结构体中ssl_method_st的每一个成员。另外要注意上面的参数ssl23_accept和ssl23_connect。对于服务端需要 s_accept参数,而客户端则只需要ssl23_connect。同时,也可以看出,这两个也是函数指针,其中ssl23_connect的实现在 s23_clnt.c 文件中,其实现后面再说。
至于上下文ssl_ctx_st,其也是一个结构体,其定义也是相当的长,这里就先不貼出来了,后面如果有需要再看情况。
这里花费很大的力气就是为了弄清楚这个参数 SSLv23_method的定义,因为这是一个很至关重要的参数,其决定了用于连接的协议以及版本为TLS1_2_VERSION,以及将来用于连接的 ssl23_connect。
而关于 ssl_lib.c 中SSL_CTX_new()的实现,也比较长,也不贴了。只要知道函数指针SSLv23_method会赋值为 SSL_CTX指针的 method 的成员变量即可。

b.发起Https握手

终于要握手了,即调用OpenSSLSocketImpl#startHandshake()。

(3)握手

HttpsGetOutputStream2.jpg

握手是https里面最核心的部分,握手过程中最核心的是传递加密方法、密钥以及证书验证等。先来看一看握手的上层Java代码。前方高能,又是非常长的一段代码。为了简单,可以不用理会整个完整的代码,对着时序图看看关键注释即可。

/**
242     * Starts a TLS/SSL handshake on this connection using some native methods
243     * from the OpenSSL library. It can negotiate new encryption keys, change
244     * cipher suites, or initiate a new session. The certificate chain is
245     * verified if the correspondent property in java.Security is set. All
246     * listeners are notified at the end of the TLS/SSL handshake.
247     */
248    @Override public synchronized void startHandshake() throws IOException {
249        synchronized (handshakeLock) {
250            checkOpen();// 状态检查
251            if (!handshakeStarted) {
252                handshakeStarted = true;
253            } else {
254                return;
255            }
256        }
257
258        // note that this modifies the global seed, not something specific to the connection
259        final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES; // RAND_SEED_LENGTH_IN_BYTES = 1024
           // 获取或者生成用于加密的随机数
260        final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
261        if (secureRandom == null) {
262            NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
263        } else {
264            NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
265        }
266        
           // 这里是客户端,所以为 true
267        final boolean client = sslParameters.getUseClientMode();
268
           // 从客户端获取上下文指针   
269        final long sslCtxNativePointer = (client) ?
270            sslParameters.getClientSessionContext().sslCtxNativePointer :
271            sslParameters.getServerSessionContext().sslCtxNativePointer;
272
273        this.sslNativePointer = 0;
274        boolean exception = true;
275        try {
               // 创建 SSL 指针
276            sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
277            guard.open("close");
278
               // npn 协议是什么协议?ALPN(Application-Layer Protocol Negotiation)也是 TLS 层的扩展,用于协商应用层使用的协议。它的前身是 NPN,最初用于支持 Google SPDY 协议(现已标准化为 HTTP/2)。
279            if (npnProtocols != null) {
280                NativeCrypto.SSL_CTX_enable_npn(sslCtxNativePointer);
281            }
282
283            // setup server certificates and private keys.
284            // clients will receive a call back to request certificates.
               // 服务器端相关内容,主要就是设置证书以及私钥,只做了解即可。
285            if (!client) {
286                Set<String> keyTypes = new HashSet<String>();
287                for (String enabledCipherSuite : enabledCipherSuites) {
288                    if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
289                        continue;
290                    }
291                    String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType();
292                    if (keyType != null) {
293                        keyTypes.add(keyType);
294                    }
295                }
296                for (String keyType : keyTypes) {
297                    try {
298                        setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
299                                                                                       null,
300                                                                                       this));
301                    } catch (CertificateEncodingException e) {
302                        throw new IOException(e);
303                    }
304                }
305            }
306
               // 使能协议,这里默认是SSLv3、TLS
307            NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
               // 设置密码组,如 md5,sha等
308            NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);

309            if (useSessionTickets) {
310                NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
311            }
312            if (hostname != null) {
313                NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname);
314            }
315
316            boolean enableSessionCreation = sslParameters.getEnableSessionCreation();
317            if (!enableSessionCreation) {
318                NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
319                                                              enableSessionCreation);
320            }
321
322            AbstractSessionContext sessionContext;
323            OpenSSLSessionImpl sessionToReuse;
324            if (client) {
325                // look for client session to reuse
326                ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext();
327                sessionContext = clientSessionContext;
328                sessionToReuse = getCachedClientSession(clientSessionContext);
329                if (sessionToReuse != null) {
330                    NativeCrypto.SSL_set_session(sslNativePointer,
331                                                 sessionToReuse.sslSessionNativePointer);
332                }
333            } else {
334                sessionContext = sslParameters.getServerSessionContext();
335                sessionToReuse = null;
336            }
337
338            // setup peer certificate verification
               // 设置证书,目前只是服务端
339            if (client) {
340                // TODO support for anonymous cipher would require us to
341                // conditionally use SSL_VERIFY_NONE
342            } else {
343                // needing client auth takes priority...
344                boolean certRequested;
345                if (sslParameters.getNeedClientAuth()) {
346                    NativeCrypto.SSL_set_verify(sslNativePointer,
347                                                NativeCrypto.SSL_VERIFY_PEER
348                                                | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
349                    certRequested = true;
350                // ... over just wanting it...
351                } else if (sslParameters.getWantClientAuth()) {
352                    NativeCrypto.SSL_set_verify(sslNativePointer,
353                                                NativeCrypto.SSL_VERIFY_PEER);
354                    certRequested = true;
355                // ... and it defaults properly so don't call SSL_set_verify in the common case.
356                } else {
357                    certRequested = false;
358                }
359
360                if (certRequested) {
361                    X509TrustManager trustManager = sslParameters.getTrustManager();
362                    X509Certificate[] issuers = trustManager.getAcceptedIssuers();
363                    if (issuers != null && issuers.length != 0) {
364                        byte[][] issuersBytes;
365                        try {
366                            issuersBytes = NativeCrypto.encodeIssuerX509Principals(issuers);
367                        } catch (CertificateEncodingException e) {
368                            throw new IOException("Problem encoding principals", e);
369                        }
                           // 下发证书链给客户端
370                        NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
371                    }
372                }
373            }
374
375            // Temporarily use a different timeout for the handshake process
               // 握手时间
376            int savedReadTimeoutMilliseconds = getSoTimeout();
377            int savedWriteTimeoutMilliseconds = getSoWriteTimeout();
378            if (handshakeTimeoutMilliseconds >= 0) {
379                setSoTimeout(handshakeTimeoutMilliseconds);
380                setSoWriteTimeout(handshakeTimeoutMilliseconds);
381            }
382
383            // TLS Channel ID
               // 设置 channel id
384            if (client) {
385                // Client-side TLS Channel ID
386                if (channelIdPrivateKey != null) {
387                    NativeCrypto.SSL_set1_tls_channel_id(sslNativePointer, channelIdPrivateKey);
388                }
389            } else {
390                // Server-side TLS Channel ID
391                if (channelIdEnabled) {
392                    NativeCrypto.SSL_enable_tls_channel_id(sslNativePointer);
393                }
394            }
395
396            int sslSessionNativePointer;
397            try {
                   // 握手
398                sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
399                        socket.getFileDescriptor$(), this, getSoTimeout(), client, npnProtocols);
400            } catch (CertificateException e) {
401                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
402                wrapper.initCause(e);
403                throw wrapper;
404            }
405            byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
406            if (sessionToReuse != null && Arrays.equals(sessionToReuse.getId(), sessionId)) {
407                this.sslSession = sessionToReuse;
408                sslSession.lastAccessedTime = System.currentTimeMillis();
409                NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
410            } else {
411                if (!enableSessionCreation) {
412                    // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled
413                    throw new IllegalStateException("SSL Session may not be created");
414                }
                   // 证书链处理
415                X509Certificate[] localCertificates
416                        = createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer));

417                X509Certificate[] peerCertificates
418                        = createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
419                this.sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
420                        peerCertificates, getPeerHostName(), getPeerPort(), sessionContext);
421                // if not, putSession later in handshakeCompleted() callback
422                if (handshakeCompleted) {
423                    sessionContext.putSession(sslSession);
424                }
425            }
426
427            // Restore the original timeout now that the handshake is complete
428            if (handshakeTimeoutMilliseconds >= 0) {
429                setSoTimeout(savedReadTimeoutMilliseconds);
430                setSoWriteTimeout(savedWriteTimeoutMilliseconds);
431            }
432
433            // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
                  // 完成握手并发出通知
434            if (handshakeCompleted) {
435                notifyHandshakeCompletedListeners();
436            }
437
438            exception = false;
439        } catch (SSLProtocolException e) {
440            throw new SSLHandshakeException(e);
441        } finally {
442            // on exceptional exit, treat the socket as closed
443            if (exception) {
444                close();
445            }
446        }
447    }

这是一段超长的代码,还是那句话,不要畏难,长归长,一句一句分析下来就短了。当然其步骤也是比较多的,如下,大概有 12 步。简单的就不做展开了,复杂的就做更深的了解
a.获取或者生成用于加密的随机数
b.从客户端获取上下文指针
c.创建 SSL 指针
调用SSL_new()函数将创建指针SSL*,即ssl_st。虽然很重要,但没有什么特别关键的就不展开了。
d.使能协议
e.设置密码套件

public static String[] getDefaultCipherSuites() {
712        return new String[] {
713            "SSL_RSA_WITH_RC4_128_MD5",
714            "SSL_RSA_WITH_RC4_128_SHA",
715            "TLS_RSA_WITH_AES_128_CBC_SHA",
716            "TLS_RSA_WITH_AES_256_CBC_SHA",
717            "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
718            "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
719            "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
720            "TLS_ECDH_RSA_WITH_RC4_128_SHA",
721            "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
722            "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
723            "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
724            "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
725            "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
726            "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
727            "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
728            "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
729            "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
730            "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
731            "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
732            "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
733            "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
734            "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
735            "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
736            "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
737            "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
738            "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
739            "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
740            "SSL_RSA_WITH_DES_CBC_SHA",
741            "SSL_DHE_RSA_WITH_DES_CBC_SHA",
742            "SSL_DHE_DSS_WITH_DES_CBC_SHA",
743            "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
744            "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
745            "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
746            "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
747            TLS_EMPTY_RENEGOTIATION_INFO_SCSV
748        };
749    }

f.设置hostname
g.创建会话
会话创建时,做了一个很重要的工作就是给 SSL 指针中handshake_func赋值。

s->handshake_func=meth->ssl_connect

这个 meth 就是上下文的 meth,而 ssl_connect 根据前面的分析,其指向的 s23_clnt.c 中的 ssl23_connect() 函数。
h.设置握手时间
i.设置频道id
j.握手
以下是一次握手过程所需要经历的状态,每个状态基本对应一个函数来处理。

StatechartHandshake.jpg

int ssl23_connect(SSL *s)
146 {
147 BUF_MEM *buf=NULL;
148 unsigned long Time=(unsigned long)time(NULL);
149 void (*cb)(const SSL *ssl,int type,int val)=NULL;
150 int ret= -1;
151 int new_state,state;
152
153 RAND_add(&Time,sizeof(Time),0);
154 ERR_clear_error();
155 clear_sys_error();
156
157 if (s->info_callback != NULL)
158     cb=s->info_callback;
159 else if (s->ctx->info_callback != NULL)
160     cb=s->ctx->info_callback;
161
162 s->in_handshake++;// 计数加 1
        // SSL 初始化,其 state 将为 SSL_ST_BEFORE|SSL_ST_CONNECT
163 if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
164
165 for (;;)
166     {
167     state=s->state;
168
169     switch(s->state)
170         {
171     case SSL_ST_BEFORE:
172     case SSL_ST_CONNECT:
173     case SSL_ST_BEFORE|SSL_ST_CONNECT: // 第一次循环时进入
174     case SSL_ST_OK|SSL_ST_CONNECT:
175
176         if (s->session != NULL)
177             {
178             SSLerr(SSL_F_SSL23_CONNECT,SSL_R_SSL23_DOING_SESSION_ID_REUSE);
179             ret= -1;
180             goto end;
181             }
182         s->server=0;
            // 通知回调函数,开始握手了
183         if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
184
185         /* s->version=TLS1_VERSION; */
186         s->type=SSL_ST_CONNECT;
187
188         if (s->init_buf == NULL)
189             {
190             if ((buf=BUF_MEM_new()) == NULL)
191                 {
192                 ret= -1;
193                 goto end;
194                 }
195             if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
196                 {
197                 ret= -1;
198                 goto end;
199                 }
200             s->init_buf=buf;
201             buf=NULL;
202             }
203
204         if (!ssl3_setup_buffers(s)) { ret= -1; goto end; }
205
206         ssl3_init_finished_mac(s);
207        // 设置状态为 SSL23_ST_CW_CLNT_HELLO_A,下次循环迭代就会进入 case SSL23_ST_CW_CLNT_HELLO_A.
208         s->state=SSL23_ST_CW_CLNT_HELLO_A;
209         s->ctx->stats.sess_connect++;
210         s->init_num=0;
211         break;
212
213     case SSL23_ST_CW_CLNT_HELLO_A:// 第二次循环
214     case SSL23_ST_CW_CLNT_HELLO_B:
215
216         s->shutdown=0;
            // 发送出 hello
217         ret=ssl23_client_hello(s);
218         if (ret <= 0) goto end;
           // 置状态为 SSL23_ST_CR_SRVR_HELLO_A
219         s->state=SSL23_ST_CR_SRVR_HELLO_A;
220         s->init_num=0;
221
222         break;
223
224     case SSL23_ST_CR_SRVR_HELLO_A:// 第三次循环
225     case SSL23_ST_CR_SRVR_HELLO_B:
           // 获取服务器的的 hello
226         ret=ssl23_get_server_hello(s);
227         if (ret >= 0) cb=NULL;
228         goto end;
229         /* break; */
230
231     default:
232         SSLerr(SSL_F_SSL23_CONNECT,SSL_R_UNKNOWN_STATE);
233         ret= -1;
234         goto end;
235         /* break; */
236         }
237
238     if (s->debug) { (void)BIO_flush(s->wbio); }
239
240     if ((cb != NULL) && (s->state != state))
241         {
242         new_state=s->state;
243         s->state=state;
244         cb(s,SSL_CB_CONNECT_LOOP,1);
245         s->state=new_state;
246         }
247     }
248end:
249 s->in_handshake--;
250 if (buf != NULL)
251     BUF_MEM_free(buf);
252 if (cb != NULL)
253     cb(s,SSL_CB_CONNECT_EXIT,ret);
254 return(ret);
255 }

其主要流程是 ssl 初始化 ——> 客户端发送 Hello ——> 获取服务端的 Hello。

客户端发送hello

static int ssl23_client_hello(SSL *s)
273 {
        .......
        // 随机数
357     p=s->s3->client_random;
358     Time=(unsigned long)time(NULL);     /* Time */
359     l2n(Time,p);

        ......
401     // 版本号
402     s->client_version = version;
403
404     if (ssl2_compat)
405         {
406         /* create SSL 2.0 compatible Client Hello */
407
408         /* two byte record header will be written last */
            .......
464         }
465     else
466         {
467         /* create Client Hello in SSL 3.0/TLS 1.0 format */
468
469         /* do the record header (5 bytes) and handshake message header (4 bytes) last */
470         d = p = &(buf[9]);
471
472         *(p++) = version_major;
473         *(p++) = version_minor;
474
475         /* Random stuff */
476         memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
477         p += SSL3_RANDOM_SIZE;
478
479         /* Session ID (zero since there is no reuse) */
480         *(p++) = 0;
481         // 所支持的 ciphers 套件
482         /* Ciphers supported (using SSL 3.0/TLS 1.0 format) */
483         i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),&(p[2]),ssl3_put_cipher_by_char);
498         s2n(i,p);
499         p+=i;
500
            .......

534
535         /* fill in 4-byte handshake header */
536         d=&(buf[5]);
            // 消息类型
537         *(d++)=SSL3_MT_CLIENT_HELLO;
538         l2n3(l,d);
539
540         l += 4;
541

565         ssl3_finish_mac(s,&(buf[5]), s->init_num - 5);
566         }
567     // 置为 SSL23_ST_CW_CLNT_HELLO_B
568     s->state=SSL23_ST_CW_CLNT_HELLO_B;
569     s->init_off=0;
570     }
571
572 /* SSL3_ST_CW_CLNT_HELLO_B */
        // 写入数据
573 ret = ssl23_write_bytes(s);
574
575 if ((ret >= 2) && s->msg_callback)
576     {
577     /* Client Hello has been sent; tell msg_callback */
578         // 回调
579     if (ssl2_compat)
580         s->msg_callback(1, SSL2_VERSION, 0, s->init_buf->data+2, ret-2, s, s->msg_callback_arg);
581     else
582         s->msg_callback(1, version, SSL3_RT_HANDSHAKE, s->init_buf->data+5, ret-5, s, s->msg_callback_arg);
583     }
584
585 return ret;
586 }

客户端发送 hello ,主要是发送了随机数,支持的密钥算法,SSL/TLS的版本号,当然还有消息类型SSL3_MT_CLIENT_HELLO。服务端在收到SSL3_MT_CLIENT_HELLO时会作出回应,也就是发送服务端的HELLO。服务端会在 s23_srvr.c 的 ssl23_get_client_hello 中处理。这里只关注 Android 端,因此不展开服务端的。我们只要知道服务端会从 SSL3_MT_CLIENT_HELLO 传过来的 Support Ciphers 里确定一份加密套件,这个套件决定了后续加密和生成摘要时具体使用哪些算法,另外还会生成一份随机数 Random2。

获取服务端的 Hello

static int ssl23_get_server_hello(SSL *s)
589 {
    ......
    // 读取数据
595 n=ssl23_read_bytes(s,7);
596
597 if (n != 7) return(n);
598 p=s->packet;
599
600 memcpy(buf,p,n);
601
       // SSL2_MT_SERVER_HELLO消息
602 if ((p[0] & 0x80) && (p[2] == SSL2_MT_SERVER_HELLO) &&
603     (p[5] == 0x00) && (p[6] == 0x02))
604     {
           ......
672     }
673 else if (p[1] == SSL3_VERSION_MAJOR &&
674          p[2] <= TLS1_2_VERSION_MINOR &&
675          ((p[0] == SSL3_RT_HANDSHAKE && p[5] == SSL3_MT_SERVER_HELLO) ||
676           (p[0] == SSL3_RT_ALERT && p[3] == 0 && p[4] == 2)))
677     {
678     /* we have sslv3 or tls1 (server hello or alert) */
679     // 服务端选定的协议版本
680     if ((p[2] == SSL3_VERSION_MINOR) &&
          ......
693         }
694     else if ((p[2] == TLS1_VERSION_MINOR) &&
695         !(s->options & SSL_OP_NO_TLSv1))
696         {
697         ......
699         }
700     else if ((p[2] == TLS1_1_VERSION_MINOR) &&
701         !(s->options & SSL_OP_NO_TLSv1_1))
702         {
703         ......
705         }
706     else if ((p[2] == TLS1_2_VERSION_MINOR) &&
707         !(s->options & SSL_OP_NO_TLSv1_2))
708         {//假设是这个版本吧,因为现在主要用的就是这个版本了
709         s->version=TLS1_2_VERSION;
                        // 这里的 method 被重新定义了为 TLSv1_2_client_method,它也是一个宏实现,其最重要和 ssl_connect 指向了 ssl3_connect.
710         s->method=TLSv1_2_client_method();
711         }
712     else
713         {
714         SSLerr(SSL_F_SSL23_GET_SERVER_HELLO,SSL_R_UNSUPPORTED_PROTOCOL);
715         goto err;
716         }
717
718     if (p[0] == SSL3_RT_ALERT && p[5] != SSL3_AL_WARNING)
719         {
720         /* fatal alert */
721
722         void (*cb)(const SSL *ssl,int type,int val)=NULL;
723         int j;
724
725         if (s->info_callback != NULL)
726             cb=s->info_callback;
727         else if (s->ctx->info_callback != NULL)
728             cb=s->ctx->info_callback;
729
730         i=p[5];
731         if (cb != NULL)
732             {
733             j=(i<<8)|p[6];
734             cb(s,SSL_CB_READ_ALERT,j);
735             }
736
737         if (s->msg_callback)
738             s->msg_callback(0, s->version, SSL3_RT_ALERT, p+5, 2, s, s->msg_callback_arg);
739
740         s->rwstate=SSL_NOTHING;
741         SSLerr(SSL_F_SSL23_GET_SERVER_HELLO,SSL_AD_REASON_OFFSET+p[6]);
742         goto err;
743         }
744
745     if (!ssl_init_wbio_buffer(s,1)) goto err;
746
747     /* we are in this state */
        // 置状态为
748     s->state=SSL3_ST_CR_SRVR_HELLO_A;
749
        ......
761     改变 handshake_func 的值为 s->method->ssl_connect
762     s->handshake_func=s->method->ssl_connect;
763     }
764 else
765     {
766     SSLerr(SSL_F_SSL23_GET_SERVER_HELLO,SSL_R_UNKNOWN_PROTOCOL);
767     goto err;
768     }
782      // 再调用 SSL_connect
783 return(SSL_connect(s));
784err:
785 return(-1);
786 }

这一段代码只读了 7 个字节,主要就是确定了协议版本以及用于执行继续握手的handshake_fun的指向。根据代码里的分析此时是指向的是 ssl3_connect。另外,此时SSL的状态为 SSL3_ST_CR_SRVR_HELLO_A。在 ssl3_connect中,对于 SSL3_ST_CR_SRVR_HELLO_A 的处理是调用 ssl3_get_server_hello()

int ssl3_get_server_hello(SSL *s)
892 {

    ......
948 /* load the server hello data */
949 /* load the server random */
    // 获取服务器的随机数
950 memcpy(s->s3->server_random,p,SSL3_RANDOM_SIZE);
951 p+=SSL3_RANDOM_SIZE;

        ......
        // 获取加密算法
1016    c=ssl_get_cipher_by_char(s,p);
        .......
        // 
1032    p+=ssl_put_cipher_by_char(s,NULL,NULL);
        .....
1146    return(1);
1147f_err:
1148    ssl3_send_alert(s,SSL3_AL_FATAL,al);
1149err:
1150    return(-1);
1151    }

证书校验
ssl3_get_server_hello()函数主要是读取了从服务器传递过来的随机数以及所选择的加密算法。此时就有两个随机数了。
ssl3_get_server_hello() 执行完成后,就会将 s->state 的置为 SSL3_ST_CR_CERT_A。对于SSL3_ST_CR_CERT_A的状态调用的是 ssl3_get_server_certificate()函数

int ssl3_get_server_certificate(SSL *s)
1154    {


1165    n=s->method->ssl_get_message(s,
1166        SSL3_ST_CR_CERT_A,
1167        SSL3_ST_CR_CERT_B,
1168        -1,
1169        s->max_cert_list,
1170        &ok);
1171

1203    for (nc=0; nc<llen; )
1204        {
1205        ......
1214        x=d2i_X509(NULL,&q,l);
1215        ......
1227        if (!sk_X509_push(sk,x))
1228            {
1229            ......
1231            }
1232        ......
1235        }
1236    // 校验证书
1237    i=ssl_verify_cert_chain(s,sk);
        ......
        // 取出公钥
1263
1264    pkey=X509_get_pubkey(x);
1265    
1336    return(ret);
1337    }
1338

主要就是检验证书,并获取公钥。
握手的后续流程中对于双向验证可能还要发送DH参数,以及客户端的证书给服务器进行校验。接收服务器的 Hello Done消息等,这些就一笔带过了。
在 ssl3_send_client_key_exchange() 函数会生成第三个随机数,然后会用服务器下发的证书中RSA的公钥对其进行加密,并传递给服务器。自此客户端与服务器双方都有三个随机数,而利用这三个随机数就可以各自生成对称加密算法的密钥,最后通过这个对称加密算法来进行通信。
k.获取证书构建 OpenSSLSeesionImpl
l.上层完成握手并发出通知

三、总结

1.SSL/TLS 是位于传输层与应用层之间的,其主要的职责就是完成握手协议以及实现数据的加解密传输。
2.Android 中的 SSL/TLS 是移植的 OpenSSL的实现,一个重磅的开源库,想要深了解的同学不妨看看其Github
3.握手是在 TCP 连接建立起来之后才进行的,这也应证了第1点其确实应该处于应用层与传输层之间。
4.握手的核心流程是:
客户端hello(随机数1,密钥套件,协议版本) -> 服务端Hello(选择的密钥,协议版本,随机数2,并下发证书) -> 服务端完成Hello -> 客户端校验证书 -> 客户端生成随机数3并用公钥加密 -> 完成握手 -> 客户端与服务端各自用三个随机数生成对称密钥进行加密通信

文章前后共持续了半个月左右才完成,然而由于水平有限,文章中难免存在纰漏以及错误之处,还请各位看到文章的同学多多包含并帮忙指出,非常感谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,406评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,976评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,302评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,366评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,372评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,457评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,872评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,521评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,717评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,523评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,590评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,299评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,859评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,883评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,127评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,760评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,290评论 2 342

推荐阅读更多精彩内容