xref: /openbsd/lib/libssl/ssl_asn1.c (revision 4fb9ab68)
1 /* $OpenBSD: ssl_asn1.c,v 1.68 2024/07/20 04:04:23 jsing Exp $ */
2 /*
3  * Copyright (c) 2016 Joel Sing <jsing@openbsd.org>
4  *
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
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <limits.h>
19 
20 #include <openssl/ssl.h>
21 #include <openssl/x509.h>
22 
23 #include "bytestring.h"
24 #include "ssl_local.h"
25 
26 #define SSLASN1_TAG	(CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC)
27 #define SSLASN1_TIME_TAG		(SSLASN1_TAG | 1)
28 #define SSLASN1_TIMEOUT_TAG		(SSLASN1_TAG | 2)
29 #define SSLASN1_PEER_CERT_TAG		(SSLASN1_TAG | 3)
30 #define SSLASN1_SESSION_ID_CTX_TAG	(SSLASN1_TAG | 4)
31 #define SSLASN1_VERIFY_RESULT_TAG	(SSLASN1_TAG | 5)
32 #define SSLASN1_HOSTNAME_TAG		(SSLASN1_TAG | 6)
33 #define SSLASN1_LIFETIME_TAG		(SSLASN1_TAG | 9)
34 #define SSLASN1_TICKET_TAG		(SSLASN1_TAG | 10)
35 
36 static uint64_t
37 time_max(void)
38 {
39 	if (sizeof(time_t) == sizeof(int32_t))
40 		return INT32_MAX;
41 	if (sizeof(time_t) == sizeof(int64_t))
42 		return INT64_MAX;
43 	return 0;
44 }
45 
46 static int
47 SSL_SESSION_encode(SSL_SESSION *s, unsigned char **out, size_t *out_len,
48     int ticket_encoding)
49 {
50 	CBB cbb, session, cipher_suite, session_id, master_key, time, timeout;
51 	CBB peer_cert, sidctx, verify_result, hostname, lifetime, ticket, value;
52 	unsigned char *peer_cert_bytes = NULL;
53 	int len, rv = 0;
54 	uint16_t cid;
55 
56 	if (!CBB_init(&cbb, 0))
57 		goto err;
58 
59 	if (!CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE))
60 		goto err;
61 
62 	/* Session ASN1 version. */
63 	if (!CBB_add_asn1_uint64(&session, SSL_SESSION_ASN1_VERSION))
64 		goto err;
65 
66 	/* TLS/SSL protocol version. */
67 	if (s->ssl_version < 0)
68 		goto err;
69 	if (!CBB_add_asn1_uint64(&session, s->ssl_version))
70 		goto err;
71 
72 	/* Cipher suite ID. */
73 	cid = (uint16_t)(s->cipher_id & SSL3_CK_VALUE_MASK);
74 	if (!CBB_add_asn1(&session, &cipher_suite, CBS_ASN1_OCTETSTRING))
75 		goto err;
76 	if (!CBB_add_u16(&cipher_suite, cid))
77 		goto err;
78 
79 	/* Session ID - zero length for a ticket. */
80 	if (!CBB_add_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING))
81 		goto err;
82 	if (!CBB_add_bytes(&session_id, s->session_id,
83 	    ticket_encoding ? 0 : s->session_id_length))
84 		goto err;
85 
86 	/* Master key. */
87 	if (!CBB_add_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING))
88 		goto err;
89 	if (!CBB_add_bytes(&master_key, s->master_key, s->master_key_length))
90 		goto err;
91 
92 	/* Time [1]. */
93 	if (s->time != 0) {
94 		if (s->time < 0)
95 			goto err;
96 		if (!CBB_add_asn1(&session, &time, SSLASN1_TIME_TAG))
97 			goto err;
98 		if (!CBB_add_asn1_uint64(&time, s->time))
99 			goto err;
100 	}
101 
102 	/* Timeout [2]. */
103 	if (s->timeout != 0) {
104 		if (s->timeout < 0)
105 			goto err;
106 		if (!CBB_add_asn1(&session, &timeout, SSLASN1_TIMEOUT_TAG))
107 			goto err;
108 		if (!CBB_add_asn1_uint64(&timeout, s->timeout))
109 			goto err;
110 	}
111 
112 	/* Peer certificate [3]. */
113 	if (s->peer_cert != NULL) {
114 		if ((len = i2d_X509(s->peer_cert, &peer_cert_bytes)) <= 0)
115 			goto err;
116 		if (!CBB_add_asn1(&session, &peer_cert, SSLASN1_PEER_CERT_TAG))
117 			goto err;
118 		if (!CBB_add_bytes(&peer_cert, peer_cert_bytes, len))
119 			goto err;
120 	}
121 
122 	/* Session ID context [4]. */
123 	/* XXX - Actually handle this as optional? */
124 	if (!CBB_add_asn1(&session, &sidctx, SSLASN1_SESSION_ID_CTX_TAG))
125 		goto err;
126 	if (!CBB_add_asn1(&sidctx, &value, CBS_ASN1_OCTETSTRING))
127 		goto err;
128 	if (!CBB_add_bytes(&value, s->sid_ctx, s->sid_ctx_length))
129 		goto err;
130 
131 	/* Verify result [5]. */
132 	if (s->verify_result != X509_V_OK) {
133 		if (s->verify_result < 0)
134 			goto err;
135 		if (!CBB_add_asn1(&session, &verify_result,
136 		    SSLASN1_VERIFY_RESULT_TAG))
137 			goto err;
138 		if (!CBB_add_asn1_uint64(&verify_result, s->verify_result))
139 			goto err;
140 	}
141 
142 	/* Hostname [6]. */
143 	if (s->tlsext_hostname != NULL) {
144 		if (!CBB_add_asn1(&session, &hostname, SSLASN1_HOSTNAME_TAG))
145 			goto err;
146 		if (!CBB_add_asn1(&hostname, &value, CBS_ASN1_OCTETSTRING))
147 			goto err;
148 		if (!CBB_add_bytes(&value, (const uint8_t *)s->tlsext_hostname,
149 		    strlen(s->tlsext_hostname)))
150 			goto err;
151 	}
152 
153 	/* PSK identity hint [7]. */
154 	/* PSK identity [8]. */
155 
156 	/* Ticket lifetime hint [9]. */
157 	if (s->tlsext_tick_lifetime_hint > 0) {
158 		if (!CBB_add_asn1(&session, &lifetime, SSLASN1_LIFETIME_TAG))
159 			goto err;
160 		if (!CBB_add_asn1_uint64(&lifetime,
161 		    s->tlsext_tick_lifetime_hint))
162 			goto err;
163 	}
164 
165 	/* Ticket [10]. */
166 	if (s->tlsext_tick != NULL) {
167 		if (!CBB_add_asn1(&session, &ticket, SSLASN1_TICKET_TAG))
168 			goto err;
169 		if (!CBB_add_asn1(&ticket, &value, CBS_ASN1_OCTETSTRING))
170 			goto err;
171 		if (!CBB_add_bytes(&value, s->tlsext_tick, s->tlsext_ticklen))
172 			goto err;
173 	}
174 
175 	/* Compression method [11]. */
176 	/* SRP username [12]. */
177 
178 	if (!CBB_finish(&cbb, out, out_len))
179 		goto err;
180 
181 	rv = 1;
182 
183  err:
184 	CBB_cleanup(&cbb);
185 	free(peer_cert_bytes);
186 
187 	return rv;
188 }
189 
190 int
191 SSL_SESSION_ticket(SSL_SESSION *ss, unsigned char **out, size_t *out_len)
192 {
193 	if (ss == NULL)
194 		return 0;
195 
196 	if (ss->cipher_id == 0)
197 		return 0;
198 
199 	return SSL_SESSION_encode(ss, out, out_len, 1);
200 }
201 
202 int
203 i2d_SSL_SESSION(SSL_SESSION *ss, unsigned char **pp)
204 {
205 	unsigned char *data = NULL;
206 	size_t data_len = 0;
207 	int rv = -1;
208 
209 	if (ss == NULL)
210 		return 0;
211 
212 	if (ss->cipher_id == 0)
213 		return 0;
214 
215 	if (!SSL_SESSION_encode(ss, &data, &data_len, 0))
216 		goto err;
217 
218 	if (data_len > INT_MAX)
219 		goto err;
220 
221 	if (pp != NULL) {
222 		if (*pp == NULL) {
223 			*pp = data;
224 			data = NULL;
225 		} else {
226 			memcpy(*pp, data, data_len);
227 			*pp += data_len;
228 		}
229 	}
230 
231 	rv = (int)data_len;
232 
233  err:
234 	freezero(data, data_len);
235 
236 	return rv;
237 }
238 LSSL_ALIAS(i2d_SSL_SESSION);
239 
240 SSL_SESSION *
241 d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, long length)
242 {
243 	CBS cbs, session, cipher_suite, session_id, master_key, peer_cert;
244 	CBS hostname, ticket;
245 	uint64_t version, tls_version, stime, timeout, verify_result, lifetime;
246 	const unsigned char *peer_cert_bytes;
247 	uint16_t cipher_value;
248 	SSL_SESSION *s = NULL;
249 	size_t data_len;
250 	int present;
251 
252 	if (a != NULL)
253 		s = *a;
254 
255 	if (s == NULL) {
256 		if ((s = SSL_SESSION_new()) == NULL) {
257 			SSLerrorx(ERR_R_MALLOC_FAILURE);
258 			return (NULL);
259 		}
260 	}
261 
262 	CBS_init(&cbs, *pp, length);
263 
264 	if (!CBS_get_asn1(&cbs, &session, CBS_ASN1_SEQUENCE))
265 		goto err;
266 
267 	/* Session ASN1 version. */
268 	if (!CBS_get_asn1_uint64(&session, &version))
269 		goto err;
270 	if (version != SSL_SESSION_ASN1_VERSION)
271 		goto err;
272 
273 	/* TLS/SSL Protocol Version. */
274 	if (!CBS_get_asn1_uint64(&session, &tls_version))
275 		goto err;
276 	if (tls_version > INT_MAX)
277 		goto err;
278 	s->ssl_version = (int)tls_version;
279 
280 	/* Cipher suite. */
281 	if (!CBS_get_asn1(&session, &cipher_suite, CBS_ASN1_OCTETSTRING))
282 		goto err;
283 	if (!CBS_get_u16(&cipher_suite, &cipher_value))
284 		goto err;
285 	if (CBS_len(&cipher_suite) != 0)
286 		goto err;
287 	s->cipher_id = SSL3_CK_ID | cipher_value;
288 
289 	/* Session ID. */
290 	if (!CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING))
291 		goto err;
292 	if (!CBS_write_bytes(&session_id, s->session_id, sizeof(s->session_id),
293 	    &s->session_id_length))
294 		goto err;
295 
296 	/* Master key. */
297 	if (!CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING))
298 		goto err;
299 	if (!CBS_write_bytes(&master_key, s->master_key, sizeof(s->master_key),
300 	    &s->master_key_length))
301 		goto err;
302 
303 	/* Time [1]. */
304 	s->time = time(NULL);
305 	if (!CBS_get_optional_asn1_uint64(&session, &stime, SSLASN1_TIME_TAG,
306 	    0))
307 		goto err;
308 	if (stime > time_max())
309 		goto err;
310 	if (stime != 0)
311 		s->time = (time_t)stime;
312 
313 	/* Timeout [2]. */
314 	s->timeout = 3;
315 	if (!CBS_get_optional_asn1_uint64(&session, &timeout,
316 	    SSLASN1_TIMEOUT_TAG, 0))
317 		goto err;
318 	if (timeout > LONG_MAX)
319 		goto err;
320 	if (timeout != 0)
321 		s->timeout = (long)timeout;
322 
323 	/* Peer certificate [3]. */
324 	X509_free(s->peer_cert);
325 	s->peer_cert = NULL;
326 	if (!CBS_get_optional_asn1(&session, &peer_cert, &present,
327 	    SSLASN1_PEER_CERT_TAG))
328 		goto err;
329 	if (present) {
330 		data_len = CBS_len(&peer_cert);
331 		if (data_len > LONG_MAX)
332 			goto err;
333 		peer_cert_bytes = CBS_data(&peer_cert);
334 		if (d2i_X509(&s->peer_cert, &peer_cert_bytes,
335 		    (long)data_len) == NULL)
336 			goto err;
337 	}
338 
339 	/* Session ID context [4]. */
340 	s->sid_ctx_length = 0;
341 	if (!CBS_get_optional_asn1_octet_string(&session, &session_id, &present,
342 	    SSLASN1_SESSION_ID_CTX_TAG))
343 		goto err;
344 	if (present) {
345 		if (!CBS_write_bytes(&session_id, (uint8_t *)&s->sid_ctx,
346 		    sizeof(s->sid_ctx), &s->sid_ctx_length))
347 			goto err;
348 	}
349 
350 	/* Verify result [5]. */
351 	s->verify_result = X509_V_OK;
352 	if (!CBS_get_optional_asn1_uint64(&session, &verify_result,
353 	    SSLASN1_VERIFY_RESULT_TAG, X509_V_OK))
354 		goto err;
355 	if (verify_result > LONG_MAX)
356 		goto err;
357 	s->verify_result = (long)verify_result;
358 
359 	/* Hostname [6]. */
360 	free(s->tlsext_hostname);
361 	s->tlsext_hostname = NULL;
362 	if (!CBS_get_optional_asn1_octet_string(&session, &hostname, &present,
363 	    SSLASN1_HOSTNAME_TAG))
364 		goto err;
365 	if (present) {
366 		if (CBS_contains_zero_byte(&hostname))
367 			goto err;
368 		if (!CBS_strdup(&hostname, &s->tlsext_hostname))
369 			goto err;
370 	}
371 
372 	/* PSK identity hint [7]. */
373 	/* PSK identity [8]. */
374 
375 	/* Ticket lifetime [9]. */
376 	s->tlsext_tick_lifetime_hint = 0;
377 	if (!CBS_get_optional_asn1_uint64(&session, &lifetime,
378 	    SSLASN1_LIFETIME_TAG, 0))
379 		goto err;
380 	if (lifetime > UINT32_MAX)
381 		goto err;
382 	if (lifetime > 0)
383 		s->tlsext_tick_lifetime_hint = (uint32_t)lifetime;
384 
385 	/* Ticket [10]. */
386 	free(s->tlsext_tick);
387 	s->tlsext_tick = NULL;
388 	if (!CBS_get_optional_asn1_octet_string(&session, &ticket, &present,
389 	    SSLASN1_TICKET_TAG))
390 		goto err;
391 	if (present) {
392 		if (!CBS_stow(&ticket, &s->tlsext_tick, &s->tlsext_ticklen))
393 			goto err;
394 	}
395 
396 	/* Compression method [11]. */
397 	/* SRP username [12]. */
398 
399 	*pp = CBS_data(&cbs);
400 
401 	if (a != NULL)
402 		*a = s;
403 
404 	return (s);
405 
406  err:
407 	ERR_asprintf_error_data("offset=%d", (int)(CBS_data(&cbs) - *pp));
408 
409 	if (s != NULL && (a == NULL || *a != s))
410 		SSL_SESSION_free(s);
411 
412 	return (NULL);
413 }
414 LSSL_ALIAS(d2i_SSL_SESSION);
415