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