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