mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-29 04:21:26 +01:00
b077aed33b
Migrate to OpenSSL 3.0 in advance of FreeBSD 14.0. OpenSSL 1.1.1 (the version we were previously using) will be EOL as of 2023-09-11. Most of the base system has already been updated for a seamless switch to OpenSSL 3.0. For many components we've added `-DOPENSSL_API_COMPAT=0x10100000L` to CFLAGS to specify the API version, which avoids deprecation warnings from OpenSSL 3.0. Changes have also been made to avoid OpenSSL APIs that were already deprecated in OpenSSL 1.1.1. The process of updating to contemporary APIs can continue after this merge. Additional changes are still required for libarchive and Kerberos- related libraries or tools; workarounds will immediately follow this commit. Fixes are in progress in the upstream projects and will be incorporated when those are next updated. There are some performance regressions in benchmarks (certain tests in `openssl speed`) and in some OpenSSL consumers in ports (e.g. haproxy). Investigation will continue for these. Netflix's testing showed no functional regression and a rather small, albeit statistically significant, increase in CPU consumption with OpenSSL 3.0. Thanks to ngie@ and des@ for updating base system components, to antoine@ and bofh@ for ports exp-runs and port fixes/workarounds, and to Netflix and everyone who tested prior to commit or contributed to this update in other ways. PR: 271615 PR: 271656 [exp-run] Relnotes: Yes Sponsored by: The FreeBSD Foundation
401 lines
12 KiB
C
401 lines
12 KiB
C
/*
|
|
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
|
* Copyright 2005 Nokia. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
* in the file LICENSE in the source distribution or at
|
|
* https://www.openssl.org/source/license.html
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "ssl_local.h"
|
|
#include <openssl/asn1t.h>
|
|
#include <openssl/x509.h>
|
|
|
|
typedef struct {
|
|
uint32_t version;
|
|
int32_t ssl_version;
|
|
ASN1_OCTET_STRING *cipher;
|
|
ASN1_OCTET_STRING *comp_id;
|
|
ASN1_OCTET_STRING *master_key;
|
|
ASN1_OCTET_STRING *session_id;
|
|
ASN1_OCTET_STRING *key_arg;
|
|
int64_t time;
|
|
int64_t timeout;
|
|
X509 *peer;
|
|
ASN1_OCTET_STRING *session_id_context;
|
|
int32_t verify_result;
|
|
ASN1_OCTET_STRING *tlsext_hostname;
|
|
uint64_t tlsext_tick_lifetime_hint;
|
|
uint32_t tlsext_tick_age_add;
|
|
ASN1_OCTET_STRING *tlsext_tick;
|
|
#ifndef OPENSSL_NO_PSK
|
|
ASN1_OCTET_STRING *psk_identity_hint;
|
|
ASN1_OCTET_STRING *psk_identity;
|
|
#endif
|
|
#ifndef OPENSSL_NO_SRP
|
|
ASN1_OCTET_STRING *srp_username;
|
|
#endif
|
|
uint64_t flags;
|
|
uint32_t max_early_data;
|
|
ASN1_OCTET_STRING *alpn_selected;
|
|
uint32_t tlsext_max_fragment_len_mode;
|
|
ASN1_OCTET_STRING *ticket_appdata;
|
|
uint32_t kex_group;
|
|
} SSL_SESSION_ASN1;
|
|
|
|
ASN1_SEQUENCE(SSL_SESSION_ASN1) = {
|
|
ASN1_EMBED(SSL_SESSION_ASN1, version, UINT32),
|
|
ASN1_EMBED(SSL_SESSION_ASN1, ssl_version, INT32),
|
|
ASN1_SIMPLE(SSL_SESSION_ASN1, cipher, ASN1_OCTET_STRING),
|
|
ASN1_SIMPLE(SSL_SESSION_ASN1, session_id, ASN1_OCTET_STRING),
|
|
ASN1_SIMPLE(SSL_SESSION_ASN1, master_key, ASN1_OCTET_STRING),
|
|
ASN1_IMP_OPT(SSL_SESSION_ASN1, key_arg, ASN1_OCTET_STRING, 0),
|
|
ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, time, ZINT64, 1),
|
|
ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, timeout, ZINT64, 2),
|
|
ASN1_EXP_OPT(SSL_SESSION_ASN1, peer, X509, 3),
|
|
ASN1_EXP_OPT(SSL_SESSION_ASN1, session_id_context, ASN1_OCTET_STRING, 4),
|
|
ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, verify_result, ZINT32, 5),
|
|
ASN1_EXP_OPT(SSL_SESSION_ASN1, tlsext_hostname, ASN1_OCTET_STRING, 6),
|
|
#ifndef OPENSSL_NO_PSK
|
|
ASN1_EXP_OPT(SSL_SESSION_ASN1, psk_identity_hint, ASN1_OCTET_STRING, 7),
|
|
ASN1_EXP_OPT(SSL_SESSION_ASN1, psk_identity, ASN1_OCTET_STRING, 8),
|
|
#endif
|
|
ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, tlsext_tick_lifetime_hint, ZUINT64, 9),
|
|
ASN1_EXP_OPT(SSL_SESSION_ASN1, tlsext_tick, ASN1_OCTET_STRING, 10),
|
|
ASN1_EXP_OPT(SSL_SESSION_ASN1, comp_id, ASN1_OCTET_STRING, 11),
|
|
#ifndef OPENSSL_NO_SRP
|
|
ASN1_EXP_OPT(SSL_SESSION_ASN1, srp_username, ASN1_OCTET_STRING, 12),
|
|
#endif
|
|
ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, flags, ZUINT64, 13),
|
|
ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, tlsext_tick_age_add, ZUINT32, 14),
|
|
ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, max_early_data, ZUINT32, 15),
|
|
ASN1_EXP_OPT(SSL_SESSION_ASN1, alpn_selected, ASN1_OCTET_STRING, 16),
|
|
ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, tlsext_max_fragment_len_mode, ZUINT32, 17),
|
|
ASN1_EXP_OPT(SSL_SESSION_ASN1, ticket_appdata, ASN1_OCTET_STRING, 18),
|
|
ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, kex_group, UINT32, 19)
|
|
} static_ASN1_SEQUENCE_END(SSL_SESSION_ASN1)
|
|
|
|
IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(SSL_SESSION_ASN1)
|
|
|
|
/* Utility functions for i2d_SSL_SESSION */
|
|
|
|
/* Initialise OCTET STRING from buffer and length */
|
|
|
|
static void ssl_session_oinit(ASN1_OCTET_STRING **dest, ASN1_OCTET_STRING *os,
|
|
const unsigned char *data, size_t len)
|
|
{
|
|
os->data = (unsigned char *)data; /* justified cast: data is not modified */
|
|
os->length = (int)len;
|
|
os->flags = 0;
|
|
*dest = os;
|
|
}
|
|
|
|
/* Initialise OCTET STRING from string */
|
|
static void ssl_session_sinit(ASN1_OCTET_STRING **dest, ASN1_OCTET_STRING *os,
|
|
const char *data)
|
|
{
|
|
if (data != NULL)
|
|
ssl_session_oinit(dest, os, (const unsigned char *)data, strlen(data));
|
|
else
|
|
*dest = NULL;
|
|
}
|
|
|
|
int i2d_SSL_SESSION(const SSL_SESSION *in, unsigned char **pp)
|
|
{
|
|
|
|
SSL_SESSION_ASN1 as;
|
|
|
|
ASN1_OCTET_STRING cipher;
|
|
unsigned char cipher_data[2];
|
|
ASN1_OCTET_STRING master_key, session_id, sid_ctx;
|
|
|
|
#ifndef OPENSSL_NO_COMP
|
|
ASN1_OCTET_STRING comp_id;
|
|
unsigned char comp_id_data;
|
|
#endif
|
|
ASN1_OCTET_STRING tlsext_hostname, tlsext_tick;
|
|
#ifndef OPENSSL_NO_SRP
|
|
ASN1_OCTET_STRING srp_username;
|
|
#endif
|
|
#ifndef OPENSSL_NO_PSK
|
|
ASN1_OCTET_STRING psk_identity, psk_identity_hint;
|
|
#endif
|
|
ASN1_OCTET_STRING alpn_selected;
|
|
ASN1_OCTET_STRING ticket_appdata;
|
|
|
|
long l;
|
|
|
|
if ((in == NULL) || ((in->cipher == NULL) && (in->cipher_id == 0)))
|
|
return 0;
|
|
|
|
memset(&as, 0, sizeof(as));
|
|
|
|
as.version = SSL_SESSION_ASN1_VERSION;
|
|
as.ssl_version = in->ssl_version;
|
|
|
|
as.kex_group = in->kex_group;
|
|
|
|
if (in->cipher == NULL)
|
|
l = in->cipher_id;
|
|
else
|
|
l = in->cipher->id;
|
|
cipher_data[0] = ((unsigned char)(l >> 8L)) & 0xff;
|
|
cipher_data[1] = ((unsigned char)(l)) & 0xff;
|
|
|
|
ssl_session_oinit(&as.cipher, &cipher, cipher_data, 2);
|
|
|
|
#ifndef OPENSSL_NO_COMP
|
|
if (in->compress_meth) {
|
|
comp_id_data = (unsigned char)in->compress_meth;
|
|
ssl_session_oinit(&as.comp_id, &comp_id, &comp_id_data, 1);
|
|
}
|
|
#endif
|
|
|
|
ssl_session_oinit(&as.master_key, &master_key,
|
|
in->master_key, in->master_key_length);
|
|
|
|
ssl_session_oinit(&as.session_id, &session_id,
|
|
in->session_id, in->session_id_length);
|
|
|
|
ssl_session_oinit(&as.session_id_context, &sid_ctx,
|
|
in->sid_ctx, in->sid_ctx_length);
|
|
|
|
as.time = (int64_t)in->time;
|
|
as.timeout = (int64_t)in->timeout;
|
|
as.verify_result = in->verify_result;
|
|
|
|
as.peer = in->peer;
|
|
|
|
ssl_session_sinit(&as.tlsext_hostname, &tlsext_hostname,
|
|
in->ext.hostname);
|
|
if (in->ext.tick) {
|
|
ssl_session_oinit(&as.tlsext_tick, &tlsext_tick,
|
|
in->ext.tick, in->ext.ticklen);
|
|
}
|
|
if (in->ext.tick_lifetime_hint > 0)
|
|
as.tlsext_tick_lifetime_hint = in->ext.tick_lifetime_hint;
|
|
as.tlsext_tick_age_add = in->ext.tick_age_add;
|
|
#ifndef OPENSSL_NO_PSK
|
|
ssl_session_sinit(&as.psk_identity_hint, &psk_identity_hint,
|
|
in->psk_identity_hint);
|
|
ssl_session_sinit(&as.psk_identity, &psk_identity, in->psk_identity);
|
|
#endif /* OPENSSL_NO_PSK */
|
|
#ifndef OPENSSL_NO_SRP
|
|
ssl_session_sinit(&as.srp_username, &srp_username, in->srp_username);
|
|
#endif /* OPENSSL_NO_SRP */
|
|
|
|
as.flags = in->flags;
|
|
as.max_early_data = in->ext.max_early_data;
|
|
|
|
if (in->ext.alpn_selected == NULL)
|
|
as.alpn_selected = NULL;
|
|
else
|
|
ssl_session_oinit(&as.alpn_selected, &alpn_selected,
|
|
in->ext.alpn_selected, in->ext.alpn_selected_len);
|
|
|
|
as.tlsext_max_fragment_len_mode = in->ext.max_fragment_len_mode;
|
|
|
|
if (in->ticket_appdata == NULL)
|
|
as.ticket_appdata = NULL;
|
|
else
|
|
ssl_session_oinit(&as.ticket_appdata, &ticket_appdata,
|
|
in->ticket_appdata, in->ticket_appdata_len);
|
|
|
|
return i2d_SSL_SESSION_ASN1(&as, pp);
|
|
|
|
}
|
|
|
|
/* Utility functions for d2i_SSL_SESSION */
|
|
|
|
/* OPENSSL_strndup an OCTET STRING */
|
|
|
|
static int ssl_session_strndup(char **pdst, ASN1_OCTET_STRING *src)
|
|
{
|
|
OPENSSL_free(*pdst);
|
|
*pdst = NULL;
|
|
if (src == NULL)
|
|
return 1;
|
|
*pdst = OPENSSL_strndup((char *)src->data, src->length);
|
|
if (*pdst == NULL)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/* Copy an OCTET STRING, return error if it exceeds maximum length */
|
|
|
|
static int ssl_session_memcpy(unsigned char *dst, size_t *pdstlen,
|
|
ASN1_OCTET_STRING *src, size_t maxlen)
|
|
{
|
|
if (src == NULL || src->length == 0) {
|
|
*pdstlen = 0;
|
|
return 1;
|
|
}
|
|
if (src->length < 0 || src->length > (int)maxlen)
|
|
return 0;
|
|
memcpy(dst, src->data, src->length);
|
|
*pdstlen = src->length;
|
|
return 1;
|
|
}
|
|
|
|
SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
|
|
long length)
|
|
{
|
|
long id;
|
|
size_t tmpl;
|
|
const unsigned char *p = *pp;
|
|
SSL_SESSION_ASN1 *as = NULL;
|
|
SSL_SESSION *ret = NULL;
|
|
|
|
as = d2i_SSL_SESSION_ASN1(NULL, &p, length);
|
|
/* ASN.1 code returns suitable error */
|
|
if (as == NULL)
|
|
goto err;
|
|
|
|
if (a == NULL || *a == NULL) {
|
|
ret = SSL_SESSION_new();
|
|
if (ret == NULL)
|
|
goto err;
|
|
} else {
|
|
ret = *a;
|
|
}
|
|
|
|
if (as->version != SSL_SESSION_ASN1_VERSION) {
|
|
ERR_raise(ERR_LIB_SSL, SSL_R_UNKNOWN_SSL_VERSION);
|
|
goto err;
|
|
}
|
|
|
|
if ((as->ssl_version >> 8) != SSL3_VERSION_MAJOR
|
|
&& (as->ssl_version >> 8) != DTLS1_VERSION_MAJOR
|
|
&& as->ssl_version != DTLS1_BAD_VER) {
|
|
ERR_raise(ERR_LIB_SSL, SSL_R_UNSUPPORTED_SSL_VERSION);
|
|
goto err;
|
|
}
|
|
|
|
ret->ssl_version = (int)as->ssl_version;
|
|
|
|
ret->kex_group = as->kex_group;
|
|
|
|
if (as->cipher->length != 2) {
|
|
ERR_raise(ERR_LIB_SSL, SSL_R_CIPHER_CODE_WRONG_LENGTH);
|
|
goto err;
|
|
}
|
|
|
|
id = 0x03000000L | ((unsigned long)as->cipher->data[0] << 8L)
|
|
| (unsigned long)as->cipher->data[1];
|
|
|
|
ret->cipher_id = id;
|
|
ret->cipher = ssl3_get_cipher_by_id(id);
|
|
if (ret->cipher == NULL)
|
|
goto err;
|
|
|
|
if (!ssl_session_memcpy(ret->session_id, &ret->session_id_length,
|
|
as->session_id, SSL3_MAX_SSL_SESSION_ID_LENGTH))
|
|
goto err;
|
|
|
|
if (!ssl_session_memcpy(ret->master_key, &tmpl,
|
|
as->master_key, TLS13_MAX_RESUMPTION_PSK_LENGTH))
|
|
goto err;
|
|
|
|
ret->master_key_length = tmpl;
|
|
|
|
if (as->time != 0)
|
|
ret->time = (time_t)as->time;
|
|
else
|
|
ret->time = time(NULL);
|
|
|
|
if (as->timeout != 0)
|
|
ret->timeout = (time_t)as->timeout;
|
|
else
|
|
ret->timeout = 3;
|
|
ssl_session_calculate_timeout(ret);
|
|
|
|
X509_free(ret->peer);
|
|
ret->peer = as->peer;
|
|
as->peer = NULL;
|
|
|
|
if (!ssl_session_memcpy(ret->sid_ctx, &ret->sid_ctx_length,
|
|
as->session_id_context, SSL_MAX_SID_CTX_LENGTH))
|
|
goto err;
|
|
|
|
/* NB: this defaults to zero which is X509_V_OK */
|
|
ret->verify_result = as->verify_result;
|
|
|
|
if (!ssl_session_strndup(&ret->ext.hostname, as->tlsext_hostname))
|
|
goto err;
|
|
|
|
#ifndef OPENSSL_NO_PSK
|
|
if (!ssl_session_strndup(&ret->psk_identity_hint, as->psk_identity_hint))
|
|
goto err;
|
|
if (!ssl_session_strndup(&ret->psk_identity, as->psk_identity))
|
|
goto err;
|
|
#endif
|
|
|
|
ret->ext.tick_lifetime_hint = (unsigned long)as->tlsext_tick_lifetime_hint;
|
|
ret->ext.tick_age_add = as->tlsext_tick_age_add;
|
|
OPENSSL_free(ret->ext.tick);
|
|
if (as->tlsext_tick != NULL) {
|
|
ret->ext.tick = as->tlsext_tick->data;
|
|
ret->ext.ticklen = as->tlsext_tick->length;
|
|
as->tlsext_tick->data = NULL;
|
|
} else {
|
|
ret->ext.tick = NULL;
|
|
}
|
|
#ifndef OPENSSL_NO_COMP
|
|
if (as->comp_id) {
|
|
if (as->comp_id->length != 1) {
|
|
ERR_raise(ERR_LIB_SSL, SSL_R_BAD_LENGTH);
|
|
goto err;
|
|
}
|
|
ret->compress_meth = as->comp_id->data[0];
|
|
} else {
|
|
ret->compress_meth = 0;
|
|
}
|
|
#endif
|
|
|
|
#ifndef OPENSSL_NO_SRP
|
|
if (!ssl_session_strndup(&ret->srp_username, as->srp_username))
|
|
goto err;
|
|
#endif /* OPENSSL_NO_SRP */
|
|
/* Flags defaults to zero which is fine */
|
|
ret->flags = (int32_t)as->flags;
|
|
ret->ext.max_early_data = as->max_early_data;
|
|
|
|
OPENSSL_free(ret->ext.alpn_selected);
|
|
if (as->alpn_selected != NULL) {
|
|
ret->ext.alpn_selected = as->alpn_selected->data;
|
|
ret->ext.alpn_selected_len = as->alpn_selected->length;
|
|
as->alpn_selected->data = NULL;
|
|
} else {
|
|
ret->ext.alpn_selected = NULL;
|
|
ret->ext.alpn_selected_len = 0;
|
|
}
|
|
|
|
ret->ext.max_fragment_len_mode = as->tlsext_max_fragment_len_mode;
|
|
|
|
OPENSSL_free(ret->ticket_appdata);
|
|
if (as->ticket_appdata != NULL) {
|
|
ret->ticket_appdata = as->ticket_appdata->data;
|
|
ret->ticket_appdata_len = as->ticket_appdata->length;
|
|
as->ticket_appdata->data = NULL;
|
|
} else {
|
|
ret->ticket_appdata = NULL;
|
|
ret->ticket_appdata_len = 0;
|
|
}
|
|
|
|
M_ASN1_free_of(as, SSL_SESSION_ASN1);
|
|
|
|
if ((a != NULL) && (*a == NULL))
|
|
*a = ret;
|
|
*pp = p;
|
|
return ret;
|
|
|
|
err:
|
|
M_ASN1_free_of(as, SSL_SESSION_ASN1);
|
|
if ((a == NULL) || (*a != ret))
|
|
SSL_SESSION_free(ret);
|
|
return NULL;
|
|
}
|