blob: b4d00813ec4ba1d32f72bee22f8e72290f7ea28f [file] [log] [blame]
Ben Schwartzded1b702017-10-25 14:41:02 -04001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "DnsTlsSocket"
Ben Schwartz33860762017-10-25 14:41:02 -040018//#define LOG_NDEBUG 0
Ben Schwartzded1b702017-10-25 14:41:02 -040019
Mike Yu5ae61542018-10-19 22:11:43 +080020#include "netd_resolv/DnsTlsSocket.h"
Ben Schwartzded1b702017-10-25 14:41:02 -040021
22#include <algorithm>
23#include <arpa/inet.h>
24#include <arpa/nameser.h>
25#include <errno.h>
Erik Klined1503072018-02-22 23:55:40 -080026#include <linux/tcp.h>
Ben Schwartzded1b702017-10-25 14:41:02 -040027#include <openssl/err.h>
Mike Yu5ae61542018-10-19 22:11:43 +080028#include <openssl/sha.h>
Bernie Innocentif944a9c2018-05-18 20:50:25 +090029#include <sys/poll.h>
Ben Schwartzded1b702017-10-25 14:41:02 -040030
Mike Yu5ae61542018-10-19 22:11:43 +080031#include "netd_resolv/DnsTlsSessionCache.h"
32#include "netd_resolv/IDnsTlsSocketObserver.h"
Ben Schwartzded1b702017-10-25 14:41:02 -040033
34#include "log/log.h"
Erik Klined1503072018-02-22 23:55:40 -080035#include "netdutils/SocketOption.h"
Ben Schwartzded1b702017-10-25 14:41:02 -040036
Ben Schwartzded1b702017-10-25 14:41:02 -040037namespace android {
Ben Schwartzded1b702017-10-25 14:41:02 -040038
Erik Klined1503072018-02-22 23:55:40 -080039using netdutils::enableSockopt;
40using netdutils::enableTcpKeepAlives;
41using netdutils::isOk;
Ben Schwartzded1b702017-10-25 14:41:02 -040042using netdutils::Status;
43
Erik Klined1503072018-02-22 23:55:40 -080044namespace net {
Ben Schwartzded1b702017-10-25 14:41:02 -040045namespace {
46
47constexpr const char kCaCertDir[] = "/system/etc/security/cacerts";
Mike Yu5ae61542018-10-19 22:11:43 +080048constexpr size_t SHA256_SIZE = SHA256_DIGEST_LENGTH;
Ben Schwartzded1b702017-10-25 14:41:02 -040049
50int waitForReading(int fd) {
Bernie Innocentif944a9c2018-05-18 20:50:25 +090051 struct pollfd fds = { .fd = fd, .events = POLLIN };
52 const int ret = TEMP_FAILURE_RETRY(poll(&fds, 1, -1));
Ben Schwartzded1b702017-10-25 14:41:02 -040053 return ret;
54}
55
56int waitForWriting(int fd) {
Bernie Innocentif944a9c2018-05-18 20:50:25 +090057 struct pollfd fds = { .fd = fd, .events = POLLOUT };
58 const int ret = TEMP_FAILURE_RETRY(poll(&fds, 1, -1));
Ben Schwartzded1b702017-10-25 14:41:02 -040059 return ret;
60}
61
62} // namespace
63
64Status DnsTlsSocket::tcpConnect() {
65 ALOGV("%u connecting TCP socket", mMark);
66 int type = SOCK_NONBLOCK | SOCK_CLOEXEC;
67 switch (mServer.protocol) {
68 case IPPROTO_TCP:
69 type |= SOCK_STREAM;
70 break;
71 default:
72 return Status(EPROTONOSUPPORT);
73 }
74
75 mSslFd.reset(socket(mServer.ss.ss_family, type, mServer.protocol));
76 if (mSslFd.get() == -1) {
77 ALOGE("Failed to create socket");
78 return Status(errno);
79 }
80
81 const socklen_t len = sizeof(mMark);
82 if (setsockopt(mSslFd.get(), SOL_SOCKET, SO_MARK, &mMark, len) == -1) {
83 ALOGE("Failed to set socket mark");
84 mSslFd.reset();
85 return Status(errno);
86 }
Erik Klined1503072018-02-22 23:55:40 -080087
88 const Status tfo = enableSockopt(mSslFd.get(), SOL_TCP, TCP_FASTOPEN_CONNECT);
89 if (!isOk(tfo) && tfo.code() != ENOPROTOOPT) {
90 ALOGI("Failed to enable TFO: %s", tfo.msg().c_str());
91 }
92
93 // Send 5 keepalives, 3 seconds apart, after 15 seconds of inactivity.
Bernie Innocenti6f9fd902018-10-11 20:50:23 +090094 enableTcpKeepAlives(mSslFd.get(), 15U, 5U, 3U).ignoreError();
Erik Klined1503072018-02-22 23:55:40 -080095
Ben Schwartzded1b702017-10-25 14:41:02 -040096 if (connect(mSslFd.get(), reinterpret_cast<const struct sockaddr *>(&mServer.ss),
97 sizeof(mServer.ss)) != 0 &&
98 errno != EINPROGRESS) {
99 ALOGV("Socket failed to connect");
100 mSslFd.reset();
101 return Status(errno);
102 }
103
104 return netdutils::status::ok;
105}
106
107bool getSPKIDigest(const X509* cert, std::vector<uint8_t>* out) {
Yi Kongbdfd57e2018-07-25 13:26:10 -0700108 int spki_len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), nullptr);
Ben Schwartzded1b702017-10-25 14:41:02 -0400109 unsigned char spki[spki_len];
110 unsigned char* temp = spki;
111 if (spki_len != i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp)) {
112 ALOGW("SPKI length mismatch");
113 return false;
114 }
115 out->resize(SHA256_SIZE);
116 unsigned int digest_len = 0;
Yi Kongbdfd57e2018-07-25 13:26:10 -0700117 int ret = EVP_Digest(spki, spki_len, out->data(), &digest_len, EVP_sha256(), nullptr);
Ben Schwartzded1b702017-10-25 14:41:02 -0400118 if (ret != 1) {
119 ALOGW("Server cert digest extraction failed");
120 return false;
121 }
122 if (digest_len != out->size()) {
123 ALOGW("Wrong digest length: %d", digest_len);
124 return false;
125 }
126 return true;
127}
128
129bool DnsTlsSocket::initialize() {
130 // This method should only be called once, at the beginning, so locking should be
131 // unnecessary. This lock only serves to help catch bugs in code that calls this method.
Bernie Innocentiabf8a342018-08-10 15:17:16 +0900132 std::lock_guard guard(mLock);
Ben Schwartzded1b702017-10-25 14:41:02 -0400133 if (mSslCtx) {
134 // This is a bug in the caller.
135 return false;
136 }
137 mSslCtx.reset(SSL_CTX_new(TLS_method()));
138 if (!mSslCtx) {
139 return false;
140 }
141
142 // Load system CA certs for hostname verification.
143 //
144 // For discussion of alternative, sustainable approaches see b/71909242.
145 if (SSL_CTX_load_verify_locations(mSslCtx.get(), nullptr, kCaCertDir) != 1) {
146 ALOGE("Failed to load CA cert dir: %s", kCaCertDir);
147 return false;
148 }
149
150 // Enable TLS false start
151 SSL_CTX_set_false_start_allowed_without_alpn(mSslCtx.get(), 1);
152 SSL_CTX_set_mode(mSslCtx.get(), SSL_MODE_ENABLE_FALSE_START);
153
154 // Enable session cache
155 mCache->prepareSslContext(mSslCtx.get());
156
157 // Connect
158 Status status = tcpConnect();
159 if (!status.ok()) {
160 return false;
161 }
162 mSsl = sslConnect(mSslFd.get());
163 if (!mSsl) {
164 return false;
165 }
Ben Schwartz33860762017-10-25 14:41:02 -0400166 int sv[2];
167 if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, sv)) {
168 return false;
169 }
170 // The two sockets are perfectly symmetrical, so the choice of which one is
171 // "in" and which one is "out" is arbitrary.
172 mIpcInFd.reset(sv[0]);
173 mIpcOutFd.reset(sv[1]);
174
175 // Start the I/O loop.
176 mLoopThread.reset(new std::thread(&DnsTlsSocket::loop, this));
Ben Schwartzded1b702017-10-25 14:41:02 -0400177
178 return true;
179}
180
181bssl::UniquePtr<SSL> DnsTlsSocket::sslConnect(int fd) {
182 if (!mSslCtx) {
183 ALOGE("Internal error: context is null in sslConnect");
184 return nullptr;
185 }
186 if (!SSL_CTX_set_min_proto_version(mSslCtx.get(), TLS1_2_VERSION)) {
187 ALOGE("Failed to set minimum TLS version");
188 return nullptr;
189 }
190
191 bssl::UniquePtr<SSL> ssl(SSL_new(mSslCtx.get()));
192 // This file descriptor is owned by mSslFd, so don't let libssl close it.
193 bssl::UniquePtr<BIO> bio(BIO_new_socket(fd, BIO_NOCLOSE));
194 SSL_set_bio(ssl.get(), bio.get(), bio.get());
195 bio.release();
196
197 if (!mCache->prepareSsl(ssl.get())) {
198 return nullptr;
199 }
200
201 if (!mServer.name.empty()) {
202 if (SSL_set_tlsext_host_name(ssl.get(), mServer.name.c_str()) != 1) {
203 ALOGE("Failed to set SNI to %s", mServer.name.c_str());
204 return nullptr;
205 }
206 X509_VERIFY_PARAM* param = SSL_get0_param(ssl.get());
Erik Klineefc13632018-03-22 11:19:02 -0700207 if (X509_VERIFY_PARAM_set1_host(param, mServer.name.data(), mServer.name.size()) != 1) {
208 ALOGE("Failed to set verify host param to %s", mServer.name.c_str());
209 return nullptr;
210 }
Ben Schwartzded1b702017-10-25 14:41:02 -0400211 // This will cause the handshake to fail if certificate verification fails.
212 SSL_set_verify(ssl.get(), SSL_VERIFY_PEER, nullptr);
213 }
214
215 bssl::UniquePtr<SSL_SESSION> session = mCache->getSession();
216 if (session) {
217 ALOGV("Setting session");
218 SSL_set_session(ssl.get(), session.get());
219 } else {
220 ALOGV("No session available");
221 }
222
223 for (;;) {
224 ALOGV("%u Calling SSL_connect", mMark);
225 int ret = SSL_connect(ssl.get());
226 ALOGV("%u SSL_connect returned %d", mMark, ret);
227 if (ret == 1) break; // SSL handshake complete;
228
229 const int ssl_err = SSL_get_error(ssl.get(), ret);
230 switch (ssl_err) {
231 case SSL_ERROR_WANT_READ:
232 if (waitForReading(fd) != 1) {
Bernie Innocentif944a9c2018-05-18 20:50:25 +0900233 ALOGW("SSL_connect read error: %d", errno);
Ben Schwartzded1b702017-10-25 14:41:02 -0400234 return nullptr;
235 }
236 break;
237 case SSL_ERROR_WANT_WRITE:
238 if (waitForWriting(fd) != 1) {
239 ALOGW("SSL_connect write error");
240 return nullptr;
241 }
242 break;
243 default:
244 ALOGW("SSL_connect error %d, errno=%d", ssl_err, errno);
245 return nullptr;
246 }
247 }
248
249 // TODO: Call SSL_shutdown before discarding the session if validation fails.
250 if (!mServer.fingerprints.empty()) {
251 ALOGV("Checking DNS over TLS fingerprint");
252
253 // We only care that the chain is internally self-consistent, not that
254 // it chains to a trusted root, so we can ignore some kinds of errors.
255 // TODO: Add a CA root verification mode that respects these errors.
256 int verify_result = SSL_get_verify_result(ssl.get());
257 switch (verify_result) {
258 case X509_V_OK:
259 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
260 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
261 case X509_V_ERR_CERT_UNTRUSTED:
262 break;
263 default:
264 ALOGW("Invalid certificate chain, error %d", verify_result);
265 return nullptr;
266 }
267
268 STACK_OF(X509) *chain = SSL_get_peer_cert_chain(ssl.get());
269 if (!chain) {
270 ALOGW("Server has null certificate");
271 return nullptr;
272 }
273 // Chain and its contents are owned by ssl, so we don't need to free explicitly.
274 bool matched = false;
275 for (size_t i = 0; i < sk_X509_num(chain); ++i) {
276 // This appears to be O(N^2), but there doesn't seem to be a straightforward
277 // way to walk a STACK_OF nondestructively in linear time.
278 X509* cert = sk_X509_value(chain, i);
279 std::vector<uint8_t> digest;
280 if (!getSPKIDigest(cert, &digest)) {
281 ALOGE("Digest computation failed");
282 return nullptr;
283 }
284
285 if (mServer.fingerprints.count(digest) > 0) {
286 matched = true;
287 break;
288 }
289 }
290
291 if (!matched) {
292 ALOGW("No matching fingerprint");
293 return nullptr;
294 }
295
296 ALOGV("DNS over TLS fingerprint is correct");
297 }
298
299 ALOGV("%u handshake complete", mMark);
300
301 return ssl;
302}
303
304void DnsTlsSocket::sslDisconnect() {
305 if (mSsl) {
306 SSL_shutdown(mSsl.get());
307 mSsl.reset();
308 }
309 mSslFd.reset();
310}
311
312bool DnsTlsSocket::sslWrite(const Slice buffer) {
313 ALOGV("%u Writing %zu bytes", mMark, buffer.size());
314 for (;;) {
315 int ret = SSL_write(mSsl.get(), buffer.base(), buffer.size());
316 if (ret == int(buffer.size())) break; // SSL write complete;
317
318 if (ret < 1) {
319 const int ssl_err = SSL_get_error(mSsl.get(), ret);
320 switch (ssl_err) {
321 case SSL_ERROR_WANT_WRITE:
322 if (waitForWriting(mSslFd.get()) != 1) {
323 ALOGV("SSL_write error");
324 return false;
325 }
326 continue;
327 case 0:
328 break; // SSL write complete;
329 default:
330 ALOGV("SSL_write error %d", ssl_err);
331 return false;
332 }
333 }
334 }
335 ALOGV("%u Wrote %zu bytes", mMark, buffer.size());
336 return true;
337}
338
Ben Schwartz33860762017-10-25 14:41:02 -0400339void DnsTlsSocket::loop() {
Bernie Innocentiabf8a342018-08-10 15:17:16 +0900340 std::lock_guard guard(mLock);
Ben Schwartz33860762017-10-25 14:41:02 -0400341 // Buffer at most one query.
342 Query q;
343
Bernie Innocentif944a9c2018-05-18 20:50:25 +0900344 const int timeout_msecs = DnsTlsSocket::kIdleTimeout.count() * 1000;
Ben Schwartz33860762017-10-25 14:41:02 -0400345 while (true) {
Bernie Innocentif944a9c2018-05-18 20:50:25 +0900346 // poll() ignores negative fds
347 struct pollfd fds[2] = { { .fd = -1 }, { .fd = -1 } };
348 enum { SSLFD = 0, IPCFD = 1 };
349
Ben Schwartz33860762017-10-25 14:41:02 -0400350 // Always listen for a response from server.
Bernie Innocentif944a9c2018-05-18 20:50:25 +0900351 fds[SSLFD].fd = mSslFd.get();
352 fds[SSLFD].events = POLLIN;
353
Ben Schwartz33860762017-10-25 14:41:02 -0400354 // If we have a pending query, also wait for space
355 // to write it, otherwise listen for a new query.
356 if (!q.query.empty()) {
Bernie Innocentif944a9c2018-05-18 20:50:25 +0900357 fds[SSLFD].events |= POLLOUT;
Ben Schwartz33860762017-10-25 14:41:02 -0400358 } else {
Bernie Innocentif944a9c2018-05-18 20:50:25 +0900359 fds[IPCFD].fd = mIpcOutFd.get();
360 fds[IPCFD].events = POLLIN;
Ben Schwartz33860762017-10-25 14:41:02 -0400361 }
Bernie Innocentif944a9c2018-05-18 20:50:25 +0900362
Mike Yu5ae61542018-10-19 22:11:43 +0800363 const int s = TEMP_FAILURE_RETRY(poll(fds, std::size(fds), timeout_msecs));
Ben Schwartz33860762017-10-25 14:41:02 -0400364 if (s == 0) {
365 ALOGV("Idle timeout");
366 break;
367 }
368 if (s < 0) {
Bernie Innocentif944a9c2018-05-18 20:50:25 +0900369 ALOGV("Poll failed: %d", errno);
Ben Schwartz33860762017-10-25 14:41:02 -0400370 break;
371 }
Bernie Innocentif944a9c2018-05-18 20:50:25 +0900372 if (fds[SSLFD].revents & (POLLIN | POLLERR)) {
Ben Schwartz33860762017-10-25 14:41:02 -0400373 if (!readResponse()) {
374 ALOGV("SSL remote close or read error.");
375 break;
376 }
377 }
Bernie Innocentif944a9c2018-05-18 20:50:25 +0900378 if (fds[IPCFD].revents & (POLLIN | POLLERR)) {
Ben Schwartz33860762017-10-25 14:41:02 -0400379 int res = read(mIpcOutFd.get(), &q, sizeof(q));
380 if (res < 0) {
381 ALOGW("Error during IPC read");
382 break;
383 } else if (res == 0) {
384 ALOGV("IPC channel closed; disconnecting");
385 break;
386 } else if (res != sizeof(q)) {
387 ALOGE("Struct size mismatch: %d != %zu", res, sizeof(q));
388 break;
389 }
Bernie Innocentif944a9c2018-05-18 20:50:25 +0900390 } else if (fds[SSLFD].revents & POLLOUT) {
Ben Schwartz33860762017-10-25 14:41:02 -0400391 // query cannot be null here.
392 if (!sendQuery(q)) {
393 break;
394 }
395 q = Query(); // Reset q to empty
396 }
Ben Schwartzded1b702017-10-25 14:41:02 -0400397 }
Ben Schwartz33860762017-10-25 14:41:02 -0400398 ALOGV("Closing IPC read FD");
399 mIpcOutFd.reset();
400 ALOGV("Disconnecting");
401 sslDisconnect();
402 ALOGV("Calling onClosed");
403 mObserver->onClosed();
404 ALOGV("Ending loop");
Ben Schwartzded1b702017-10-25 14:41:02 -0400405}
406
Ben Schwartz33860762017-10-25 14:41:02 -0400407DnsTlsSocket::~DnsTlsSocket() {
408 ALOGV("Destructor");
409 // This will trigger an orderly shutdown in loop().
410 mIpcInFd.reset();
411 {
412 // Wait for the orderly shutdown to complete.
Bernie Innocentiabf8a342018-08-10 15:17:16 +0900413 std::lock_guard guard(mLock);
Ben Schwartz33860762017-10-25 14:41:02 -0400414 if (mLoopThread && std::this_thread::get_id() == mLoopThread->get_id()) {
415 ALOGE("Violation of re-entrance precondition");
416 return;
417 }
418 }
419 if (mLoopThread) {
420 ALOGV("Waiting for loop thread to terminate");
421 mLoopThread->join();
422 mLoopThread.reset();
423 }
424 ALOGV("Destructor completed");
425}
426
427bool DnsTlsSocket::query(uint16_t id, const Slice query) {
428 const Query q = { .id = id, .query = query };
429 if (!mIpcInFd) {
430 return false;
431 }
432 int written = write(mIpcInFd.get(), &q, sizeof(q));
433 return written == sizeof(q);
434}
435
436// Read exactly len bytes into buffer or fail with an SSL error code
437int DnsTlsSocket::sslRead(const Slice buffer, bool wait) {
Ben Schwartzded1b702017-10-25 14:41:02 -0400438 size_t remaining = buffer.size();
439 while (remaining > 0) {
440 int ret = SSL_read(mSsl.get(), buffer.limit() - remaining, remaining);
441 if (ret == 0) {
442 ALOGW_IF(remaining < buffer.size(), "SSL closed with %zu of %zu bytes remaining",
443 remaining, buffer.size());
Ben Schwartz33860762017-10-25 14:41:02 -0400444 return SSL_ERROR_ZERO_RETURN;
Ben Schwartzded1b702017-10-25 14:41:02 -0400445 }
446
447 if (ret < 0) {
448 const int ssl_err = SSL_get_error(mSsl.get(), ret);
Ben Schwartz33860762017-10-25 14:41:02 -0400449 if (wait && ssl_err == SSL_ERROR_WANT_READ) {
Ben Schwartzded1b702017-10-25 14:41:02 -0400450 if (waitForReading(mSslFd.get()) != 1) {
Bernie Innocentif944a9c2018-05-18 20:50:25 +0900451 ALOGV("Poll failed in sslRead: %d", errno);
Ben Schwartz33860762017-10-25 14:41:02 -0400452 return SSL_ERROR_SYSCALL;
Ben Schwartzded1b702017-10-25 14:41:02 -0400453 }
454 continue;
455 } else {
456 ALOGV("SSL_read error %d", ssl_err);
Ben Schwartz33860762017-10-25 14:41:02 -0400457 return ssl_err;
Ben Schwartzded1b702017-10-25 14:41:02 -0400458 }
459 }
460
461 remaining -= ret;
Ben Schwartz33860762017-10-25 14:41:02 -0400462 wait = true; // Once a read is started, try to finish.
Ben Schwartzded1b702017-10-25 14:41:02 -0400463 }
Ben Schwartz33860762017-10-25 14:41:02 -0400464 return SSL_ERROR_NONE;
Ben Schwartzded1b702017-10-25 14:41:02 -0400465}
466
467bool DnsTlsSocket::sendQuery(const Query& q) {
468 ALOGV("sending query");
469 // Compose the entire message in a single buffer, so that it can be
470 // sent as a single TLS record.
471 std::vector<uint8_t> buf(q.query.size() + 4);
472 // Write 2-byte length
473 uint16_t len = q.query.size() + 2; // + 2 for the ID.
474 buf[0] = len >> 8;
475 buf[1] = len;
476 // Write 2-byte ID
477 buf[2] = q.id >> 8;
478 buf[3] = q.id;
479 // Copy body
480 std::memcpy(buf.data() + 4, q.query.base(), q.query.size());
481 if (!sslWrite(netdutils::makeSlice(buf))) {
482 return false;
483 }
484 ALOGV("%u SSL_write complete", mMark);
485 return true;
486}
487
Ben Schwartz33860762017-10-25 14:41:02 -0400488bool DnsTlsSocket::readResponse() {
Ben Schwartzded1b702017-10-25 14:41:02 -0400489 ALOGV("reading response");
490 uint8_t responseHeader[2];
Ben Schwartz33860762017-10-25 14:41:02 -0400491 int err = sslRead(Slice(responseHeader, 2), false);
492 if (err == SSL_ERROR_WANT_READ) {
493 ALOGV("Ignoring spurious wakeup from server");
494 return true;
495 }
496 if (err != SSL_ERROR_NONE) {
497 return false;
Ben Schwartzded1b702017-10-25 14:41:02 -0400498 }
499 // Truncate responses larger than MAX_SIZE. This is safe because a DNS packet is
500 // always invalid when truncated, so the response will be treated as an error.
501 constexpr uint16_t MAX_SIZE = 8192;
502 const uint16_t responseSize = (responseHeader[0] << 8) | responseHeader[1];
503 ALOGV("%u Expecting response of size %i", mMark, responseSize);
504 std::vector<uint8_t> response(std::min(responseSize, MAX_SIZE));
Ben Schwartz33860762017-10-25 14:41:02 -0400505 if (sslRead(netdutils::makeSlice(response), true) != SSL_ERROR_NONE) {
Ben Schwartzded1b702017-10-25 14:41:02 -0400506 ALOGV("%u Failed to read %zu bytes", mMark, response.size());
Ben Schwartz33860762017-10-25 14:41:02 -0400507 return false;
Ben Schwartzded1b702017-10-25 14:41:02 -0400508 }
509 uint16_t remainingBytes = responseSize - response.size();
510 while (remainingBytes > 0) {
511 constexpr uint16_t CHUNK_SIZE = 2048;
512 std::vector<uint8_t> discard(std::min(remainingBytes, CHUNK_SIZE));
Ben Schwartz33860762017-10-25 14:41:02 -0400513 if (sslRead(netdutils::makeSlice(discard), true) != SSL_ERROR_NONE) {
Ben Schwartzded1b702017-10-25 14:41:02 -0400514 ALOGV("%u Failed to discard %zu bytes", mMark, discard.size());
Ben Schwartz33860762017-10-25 14:41:02 -0400515 return false;
Ben Schwartzded1b702017-10-25 14:41:02 -0400516 }
517 remainingBytes -= discard.size();
518 }
519 ALOGV("%u SSL_read complete", mMark);
520
Ben Schwartz33860762017-10-25 14:41:02 -0400521 mObserver->onResponse(std::move(response));
522 return true;
Ben Schwartzded1b702017-10-25 14:41:02 -0400523}
524
525} // end of namespace net
526} // end of namespace android