Branch data Line data Source code
1 : : /*
2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
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 : : * A copy of the License is located at
7 : : *
8 : : * http://aws.amazon.com/apache2.0
9 : : *
10 : : * or in the "license" file accompanying this file. This file is distributed
11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 : : * express or implied. See the License for the specific language governing
13 : : * permissions and limitations under the License.
14 : : */
15 : :
16 : : #pragma once
17 : :
18 : : #include <limits.h>
19 : : #include <stdarg.h>
20 : : #include <stdint.h>
21 : : #include <stdlib.h>
22 : : #ifndef _WIN32
23 : : #include <sys/uio.h>
24 : : #endif
25 : :
26 : : #include "utils/s2n_blob.h"
27 : : #include "utils/s2n_result.h"
28 : :
29 : : #define S2N_MIN_STUFFER_GROWTH_IN_BYTES 1024
30 : :
31 : : /* Using a non-zero value
32 : : * (a) makes wiped data easy to see in the debugger
33 : : * (b) makes use of wiped data obvious since this is unlikely to be a valid bit pattern
34 : : */
35 : : #define S2N_WIPE_PATTERN 'w'
36 : :
37 : : #define SIZEOF_IN_BITS(t) (sizeof(t) * CHAR_BIT)
38 : :
39 : 116970 : #define SIZEOF_UINT24 3
40 : :
41 : : struct s2n_stuffer {
42 : : /* The data for the s2n_stuffer */
43 : : struct s2n_blob blob;
44 : :
45 : : /* Cursors to the current read/write position in the s2n_stuffer */
46 : : uint32_t read_cursor;
47 : : uint32_t write_cursor;
48 : : uint32_t high_water_mark;
49 : :
50 : : /* Was this stuffer alloc()'d?
51 : : * This field controls whether the stuffer "owns" the blob. If the stuffer
52 : : * was allocated, then `blob` must be freed when the stuffer is freed. If the
53 : : * stuffer was not allocated, then the blob must not be freed by the stuffer, even if the
54 : : * blob itself is allocated. */
55 : : unsigned int alloced : 1;
56 : :
57 : : /* Is this stuffer growable? */
58 : : unsigned int growable : 1;
59 : :
60 : : /* Can this stuffer be safely resized?
61 : : * A growable stuffer can be temporarily tainted by a raw read/write,
62 : : * preventing it from resizing. */
63 : : unsigned int tainted : 1;
64 : : };
65 : :
66 : 14015730 : #define s2n_stuffer_data_available(s) ((s)->write_cursor - (s)->read_cursor)
67 : 66391506 : #define s2n_stuffer_space_remaining(s) ((s)->blob.size - (s)->write_cursor)
68 : 41550209 : #define s2n_stuffer_is_wiped(s) ((s)->high_water_mark == 0)
69 : 3820598 : #define s2n_stuffer_is_freed(s) ((s)->blob.data == NULL)
70 : : /* Check basic validity constraints on the stuffer: e.g. that cursors point within the blob */
71 : : S2N_RESULT s2n_stuffer_validate(const struct s2n_stuffer *stuffer);
72 : :
73 : : /* Initialize and destroying stuffers */
74 : : int S2N_RESULT_MUST_USE s2n_stuffer_init(struct s2n_stuffer *stuffer, struct s2n_blob *in);
75 : : int S2N_RESULT_MUST_USE s2n_stuffer_init_written(struct s2n_stuffer *stuffer, struct s2n_blob *in);
76 : : int S2N_RESULT_MUST_USE s2n_stuffer_alloc(struct s2n_stuffer *stuffer, const uint32_t size);
77 : : int S2N_RESULT_MUST_USE s2n_stuffer_growable_alloc(struct s2n_stuffer *stuffer, const uint32_t size);
78 : : int s2n_stuffer_free(struct s2n_stuffer *stuffer);
79 : : /**
80 : : * Frees the stuffer without zeroizing the contained data.
81 : : *
82 : : * This should only be used in scenarios where the data is encrypted or has been
83 : : * cleared with `s2n_stuffer_erase_and_read`. In most cases, prefer `s2n_stuffer_free`.
84 : : */
85 : : int S2N_RESULT_MUST_USE s2n_stuffer_free_without_wipe(struct s2n_stuffer *stuffer);
86 : : int S2N_RESULT_MUST_USE s2n_stuffer_resize(struct s2n_stuffer *stuffer, const uint32_t size);
87 : : int S2N_RESULT_MUST_USE s2n_stuffer_resize_if_empty(struct s2n_stuffer *stuffer, const uint32_t size);
88 : : int S2N_RESULT_MUST_USE s2n_stuffer_rewind_read(struct s2n_stuffer *stuffer, const uint32_t size);
89 : : int S2N_RESULT_MUST_USE s2n_stuffer_reread(struct s2n_stuffer *stuffer);
90 : : int S2N_RESULT_MUST_USE s2n_stuffer_rewrite(struct s2n_stuffer *stuffer);
91 : : int S2N_RESULT_MUST_USE s2n_stuffer_shift(struct s2n_stuffer *stuffer);
92 : : int s2n_stuffer_wipe(struct s2n_stuffer *stuffer);
93 : : int s2n_stuffer_wipe_n(struct s2n_stuffer *stuffer, const uint32_t n);
94 : : bool s2n_stuffer_is_consumed(struct s2n_stuffer *stuffer);
95 : :
96 : : /* Basic read and write */
97 : : int S2N_RESULT_MUST_USE s2n_stuffer_read(struct s2n_stuffer *stuffer, struct s2n_blob *out);
98 : : int S2N_RESULT_MUST_USE s2n_stuffer_erase_and_read(struct s2n_stuffer *stuffer, struct s2n_blob *out);
99 : : int S2N_RESULT_MUST_USE s2n_stuffer_write(struct s2n_stuffer *stuffer, const struct s2n_blob *in);
100 : : int S2N_RESULT_MUST_USE s2n_stuffer_read_bytes(struct s2n_stuffer *stuffer, uint8_t *out, uint32_t n);
101 : : int S2N_RESULT_MUST_USE s2n_stuffer_erase_and_read_bytes(struct s2n_stuffer *stuffer, uint8_t *data, uint32_t size);
102 : : int S2N_RESULT_MUST_USE s2n_stuffer_write_bytes(struct s2n_stuffer *stuffer, const uint8_t *in, const uint32_t n);
103 : : int S2N_RESULT_MUST_USE s2n_stuffer_writev_bytes(struct s2n_stuffer *stuffer, const struct iovec *iov, size_t iov_count,
104 : : uint32_t offs, uint32_t size);
105 : : int S2N_RESULT_MUST_USE s2n_stuffer_skip_read(struct s2n_stuffer *stuffer, uint32_t n);
106 : : int S2N_RESULT_MUST_USE s2n_stuffer_skip_write(struct s2n_stuffer *stuffer, const uint32_t n);
107 : :
108 : : /* Tries to reserve enough space to write n additional bytes into the stuffer.*/
109 : : int S2N_RESULT_MUST_USE s2n_stuffer_reserve_space(struct s2n_stuffer *stuffer, uint32_t n);
110 : :
111 : : /* Raw read/write move the cursor along and give you a pointer you can
112 : : * read/write data_len bytes from/to in-place.
113 : : */
114 : : void *s2n_stuffer_raw_write(struct s2n_stuffer *stuffer, const uint32_t data_len);
115 : : void *s2n_stuffer_raw_read(struct s2n_stuffer *stuffer, uint32_t data_len);
116 : :
117 : : /* Send/receive stuffer to/from a file descriptor */
118 : : int s2n_stuffer_recv_from_fd(struct s2n_stuffer *stuffer, const int rfd, const uint32_t len,
119 : : uint32_t *bytes_written);
120 : : int s2n_stuffer_send_to_fd(struct s2n_stuffer *stuffer, const int wfd, const uint32_t len, uint32_t *bytes_sent);
121 : :
122 : : /* Read and write integers in network order */
123 : : int S2N_RESULT_MUST_USE s2n_stuffer_read_uint8(struct s2n_stuffer *stuffer, uint8_t *u);
124 : : int S2N_RESULT_MUST_USE s2n_stuffer_read_uint16(struct s2n_stuffer *stuffer, uint16_t *u);
125 : : int S2N_RESULT_MUST_USE s2n_stuffer_read_uint24(struct s2n_stuffer *stuffer, uint32_t *u);
126 : : int S2N_RESULT_MUST_USE s2n_stuffer_read_uint32(struct s2n_stuffer *stuffer, uint32_t *u);
127 : : int S2N_RESULT_MUST_USE s2n_stuffer_read_uint64(struct s2n_stuffer *stuffer, uint64_t *u);
128 : :
129 : : int S2N_RESULT_MUST_USE s2n_stuffer_write_uint8(struct s2n_stuffer *stuffer, const uint8_t u);
130 : : int S2N_RESULT_MUST_USE s2n_stuffer_write_uint16(struct s2n_stuffer *stuffer, const uint16_t u);
131 : : int S2N_RESULT_MUST_USE s2n_stuffer_write_uint24(struct s2n_stuffer *stuffer, const uint32_t u);
132 : : int S2N_RESULT_MUST_USE s2n_stuffer_write_uint32(struct s2n_stuffer *stuffer, const uint32_t u);
133 : : int S2N_RESULT_MUST_USE s2n_stuffer_write_uint64(struct s2n_stuffer *stuffer, const uint64_t u);
134 : :
135 : : /* Allocate space now for network order integers that will be written later.
136 : : * These are primarily intended to handle the vector type defined in the RFC:
137 : : * https://tools.ietf.org/html/rfc8446#section-3.4 */
138 : : struct s2n_stuffer_reservation {
139 : : struct s2n_stuffer *stuffer;
140 : : uint32_t write_cursor;
141 : : uint8_t length;
142 : : };
143 : : /* Check basic validity constraints on the s2n_stuffer_reservation: e.g. stuffer validity. */
144 : : S2N_RESULT s2n_stuffer_reservation_validate(const struct s2n_stuffer_reservation *reservation);
145 : : int S2N_RESULT_MUST_USE s2n_stuffer_reserve_uint8(struct s2n_stuffer *stuffer, struct s2n_stuffer_reservation *reservation);
146 : : int S2N_RESULT_MUST_USE s2n_stuffer_reserve_uint16(struct s2n_stuffer *stuffer, struct s2n_stuffer_reservation *reservation);
147 : : int S2N_RESULT_MUST_USE s2n_stuffer_reserve_uint24(struct s2n_stuffer *stuffer, struct s2n_stuffer_reservation *reservation);
148 : : int S2N_RESULT_MUST_USE s2n_stuffer_write_reservation(struct s2n_stuffer_reservation *reservation, const uint32_t value);
149 : : /* Reservations are primarily intended to handle the variable-length vector type
150 : : * defined in the RFC: https://tools.ietf.org/html/rfc8446#section-3.4
151 : : * Variable-length vectors are preceded by the total size of the vector in bytes
152 : : * (not to be confused with the number of elements in the vector).
153 : : *
154 : : * These methods calculate the size of the vector just written to a stuffer based
155 : : * on the stuffer's current write cursor.
156 : : */
157 : : int S2N_RESULT_MUST_USE s2n_stuffer_get_vector_size(const struct s2n_stuffer_reservation *reservation, uint32_t *size);
158 : : int S2N_RESULT_MUST_USE s2n_stuffer_write_vector_size(struct s2n_stuffer_reservation *reservation);
159 : :
160 : : /* Copy one stuffer to another */
161 : : int s2n_stuffer_copy(struct s2n_stuffer *from, struct s2n_stuffer *to, uint32_t len);
162 : :
163 : : /* Convert between hex strings and raw bytes.
164 : : *
165 : : * When reading hex, the characters can be uppercase or lowercase.
166 : : * When writing hex, lowercase characters are used.
167 : : *
168 : : * Examples:
169 : : * "1234567890ABCdef" == [ 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef ]
170 : : * "FF" == 255 or [ 0xff ]
171 : : * "0001" == 1 or [ 0x00, 0x01 ]
172 : : */
173 : : S2N_RESULT s2n_hex_digit(uint8_t half_byte, uint8_t *hex_digit);
174 : : S2N_RESULT s2n_stuffer_read_hex(struct s2n_stuffer *hex_in, const struct s2n_blob *bytes_out);
175 : : S2N_RESULT s2n_stuffer_write_hex(struct s2n_stuffer *hex_out, const struct s2n_blob *bytes_in);
176 : : S2N_RESULT s2n_stuffer_read_uint8_hex(struct s2n_stuffer *stuffer, uint8_t *u);
177 : : S2N_RESULT s2n_stuffer_write_uint8_hex(struct s2n_stuffer *stuffer, uint8_t u);
178 : : S2N_RESULT s2n_stuffer_read_uint16_hex(struct s2n_stuffer *stuffer, uint16_t *u);
179 : : S2N_RESULT s2n_stuffer_write_uint16_hex(struct s2n_stuffer *stuffer, uint16_t u);
180 : :
181 : : /**
182 : : * Given base64 data in `stuffer`, write the decoded (binary) data into `out`.
183 : : *
184 : : * DANGER: If the data to be read is not a multiple of 4, any trailing bytes will
185 : : * be silently ignored.
186 : : */
187 : : int s2n_stuffer_read_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *out);
188 : :
189 : : /* Given some binary data in `in`, write the encoded (base64) data to `stuffer`. */
190 : : int s2n_stuffer_write_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *in);
191 : :
192 : : /* Useful for text manipulation ... */
193 : : #define s2n_stuffer_write_char(stuffer, c) s2n_stuffer_write_uint8((stuffer), (uint8_t) (c))
194 : : #define s2n_stuffer_read_char(stuffer, c) s2n_stuffer_read_uint8((stuffer), (uint8_t *) (c))
195 : : #define s2n_stuffer_write_str(stuffer, c) s2n_stuffer_write_bytes((stuffer), (const uint8_t *) (c), strlen((c)))
196 : : #define s2n_stuffer_write_text(stuffer, c, n) s2n_stuffer_write_bytes((stuffer), (const uint8_t *) (c), (n))
197 : : #define s2n_stuffer_read_text(stuffer, c, n) s2n_stuffer_read_bytes((stuffer), (uint8_t *) (c), (n))
198 : : int S2N_RESULT_MUST_USE s2n_stuffer_read_expected_str(struct s2n_stuffer *stuffer, const char *expected);
199 : : int S2N_RESULT_MUST_USE s2n_stuffer_peek_char(struct s2n_stuffer *stuffer, char *c);
200 : : int S2N_RESULT_MUST_USE s2n_stuffer_read_token(struct s2n_stuffer *stuffer, struct s2n_stuffer *token, char delim);
201 : : int S2N_RESULT_MUST_USE s2n_stuffer_read_line(struct s2n_stuffer *stuffer, struct s2n_stuffer *token);
202 : : int S2N_RESULT_MUST_USE s2n_stuffer_peek_check_for_str(struct s2n_stuffer *s2n_stuffer, const char *expected);
203 : : int S2N_RESULT_MUST_USE s2n_stuffer_skip_whitespace(struct s2n_stuffer *stuffer, uint32_t *skipped);
204 : : int S2N_RESULT_MUST_USE s2n_stuffer_skip_to_char(struct s2n_stuffer *stuffer, char target);
205 : : int S2N_RESULT_MUST_USE s2n_stuffer_skip_expected_char(struct s2n_stuffer *stuffer, const char expected, const uint32_t min,
206 : : const uint32_t max, uint32_t *skipped);
207 : : int S2N_RESULT_MUST_USE s2n_stuffer_skip_read_until(struct s2n_stuffer *stuffer, const char *target);
208 : : int S2N_RESULT_MUST_USE s2n_stuffer_alloc_ro_from_string(struct s2n_stuffer *stuffer, const char *str);
209 : : int S2N_RESULT_MUST_USE s2n_stuffer_init_ro_from_string(struct s2n_stuffer *stuffer, uint8_t *data, uint32_t length);
210 : :
211 : : /* Stuffer versions of sprintf methods, except:
212 : : * - They write bytes, not strings. They do not write a final '\0'. Unfortunately,
213 : : * they do still require enough space for a final '\0'-- we'd have to reimplement
214 : : * sprintf to avoid that.
215 : : * - vprintf does not consume the vargs. It calls va_copy before using
216 : : * the varg argument, so can be called repeatedly with the same vargs.
217 : : */
218 : : int S2N_RESULT_MUST_USE s2n_stuffer_printf(struct s2n_stuffer *stuffer, const char *format, ...);
219 : : int S2N_RESULT_MUST_USE s2n_stuffer_vprintf(struct s2n_stuffer *stuffer, const char *format, va_list vargs);
220 : :
221 : : /* Read a private key from a PEM encoded stuffer to an ASN1/DER encoded one */
222 : : int S2N_RESULT_MUST_USE s2n_stuffer_private_key_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1, int *type);
223 : :
224 : : /* Read a certificate from a PEM encoded stuffer to an ASN1/DER encoded one */
225 : : int S2N_RESULT_MUST_USE s2n_stuffer_certificate_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1);
226 : : bool s2n_stuffer_has_pem_encapsulated_block(struct s2n_stuffer *pem);
227 : :
228 : : /* Read a CRL from a PEM encoded stuffer to an ASN1/DER encoded one */
229 : : int S2N_RESULT_MUST_USE s2n_stuffer_crl_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *asn1);
230 : :
231 : : /* Read DH parameters om a PEM encoded stuffer to a PKCS3 encoded one */
232 : : int S2N_RESULT_MUST_USE s2n_stuffer_dhparams_from_pem(struct s2n_stuffer *pem, struct s2n_stuffer *pkcs3);
233 : :
234 : : bool s2n_is_base64_char(unsigned char c);
235 : :
236 : : /* Copies all valid data from "stuffer" into "out".
237 : : * The old blob "out" pointed to is freed.
238 : : * It is the responsibility of the caller to free the free "out".
239 : : */
240 : : int S2N_RESULT_MUST_USE s2n_stuffer_extract_blob(struct s2n_stuffer *stuffer, struct s2n_blob *out);
|