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