diff options
Diffstat (limited to 'src/lib/libssl/tls_buffer.c')
| -rw-r--r-- | src/lib/libssl/tls_buffer.c | 133 |
1 files changed, 126 insertions, 7 deletions
diff --git a/src/lib/libssl/tls_buffer.c b/src/lib/libssl/tls_buffer.c index 9bb6b62e51..f70cfbc1a0 100644 --- a/src/lib/libssl/tls_buffer.c +++ b/src/lib/libssl/tls_buffer.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* $OpenBSD: tls_buffer.c,v 1.2 2022/07/20 06:32:24 jsing Exp $ */ | 1 | /* $OpenBSD: tls_buffer.c,v 1.3 2022/07/22 19:33:53 jsing Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2018, 2019 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2018, 2019, 2022 Joel Sing <jsing@openbsd.org> |
| 4 | * | 4 | * |
| 5 | * Permission to use, copy, modify, and distribute this software for any | 5 | * Permission to use, copy, modify, and distribute this software for any |
| 6 | * purpose with or without fee is hereby granted, provided that the above | 6 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -21,8 +21,11 @@ | |||
| 21 | #include "bytestring.h" | 21 | #include "bytestring.h" |
| 22 | #include "tls_internal.h" | 22 | #include "tls_internal.h" |
| 23 | 23 | ||
| 24 | #define TLS_BUFFER_CAPACITY_LIMIT (1024 * 1024) | ||
| 25 | |||
| 24 | struct tls_buffer { | 26 | struct tls_buffer { |
| 25 | size_t capacity; | 27 | size_t capacity; |
| 28 | size_t capacity_limit; | ||
| 26 | uint8_t *data; | 29 | uint8_t *data; |
| 27 | size_t len; | 30 | size_t len; |
| 28 | size_t offset; | 31 | size_t offset; |
| @@ -38,6 +41,8 @@ tls_buffer_new(size_t init_size) | |||
| 38 | if ((buf = calloc(1, sizeof(struct tls_buffer))) == NULL) | 41 | if ((buf = calloc(1, sizeof(struct tls_buffer))) == NULL) |
| 39 | goto err; | 42 | goto err; |
| 40 | 43 | ||
| 44 | buf->capacity_limit = TLS_BUFFER_CAPACITY_LIMIT; | ||
| 45 | |||
| 41 | if (!tls_buffer_resize(buf, init_size)) | 46 | if (!tls_buffer_resize(buf, init_size)) |
| 42 | goto err; | 47 | goto err; |
| 43 | 48 | ||
| @@ -50,32 +55,76 @@ tls_buffer_new(size_t init_size) | |||
| 50 | } | 55 | } |
| 51 | 56 | ||
| 52 | void | 57 | void |
| 58 | tls_buffer_clear(struct tls_buffer *buf) | ||
| 59 | { | ||
| 60 | freezero(buf->data, buf->capacity); | ||
| 61 | |||
| 62 | buf->data = NULL; | ||
| 63 | buf->capacity = 0; | ||
| 64 | buf->len = 0; | ||
| 65 | buf->offset = 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | void | ||
| 53 | tls_buffer_free(struct tls_buffer *buf) | 69 | tls_buffer_free(struct tls_buffer *buf) |
| 54 | { | 70 | { |
| 55 | if (buf == NULL) | 71 | if (buf == NULL) |
| 56 | return; | 72 | return; |
| 57 | 73 | ||
| 58 | freezero(buf->data, buf->capacity); | 74 | tls_buffer_clear(buf); |
| 75 | |||
| 59 | freezero(buf, sizeof(struct tls_buffer)); | 76 | freezero(buf, sizeof(struct tls_buffer)); |
| 60 | } | 77 | } |
| 61 | 78 | ||
| 62 | static int | 79 | static int |
| 80 | tls_buffer_grow(struct tls_buffer *buf, size_t capacity) | ||
| 81 | { | ||
| 82 | if (buf->capacity >= capacity) | ||
| 83 | return 1; | ||
| 84 | |||
| 85 | return tls_buffer_resize(buf, capacity); | ||
| 86 | } | ||
| 87 | |||
| 88 | static int | ||
| 63 | tls_buffer_resize(struct tls_buffer *buf, size_t capacity) | 89 | tls_buffer_resize(struct tls_buffer *buf, size_t capacity) |
| 64 | { | 90 | { |
| 65 | uint8_t *data; | 91 | uint8_t *data; |
| 66 | 92 | ||
| 93 | /* | ||
| 94 | * XXX - Consider maintaining a minimum size and growing more | ||
| 95 | * intelligently (rather than exactly). | ||
| 96 | */ | ||
| 67 | if (buf->capacity == capacity) | 97 | if (buf->capacity == capacity) |
| 68 | return 1; | 98 | return 1; |
| 69 | 99 | ||
| 100 | if (capacity > buf->capacity_limit) | ||
| 101 | return 0; | ||
| 102 | |||
| 70 | if ((data = recallocarray(buf->data, buf->capacity, capacity, 1)) == NULL) | 103 | if ((data = recallocarray(buf->data, buf->capacity, capacity, 1)) == NULL) |
| 71 | return 0; | 104 | return 0; |
| 72 | 105 | ||
| 73 | buf->data = data; | 106 | buf->data = data; |
| 74 | buf->capacity = capacity; | 107 | buf->capacity = capacity; |
| 75 | 108 | ||
| 109 | /* Ensure that len and offset are valid if capacity decreased. */ | ||
| 110 | if (buf->len > buf->capacity) | ||
| 111 | buf->len = buf->capacity; | ||
| 112 | if (buf->offset > buf->len) | ||
| 113 | buf->offset = buf->len; | ||
| 114 | |||
| 76 | return 1; | 115 | return 1; |
| 77 | } | 116 | } |
| 78 | 117 | ||
| 118 | void | ||
| 119 | tls_buffer_set_capacity_limit(struct tls_buffer *buf, size_t limit) | ||
| 120 | { | ||
| 121 | /* | ||
| 122 | * XXX - do we want to force a resize if this limit is less than current | ||
| 123 | * capacity... and what do we do with existing data? Force a clear? | ||
| 124 | */ | ||
| 125 | buf->capacity_limit = limit; | ||
| 126 | } | ||
| 127 | |||
| 79 | ssize_t | 128 | ssize_t |
| 80 | tls_buffer_extend(struct tls_buffer *buf, size_t len, | 129 | tls_buffer_extend(struct tls_buffer *buf, size_t len, |
| 81 | tls_read_cb read_cb, void *cb_arg) | 130 | tls_read_cb read_cb, void *cb_arg) |
| @@ -106,10 +155,79 @@ tls_buffer_extend(struct tls_buffer *buf, size_t len, | |||
| 106 | } | 155 | } |
| 107 | } | 156 | } |
| 108 | 157 | ||
| 109 | void | 158 | ssize_t |
| 110 | tls_buffer_cbs(struct tls_buffer *buf, CBS *cbs) | 159 | tls_buffer_read(struct tls_buffer *buf, uint8_t *rbuf, size_t n) |
| 160 | { | ||
| 161 | if (buf->offset > buf->len) | ||
| 162 | return TLS_IO_FAILURE; | ||
| 163 | |||
| 164 | if (buf->offset == buf->len) | ||
| 165 | return TLS_IO_WANT_POLLIN; | ||
| 166 | |||
| 167 | if (n > buf->len - buf->offset) | ||
| 168 | n = buf->len - buf->offset; | ||
| 169 | |||
| 170 | memcpy(rbuf, &buf->data[buf->offset], n); | ||
| 171 | |||
| 172 | buf->offset += n; | ||
| 173 | |||
| 174 | return n; | ||
| 175 | } | ||
| 176 | |||
| 177 | ssize_t | ||
| 178 | tls_buffer_write(struct tls_buffer *buf, const uint8_t *wbuf, size_t n) | ||
| 179 | { | ||
| 180 | if (buf->offset > buf->len) | ||
| 181 | return TLS_IO_FAILURE; | ||
| 182 | |||
| 183 | /* | ||
| 184 | * To avoid continually growing the buffer, pull data up to the | ||
| 185 | * start of the buffer. If all data has been read then we can simply | ||
| 186 | * reset, otherwise wait until we're going to save at least 4KB of | ||
| 187 | * memory to reduce overhead. | ||
| 188 | */ | ||
| 189 | if (buf->offset == buf->len) { | ||
| 190 | buf->len = 0; | ||
| 191 | buf->offset = 0; | ||
| 192 | } | ||
| 193 | if (buf->offset >= 4096) { | ||
| 194 | memmove(buf->data, &buf->data[buf->offset], | ||
| 195 | buf->len - buf->offset); | ||
| 196 | buf->len -= buf->offset; | ||
| 197 | buf->offset = 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | if (buf->len > SIZE_MAX - n) | ||
| 201 | return TLS_IO_FAILURE; | ||
| 202 | if (!tls_buffer_grow(buf, buf->len + n)) | ||
| 203 | return TLS_IO_FAILURE; | ||
| 204 | |||
| 205 | memcpy(&buf->data[buf->len], wbuf, n); | ||
| 206 | |||
| 207 | buf->len += n; | ||
| 208 | |||
| 209 | return n; | ||
| 210 | } | ||
| 211 | |||
| 212 | int | ||
| 213 | tls_buffer_append(struct tls_buffer *buf, const uint8_t *wbuf, size_t n) | ||
| 214 | { | ||
| 215 | return tls_buffer_write(buf, wbuf, n) == n; | ||
| 216 | } | ||
| 217 | |||
| 218 | int | ||
| 219 | tls_buffer_data(struct tls_buffer *buf, CBS *out_cbs) | ||
| 111 | { | 220 | { |
| 112 | CBS_init(cbs, buf->data, buf->len); | 221 | CBS cbs; |
| 222 | |||
| 223 | CBS_init(&cbs, buf->data, buf->len); | ||
| 224 | |||
| 225 | if (!CBS_skip(&cbs, buf->offset)) | ||
| 226 | return 0; | ||
| 227 | |||
| 228 | CBS_dup(&cbs, out_cbs); | ||
| 229 | |||
| 230 | return 1; | ||
| 113 | } | 231 | } |
| 114 | 232 | ||
| 115 | int | 233 | int |
| @@ -121,9 +239,10 @@ tls_buffer_finish(struct tls_buffer *buf, uint8_t **out, size_t *out_len) | |||
| 121 | *out = buf->data; | 239 | *out = buf->data; |
| 122 | *out_len = buf->len; | 240 | *out_len = buf->len; |
| 123 | 241 | ||
| 124 | buf->capacity = 0; | ||
| 125 | buf->data = NULL; | 242 | buf->data = NULL; |
| 243 | buf->capacity = 0; | ||
| 126 | buf->len = 0; | 244 | buf->len = 0; |
| 245 | buf->offset = 0; | ||
| 127 | 246 | ||
| 128 | return 1; | 247 | return 1; |
| 129 | } | 248 | } |
