xref: /openbsd-src/lib/libssl/ssl_asn1.c (revision f4fe6251b363bc47c99c75caa60c829516bf905e)
1*f4fe6251Sjsing /* $OpenBSD: ssl_asn1.c,v 1.69 2024/07/22 14:47:15 jsing Exp $ */
24840f750Sjsing /*
34840f750Sjsing  * Copyright (c) 2016 Joel Sing <jsing@openbsd.org>
45b37fcf3Sryker  *
54840f750Sjsing  * Permission to use, copy, modify, and distribute this software for any
64840f750Sjsing  * purpose with or without fee is hereby granted, provided that the above
74840f750Sjsing  * copyright notice and this permission notice appear in all copies.
85b37fcf3Sryker  *
94840f750Sjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
104840f750Sjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
114840f750Sjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
124840f750Sjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
134840f750Sjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
144840f750Sjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
154840f750Sjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
165b37fcf3Sryker  */
175b37fcf3Sryker 
184840f750Sjsing #include <limits.h>
194840f750Sjsing 
204840f750Sjsing #include <openssl/ssl.h>
214840f750Sjsing #include <openssl/x509.h>
2219017dcfSjsing 
234840f750Sjsing #include "bytestring.h"
24c9675a23Stb #include "ssl_local.h"
255b37fcf3Sryker 
264840f750Sjsing #define SSLASN1_TAG	(CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC)
274840f750Sjsing #define SSLASN1_TIME_TAG		(SSLASN1_TAG | 1)
284840f750Sjsing #define SSLASN1_TIMEOUT_TAG		(SSLASN1_TAG | 2)
294840f750Sjsing #define SSLASN1_PEER_CERT_TAG		(SSLASN1_TAG | 3)
304840f750Sjsing #define SSLASN1_SESSION_ID_CTX_TAG	(SSLASN1_TAG | 4)
314840f750Sjsing #define SSLASN1_VERIFY_RESULT_TAG	(SSLASN1_TAG | 5)
324840f750Sjsing #define SSLASN1_HOSTNAME_TAG		(SSLASN1_TAG | 6)
334840f750Sjsing #define SSLASN1_LIFETIME_TAG		(SSLASN1_TAG | 9)
344840f750Sjsing #define SSLASN1_TICKET_TAG		(SSLASN1_TAG | 10)
35277613e9Sjsing 
364840f750Sjsing static uint64_t
374840f750Sjsing time_max(void)
384840f750Sjsing {
394840f750Sjsing 	if (sizeof(time_t) == sizeof(int32_t))
404840f750Sjsing 		return INT32_MAX;
414840f750Sjsing 	if (sizeof(time_t) == sizeof(int64_t))
424840f750Sjsing 		return INT64_MAX;
434840f750Sjsing 	return 0;
444840f750Sjsing }
455b37fcf3Sryker 
4612fe7be0Sjsing static int
4712fe7be0Sjsing SSL_SESSION_encode(SSL_SESSION *s, unsigned char **out, size_t *out_len,
4812fe7be0Sjsing     int ticket_encoding)
495b37fcf3Sryker {
504840f750Sjsing 	CBB cbb, session, cipher_suite, session_id, master_key, time, timeout;
5112fe7be0Sjsing 	CBB peer_cert, sidctx, verify_result, hostname, lifetime, ticket, value;
5212fe7be0Sjsing 	unsigned char *peer_cert_bytes = NULL;
5312fe7be0Sjsing 	int len, rv = 0;
545b37fcf3Sryker 
554840f750Sjsing 	if (!CBB_init(&cbb, 0))
564840f750Sjsing 		goto err;
575b37fcf3Sryker 
584840f750Sjsing 	if (!CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE))
594840f750Sjsing 		goto err;
605b37fcf3Sryker 
614840f750Sjsing 	/* Session ASN1 version. */
624840f750Sjsing 	if (!CBB_add_asn1_uint64(&session, SSL_SESSION_ASN1_VERSION))
634840f750Sjsing 		goto err;
645b37fcf3Sryker 
654840f750Sjsing 	/* TLS/SSL protocol version. */
664840f750Sjsing 	if (s->ssl_version < 0)
674840f750Sjsing 		goto err;
684840f750Sjsing 	if (!CBB_add_asn1_uint64(&session, s->ssl_version))
694840f750Sjsing 		goto err;
70913ec974Sbeck 
71*f4fe6251Sjsing 	/* Cipher suite value. */
724840f750Sjsing 	if (!CBB_add_asn1(&session, &cipher_suite, CBS_ASN1_OCTETSTRING))
734840f750Sjsing 		goto err;
74*f4fe6251Sjsing 	if (!CBB_add_u16(&cipher_suite, s->cipher_value))
754840f750Sjsing 		goto err;
764840f750Sjsing 
7712fe7be0Sjsing 	/* Session ID - zero length for a ticket. */
784840f750Sjsing 	if (!CBB_add_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING))
794840f750Sjsing 		goto err;
8012fe7be0Sjsing 	if (!CBB_add_bytes(&session_id, s->session_id,
8112fe7be0Sjsing 	    ticket_encoding ? 0 : s->session_id_length))
824840f750Sjsing 		goto err;
834840f750Sjsing 
844840f750Sjsing 	/* Master key. */
854840f750Sjsing 	if (!CBB_add_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING))
864840f750Sjsing 		goto err;
874840f750Sjsing 	if (!CBB_add_bytes(&master_key, s->master_key, s->master_key_length))
884840f750Sjsing 		goto err;
894840f750Sjsing 
904840f750Sjsing 	/* Time [1]. */
914840f750Sjsing 	if (s->time != 0) {
924840f750Sjsing 		if (s->time < 0)
934840f750Sjsing 			goto err;
944840f750Sjsing 		if (!CBB_add_asn1(&session, &time, SSLASN1_TIME_TAG))
954840f750Sjsing 			goto err;
964840f750Sjsing 		if (!CBB_add_asn1_uint64(&time, s->time))
974840f750Sjsing 			goto err;
985b37fcf3Sryker 	}
995b37fcf3Sryker 
1004840f750Sjsing 	/* Timeout [2]. */
1014840f750Sjsing 	if (s->timeout != 0) {
1024840f750Sjsing 		if (s->timeout < 0)
1034840f750Sjsing 			goto err;
1044840f750Sjsing 		if (!CBB_add_asn1(&session, &timeout, SSLASN1_TIMEOUT_TAG))
1054840f750Sjsing 			goto err;
1064840f750Sjsing 		if (!CBB_add_asn1_uint64(&timeout, s->timeout))
1074840f750Sjsing 			goto err;
1085b37fcf3Sryker 	}
1095b37fcf3Sryker 
1104840f750Sjsing 	/* Peer certificate [3]. */
111666c9986Sjsing 	if (s->peer_cert != NULL) {
112666c9986Sjsing 		if ((len = i2d_X509(s->peer_cert, &peer_cert_bytes)) <= 0)
1134840f750Sjsing 			goto err;
1142a0c2d29Sjsing 		if (!CBB_add_asn1(&session, &peer_cert, SSLASN1_PEER_CERT_TAG))
1152a0c2d29Sjsing 			goto err;
1162a0c2d29Sjsing 		if (!CBB_add_bytes(&peer_cert, peer_cert_bytes, len))
1174840f750Sjsing 			goto err;
11871d15c93Sjsing 	}
11971d15c93Sjsing 
1204840f750Sjsing 	/* Session ID context [4]. */
1214840f750Sjsing 	/* XXX - Actually handle this as optional? */
1224840f750Sjsing 	if (!CBB_add_asn1(&session, &sidctx, SSLASN1_SESSION_ID_CTX_TAG))
1234840f750Sjsing 		goto err;
1244840f750Sjsing 	if (!CBB_add_asn1(&sidctx, &value, CBS_ASN1_OCTETSTRING))
1254840f750Sjsing 		goto err;
1264840f750Sjsing 	if (!CBB_add_bytes(&value, s->sid_ctx, s->sid_ctx_length))
1274840f750Sjsing 		goto err;
12871d15c93Sjsing 
1294840f750Sjsing 	/* Verify result [5]. */
1304840f750Sjsing 	if (s->verify_result != X509_V_OK) {
1314840f750Sjsing 		if (s->verify_result < 0)
1324840f750Sjsing 			goto err;
1334840f750Sjsing 		if (!CBB_add_asn1(&session, &verify_result,
1344840f750Sjsing 		    SSLASN1_VERIFY_RESULT_TAG))
1354840f750Sjsing 			goto err;
1364840f750Sjsing 		if (!CBB_add_asn1_uint64(&verify_result, s->verify_result))
1374840f750Sjsing 			goto err;
138ba5406e9Sbeck 	}
139ba5406e9Sbeck 
1404840f750Sjsing 	/* Hostname [6]. */
1414840f750Sjsing 	if (s->tlsext_hostname != NULL) {
1424840f750Sjsing 		if (!CBB_add_asn1(&session, &hostname, SSLASN1_HOSTNAME_TAG))
1434840f750Sjsing 			goto err;
1444840f750Sjsing 		if (!CBB_add_asn1(&hostname, &value, CBS_ASN1_OCTETSTRING))
1454840f750Sjsing 			goto err;
146bc99fb9aSjsing 		if (!CBB_add_bytes(&value, (const uint8_t *)s->tlsext_hostname,
1474840f750Sjsing 		    strlen(s->tlsext_hostname)))
1484840f750Sjsing 			goto err;
1494fcf65c5Sdjm 	}
15071d15c93Sjsing 
1514840f750Sjsing 	/* PSK identity hint [7]. */
1524840f750Sjsing 	/* PSK identity [8]. */
15371d15c93Sjsing 
1544840f750Sjsing 	/* Ticket lifetime hint [9]. */
1554840f750Sjsing 	if (s->tlsext_tick_lifetime_hint > 0) {
1564840f750Sjsing 		if (!CBB_add_asn1(&session, &lifetime, SSLASN1_LIFETIME_TAG))
1574840f750Sjsing 			goto err;
1584840f750Sjsing 		if (!CBB_add_asn1_uint64(&lifetime,
1594840f750Sjsing 		    s->tlsext_tick_lifetime_hint))
1604840f750Sjsing 			goto err;
1614fcf65c5Sdjm 	}
1620a5d6edeSdjm 
1634840f750Sjsing 	/* Ticket [10]. */
16412fe7be0Sjsing 	if (s->tlsext_tick != NULL) {
1654840f750Sjsing 		if (!CBB_add_asn1(&session, &ticket, SSLASN1_TICKET_TAG))
1664840f750Sjsing 			goto err;
1674840f750Sjsing 		if (!CBB_add_asn1(&ticket, &value, CBS_ASN1_OCTETSTRING))
1684840f750Sjsing 			goto err;
1694840f750Sjsing 		if (!CBB_add_bytes(&value, s->tlsext_tick, s->tlsext_ticklen))
1704840f750Sjsing 			goto err;
17171d15c93Sjsing 	}
17219017dcfSjsing 
1734840f750Sjsing 	/* Compression method [11]. */
1744840f750Sjsing 	/* SRP username [12]. */
1750a5d6edeSdjm 
17612fe7be0Sjsing 	if (!CBB_finish(&cbb, out, out_len))
17712fe7be0Sjsing 		goto err;
17812fe7be0Sjsing 
17912fe7be0Sjsing 	rv = 1;
18012fe7be0Sjsing 
18112fe7be0Sjsing  err:
18212fe7be0Sjsing 	CBB_cleanup(&cbb);
18312fe7be0Sjsing 	free(peer_cert_bytes);
18412fe7be0Sjsing 
18512fe7be0Sjsing 	return rv;
18612fe7be0Sjsing }
18712fe7be0Sjsing 
18812fe7be0Sjsing int
18912fe7be0Sjsing SSL_SESSION_ticket(SSL_SESSION *ss, unsigned char **out, size_t *out_len)
19012fe7be0Sjsing {
19112fe7be0Sjsing 	if (ss == NULL)
19212fe7be0Sjsing 		return 0;
19312fe7be0Sjsing 
194*f4fe6251Sjsing 	if (ss->cipher_value == 0)
19512fe7be0Sjsing 		return 0;
19612fe7be0Sjsing 
19712fe7be0Sjsing 	return SSL_SESSION_encode(ss, out, out_len, 1);
19812fe7be0Sjsing }
19912fe7be0Sjsing 
20012fe7be0Sjsing int
20112fe7be0Sjsing i2d_SSL_SESSION(SSL_SESSION *ss, unsigned char **pp)
20212fe7be0Sjsing {
20312fe7be0Sjsing 	unsigned char *data = NULL;
20412fe7be0Sjsing 	size_t data_len = 0;
20512fe7be0Sjsing 	int rv = -1;
20612fe7be0Sjsing 
20712fe7be0Sjsing 	if (ss == NULL)
20812fe7be0Sjsing 		return 0;
20912fe7be0Sjsing 
210*f4fe6251Sjsing 	if (ss->cipher_value == 0)
21112fe7be0Sjsing 		return 0;
21212fe7be0Sjsing 
21312fe7be0Sjsing 	if (!SSL_SESSION_encode(ss, &data, &data_len, 0))
2144840f750Sjsing 		goto err;
2155b37fcf3Sryker 
2164840f750Sjsing 	if (data_len > INT_MAX)
2174840f750Sjsing 		goto err;
21819017dcfSjsing 
2194840f750Sjsing 	if (pp != NULL) {
2204840f750Sjsing 		if (*pp == NULL) {
2214840f750Sjsing 			*pp = data;
2224840f750Sjsing 			data = NULL;
2234840f750Sjsing 		} else {
2244840f750Sjsing 			memcpy(*pp, data, data_len);
225661c9ff0Sjsing 			*pp += data_len;
2264840f750Sjsing 		}
2274840f750Sjsing 	}
2284840f750Sjsing 
2294840f750Sjsing 	rv = (int)data_len;
2304840f750Sjsing 
2314840f750Sjsing  err:
232fc714125Sjsing 	freezero(data, data_len);
2334840f750Sjsing 
2344840f750Sjsing 	return rv;
2355b37fcf3Sryker }
23671e04849Sbeck LSSL_ALIAS(i2d_SSL_SESSION);
2375b37fcf3Sryker 
238dbea66cdSguenther SSL_SESSION *
239dbea66cdSguenther d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, long length)
2405b37fcf3Sryker {
2414840f750Sjsing 	CBS cbs, session, cipher_suite, session_id, master_key, peer_cert;
2424840f750Sjsing 	CBS hostname, ticket;
2434840f750Sjsing 	uint64_t version, tls_version, stime, timeout, verify_result, lifetime;
2444840f750Sjsing 	const unsigned char *peer_cert_bytes;
2454840f750Sjsing 	SSL_SESSION *s = NULL;
2464840f750Sjsing 	size_t data_len;
2474840f750Sjsing 	int present;
248277613e9Sjsing 
249277613e9Sjsing 	if (a != NULL)
2504840f750Sjsing 		s = *a;
251277613e9Sjsing 
2524840f750Sjsing 	if (s == NULL) {
2534840f750Sjsing 		if ((s = SSL_SESSION_new()) == NULL) {
254c9d7abb7Sbeck 			SSLerrorx(ERR_R_MALLOC_FAILURE);
255b084c069Smiod 			return (NULL);
2564840f750Sjsing 		}
2574840f750Sjsing 	}
2584840f750Sjsing 
2594840f750Sjsing 	CBS_init(&cbs, *pp, length);
2604840f750Sjsing 
2614840f750Sjsing 	if (!CBS_get_asn1(&cbs, &session, CBS_ASN1_SEQUENCE))
2624840f750Sjsing 		goto err;
2634840f750Sjsing 
2644840f750Sjsing 	/* Session ASN1 version. */
2654840f750Sjsing 	if (!CBS_get_asn1_uint64(&session, &version))
2664840f750Sjsing 		goto err;
2674840f750Sjsing 	if (version != SSL_SESSION_ASN1_VERSION)
2684840f750Sjsing 		goto err;
2694840f750Sjsing 
2704840f750Sjsing 	/* TLS/SSL Protocol Version. */
2714840f750Sjsing 	if (!CBS_get_asn1_uint64(&session, &tls_version))
2724840f750Sjsing 		goto err;
2734840f750Sjsing 	if (tls_version > INT_MAX)
2744840f750Sjsing 		goto err;
2754840f750Sjsing 	s->ssl_version = (int)tls_version;
2764840f750Sjsing 
277*f4fe6251Sjsing 	/* Cipher suite value. */
2784840f750Sjsing 	if (!CBS_get_asn1(&session, &cipher_suite, CBS_ASN1_OCTETSTRING))
2794840f750Sjsing 		goto err;
280*f4fe6251Sjsing 	if (!CBS_get_u16(&cipher_suite, &s->cipher_value))
2814840f750Sjsing 		goto err;
2824840f750Sjsing 	if (CBS_len(&cipher_suite) != 0)
2834840f750Sjsing 		goto err;
2844840f750Sjsing 
2854840f750Sjsing 	/* Session ID. */
2864840f750Sjsing 	if (!CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING))
2874840f750Sjsing 		goto err;
2884840f750Sjsing 	if (!CBS_write_bytes(&session_id, s->session_id, sizeof(s->session_id),
289ef6795cfStb 	    &s->session_id_length))
2904840f750Sjsing 		goto err;
2914840f750Sjsing 
2924840f750Sjsing 	/* Master key. */
2934840f750Sjsing 	if (!CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING))
2944840f750Sjsing 		goto err;
2954840f750Sjsing 	if (!CBS_write_bytes(&master_key, s->master_key, sizeof(s->master_key),
29685792bddStb 	    &s->master_key_length))
2974840f750Sjsing 		goto err;
2984840f750Sjsing 
2994840f750Sjsing 	/* Time [1]. */
3004840f750Sjsing 	s->time = time(NULL);
3014840f750Sjsing 	if (!CBS_get_optional_asn1_uint64(&session, &stime, SSLASN1_TIME_TAG,
3024840f750Sjsing 	    0))
3034840f750Sjsing 		goto err;
3044840f750Sjsing 	if (stime > time_max())
3054840f750Sjsing 		goto err;
3064840f750Sjsing 	if (stime != 0)
3074840f750Sjsing 		s->time = (time_t)stime;
3084840f750Sjsing 
3094840f750Sjsing 	/* Timeout [2]. */
3104840f750Sjsing 	s->timeout = 3;
3114840f750Sjsing 	if (!CBS_get_optional_asn1_uint64(&session, &timeout,
3124840f750Sjsing 	    SSLASN1_TIMEOUT_TAG, 0))
3134840f750Sjsing 		goto err;
3144840f750Sjsing 	if (timeout > LONG_MAX)
3154840f750Sjsing 		goto err;
3164840f750Sjsing 	if (timeout != 0)
3174840f750Sjsing 		s->timeout = (long)timeout;
3184840f750Sjsing 
3194840f750Sjsing 	/* Peer certificate [3]. */
320666c9986Sjsing 	X509_free(s->peer_cert);
321666c9986Sjsing 	s->peer_cert = NULL;
3222a0c2d29Sjsing 	if (!CBS_get_optional_asn1(&session, &peer_cert, &present,
3234840f750Sjsing 	    SSLASN1_PEER_CERT_TAG))
3244840f750Sjsing 		goto err;
3254840f750Sjsing 	if (present) {
3264840f750Sjsing 		data_len = CBS_len(&peer_cert);
3274840f750Sjsing 		if (data_len > LONG_MAX)
3284840f750Sjsing 			goto err;
3294840f750Sjsing 		peer_cert_bytes = CBS_data(&peer_cert);
330666c9986Sjsing 		if (d2i_X509(&s->peer_cert, &peer_cert_bytes,
3314840f750Sjsing 		    (long)data_len) == NULL)
3324840f750Sjsing 			goto err;
3334840f750Sjsing 	}
3344840f750Sjsing 
3354840f750Sjsing 	/* Session ID context [4]. */
3364840f750Sjsing 	s->sid_ctx_length = 0;
3374840f750Sjsing 	if (!CBS_get_optional_asn1_octet_string(&session, &session_id, &present,
3384840f750Sjsing 	    SSLASN1_SESSION_ID_CTX_TAG))
3394840f750Sjsing 		goto err;
3404840f750Sjsing 	if (present) {
3414840f750Sjsing 		if (!CBS_write_bytes(&session_id, (uint8_t *)&s->sid_ctx,
342b0272491Stb 		    sizeof(s->sid_ctx), &s->sid_ctx_length))
3434840f750Sjsing 			goto err;
3444840f750Sjsing 	}
3454840f750Sjsing 
3464840f750Sjsing 	/* Verify result [5]. */
3474840f750Sjsing 	s->verify_result = X509_V_OK;
3484840f750Sjsing 	if (!CBS_get_optional_asn1_uint64(&session, &verify_result,
3494840f750Sjsing 	    SSLASN1_VERIFY_RESULT_TAG, X509_V_OK))
3504840f750Sjsing 		goto err;
3514840f750Sjsing 	if (verify_result > LONG_MAX)
3524840f750Sjsing 		goto err;
3534840f750Sjsing 	s->verify_result = (long)verify_result;
3544840f750Sjsing 
3554840f750Sjsing 	/* Hostname [6]. */
3564840f750Sjsing 	free(s->tlsext_hostname);
3574840f750Sjsing 	s->tlsext_hostname = NULL;
3584840f750Sjsing 	if (!CBS_get_optional_asn1_octet_string(&session, &hostname, &present,
3594840f750Sjsing 	    SSLASN1_HOSTNAME_TAG))
3604840f750Sjsing 		goto err;
3614840f750Sjsing 	if (present) {
3624840f750Sjsing 		if (CBS_contains_zero_byte(&hostname))
3634840f750Sjsing 			goto err;
3644840f750Sjsing 		if (!CBS_strdup(&hostname, &s->tlsext_hostname))
3654840f750Sjsing 			goto err;
3664840f750Sjsing 	}
3674840f750Sjsing 
3684840f750Sjsing 	/* PSK identity hint [7]. */
3694840f750Sjsing 	/* PSK identity [8]. */
3704840f750Sjsing 
3714840f750Sjsing 	/* Ticket lifetime [9]. */
3724840f750Sjsing 	s->tlsext_tick_lifetime_hint = 0;
3734840f750Sjsing 	if (!CBS_get_optional_asn1_uint64(&session, &lifetime,
3744840f750Sjsing 	    SSLASN1_LIFETIME_TAG, 0))
3754840f750Sjsing 		goto err;
37618631d23Sjsing 	if (lifetime > UINT32_MAX)
3774840f750Sjsing 		goto err;
3784840f750Sjsing 	if (lifetime > 0)
37918631d23Sjsing 		s->tlsext_tick_lifetime_hint = (uint32_t)lifetime;
3804840f750Sjsing 
3814840f750Sjsing 	/* Ticket [10]. */
3824840f750Sjsing 	free(s->tlsext_tick);
3834840f750Sjsing 	s->tlsext_tick = NULL;
3844840f750Sjsing 	if (!CBS_get_optional_asn1_octet_string(&session, &ticket, &present,
3854840f750Sjsing 	    SSLASN1_TICKET_TAG))
3864840f750Sjsing 		goto err;
3874840f750Sjsing 	if (present) {
3884840f750Sjsing 		if (!CBS_stow(&ticket, &s->tlsext_tick, &s->tlsext_ticklen))
3894840f750Sjsing 			goto err;
3904840f750Sjsing 	}
3914840f750Sjsing 
3924840f750Sjsing 	/* Compression method [11]. */
3934840f750Sjsing 	/* SRP username [12]. */
3944840f750Sjsing 
3954840f750Sjsing 	*pp = CBS_data(&cbs);
3964840f750Sjsing 
3974840f750Sjsing 	if (a != NULL)
3984840f750Sjsing 		*a = s;
3994840f750Sjsing 
4004840f750Sjsing 	return (s);
401277613e9Sjsing 
402277613e9Sjsing  err:
4034840f750Sjsing 	ERR_asprintf_error_data("offset=%d", (int)(CBS_data(&cbs) - *pp));
4044840f750Sjsing 
4054840f750Sjsing 	if (s != NULL && (a == NULL || *a != s))
4064840f750Sjsing 		SSL_SESSION_free(s);
407277613e9Sjsing 
408277613e9Sjsing 	return (NULL);
4095b37fcf3Sryker }
41071e04849Sbeck LSSL_ALIAS(d2i_SSL_SESSION);
411