1 /* $OpenBSD: ssl_asn1.c,v 1.57 2018/08/27 16:42:48 jsing Exp $ */
3 * Copyright (c) 2016 Joel Sing <jsing@openbsd.org>
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.
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.
20 #include <openssl/ssl.h>
21 #include <openssl/x509.h>
25 #include "bytestring.h"
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)
40 if (sizeof(time_t) == sizeof(int32_t))
42 if (sizeof(time_t) == sizeof(int64_t))
48 SSL_SESSION_encode(SSL_SESSION
*s
, unsigned char **out
, size_t *out_len
,
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
;
57 if (!CBB_init(&cbb
, 0))
60 if (!CBB_add_asn1(&cbb
, &session
, CBS_ASN1_SEQUENCE
))
63 /* Session ASN1 version. */
64 if (!CBB_add_asn1_uint64(&session
, SSL_SESSION_ASN1_VERSION
))
67 /* TLS/SSL protocol version. */
68 if (s
->ssl_version
< 0)
70 if (!CBB_add_asn1_uint64(&session
, s
->ssl_version
))
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
))
80 if (!CBB_add_u16(&cipher_suite
, cid
))
83 /* Session ID - zero length for a ticket. */
84 if (!CBB_add_asn1(&session
, &session_id
, CBS_ASN1_OCTETSTRING
))
86 if (!CBB_add_bytes(&session_id
, s
->session_id
,
87 ticket_encoding
? 0 : s
->session_id_length
))
91 if (!CBB_add_asn1(&session
, &master_key
, CBS_ASN1_OCTETSTRING
))
93 if (!CBB_add_bytes(&master_key
, s
->master_key
, s
->master_key_length
))
100 if (!CBB_add_asn1(&session
, &time
, SSLASN1_TIME_TAG
))
102 if (!CBB_add_asn1_uint64(&time
, s
->time
))
107 if (s
->timeout
!= 0) {
110 if (!CBB_add_asn1(&session
, &timeout
, SSLASN1_TIMEOUT_TAG
))
112 if (!CBB_add_asn1_uint64(&timeout
, s
->timeout
))
116 /* Peer certificate [3]. */
117 if (s
->peer
!= NULL
) {
118 if ((len
= i2d_X509(s
->peer
, &peer_cert_bytes
)) <= 0)
120 if (!CBB_add_asn1(&session
, &peer_cert
, SSLASN1_PEER_CERT_TAG
))
122 if (!CBB_add_bytes(&peer_cert
, peer_cert_bytes
, len
))
126 /* Session ID context [4]. */
127 /* XXX - Actually handle this as optional? */
128 if (!CBB_add_asn1(&session
, &sidctx
, SSLASN1_SESSION_ID_CTX_TAG
))
130 if (!CBB_add_asn1(&sidctx
, &value
, CBS_ASN1_OCTETSTRING
))
132 if (!CBB_add_bytes(&value
, s
->sid_ctx
, s
->sid_ctx_length
))
135 /* Verify result [5]. */
136 if (s
->verify_result
!= X509_V_OK
) {
137 if (s
->verify_result
< 0)
139 if (!CBB_add_asn1(&session
, &verify_result
,
140 SSLASN1_VERIFY_RESULT_TAG
))
142 if (!CBB_add_asn1_uint64(&verify_result
, s
->verify_result
))
147 if (s
->tlsext_hostname
!= NULL
) {
148 if (!CBB_add_asn1(&session
, &hostname
, SSLASN1_HOSTNAME_TAG
))
150 if (!CBB_add_asn1(&hostname
, &value
, CBS_ASN1_OCTETSTRING
))
152 if (!CBB_add_bytes(&value
, (const uint8_t *)s
->tlsext_hostname
,
153 strlen(s
->tlsext_hostname
)))
157 /* PSK identity hint [7]. */
158 /* PSK identity [8]. */
160 /* Ticket lifetime hint [9]. */
161 if (s
->tlsext_tick_lifetime_hint
> 0) {
162 if (!CBB_add_asn1(&session
, &lifetime
, SSLASN1_LIFETIME_TAG
))
164 if (!CBB_add_asn1_uint64(&lifetime
,
165 s
->tlsext_tick_lifetime_hint
))
170 if (s
->tlsext_tick
!= NULL
) {
171 if (!CBB_add_asn1(&session
, &ticket
, SSLASN1_TICKET_TAG
))
173 if (!CBB_add_asn1(&ticket
, &value
, CBS_ASN1_OCTETSTRING
))
175 if (!CBB_add_bytes(&value
, s
->tlsext_tick
, s
->tlsext_ticklen
))
179 /* Compression method [11]. */
180 /* SRP username [12]. */
182 if (!CBB_finish(&cbb
, out
, out_len
))
189 free(peer_cert_bytes
);
195 SSL_SESSION_ticket(SSL_SESSION
*ss
, unsigned char **out
, size_t *out_len
)
200 if (ss
->cipher
== NULL
&& ss
->cipher_id
== 0)
203 return SSL_SESSION_encode(ss
, out
, out_len
, 1);
207 i2d_SSL_SESSION(SSL_SESSION
*ss
, unsigned char **pp
)
209 unsigned char *data
= NULL
;
216 if (ss
->cipher
== NULL
&& ss
->cipher_id
== 0)
219 if (!SSL_SESSION_encode(ss
, &data
, &data_len
, 0))
222 if (data_len
> INT_MAX
)
230 memcpy(*pp
, data
, data_len
);
238 freezero(data
, data_len
);
244 d2i_SSL_SESSION(SSL_SESSION
**a
, const unsigned char **pp
, long length
)
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
;
259 if ((s
= SSL_SESSION_new()) == NULL
) {
260 SSLerrorx(ERR_R_MALLOC_FAILURE
);
265 CBS_init(&cbs
, *pp
, length
);
267 if (!CBS_get_asn1(&cbs
, &session
, CBS_ASN1_SEQUENCE
))
270 /* Session ASN1 version. */
271 if (!CBS_get_asn1_uint64(&session
, &version
))
273 if (version
!= SSL_SESSION_ASN1_VERSION
)
276 /* TLS/SSL Protocol Version. */
277 if (!CBS_get_asn1_uint64(&session
, &tls_version
))
279 if (tls_version
> INT_MAX
)
281 s
->ssl_version
= (int)tls_version
;
284 if (!CBS_get_asn1(&session
, &cipher_suite
, CBS_ASN1_OCTETSTRING
))
286 if (!CBS_get_u16(&cipher_suite
, &cipher_value
))
288 if (CBS_len(&cipher_suite
) != 0)
291 /* XXX - populate cipher instead? */
293 s
->cipher_id
= SSL3_CK_ID
| cipher_value
;
296 if (!CBS_get_asn1(&session
, &session_id
, CBS_ASN1_OCTETSTRING
))
298 if (!CBS_write_bytes(&session_id
, s
->session_id
, sizeof(s
->session_id
),
301 if (data_len
> UINT_MAX
)
303 s
->session_id_length
= (unsigned int)data_len
;
306 if (!CBS_get_asn1(&session
, &master_key
, CBS_ASN1_OCTETSTRING
))
308 if (!CBS_write_bytes(&master_key
, s
->master_key
, sizeof(s
->master_key
),
311 if (data_len
> INT_MAX
)
313 s
->master_key_length
= (int)data_len
;
316 s
->time
= time(NULL
);
317 if (!CBS_get_optional_asn1_uint64(&session
, &stime
, SSLASN1_TIME_TAG
,
320 if (stime
> time_max())
323 s
->time
= (time_t)stime
;
327 if (!CBS_get_optional_asn1_uint64(&session
, &timeout
,
328 SSLASN1_TIMEOUT_TAG
, 0))
330 if (timeout
> LONG_MAX
)
333 s
->timeout
= (long)timeout
;
335 /* Peer certificate [3]. */
338 if (!CBS_get_optional_asn1(&session
, &peer_cert
, &present
,
339 SSLASN1_PEER_CERT_TAG
))
342 data_len
= CBS_len(&peer_cert
);
343 if (data_len
> LONG_MAX
)
345 peer_cert_bytes
= CBS_data(&peer_cert
);
346 if (d2i_X509(&s
->peer
, &peer_cert_bytes
,
347 (long)data_len
) == NULL
)
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
))
357 if (!CBS_write_bytes(&session_id
, (uint8_t *)&s
->sid_ctx
,
358 sizeof(s
->sid_ctx
), &data_len
))
360 if (data_len
> UINT_MAX
)
362 s
->sid_ctx_length
= (unsigned int)data_len
;
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
))
370 if (verify_result
> LONG_MAX
)
372 s
->verify_result
= (long)verify_result
;
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
))
381 if (CBS_contains_zero_byte(&hostname
))
383 if (!CBS_strdup(&hostname
, &s
->tlsext_hostname
))
387 /* PSK identity hint [7]. */
388 /* PSK identity [8]. */
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))
398 if (lifetime
> LONG_MAX
)
401 s
->tlsext_tick_lifetime_hint
= (long)lifetime
;
404 free(s
->tlsext_tick
);
405 s
->tlsext_tick
= NULL
;
406 if (!CBS_get_optional_asn1_octet_string(&session
, &ticket
, &present
,
410 if (!CBS_stow(&ticket
, &s
->tlsext_tick
, &s
->tlsext_ticklen
))
414 /* Compression method [11]. */
415 /* SRP username [12]. */
417 *pp
= CBS_data(&cbs
);
425 ERR_asprintf_error_data("offset=%d", (int)(CBS_data(&cbs
) - *pp
));
427 if (s
!= NULL
&& (a
== NULL
|| *a
!= s
))