1 /* $OpenBSD: ssl_asn1.c,v 1.55 2017/05/06 16:18:36 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 i2d_SSL_SESSION(SSL_SESSION
*s
, unsigned char **pp
)
50 CBB cbb
, session
, cipher_suite
, session_id
, master_key
, time
, timeout
;
51 CBB peer_cert
, sidctx
, verify_result
, hostname
, lifetime
, ticket
;
53 unsigned char *data
= NULL
, *peer_cert_bytes
= NULL
;
61 if (s
->cipher
== NULL
&& s
->cipher_id
== 0)
64 if (!CBB_init(&cbb
, 0))
67 if (!CBB_add_asn1(&cbb
, &session
, CBS_ASN1_SEQUENCE
))
70 /* Session ASN1 version. */
71 if (!CBB_add_asn1_uint64(&session
, SSL_SESSION_ASN1_VERSION
))
74 /* TLS/SSL protocol version. */
75 if (s
->ssl_version
< 0)
77 if (!CBB_add_asn1_uint64(&session
, s
->ssl_version
))
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
))
87 if (!CBB_add_u16(&cipher_suite
, cid
))
91 if (!CBB_add_asn1(&session
, &session_id
, CBS_ASN1_OCTETSTRING
))
93 if (!CBB_add_bytes(&session_id
, s
->session_id
, s
->session_id_length
))
97 if (!CBB_add_asn1(&session
, &master_key
, CBS_ASN1_OCTETSTRING
))
99 if (!CBB_add_bytes(&master_key
, s
->master_key
, s
->master_key_length
))
106 if (!CBB_add_asn1(&session
, &time
, SSLASN1_TIME_TAG
))
108 if (!CBB_add_asn1_uint64(&time
, s
->time
))
113 if (s
->timeout
!= 0) {
116 if (!CBB_add_asn1(&session
, &timeout
, SSLASN1_TIMEOUT_TAG
))
118 if (!CBB_add_asn1_uint64(&timeout
, s
->timeout
))
122 /* Peer certificate [3]. */
123 if (s
->peer
!= NULL
) {
124 if ((len
= i2d_X509(s
->peer
, &peer_cert_bytes
)) <= 0)
126 if (!CBB_add_asn1(&session
, &peer_cert
, SSLASN1_PEER_CERT_TAG
))
128 if (!CBB_add_bytes(&peer_cert
, peer_cert_bytes
, len
))
132 /* Session ID context [4]. */
133 /* XXX - Actually handle this as optional? */
134 if (!CBB_add_asn1(&session
, &sidctx
, SSLASN1_SESSION_ID_CTX_TAG
))
136 if (!CBB_add_asn1(&sidctx
, &value
, CBS_ASN1_OCTETSTRING
))
138 if (!CBB_add_bytes(&value
, s
->sid_ctx
, s
->sid_ctx_length
))
141 /* Verify result [5]. */
142 if (s
->verify_result
!= X509_V_OK
) {
143 if (s
->verify_result
< 0)
145 if (!CBB_add_asn1(&session
, &verify_result
,
146 SSLASN1_VERIFY_RESULT_TAG
))
148 if (!CBB_add_asn1_uint64(&verify_result
, s
->verify_result
))
153 if (s
->tlsext_hostname
!= NULL
) {
154 if (!CBB_add_asn1(&session
, &hostname
, SSLASN1_HOSTNAME_TAG
))
156 if (!CBB_add_asn1(&hostname
, &value
, CBS_ASN1_OCTETSTRING
))
158 if (!CBB_add_bytes(&value
, (const uint8_t *)s
->tlsext_hostname
,
159 strlen(s
->tlsext_hostname
)))
163 /* PSK identity hint [7]. */
164 /* PSK identity [8]. */
166 /* Ticket lifetime hint [9]. */
167 if (s
->tlsext_tick_lifetime_hint
> 0) {
168 if (!CBB_add_asn1(&session
, &lifetime
, SSLASN1_LIFETIME_TAG
))
170 if (!CBB_add_asn1_uint64(&lifetime
,
171 s
->tlsext_tick_lifetime_hint
))
176 if (s
->tlsext_tick
) {
177 if (!CBB_add_asn1(&session
, &ticket
, SSLASN1_TICKET_TAG
))
179 if (!CBB_add_asn1(&ticket
, &value
, CBS_ASN1_OCTETSTRING
))
181 if (!CBB_add_bytes(&value
, s
->tlsext_tick
, s
->tlsext_ticklen
))
185 /* Compression method [11]. */
186 /* SRP username [12]. */
188 if (!CBB_finish(&cbb
, &data
, &data_len
))
191 if (data_len
> INT_MAX
)
199 memcpy(*pp
, data
, data_len
);
207 CBB_cleanup(&session
);
208 freezero(data
, data_len
);
209 free(peer_cert_bytes
);
215 d2i_SSL_SESSION(SSL_SESSION
**a
, const unsigned char **pp
, long length
)
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
;
230 if ((s
= SSL_SESSION_new()) == NULL
) {
231 SSLerrorx(ERR_R_MALLOC_FAILURE
);
236 CBS_init(&cbs
, *pp
, length
);
238 if (!CBS_get_asn1(&cbs
, &session
, CBS_ASN1_SEQUENCE
))
241 /* Session ASN1 version. */
242 if (!CBS_get_asn1_uint64(&session
, &version
))
244 if (version
!= SSL_SESSION_ASN1_VERSION
)
247 /* TLS/SSL Protocol Version. */
248 if (!CBS_get_asn1_uint64(&session
, &tls_version
))
250 if (tls_version
> INT_MAX
)
252 s
->ssl_version
= (int)tls_version
;
255 if (!CBS_get_asn1(&session
, &cipher_suite
, CBS_ASN1_OCTETSTRING
))
257 if (!CBS_get_u16(&cipher_suite
, &cipher_value
))
259 if (CBS_len(&cipher_suite
) != 0)
262 /* XXX - populate cipher instead? */
264 s
->cipher_id
= SSL3_CK_ID
| cipher_value
;
267 if (!CBS_get_asn1(&session
, &session_id
, CBS_ASN1_OCTETSTRING
))
269 if (!CBS_write_bytes(&session_id
, s
->session_id
, sizeof(s
->session_id
),
272 if (data_len
> UINT_MAX
)
274 s
->session_id_length
= (unsigned int)data_len
;
277 if (!CBS_get_asn1(&session
, &master_key
, CBS_ASN1_OCTETSTRING
))
279 if (!CBS_write_bytes(&master_key
, s
->master_key
, sizeof(s
->master_key
),
282 if (data_len
> INT_MAX
)
284 s
->master_key_length
= (int)data_len
;
287 s
->time
= time(NULL
);
288 if (!CBS_get_optional_asn1_uint64(&session
, &stime
, SSLASN1_TIME_TAG
,
291 if (stime
> time_max())
294 s
->time
= (time_t)stime
;
298 if (!CBS_get_optional_asn1_uint64(&session
, &timeout
,
299 SSLASN1_TIMEOUT_TAG
, 0))
301 if (timeout
> LONG_MAX
)
304 s
->timeout
= (long)timeout
;
306 /* Peer certificate [3]. */
309 if (!CBS_get_optional_asn1(&session
, &peer_cert
, &present
,
310 SSLASN1_PEER_CERT_TAG
))
313 data_len
= CBS_len(&peer_cert
);
314 if (data_len
> LONG_MAX
)
316 peer_cert_bytes
= CBS_data(&peer_cert
);
317 if (d2i_X509(&s
->peer
, &peer_cert_bytes
,
318 (long)data_len
) == NULL
)
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
))
328 if (!CBS_write_bytes(&session_id
, (uint8_t *)&s
->sid_ctx
,
329 sizeof(s
->sid_ctx
), &data_len
))
331 if (data_len
> UINT_MAX
)
333 s
->sid_ctx_length
= (unsigned int)data_len
;
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
))
341 if (verify_result
> LONG_MAX
)
343 s
->verify_result
= (long)verify_result
;
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
))
352 if (CBS_contains_zero_byte(&hostname
))
354 if (!CBS_strdup(&hostname
, &s
->tlsext_hostname
))
358 /* PSK identity hint [7]. */
359 /* PSK identity [8]. */
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))
369 if (lifetime
> LONG_MAX
)
372 s
->tlsext_tick_lifetime_hint
= (long)lifetime
;
375 free(s
->tlsext_tick
);
376 s
->tlsext_tick
= NULL
;
377 if (!CBS_get_optional_asn1_octet_string(&session
, &ticket
, &present
,
381 if (!CBS_stow(&ticket
, &s
->tlsext_tick
, &s
->tlsext_ticklen
))
385 /* Compression method [11]. */
386 /* SRP username [12]. */
388 *pp
= CBS_data(&cbs
);
396 ERR_asprintf_error_data("offset=%d", (int)(CBS_data(&cbs
) - *pp
));
398 if (s
!= NULL
&& (a
== NULL
|| *a
!= s
))