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