1*1a96fba6SXin Li // Copyright 2015 The Chromium OS Authors. All rights reserved.
2*1a96fba6SXin Li // Use of this source code is governed by a BSD-style license that can be
3*1a96fba6SXin Li // found in the LICENSE file.
4*1a96fba6SXin Li
5*1a96fba6SXin Li #include <brillo/streams/openssl_stream_bio.h>
6*1a96fba6SXin Li
7*1a96fba6SXin Li #include <openssl/bio.h>
8*1a96fba6SXin Li
9*1a96fba6SXin Li #include <base/numerics/safe_conversions.h>
10*1a96fba6SXin Li #include <brillo/streams/stream.h>
11*1a96fba6SXin Li
12*1a96fba6SXin Li namespace brillo {
13*1a96fba6SXin Li
14*1a96fba6SXin Li namespace {
15*1a96fba6SXin Li
16*1a96fba6SXin Li // TODO(crbug.com/984789): Remove once support for OpenSSL <1.1 is dropped.
17*1a96fba6SXin Li #if OPENSSL_VERSION_NUMBER < 0x10100000L
BIO_set_data(BIO * a,void * ptr)18*1a96fba6SXin Li static void BIO_set_data(BIO* a, void* ptr) {
19*1a96fba6SXin Li a->ptr = ptr;
20*1a96fba6SXin Li }
21*1a96fba6SXin Li
BIO_get_data(BIO * a)22*1a96fba6SXin Li static void* BIO_get_data(BIO* a) {
23*1a96fba6SXin Li return a->ptr;
24*1a96fba6SXin Li }
25*1a96fba6SXin Li
BIO_set_init(BIO * a,int init)26*1a96fba6SXin Li static void BIO_set_init(BIO* a, int init) {
27*1a96fba6SXin Li a->init = init;
28*1a96fba6SXin Li }
29*1a96fba6SXin Li
BIO_get_init(BIO * a)30*1a96fba6SXin Li static int BIO_get_init(BIO* a) {
31*1a96fba6SXin Li return a->init;
32*1a96fba6SXin Li }
33*1a96fba6SXin Li
BIO_set_shutdown(BIO * a,int shut)34*1a96fba6SXin Li static void BIO_set_shutdown(BIO* a, int shut) {
35*1a96fba6SXin Li a->shutdown = shut;
36*1a96fba6SXin Li }
37*1a96fba6SXin Li #endif
38*1a96fba6SXin Li
39*1a96fba6SXin Li // Internal functions for implementing OpenSSL BIO on brillo::Stream.
stream_write(BIO * bio,const char * buf,int size)40*1a96fba6SXin Li int stream_write(BIO* bio, const char* buf, int size) {
41*1a96fba6SXin Li brillo::Stream* stream = static_cast<brillo::Stream*>(BIO_get_data(bio));
42*1a96fba6SXin Li size_t written = 0;
43*1a96fba6SXin Li BIO_clear_retry_flags(bio);
44*1a96fba6SXin Li if (!stream->WriteNonBlocking(buf, size, &written, nullptr))
45*1a96fba6SXin Li return -1;
46*1a96fba6SXin Li
47*1a96fba6SXin Li if (written == 0) {
48*1a96fba6SXin Li // Socket's output buffer is full, try again later.
49*1a96fba6SXin Li BIO_set_retry_write(bio);
50*1a96fba6SXin Li return -1;
51*1a96fba6SXin Li }
52*1a96fba6SXin Li return base::checked_cast<int>(written);
53*1a96fba6SXin Li }
54*1a96fba6SXin Li
stream_read(BIO * bio,char * buf,int size)55*1a96fba6SXin Li int stream_read(BIO* bio, char* buf, int size) {
56*1a96fba6SXin Li brillo::Stream* stream = static_cast<brillo::Stream*>(BIO_get_data(bio));
57*1a96fba6SXin Li size_t read = 0;
58*1a96fba6SXin Li BIO_clear_retry_flags(bio);
59*1a96fba6SXin Li bool eos = false;
60*1a96fba6SXin Li if (!stream->ReadNonBlocking(buf, size, &read, &eos, nullptr))
61*1a96fba6SXin Li return -1;
62*1a96fba6SXin Li
63*1a96fba6SXin Li if (read == 0 && !eos) {
64*1a96fba6SXin Li // If no data is available on the socket and it is still not closed,
65*1a96fba6SXin Li // ask OpenSSL to try again later.
66*1a96fba6SXin Li BIO_set_retry_read(bio);
67*1a96fba6SXin Li return -1;
68*1a96fba6SXin Li }
69*1a96fba6SXin Li return base::checked_cast<int>(read);
70*1a96fba6SXin Li }
71*1a96fba6SXin Li
72*1a96fba6SXin Li // NOLINTNEXTLINE(runtime/int)
stream_ctrl(BIO * bio,int cmd,long,void *)73*1a96fba6SXin Li long stream_ctrl(BIO* bio, int cmd, long /* num */, void* /* ptr */) {
74*1a96fba6SXin Li if (cmd == BIO_CTRL_FLUSH) {
75*1a96fba6SXin Li brillo::Stream* stream = static_cast<brillo::Stream*>(BIO_get_data(bio));
76*1a96fba6SXin Li return stream->FlushBlocking(nullptr) ? 1 : 0;
77*1a96fba6SXin Li }
78*1a96fba6SXin Li return 0;
79*1a96fba6SXin Li }
80*1a96fba6SXin Li
stream_new(BIO * bio)81*1a96fba6SXin Li int stream_new(BIO* bio) {
82*1a96fba6SXin Li // By default do not close underlying stream on shutdown.
83*1a96fba6SXin Li BIO_set_shutdown(bio, 0);
84*1a96fba6SXin Li BIO_set_init(bio, 0);
85*1a96fba6SXin Li return 1;
86*1a96fba6SXin Li }
87*1a96fba6SXin Li
stream_free(BIO * bio)88*1a96fba6SXin Li int stream_free(BIO* bio) {
89*1a96fba6SXin Li if (!bio)
90*1a96fba6SXin Li return 0;
91*1a96fba6SXin Li
92*1a96fba6SXin Li if (BIO_get_init(bio)) {
93*1a96fba6SXin Li BIO_set_data(bio, nullptr);
94*1a96fba6SXin Li BIO_set_init(bio, 0);
95*1a96fba6SXin Li }
96*1a96fba6SXin Li return 1;
97*1a96fba6SXin Li }
98*1a96fba6SXin Li
99*1a96fba6SXin Li #if OPENSSL_VERSION_NUMBER < 0x10100000L
100*1a96fba6SXin Li // TODO(crbug.com/984789): Remove #ifdef once support for OpenSSL <1.1 is
101*1a96fba6SXin Li // dropped.
102*1a96fba6SXin Li
103*1a96fba6SXin Li // BIO_METHOD structure describing the BIO built on top of brillo::Stream.
104*1a96fba6SXin Li BIO_METHOD stream_method = {
105*1a96fba6SXin Li 0x7F | BIO_TYPE_SOURCE_SINK, // type: 0x7F is an arbitrary unused type ID.
106*1a96fba6SXin Li "stream", // name
107*1a96fba6SXin Li stream_write, // write function
108*1a96fba6SXin Li stream_read, // read function
109*1a96fba6SXin Li nullptr, // puts function, not implemented
110*1a96fba6SXin Li nullptr, // gets function, not implemented
111*1a96fba6SXin Li stream_ctrl, // control function
112*1a96fba6SXin Li stream_new, // creation
113*1a96fba6SXin Li stream_free, // free
114*1a96fba6SXin Li nullptr, // callback function, not used
115*1a96fba6SXin Li };
116*1a96fba6SXin Li
stream_get_method()117*1a96fba6SXin Li BIO_METHOD* stream_get_method() {
118*1a96fba6SXin Li return &stream_method;
119*1a96fba6SXin Li }
120*1a96fba6SXin Li
121*1a96fba6SXin Li #else
122*1a96fba6SXin Li
stream_get_method()123*1a96fba6SXin Li BIO_METHOD* stream_get_method() {
124*1a96fba6SXin Li static BIO_METHOD* stream_method;
125*1a96fba6SXin Li
126*1a96fba6SXin Li if (!stream_method) {
127*1a96fba6SXin Li stream_method = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK,
128*1a96fba6SXin Li "stream");
129*1a96fba6SXin Li BIO_meth_set_write(stream_method, stream_write);
130*1a96fba6SXin Li BIO_meth_set_read(stream_method, stream_read);
131*1a96fba6SXin Li BIO_meth_set_ctrl(stream_method, stream_ctrl);
132*1a96fba6SXin Li BIO_meth_set_create(stream_method, stream_new);
133*1a96fba6SXin Li BIO_meth_set_destroy(stream_method, stream_free);
134*1a96fba6SXin Li }
135*1a96fba6SXin Li
136*1a96fba6SXin Li return stream_method;
137*1a96fba6SXin Li }
138*1a96fba6SXin Li
139*1a96fba6SXin Li #endif
140*1a96fba6SXin Li
141*1a96fba6SXin Li } // anonymous namespace
142*1a96fba6SXin Li
BIO_new_stream(brillo::Stream * stream)143*1a96fba6SXin Li BIO* BIO_new_stream(brillo::Stream* stream) {
144*1a96fba6SXin Li BIO* bio = BIO_new(stream_get_method());
145*1a96fba6SXin Li if (bio) {
146*1a96fba6SXin Li BIO_set_data(bio, stream);
147*1a96fba6SXin Li BIO_set_init(bio, 1);
148*1a96fba6SXin Li }
149*1a96fba6SXin Li return bio;
150*1a96fba6SXin Li }
151*1a96fba6SXin Li
152*1a96fba6SXin Li } // namespace brillo
153