OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This file includes code SSLClientSocketNSS::DoVerifyCertComplete() derived | 5 // This file includes code SSLClientSocketNSS::DoVerifyCertComplete() derived |
6 // from AuthCertificateCallback() in | 6 // from AuthCertificateCallback() in |
7 // mozilla/security/manager/ssl/src/nsNSSCallbacks.cpp. | 7 // mozilla/security/manager/ssl/src/nsNSSCallbacks.cpp. |
8 | 8 |
9 /* ***** BEGIN LICENSE BLOCK ***** | 9 /* ***** BEGIN LICENSE BLOCK ***** |
10 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | 10 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
110 #include <wincrypt.h> | 110 #include <wincrypt.h> |
111 #elif defined(OS_MACOSX) | 111 #elif defined(OS_MACOSX) |
112 #include <Security/SecBase.h> | 112 #include <Security/SecBase.h> |
113 #include <Security/SecCertificate.h> | 113 #include <Security/SecCertificate.h> |
114 #include <Security/SecIdentity.h> | 114 #include <Security/SecIdentity.h> |
115 #include "base/mac/mac_logging.h" | 115 #include "base/mac/mac_logging.h" |
116 #elif defined(USE_NSS) | 116 #elif defined(USE_NSS) |
117 #include <dlfcn.h> | 117 #include <dlfcn.h> |
118 #endif | 118 #endif |
119 | 119 |
120 namespace net { | |
121 | |
122 // State machines are easier to debug if you log state transitions. | |
123 // Enable these if you want to see what's going on. | |
124 #if 1 | |
125 #define EnterFunction(x) | |
126 #define LeaveFunction(x) | |
127 #define GotoState(s) next_handshake_state_ = s | |
128 #else | |
129 #define EnterFunction(x)\ | |
130 VLOG(1) << (void *)this << " " << __FUNCTION__ << " enter " << x\ | |
131 << "; next_handshake_state " << next_handshake_state_ | |
132 #define LeaveFunction(x)\ | |
133 VLOG(1) << (void *)this << " " << __FUNCTION__ << " leave " << x\ | |
134 << "; next_handshake_state " << next_handshake_state_ | |
135 #define GotoState(s)\ | |
136 do {\ | |
137 VLOG(1) << (void *)this << " " << __FUNCTION__ << " jump to state " << s;\ | |
138 next_handshake_state_ = s;\ | |
139 } while (0) | |
140 #endif | |
141 | |
142 namespace { | |
143 | |
120 // SSL plaintext fragments are shorter than 16KB. Although the record layer | 144 // SSL plaintext fragments are shorter than 16KB. Although the record layer |
121 // overhead is allowed to be 2K + 5 bytes, in practice the overhead is much | 145 // overhead is allowed to be 2K + 5 bytes, in practice the overhead is much |
122 // smaller than 1KB. So a 17KB buffer should be large enough to hold an | 146 // smaller than 1KB. So a 17KB buffer should be large enough to hold an |
123 // entire SSL record. | 147 // entire SSL record. |
124 static const int kRecvBufferSize = 17 * 1024; | 148 const int kRecvBufferSize = 17 * 1024; |
125 static const int kSendBufferSize = 17 * 1024; | 149 const int kSendBufferSize = 17 * 1024; |
150 | |
151 // Used by SSLClientSocketNSS::Core to indicate there is no read result | |
152 // obtained by a previous operation waiting to be returned to the caller. | |
wtc
2013/02/15 23:14:49
It'd be nice to point out this constant can be any
| |
153 const int kNoPendingReadResult = 1; | |
126 | 154 |
127 #if defined(OS_WIN) | 155 #if defined(OS_WIN) |
128 // CERT_OCSP_RESPONSE_PROP_ID is only implemented on Vista+, but it can be | 156 // CERT_OCSP_RESPONSE_PROP_ID is only implemented on Vista+, but it can be |
129 // set on Windows XP without error. There is some overhead from the server | 157 // set on Windows XP without error. There is some overhead from the server |
130 // sending the OCSP response if it supports the extension, for the subset of | 158 // sending the OCSP response if it supports the extension, for the subset of |
131 // XP clients who will request it but be unable to use it, but this is an | 159 // XP clients who will request it but be unable to use it, but this is an |
132 // acceptable trade-off for simplicity of implementation. | 160 // acceptable trade-off for simplicity of implementation. |
133 static bool IsOCSPStaplingSupported() { | 161 bool IsOCSPStaplingSupported() { |
134 return true; | 162 return true; |
135 } | 163 } |
136 #elif defined(USE_NSS) | 164 #elif defined(USE_NSS) |
137 typedef SECStatus | 165 typedef SECStatus |
138 (*CacheOCSPResponseFromSideChannelFunction)( | 166 (*CacheOCSPResponseFromSideChannelFunction)( |
139 CERTCertDBHandle *handle, CERTCertificate *cert, PRTime time, | 167 CERTCertDBHandle *handle, CERTCertificate *cert, PRTime time, |
140 SECItem *encodedResponse, void *pwArg); | 168 SECItem *encodedResponse, void *pwArg); |
141 | 169 |
142 // On Linux, we dynamically link against the system version of libnss3.so. In | 170 // On Linux, we dynamically link against the system version of libnss3.so. In |
143 // order to continue working on systems without up-to-date versions of NSS we | 171 // order to continue working on systems without up-to-date versions of NSS we |
(...skipping 18 matching lines...) Expand all Loading... | |
162 RuntimeLibNSSFunctionPointers() { | 190 RuntimeLibNSSFunctionPointers() { |
163 cache_ocsp_response_from_side_channel_ = | 191 cache_ocsp_response_from_side_channel_ = |
164 (CacheOCSPResponseFromSideChannelFunction) | 192 (CacheOCSPResponseFromSideChannelFunction) |
165 dlsym(RTLD_DEFAULT, "CERT_CacheOCSPResponseFromSideChannel"); | 193 dlsym(RTLD_DEFAULT, "CERT_CacheOCSPResponseFromSideChannel"); |
166 } | 194 } |
167 | 195 |
168 CacheOCSPResponseFromSideChannelFunction | 196 CacheOCSPResponseFromSideChannelFunction |
169 cache_ocsp_response_from_side_channel_; | 197 cache_ocsp_response_from_side_channel_; |
170 }; | 198 }; |
171 | 199 |
172 static CacheOCSPResponseFromSideChannelFunction | 200 CacheOCSPResponseFromSideChannelFunction |
173 GetCacheOCSPResponseFromSideChannelFunction() { | 201 GetCacheOCSPResponseFromSideChannelFunction() { |
174 return RuntimeLibNSSFunctionPointers::GetInstance() | 202 return RuntimeLibNSSFunctionPointers::GetInstance() |
175 ->GetCacheOCSPResponseFromSideChannelFunction(); | 203 ->GetCacheOCSPResponseFromSideChannelFunction(); |
176 } | 204 } |
177 | 205 |
178 static bool IsOCSPStaplingSupported() { | 206 bool IsOCSPStaplingSupported() { |
179 return GetCacheOCSPResponseFromSideChannelFunction() != NULL; | 207 return GetCacheOCSPResponseFromSideChannelFunction() != NULL; |
180 } | 208 } |
181 #else | 209 #else |
182 // TODO(agl): Figure out if we can plumb the OCSP response into Mac's system | 210 // TODO(agl): Figure out if we can plumb the OCSP response into Mac's system |
183 // certificate validation functions. | 211 // certificate validation functions. |
184 static bool IsOCSPStaplingSupported() { | 212 bool IsOCSPStaplingSupported() { |
185 return false; | 213 return false; |
186 } | 214 } |
187 #endif | 215 #endif |
188 | 216 |
189 namespace net { | |
190 | |
191 // State machines are easier to debug if you log state transitions. | |
192 // Enable these if you want to see what's going on. | |
193 #if 1 | |
194 #define EnterFunction(x) | |
195 #define LeaveFunction(x) | |
196 #define GotoState(s) next_handshake_state_ = s | |
197 #else | |
198 #define EnterFunction(x)\ | |
199 VLOG(1) << (void *)this << " " << __FUNCTION__ << " enter " << x\ | |
200 << "; next_handshake_state " << next_handshake_state_ | |
201 #define LeaveFunction(x)\ | |
202 VLOG(1) << (void *)this << " " << __FUNCTION__ << " leave " << x\ | |
203 << "; next_handshake_state " << next_handshake_state_ | |
204 #define GotoState(s)\ | |
205 do {\ | |
206 VLOG(1) << (void *)this << " " << __FUNCTION__ << " jump to state " << s;\ | |
207 next_handshake_state_ = s;\ | |
208 } while (0) | |
209 #endif | |
210 | |
211 namespace { | |
212 | |
213 class FreeCERTCertificate { | 217 class FreeCERTCertificate { |
214 public: | 218 public: |
215 inline void operator()(CERTCertificate* x) const { | 219 inline void operator()(CERTCertificate* x) const { |
216 CERT_DestroyCertificate(x); | 220 CERT_DestroyCertificate(x); |
217 } | 221 } |
218 }; | 222 }; |
219 typedef scoped_ptr_malloc<CERTCertificate, FreeCERTCertificate> | 223 typedef scoped_ptr_malloc<CERTCertificate, FreeCERTCertificate> |
220 ScopedCERTCertificate; | 224 ScopedCERTCertificate; |
221 | 225 |
222 #if defined(OS_WIN) | 226 #if defined(OS_WIN) |
(...skipping 607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
830 //////////////////////////////////////////////////////////////////////////// | 834 //////////////////////////////////////////////////////////////////////////// |
831 HostPortPair host_and_port_; | 835 HostPortPair host_and_port_; |
832 SSLConfig ssl_config_; | 836 SSLConfig ssl_config_; |
833 | 837 |
834 // NSS SSL socket. | 838 // NSS SSL socket. |
835 PRFileDesc* nss_fd_; | 839 PRFileDesc* nss_fd_; |
836 | 840 |
837 // Buffers for the network end of the SSL state machine | 841 // Buffers for the network end of the SSL state machine |
838 memio_Private* nss_bufs_; | 842 memio_Private* nss_bufs_; |
839 | 843 |
844 // Used by DoPayloadRead() when attempting to fill the caller's buffer with | |
845 // as much data as possible, without blocking. | |
846 // If DoPayloadRead() encounters an error after having read some data, stores | |
847 // the results to return on the *next* call to DoPayloadRead(). A value of | |
848 // kNoPendingReadResult indicates there is no pending result, otherwise 0 | |
849 // indicates EOF and < 0 indicates an error. | |
850 int pending_read_result_; | |
851 // Contains the previously observed NSS error. Only valid when | |
852 // pending_read_result_ != kNoPendingReadResult. | |
853 PRErrorCode pending_read_nss_error_; | |
854 | |
840 // The certificate chain, in DER form, that is expected to be received from | 855 // The certificate chain, in DER form, that is expected to be received from |
841 // the server. | 856 // the server. |
842 std::vector<std::string> predicted_certs_; | 857 std::vector<std::string> predicted_certs_; |
843 | 858 |
844 State next_handshake_state_; | 859 State next_handshake_state_; |
845 | 860 |
846 // True if channel ID extension was negotiated. | 861 // True if channel ID extension was negotiated. |
847 bool channel_id_xtn_negotiated_; | 862 bool channel_id_xtn_negotiated_; |
848 // True if the handshake state machine was interrupted for channel ID. | 863 // True if the handshake state machine was interrupted for channel ID. |
849 bool channel_id_needed_; | 864 bool channel_id_needed_; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
905 weak_net_log_factory_(net_log), | 920 weak_net_log_factory_(net_log), |
906 server_bound_cert_service_(server_bound_cert_service), | 921 server_bound_cert_service_(server_bound_cert_service), |
907 unhandled_buffer_size_(0), | 922 unhandled_buffer_size_(0), |
908 nss_waiting_read_(false), | 923 nss_waiting_read_(false), |
909 nss_waiting_write_(false), | 924 nss_waiting_write_(false), |
910 nss_is_closed_(false), | 925 nss_is_closed_(false), |
911 host_and_port_(host_and_port), | 926 host_and_port_(host_and_port), |
912 ssl_config_(ssl_config), | 927 ssl_config_(ssl_config), |
913 nss_fd_(NULL), | 928 nss_fd_(NULL), |
914 nss_bufs_(NULL), | 929 nss_bufs_(NULL), |
930 pending_read_result_(kNoPendingReadResult), | |
931 pending_read_nss_error_(0), | |
915 next_handshake_state_(STATE_NONE), | 932 next_handshake_state_(STATE_NONE), |
916 channel_id_xtn_negotiated_(false), | 933 channel_id_xtn_negotiated_(false), |
917 channel_id_needed_(false), | 934 channel_id_needed_(false), |
918 client_auth_cert_needed_(false), | 935 client_auth_cert_needed_(false), |
919 handshake_callback_called_(false), | 936 handshake_callback_called_(false), |
920 transport_recv_busy_(false), | 937 transport_recv_busy_(false), |
921 transport_recv_eof_(false), | 938 transport_recv_eof_(false), |
922 transport_send_busy_(false), | 939 transport_send_busy_(false), |
923 user_read_buf_len_(0), | 940 user_read_buf_len_(0), |
924 user_write_buf_len_(0), | 941 user_write_buf_len_(0), |
(...skipping 1013 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1938 SetChannelIDProvided(); | 1955 SetChannelIDProvided(); |
1939 GotoState(STATE_HANDSHAKE); | 1956 GotoState(STATE_HANDSHAKE); |
1940 return OK; | 1957 return OK; |
1941 } | 1958 } |
1942 | 1959 |
1943 int SSLClientSocketNSS::Core::DoPayloadRead() { | 1960 int SSLClientSocketNSS::Core::DoPayloadRead() { |
1944 DCHECK(OnNSSTaskRunner()); | 1961 DCHECK(OnNSSTaskRunner()); |
1945 DCHECK(user_read_buf_); | 1962 DCHECK(user_read_buf_); |
1946 DCHECK_GT(user_read_buf_len_, 0); | 1963 DCHECK_GT(user_read_buf_len_, 0); |
1947 | 1964 |
1948 int rv = PR_Read(nss_fd_, user_read_buf_->data(), user_read_buf_len_); | 1965 int rv; |
1949 // Update NSSTaskRunner status because PR_Read may consume |nss_bufs_|, then | 1966 // If a previous greedy read resulted in an error that was not consumed (eg: |
1950 // following |amount_in_read_buffer| may be changed here. | 1967 // due to the caller having read some data successfully), then return that |
1951 int amount_in_read_buffer = memio_GetReadableBufferSize(nss_bufs_); | 1968 // pending error now. |
1952 PostOrRunCallback( | 1969 if (pending_read_result_ != kNoPendingReadResult) { |
1953 FROM_HERE, | 1970 rv = pending_read_result_; |
1954 base::Bind(&Core::OnNSSBufferUpdated, this, amount_in_read_buffer)); | 1971 PRErrorCode prerr = pending_read_nss_error_; |
1972 pending_read_result_ = kNoPendingReadResult; | |
1973 pending_read_nss_error_ = 0; | |
1955 | 1974 |
1956 if (client_auth_cert_needed_) { | 1975 if (rv == 0) { |
1957 // We don't need to invalidate the non-client-authenticated SSL session | 1976 PostOrRunCallback( |
1958 // because the server will renegotiate anyway. | 1977 FROM_HERE, |
1959 rv = ERR_SSL_CLIENT_AUTH_CERT_NEEDED; | 1978 base::Bind(&LogByteTransferEvent, weak_net_log_, |
1960 PostOrRunCallback( | 1979 NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED, rv, |
1961 FROM_HERE, | 1980 scoped_refptr<IOBuffer>(user_read_buf_))); |
1962 base::Bind(&AddLogEventWithCallback, weak_net_log_, | 1981 } else if (rv != ERR_IO_PENDING) { |
wtc
2013/02/15 23:14:49
I believe rv cannot be ERR_IO_PENDING.
| |
1963 NetLog::TYPE_SSL_READ_ERROR, | 1982 PostOrRunCallback( |
1964 CreateNetLogSSLErrorCallback(rv, 0))); | 1983 FROM_HERE, |
1984 base::Bind(&AddLogEventWithCallback, weak_net_log_, | |
1985 NetLog::TYPE_SSL_READ_ERROR, | |
1986 CreateNetLogSSLErrorCallback(rv, prerr))); | |
1987 } | |
1965 return rv; | 1988 return rv; |
1966 } | 1989 } |
1990 | |
1991 // Perform a greedy read, attempting to read as much as the caller has | |
1992 // requested. In the current NSS implementation, PR_Read will return | |
1993 // exactly one SSL application data record's worth of data per invocation. | |
1994 // The record size is dictated by the server, and may be noticeably smaller | |
1995 // than the caller's buffer. This may be as little as a single byte, if the | |
1996 // server is performing 1/n-1 record splitting. | |
1997 // | |
1998 // However, this greedy read may result in renegotiations/re-handshakes | |
1999 // happening or may lead to some data being read, followed by an EOF (such as | |
2000 // a TLS close-notify). If at least some data was read, then that result | |
2001 // should be deferred until the next call to DoPayloadRead(). Otherwise, if no | |
2002 // data was read, it's safe to return the error or EOF immediately. | |
2003 int total_bytes_read = 0; | |
2004 do { | |
2005 rv = PR_Read(nss_fd_, user_read_buf_->data() + total_bytes_read, | |
2006 user_read_buf_len_ - total_bytes_read); | |
2007 if (rv > 0) | |
2008 total_bytes_read += rv; | |
2009 } while (total_bytes_read < user_read_buf_len_ && rv > 0); | |
2010 int amount_in_read_buffer = memio_GetReadableBufferSize(nss_bufs_); | |
2011 PostOrRunCallback(FROM_HERE, base::Bind(&Core::OnNSSBufferUpdated, this, | |
2012 amount_in_read_buffer)); | |
2013 | |
2014 if (total_bytes_read == user_read_buf_len_) { | |
2015 // The caller's entire request was satisfied without error. No further | |
2016 // processing needed. | |
2017 rv = total_bytes_read; | |
2018 } else { | |
2019 // Otherwise, an error occurred (rv <= 0). The error needs to be handled | |
2020 // immediately, while the NSPR/NSS errors are still available in | |
2021 // thread-local storage. However, the handled/remapped error code should | |
2022 // only be returned if no application data was already read; if it was, the | |
2023 // error code should be deferred until the next call of DoPayloadRead. | |
2024 // | |
2025 // If no data was read, |*next_result| will point to the return value of | |
2026 // this function. If at least some data was read, |*next_result| will point | |
2027 // to |pending_read_error_|, to be returned in a future call to | |
2028 // DoPayloadRead() (e.g.: after the current data is handled). | |
2029 int* next_result = &rv; | |
2030 if (total_bytes_read > 0) { | |
2031 pending_read_result_ = rv; | |
2032 rv = total_bytes_read; | |
2033 next_result = &pending_read_result_; | |
2034 } | |
2035 | |
2036 if (client_auth_cert_needed_) { | |
2037 *next_result = ERR_SSL_CLIENT_AUTH_CERT_NEEDED; | |
2038 pending_read_nss_error_ = 0; | |
2039 } else if (*next_result < 0) { | |
2040 // If *next_result == 0, then that indicates EOF, and no special error | |
2041 // handling is needed. | |
2042 pending_read_nss_error_ = PR_GetError(); | |
2043 if (pending_read_nss_error_ == PR_WOULD_BLOCK_ERROR) { | |
2044 pending_read_nss_error_ = 0; | |
2045 if (rv > 0) { | |
2046 // If at least some data was read from PR_Read(), do not treat | |
2047 // insufficient data as an error to return in the next call to | |
2048 // DoPayloadRead() - instead, let the call fall through to check | |
2049 // PR_Read() again. This is because DoTransportIO() may complete | |
2050 // in between the next call to DoPayloadRead(), and thus it is | |
2051 // important to check PR_Read() on subsequent invocations to see | |
2052 // if a complete record may now be read. | |
2053 pending_read_result_ = kNoPendingReadResult; | |
2054 } else { | |
2055 *next_result = ERR_IO_PENDING; | |
wtc
2013/02/15 23:14:49
I think it's clearer to use |rv| here:
rv = ER
| |
2056 } | |
2057 } else { | |
2058 *next_result = HandleNSSError(pending_read_nss_error_, false); | |
wtc
2013/02/15 23:14:49
HandleNSSError maps PR_WOULD_BLOCK_ERROR to ERR_IO
| |
2059 } | |
2060 } | |
2061 } | |
2062 | |
wtc
2013/02/15 23:14:49
Here you can CHECK or DCHECK that we never set
pen
| |
1967 if (rv >= 0) { | 2063 if (rv >= 0) { |
1968 PostOrRunCallback( | 2064 PostOrRunCallback( |
1969 FROM_HERE, | 2065 FROM_HERE, |
1970 base::Bind(&LogByteTransferEvent, weak_net_log_, | 2066 base::Bind(&LogByteTransferEvent, weak_net_log_, |
1971 NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED, rv, | 2067 NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED, rv, |
1972 scoped_refptr<IOBuffer>(user_read_buf_))); | 2068 scoped_refptr<IOBuffer>(user_read_buf_))); |
1973 return rv; | 2069 } else if (rv != ERR_IO_PENDING) { |
2070 PostOrRunCallback( | |
2071 FROM_HERE, | |
2072 base::Bind(&AddLogEventWithCallback, weak_net_log_, | |
2073 NetLog::TYPE_SSL_READ_ERROR, | |
2074 CreateNetLogSSLErrorCallback(rv, pending_read_nss_error_))); | |
2075 pending_read_nss_error_ = 0; | |
1974 } | 2076 } |
1975 PRErrorCode prerr = PR_GetError(); | |
1976 if (prerr == PR_WOULD_BLOCK_ERROR) | |
1977 return ERR_IO_PENDING; | |
1978 | |
1979 rv = HandleNSSError(prerr, false); | |
1980 PostOrRunCallback( | |
1981 FROM_HERE, | |
1982 base::Bind(&AddLogEventWithCallback, weak_net_log_, | |
1983 NetLog::TYPE_SSL_READ_ERROR, | |
1984 CreateNetLogSSLErrorCallback(rv, prerr))); | |
1985 return rv; | 2077 return rv; |
1986 } | 2078 } |
1987 | 2079 |
1988 int SSLClientSocketNSS::Core::DoPayloadWrite() { | 2080 int SSLClientSocketNSS::Core::DoPayloadWrite() { |
1989 DCHECK(OnNSSTaskRunner()); | 2081 DCHECK(OnNSSTaskRunner()); |
1990 | 2082 |
1991 DCHECK(user_write_buf_); | 2083 DCHECK(user_write_buf_); |
1992 | 2084 |
1993 int old_amount_in_read_buffer = memio_GetReadableBufferSize(nss_bufs_); | 2085 int old_amount_in_read_buffer = memio_GetReadableBufferSize(nss_bufs_); |
1994 int rv = PR_Write(nss_fd_, user_write_buf_->data(), user_write_buf_len_); | 2086 int rv = PR_Write(nss_fd_, user_write_buf_->data(), user_write_buf_len_); |
(...skipping 1444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3439 EnsureThreadIdAssigned(); | 3531 EnsureThreadIdAssigned(); |
3440 base::AutoLock auto_lock(lock_); | 3532 base::AutoLock auto_lock(lock_); |
3441 return valid_thread_id_ == base::PlatformThread::CurrentId(); | 3533 return valid_thread_id_ == base::PlatformThread::CurrentId(); |
3442 } | 3534 } |
3443 | 3535 |
3444 ServerBoundCertService* SSLClientSocketNSS::GetServerBoundCertService() const { | 3536 ServerBoundCertService* SSLClientSocketNSS::GetServerBoundCertService() const { |
3445 return server_bound_cert_service_; | 3537 return server_bound_cert_service_; |
3446 } | 3538 } |
3447 | 3539 |
3448 } // namespace net | 3540 } // namespace net |
OLD | NEW |