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