1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * Stream/crypto handshake adapter for the client side. 4 * 5 * The client composes CHLO, writes it to the stream, and wait for the 6 * server response, which it processes. 7 */ 8 9#include <assert.h> 10#include <errno.h> 11#include <stdarg.h> 12#include <stdlib.h> 13#include <string.h> 14#include <sys/queue.h> 15 16#include "lsquic_int_types.h" 17#include "lsquic.h" 18 19#include "lsquic_str.h" 20#include "lsquic_enc_sess.h" 21#include "lsquic_chsk_stream.h" 22#include "lsquic_ver_neg.h" 23#include "lsquic_hash.h" 24#include "lsquic_conn.h" 25#include "lsquic_mm.h" 26#include "lsquic_sizes.h" 27#include "lsquic_full_conn.h" 28 29#define LSQUIC_LOGGER_MODULE LSQLM_HSK_ADAPTER 30#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(c_hsk->lconn) 31#include "lsquic_logger.h" 32 33 34static lsquic_stream_ctx_t * 35hsk_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream) 36{ 37 struct client_hsk_ctx *const c_hsk = stream_if_ctx; 38 39 LSQ_DEBUG("stream created"); 40 41 lsquic_stream_wantwrite(stream, 1); 42 43 return (void *) c_hsk; 44} 45 46 47static void 48hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh) 49{ 50 struct client_hsk_ctx *const c_hsk = (struct client_hsk_ctx *) sh; 51 ssize_t nread; 52 int s; 53 enum lsquic_hsk_status status; 54 55 if (!c_hsk->buf_in) 56 { 57 c_hsk->buf_in = lsquic_mm_get_16k(c_hsk->mm); 58 if (!c_hsk->buf_in) 59 { 60 LSQ_WARN("could not get buffer: %s", strerror(errno)); 61 lsquic_stream_wantread(stream, 0); 62 lsquic_conn_close(c_hsk->lconn); 63 return; 64 } 65 c_hsk->buf_sz = 16 * 1024; 66 c_hsk->buf_off = 0; 67 } 68 69 nread = lsquic_stream_read(stream, c_hsk->buf_in + c_hsk->buf_off, 70 c_hsk->buf_sz - c_hsk->buf_off); 71 if (nread <= 0) 72 { 73 if (nread < 0) 74 LSQ_INFO("Could not read from handshake stream: %s", 75 strerror(errno)); 76 else 77 LSQ_INFO("Handshake stream closed (odd)"); 78 lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in); 79 c_hsk->buf_in = NULL; 80 lsquic_stream_wantread(stream, 0); 81 lsquic_conn_close(c_hsk->lconn); 82 return; 83 } 84 c_hsk->buf_off += nread; 85 86 s = c_hsk->lconn->cn_esf.g->esf_handle_chlo_reply(c_hsk->lconn->cn_enc_session, 87 c_hsk->buf_in, c_hsk->buf_off); 88 LSQ_DEBUG("lsquic_enc_session_handle_chlo_reply returned %d", s); 89 switch (s) 90 { 91 case DATA_NOT_ENOUGH: 92 if (c_hsk->buf_off < c_hsk->buf_sz) 93 LSQ_INFO("not enough server response has arrived, continue " 94 "buffering"); 95 else 96 { 97 LSQ_INFO("read in %u bytes of server response, and it is still " 98 "not enough: giving up", c_hsk->buf_off); 99 lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in); 100 c_hsk->buf_in = NULL; 101 lsquic_stream_wantread(stream, 0); 102 c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, LSQ_HSK_FAIL); 103 lsquic_conn_close(c_hsk->lconn); 104 } 105 break; 106 case DATA_NO_ERROR: 107 lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in); 108 c_hsk->buf_in = NULL; 109 lsquic_stream_wantread(stream, 0); 110 if (c_hsk->lconn->cn_esf.g->esf_is_hsk_done(c_hsk->lconn->cn_enc_session)) 111 { 112 LSQ_DEBUG("handshake is successful, inform connection"); 113 status = (c_hsk->lconn->cn_esf_c->esf_did_sess_resume_succeed( 114 c_hsk->lconn->cn_enc_session)) ? LSQ_HSK_RESUMED_OK : LSQ_HSK_OK; 115 c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, status); 116 } 117 else 118 { 119 LSQ_DEBUG("handshake not yet complete, will generate another " 120 "message"); 121 lsquic_stream_wantwrite(stream, 1); 122 } 123 break; 124 case HS_SREJ: 125 LSQ_DEBUG("got HS_SREJ"); 126 c_hsk->buf_off = 0; 127 lsquic_stream_wantread(stream, 0); 128 if (0 == lsquic_gquic_full_conn_srej(c_hsk->lconn)) 129 lsquic_stream_wantwrite(stream, 1); 130 break; 131 default: 132 LSQ_WARN("lsquic_enc_session_handle_chlo_reply returned unknown value %d", s); 133 /* fallthru */ 134 case DATA_FORMAT_ERROR: 135 LSQ_INFO("lsquic_enc_session_handle_chlo_reply returned an error"); 136 lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in); 137 c_hsk->buf_in = NULL; 138 lsquic_stream_wantread(stream, 0); 139 c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, LSQ_HSK_FAIL); 140 lsquic_conn_close(c_hsk->lconn); 141 break; 142 } 143} 144 145 146/* In this function, we assume that we can write the whole message in one 147 * shot. Otherwise, this is an error. 148 */ 149static void 150hsk_client_on_write (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh) 151{ 152 struct client_hsk_ctx *const c_hsk = (struct client_hsk_ctx *) sh; 153 unsigned char *buf; 154 size_t len; 155 ssize_t nw; 156 157 lsquic_stream_wantwrite(stream, 0); 158 159 buf = lsquic_mm_get_4k(c_hsk->mm); 160 if (!buf) 161 { 162 LSQ_WARN("cannot allocate buffer: %s", strerror(errno)); 163 lsquic_conn_close(c_hsk->lconn); 164 return; 165 } 166 len = 4 * 1024; 167 168 if (0 != c_hsk->lconn->cn_esf.g->esf_gen_chlo(c_hsk->lconn->cn_enc_session, 169 c_hsk->ver_neg->vn_ver, buf, &len)) 170 { 171 LSQ_WARN("cannot create CHLO message"); 172 lsquic_mm_put_4k(c_hsk->mm, buf); 173 lsquic_conn_close(c_hsk->lconn); 174 return; 175 } 176 177 nw = lsquic_stream_write(stream, buf, len); 178 lsquic_mm_put_4k(c_hsk->mm, buf); 179 180 if (nw < 0) 181 LSQ_INFO("error writing to stream: %s", strerror(errno)); 182 else if ((size_t) nw == len) 183 { 184 LSQ_INFO("wrote %zd bytes of CHLO to stream", nw); 185 lsquic_stream_flush(stream); 186 lsquic_stream_wantread(stream, 1); 187 } 188 else 189 LSQ_INFO("could only write %zd bytes to stream instead of %zd", 190 nw, len); 191} 192 193 194static void 195hsk_client_on_close (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh) 196{ 197 struct client_hsk_ctx *const c_hsk = (struct client_hsk_ctx *) sh; 198 if (c_hsk->buf_in) 199 lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in); 200 LSQ_DEBUG("stream closed"); 201} 202 203 204const struct lsquic_stream_if lsquic_client_hsk_stream_if = 205{ 206 .on_new_stream = hsk_client_on_new_stream, 207 .on_read = hsk_client_on_read, 208 .on_write = hsk_client_on_write, 209 .on_close = hsk_client_on_close, 210}; 211