xref: /dragonfly/crypto/libressl/ssl/ssl_asn1.c (revision 961e30ea7dc61d1112b778ea4981eac68129fb86)
1 /* $OpenBSD: ssl_asn1.c,v 1.65 2022/06/07 17:53:42 tb 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 & SSL3_CK_VALUE_MASK);
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_cert != NULL) {
117                     if ((len = i2d_X509(s->peer_cert, &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               &s->session_id_length))
299                     goto err;
300 
301           /* Master key. */
302           if (!CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING))
303                     goto err;
304           if (!CBS_write_bytes(&master_key, s->master_key, sizeof(s->master_key),
305               &s->master_key_length))
306                     goto err;
307 
308           /* Time [1]. */
309           s->time = time(NULL);
310           if (!CBS_get_optional_asn1_uint64(&session, &stime, SSLASN1_TIME_TAG,
311               0))
312                     goto err;
313           if (stime > time_max())
314                     goto err;
315           if (stime != 0)
316                     s->time = (time_t)stime;
317 
318           /* Timeout [2]. */
319           s->timeout = 3;
320           if (!CBS_get_optional_asn1_uint64(&session, &timeout,
321               SSLASN1_TIMEOUT_TAG, 0))
322                     goto err;
323           if (timeout > LONG_MAX)
324                     goto err;
325           if (timeout != 0)
326                     s->timeout = (long)timeout;
327 
328           /* Peer certificate [3]. */
329           X509_free(s->peer_cert);
330           s->peer_cert = NULL;
331           if (!CBS_get_optional_asn1(&session, &peer_cert, &present,
332               SSLASN1_PEER_CERT_TAG))
333                     goto err;
334           if (present) {
335                     data_len = CBS_len(&peer_cert);
336                     if (data_len > LONG_MAX)
337                               goto err;
338                     peer_cert_bytes = CBS_data(&peer_cert);
339                     if (d2i_X509(&s->peer_cert, &peer_cert_bytes,
340                         (long)data_len) == NULL)
341                               goto err;
342           }
343 
344           /* Session ID context [4]. */
345           s->sid_ctx_length = 0;
346           if (!CBS_get_optional_asn1_octet_string(&session, &session_id, &present,
347               SSLASN1_SESSION_ID_CTX_TAG))
348                     goto err;
349           if (present) {
350                     if (!CBS_write_bytes(&session_id, (uint8_t *)&s->sid_ctx,
351                         sizeof(s->sid_ctx), &s->sid_ctx_length))
352                               goto err;
353           }
354 
355           /* Verify result [5]. */
356           s->verify_result = X509_V_OK;
357           if (!CBS_get_optional_asn1_uint64(&session, &verify_result,
358               SSLASN1_VERIFY_RESULT_TAG, X509_V_OK))
359                     goto err;
360           if (verify_result > LONG_MAX)
361                     goto err;
362           s->verify_result = (long)verify_result;
363 
364           /* Hostname [6]. */
365           free(s->tlsext_hostname);
366           s->tlsext_hostname = NULL;
367           if (!CBS_get_optional_asn1_octet_string(&session, &hostname, &present,
368               SSLASN1_HOSTNAME_TAG))
369                     goto err;
370           if (present) {
371                     if (CBS_contains_zero_byte(&hostname))
372                               goto err;
373                     if (!CBS_strdup(&hostname, &s->tlsext_hostname))
374                               goto err;
375           }
376 
377           /* PSK identity hint [7]. */
378           /* PSK identity [8]. */
379 
380           /* Ticket lifetime [9]. */
381           s->tlsext_tick_lifetime_hint = 0;
382           if (!CBS_get_optional_asn1_uint64(&session, &lifetime,
383               SSLASN1_LIFETIME_TAG, 0))
384                     goto err;
385           if (lifetime > UINT32_MAX)
386                     goto err;
387           if (lifetime > 0)
388                     s->tlsext_tick_lifetime_hint = (uint32_t)lifetime;
389 
390           /* Ticket [10]. */
391           free(s->tlsext_tick);
392           s->tlsext_tick = NULL;
393           if (!CBS_get_optional_asn1_octet_string(&session, &ticket, &present,
394               SSLASN1_TICKET_TAG))
395                     goto err;
396           if (present) {
397                     if (!CBS_stow(&ticket, &s->tlsext_tick, &s->tlsext_ticklen))
398                               goto err;
399           }
400 
401           /* Compression method [11]. */
402           /* SRP username [12]. */
403 
404           *pp = CBS_data(&cbs);
405 
406           if (a != NULL)
407                     *a = s;
408 
409           return (s);
410 
411  err:
412           ERR_asprintf_error_data("offset=%d", (int)(CBS_data(&cbs) - *pp));
413 
414           if (s != NULL && (a == NULL || *a != s))
415                     SSL_SESSION_free(s);
416 
417           return (NULL);
418 }
419