6006 lines
167 KiB
C
6006 lines
167 KiB
C
/*
|
|
* Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
|
|
* Copyright (c) 2002, Oracle and/or its affiliates. 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
|
|
*/
|
|
|
|
/* We need to use some engine deprecated APIs */
|
|
#define OPENSSL_SUPPRESS_DEPRECATED
|
|
|
|
#include <stdio.h>
|
|
#include "ssl_local.h"
|
|
#include "e_os.h"
|
|
#include <openssl/objects.h>
|
|
#include <openssl/x509v3.h>
|
|
#include <openssl/rand.h>
|
|
#include <openssl/ocsp.h>
|
|
#include <openssl/dh.h>
|
|
#include <openssl/engine.h>
|
|
#include <openssl/async.h>
|
|
#include <openssl/ct.h>
|
|
#include <openssl/trace.h>
|
|
#include "internal/cryptlib.h"
|
|
#include "internal/refcount.h"
|
|
#include "internal/ktls.h"
|
|
|
|
DEFINE_STACK_OF(SCT)
|
|
|
|
static int ssl_undefined_function_1(SSL *ssl, SSL3_RECORD *r, size_t s, int t,
|
|
SSL_MAC_BUF *mac, size_t macsize)
|
|
{
|
|
return ssl_undefined_function(ssl);
|
|
}
|
|
|
|
static int ssl_undefined_function_2(SSL *ssl, SSL3_RECORD *r, unsigned char *s,
|
|
int t)
|
|
{
|
|
return ssl_undefined_function(ssl);
|
|
}
|
|
|
|
static int ssl_undefined_function_3(SSL *ssl, unsigned char *r,
|
|
unsigned char *s, size_t t, size_t *u)
|
|
{
|
|
return ssl_undefined_function(ssl);
|
|
}
|
|
|
|
static int ssl_undefined_function_4(SSL *ssl, int r)
|
|
{
|
|
return ssl_undefined_function(ssl);
|
|
}
|
|
|
|
static size_t ssl_undefined_function_5(SSL *ssl, const char *r, size_t s,
|
|
unsigned char *t)
|
|
{
|
|
return ssl_undefined_function(ssl);
|
|
}
|
|
|
|
static int ssl_undefined_function_6(int r)
|
|
{
|
|
return ssl_undefined_function(NULL);
|
|
}
|
|
|
|
static int ssl_undefined_function_7(SSL *ssl, unsigned char *r, size_t s,
|
|
const char *t, size_t u,
|
|
const unsigned char *v, size_t w, int x)
|
|
{
|
|
return ssl_undefined_function(ssl);
|
|
}
|
|
|
|
SSL3_ENC_METHOD ssl3_undef_enc_method = {
|
|
ssl_undefined_function_1,
|
|
ssl_undefined_function_2,
|
|
ssl_undefined_function,
|
|
ssl_undefined_function_3,
|
|
ssl_undefined_function_4,
|
|
ssl_undefined_function_5,
|
|
NULL, /* client_finished_label */
|
|
0, /* client_finished_label_len */
|
|
NULL, /* server_finished_label */
|
|
0, /* server_finished_label_len */
|
|
ssl_undefined_function_6,
|
|
ssl_undefined_function_7,
|
|
};
|
|
|
|
struct ssl_async_args {
|
|
SSL *s;
|
|
void *buf;
|
|
size_t num;
|
|
enum { READFUNC, WRITEFUNC, OTHERFUNC } type;
|
|
union {
|
|
int (*func_read) (SSL *, void *, size_t, size_t *);
|
|
int (*func_write) (SSL *, const void *, size_t, size_t *);
|
|
int (*func_other) (SSL *);
|
|
} f;
|
|
};
|
|
|
|
static const struct {
|
|
uint8_t mtype;
|
|
uint8_t ord;
|
|
int nid;
|
|
} dane_mds[] = {
|
|
{
|
|
DANETLS_MATCHING_FULL, 0, NID_undef
|
|
},
|
|
{
|
|
DANETLS_MATCHING_2256, 1, NID_sha256
|
|
},
|
|
{
|
|
DANETLS_MATCHING_2512, 2, NID_sha512
|
|
},
|
|
};
|
|
|
|
static int dane_ctx_enable(struct dane_ctx_st *dctx)
|
|
{
|
|
const EVP_MD **mdevp;
|
|
uint8_t *mdord;
|
|
uint8_t mdmax = DANETLS_MATCHING_LAST;
|
|
int n = ((int)mdmax) + 1; /* int to handle PrivMatch(255) */
|
|
size_t i;
|
|
|
|
if (dctx->mdevp != NULL)
|
|
return 1;
|
|
|
|
mdevp = OPENSSL_zalloc(n * sizeof(*mdevp));
|
|
mdord = OPENSSL_zalloc(n * sizeof(*mdord));
|
|
|
|
if (mdord == NULL || mdevp == NULL) {
|
|
OPENSSL_free(mdord);
|
|
OPENSSL_free(mdevp);
|
|
SSLerr(SSL_F_DANE_CTX_ENABLE, ERR_R_MALLOC_FAILURE);
|
|
return 0;
|
|
}
|
|
|
|
/* Install default entries */
|
|
for (i = 0; i < OSSL_NELEM(dane_mds); ++i) {
|
|
const EVP_MD *md;
|
|
|
|
if (dane_mds[i].nid == NID_undef ||
|
|
(md = EVP_get_digestbynid(dane_mds[i].nid)) == NULL)
|
|
continue;
|
|
mdevp[dane_mds[i].mtype] = md;
|
|
mdord[dane_mds[i].mtype] = dane_mds[i].ord;
|
|
}
|
|
|
|
dctx->mdevp = mdevp;
|
|
dctx->mdord = mdord;
|
|
dctx->mdmax = mdmax;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void dane_ctx_final(struct dane_ctx_st *dctx)
|
|
{
|
|
OPENSSL_free(dctx->mdevp);
|
|
dctx->mdevp = NULL;
|
|
|
|
OPENSSL_free(dctx->mdord);
|
|
dctx->mdord = NULL;
|
|
dctx->mdmax = 0;
|
|
}
|
|
|
|
static void tlsa_free(danetls_record *t)
|
|
{
|
|
if (t == NULL)
|
|
return;
|
|
OPENSSL_free(t->data);
|
|
EVP_PKEY_free(t->spki);
|
|
OPENSSL_free(t);
|
|
}
|
|
|
|
static void dane_final(SSL_DANE *dane)
|
|
{
|
|
sk_danetls_record_pop_free(dane->trecs, tlsa_free);
|
|
dane->trecs = NULL;
|
|
|
|
sk_X509_pop_free(dane->certs, X509_free);
|
|
dane->certs = NULL;
|
|
|
|
X509_free(dane->mcert);
|
|
dane->mcert = NULL;
|
|
dane->mtlsa = NULL;
|
|
dane->mdpth = -1;
|
|
dane->pdpth = -1;
|
|
}
|
|
|
|
/*
|
|
* dane_copy - Copy dane configuration, sans verification state.
|
|
*/
|
|
static int ssl_dane_dup(SSL *to, SSL *from)
|
|
{
|
|
int num;
|
|
int i;
|
|
|
|
if (!DANETLS_ENABLED(&from->dane))
|
|
return 1;
|
|
|
|
num = sk_danetls_record_num(from->dane.trecs);
|
|
dane_final(&to->dane);
|
|
to->dane.flags = from->dane.flags;
|
|
to->dane.dctx = &to->ctx->dane;
|
|
to->dane.trecs = sk_danetls_record_new_reserve(NULL, num);
|
|
|
|
if (to->dane.trecs == NULL) {
|
|
SSLerr(SSL_F_SSL_DANE_DUP, ERR_R_MALLOC_FAILURE);
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < num; ++i) {
|
|
danetls_record *t = sk_danetls_record_value(from->dane.trecs, i);
|
|
|
|
if (SSL_dane_tlsa_add(to, t->usage, t->selector, t->mtype,
|
|
t->data, t->dlen) <= 0)
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int dane_mtype_set(struct dane_ctx_st *dctx,
|
|
const EVP_MD *md, uint8_t mtype, uint8_t ord)
|
|
{
|
|
int i;
|
|
|
|
if (mtype == DANETLS_MATCHING_FULL && md != NULL) {
|
|
SSLerr(SSL_F_DANE_MTYPE_SET, SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL);
|
|
return 0;
|
|
}
|
|
|
|
if (mtype > dctx->mdmax) {
|
|
const EVP_MD **mdevp;
|
|
uint8_t *mdord;
|
|
int n = ((int)mtype) + 1;
|
|
|
|
mdevp = OPENSSL_realloc(dctx->mdevp, n * sizeof(*mdevp));
|
|
if (mdevp == NULL) {
|
|
SSLerr(SSL_F_DANE_MTYPE_SET, ERR_R_MALLOC_FAILURE);
|
|
return -1;
|
|
}
|
|
dctx->mdevp = mdevp;
|
|
|
|
mdord = OPENSSL_realloc(dctx->mdord, n * sizeof(*mdord));
|
|
if (mdord == NULL) {
|
|
SSLerr(SSL_F_DANE_MTYPE_SET, ERR_R_MALLOC_FAILURE);
|
|
return -1;
|
|
}
|
|
dctx->mdord = mdord;
|
|
|
|
/* Zero-fill any gaps */
|
|
for (i = dctx->mdmax + 1; i < mtype; ++i) {
|
|
mdevp[i] = NULL;
|
|
mdord[i] = 0;
|
|
}
|
|
|
|
dctx->mdmax = mtype;
|
|
}
|
|
|
|
dctx->mdevp[mtype] = md;
|
|
/* Coerce ordinal of disabled matching types to 0 */
|
|
dctx->mdord[mtype] = (md == NULL) ? 0 : ord;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static const EVP_MD *tlsa_md_get(SSL_DANE *dane, uint8_t mtype)
|
|
{
|
|
if (mtype > dane->dctx->mdmax)
|
|
return NULL;
|
|
return dane->dctx->mdevp[mtype];
|
|
}
|
|
|
|
static int dane_tlsa_add(SSL_DANE *dane,
|
|
uint8_t usage,
|
|
uint8_t selector,
|
|
uint8_t mtype, unsigned const char *data, size_t dlen)
|
|
{
|
|
danetls_record *t;
|
|
const EVP_MD *md = NULL;
|
|
int ilen = (int)dlen;
|
|
int i;
|
|
int num;
|
|
|
|
if (dane->trecs == NULL) {
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_NOT_ENABLED);
|
|
return -1;
|
|
}
|
|
|
|
if (ilen < 0 || dlen != (size_t)ilen) {
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_DATA_LENGTH);
|
|
return 0;
|
|
}
|
|
|
|
if (usage > DANETLS_USAGE_LAST) {
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE);
|
|
return 0;
|
|
}
|
|
|
|
if (selector > DANETLS_SELECTOR_LAST) {
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_SELECTOR);
|
|
return 0;
|
|
}
|
|
|
|
if (mtype != DANETLS_MATCHING_FULL) {
|
|
md = tlsa_md_get(dane, mtype);
|
|
if (md == NULL) {
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_MATCHING_TYPE);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (md != NULL && dlen != (size_t)EVP_MD_size(md)) {
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH);
|
|
return 0;
|
|
}
|
|
if (!data) {
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_NULL_DATA);
|
|
return 0;
|
|
}
|
|
|
|
if ((t = OPENSSL_zalloc(sizeof(*t))) == NULL) {
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE);
|
|
return -1;
|
|
}
|
|
|
|
t->usage = usage;
|
|
t->selector = selector;
|
|
t->mtype = mtype;
|
|
t->data = OPENSSL_malloc(dlen);
|
|
if (t->data == NULL) {
|
|
tlsa_free(t);
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE);
|
|
return -1;
|
|
}
|
|
memcpy(t->data, data, dlen);
|
|
t->dlen = dlen;
|
|
|
|
/* Validate and cache full certificate or public key */
|
|
if (mtype == DANETLS_MATCHING_FULL) {
|
|
const unsigned char *p = data;
|
|
X509 *cert = NULL;
|
|
EVP_PKEY *pkey = NULL;
|
|
|
|
switch (selector) {
|
|
case DANETLS_SELECTOR_CERT:
|
|
if (!d2i_X509(&cert, &p, ilen) || p < data ||
|
|
dlen != (size_t)(p - data)) {
|
|
tlsa_free(t);
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_CERTIFICATE);
|
|
return 0;
|
|
}
|
|
if (X509_get0_pubkey(cert) == NULL) {
|
|
tlsa_free(t);
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_CERTIFICATE);
|
|
return 0;
|
|
}
|
|
|
|
if ((DANETLS_USAGE_BIT(usage) & DANETLS_TA_MASK) == 0) {
|
|
X509_free(cert);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* For usage DANE-TA(2), we support authentication via "2 0 0" TLSA
|
|
* records that contain full certificates of trust-anchors that are
|
|
* not present in the wire chain. For usage PKIX-TA(0), we augment
|
|
* the chain with untrusted Full(0) certificates from DNS, in case
|
|
* they are missing from the chain.
|
|
*/
|
|
if ((dane->certs == NULL &&
|
|
(dane->certs = sk_X509_new_null()) == NULL) ||
|
|
!sk_X509_push(dane->certs, cert)) {
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE);
|
|
X509_free(cert);
|
|
tlsa_free(t);
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case DANETLS_SELECTOR_SPKI:
|
|
if (!d2i_PUBKEY(&pkey, &p, ilen) || p < data ||
|
|
dlen != (size_t)(p - data)) {
|
|
tlsa_free(t);
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_PUBLIC_KEY);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* For usage DANE-TA(2), we support authentication via "2 1 0" TLSA
|
|
* records that contain full bare keys of trust-anchors that are
|
|
* not present in the wire chain.
|
|
*/
|
|
if (usage == DANETLS_USAGE_DANE_TA)
|
|
t->spki = pkey;
|
|
else
|
|
EVP_PKEY_free(pkey);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*-
|
|
* Find the right insertion point for the new record.
|
|
*
|
|
* See crypto/x509/x509_vfy.c. We sort DANE-EE(3) records first, so that
|
|
* they can be processed first, as they require no chain building, and no
|
|
* expiration or hostname checks. Because DANE-EE(3) is numerically
|
|
* largest, this is accomplished via descending sort by "usage".
|
|
*
|
|
* We also sort in descending order by matching ordinal to simplify
|
|
* the implementation of digest agility in the verification code.
|
|
*
|
|
* The choice of order for the selector is not significant, so we
|
|
* use the same descending order for consistency.
|
|
*/
|
|
num = sk_danetls_record_num(dane->trecs);
|
|
for (i = 0; i < num; ++i) {
|
|
danetls_record *rec = sk_danetls_record_value(dane->trecs, i);
|
|
|
|
if (rec->usage > usage)
|
|
continue;
|
|
if (rec->usage < usage)
|
|
break;
|
|
if (rec->selector > selector)
|
|
continue;
|
|
if (rec->selector < selector)
|
|
break;
|
|
if (dane->dctx->mdord[rec->mtype] > dane->dctx->mdord[mtype])
|
|
continue;
|
|
break;
|
|
}
|
|
|
|
if (!sk_danetls_record_insert(dane->trecs, t, i)) {
|
|
tlsa_free(t);
|
|
SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE);
|
|
return -1;
|
|
}
|
|
dane->umask |= DANETLS_USAGE_BIT(usage);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Return 0 if there is only one version configured and it was disabled
|
|
* at configure time. Return 1 otherwise.
|
|
*/
|
|
static int ssl_check_allowed_versions(int min_version, int max_version)
|
|
{
|
|
int minisdtls = 0, maxisdtls = 0;
|
|
|
|
/* Figure out if we're doing DTLS versions or TLS versions */
|
|
if (min_version == DTLS1_BAD_VER
|
|
|| min_version >> 8 == DTLS1_VERSION_MAJOR)
|
|
minisdtls = 1;
|
|
if (max_version == DTLS1_BAD_VER
|
|
|| max_version >> 8 == DTLS1_VERSION_MAJOR)
|
|
maxisdtls = 1;
|
|
/* A wildcard version of 0 could be DTLS or TLS. */
|
|
if ((minisdtls && !maxisdtls && max_version != 0)
|
|
|| (maxisdtls && !minisdtls && min_version != 0)) {
|
|
/* Mixing DTLS and TLS versions will lead to sadness; deny it. */
|
|
return 0;
|
|
}
|
|
|
|
if (minisdtls || maxisdtls) {
|
|
/* Do DTLS version checks. */
|
|
if (min_version == 0)
|
|
/* Ignore DTLS1_BAD_VER */
|
|
min_version = DTLS1_VERSION;
|
|
if (max_version == 0)
|
|
max_version = DTLS1_2_VERSION;
|
|
#ifdef OPENSSL_NO_DTLS1_2
|
|
if (max_version == DTLS1_2_VERSION)
|
|
max_version = DTLS1_VERSION;
|
|
#endif
|
|
#ifdef OPENSSL_NO_DTLS1
|
|
if (min_version == DTLS1_VERSION)
|
|
min_version = DTLS1_2_VERSION;
|
|
#endif
|
|
/* Done massaging versions; do the check. */
|
|
if (0
|
|
#ifdef OPENSSL_NO_DTLS1
|
|
|| (DTLS_VERSION_GE(min_version, DTLS1_VERSION)
|
|
&& DTLS_VERSION_GE(DTLS1_VERSION, max_version))
|
|
#endif
|
|
#ifdef OPENSSL_NO_DTLS1_2
|
|
|| (DTLS_VERSION_GE(min_version, DTLS1_2_VERSION)
|
|
&& DTLS_VERSION_GE(DTLS1_2_VERSION, max_version))
|
|
#endif
|
|
)
|
|
return 0;
|
|
} else {
|
|
/* Regular TLS version checks. */
|
|
if (min_version == 0)
|
|
min_version = SSL3_VERSION;
|
|
if (max_version == 0)
|
|
max_version = TLS1_3_VERSION;
|
|
#ifdef OPENSSL_NO_TLS1_3
|
|
if (max_version == TLS1_3_VERSION)
|
|
max_version = TLS1_2_VERSION;
|
|
#endif
|
|
#ifdef OPENSSL_NO_TLS1_2
|
|
if (max_version == TLS1_2_VERSION)
|
|
max_version = TLS1_1_VERSION;
|
|
#endif
|
|
#ifdef OPENSSL_NO_TLS1_1
|
|
if (max_version == TLS1_1_VERSION)
|
|
max_version = TLS1_VERSION;
|
|
#endif
|
|
#ifdef OPENSSL_NO_TLS1
|
|
if (max_version == TLS1_VERSION)
|
|
max_version = SSL3_VERSION;
|
|
#endif
|
|
#ifdef OPENSSL_NO_SSL3
|
|
if (min_version == SSL3_VERSION)
|
|
min_version = TLS1_VERSION;
|
|
#endif
|
|
#ifdef OPENSSL_NO_TLS1
|
|
if (min_version == TLS1_VERSION)
|
|
min_version = TLS1_1_VERSION;
|
|
#endif
|
|
#ifdef OPENSSL_NO_TLS1_1
|
|
if (min_version == TLS1_1_VERSION)
|
|
min_version = TLS1_2_VERSION;
|
|
#endif
|
|
#ifdef OPENSSL_NO_TLS1_2
|
|
if (min_version == TLS1_2_VERSION)
|
|
min_version = TLS1_3_VERSION;
|
|
#endif
|
|
/* Done massaging versions; do the check. */
|
|
if (0
|
|
#ifdef OPENSSL_NO_SSL3
|
|
|| (min_version <= SSL3_VERSION && SSL3_VERSION <= max_version)
|
|
#endif
|
|
#ifdef OPENSSL_NO_TLS1
|
|
|| (min_version <= TLS1_VERSION && TLS1_VERSION <= max_version)
|
|
#endif
|
|
#ifdef OPENSSL_NO_TLS1_1
|
|
|| (min_version <= TLS1_1_VERSION && TLS1_1_VERSION <= max_version)
|
|
#endif
|
|
#ifdef OPENSSL_NO_TLS1_2
|
|
|| (min_version <= TLS1_2_VERSION && TLS1_2_VERSION <= max_version)
|
|
#endif
|
|
#ifdef OPENSSL_NO_TLS1_3
|
|
|| (min_version <= TLS1_3_VERSION && TLS1_3_VERSION <= max_version)
|
|
#endif
|
|
)
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#if defined(__TANDEM) && defined(OPENSSL_VPROC)
|
|
/*
|
|
* Define a VPROC function for HP NonStop build ssl library.
|
|
* This is used by platform version identification tools.
|
|
* Do not inline this procedure or make it static.
|
|
*/
|
|
# define OPENSSL_VPROC_STRING_(x) x##_SSL
|
|
# define OPENSSL_VPROC_STRING(x) OPENSSL_VPROC_STRING_(x)
|
|
# define OPENSSL_VPROC_FUNC OPENSSL_VPROC_STRING(OPENSSL_VPROC)
|
|
void OPENSSL_VPROC_FUNC(void) {}
|
|
#endif
|
|
|
|
|
|
static void clear_ciphers(SSL *s)
|
|
{
|
|
/* clear the current cipher */
|
|
ssl_clear_cipher_ctx(s);
|
|
ssl_clear_hash_ctx(&s->read_hash);
|
|
ssl_clear_hash_ctx(&s->write_hash);
|
|
}
|
|
|
|
int SSL_clear(SSL *s)
|
|
{
|
|
if (s->method == NULL) {
|
|
SSLerr(SSL_F_SSL_CLEAR, SSL_R_NO_METHOD_SPECIFIED);
|
|
return 0;
|
|
}
|
|
|
|
if (ssl_clear_bad_session(s)) {
|
|
SSL_SESSION_free(s->session);
|
|
s->session = NULL;
|
|
}
|
|
SSL_SESSION_free(s->psksession);
|
|
s->psksession = NULL;
|
|
OPENSSL_free(s->psksession_id);
|
|
s->psksession_id = NULL;
|
|
s->psksession_id_len = 0;
|
|
s->hello_retry_request = 0;
|
|
s->sent_tickets = 0;
|
|
|
|
s->error = 0;
|
|
s->hit = 0;
|
|
s->shutdown = 0;
|
|
|
|
if (s->renegotiate) {
|
|
SSLerr(SSL_F_SSL_CLEAR, ERR_R_INTERNAL_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
ossl_statem_clear(s);
|
|
|
|
s->version = s->method->version;
|
|
s->client_version = s->version;
|
|
s->rwstate = SSL_NOTHING;
|
|
|
|
BUF_MEM_free(s->init_buf);
|
|
s->init_buf = NULL;
|
|
clear_ciphers(s);
|
|
s->first_packet = 0;
|
|
|
|
s->key_update = SSL_KEY_UPDATE_NONE;
|
|
|
|
EVP_MD_CTX_free(s->pha_dgst);
|
|
s->pha_dgst = NULL;
|
|
|
|
/* Reset DANE verification result state */
|
|
s->dane.mdpth = -1;
|
|
s->dane.pdpth = -1;
|
|
X509_free(s->dane.mcert);
|
|
s->dane.mcert = NULL;
|
|
s->dane.mtlsa = NULL;
|
|
|
|
/* Clear the verification result peername */
|
|
X509_VERIFY_PARAM_move_peername(s->param, NULL);
|
|
|
|
/* Clear any shared connection state */
|
|
OPENSSL_free(s->shared_sigalgs);
|
|
s->shared_sigalgs = NULL;
|
|
s->shared_sigalgslen = 0;
|
|
|
|
/*
|
|
* Check to see if we were changed into a different method, if so, revert
|
|
* back.
|
|
*/
|
|
if (s->method != s->ctx->method) {
|
|
s->method->ssl_free(s);
|
|
s->method = s->ctx->method;
|
|
if (!s->method->ssl_new(s))
|
|
return 0;
|
|
} else {
|
|
if (!s->method->ssl_clear(s))
|
|
return 0;
|
|
}
|
|
|
|
RECORD_LAYER_clear(&s->rlayer);
|
|
|
|
return 1;
|
|
}
|
|
|
|
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
|
/** Used to change an SSL_CTXs default SSL method type */
|
|
int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth)
|
|
{
|
|
STACK_OF(SSL_CIPHER) *sk;
|
|
|
|
ctx->method = meth;
|
|
|
|
if (!SSL_CTX_set_ciphersuites(ctx, OSSL_default_ciphersuites())) {
|
|
SSLerr(SSL_F_SSL_CTX_SET_SSL_VERSION, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS);
|
|
return 0;
|
|
}
|
|
sk = ssl_create_cipher_list(ctx->method,
|
|
ctx->tls13_ciphersuites,
|
|
&(ctx->cipher_list),
|
|
&(ctx->cipher_list_by_id),
|
|
OSSL_default_cipher_list(), ctx->cert);
|
|
if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= 0)) {
|
|
SSLerr(SSL_F_SSL_CTX_SET_SSL_VERSION, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
SSL *SSL_new(SSL_CTX *ctx)
|
|
{
|
|
SSL *s;
|
|
|
|
if (ctx == NULL) {
|
|
SSLerr(SSL_F_SSL_NEW, SSL_R_NULL_SSL_CTX);
|
|
return NULL;
|
|
}
|
|
if (ctx->method == NULL) {
|
|
SSLerr(SSL_F_SSL_NEW, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION);
|
|
return NULL;
|
|
}
|
|
|
|
s = OPENSSL_zalloc(sizeof(*s));
|
|
if (s == NULL)
|
|
goto err;
|
|
|
|
s->references = 1;
|
|
s->lock = CRYPTO_THREAD_lock_new();
|
|
if (s->lock == NULL) {
|
|
OPENSSL_free(s);
|
|
s = NULL;
|
|
goto err;
|
|
}
|
|
|
|
RECORD_LAYER_init(&s->rlayer, s);
|
|
|
|
s->options = ctx->options;
|
|
s->dane.flags = ctx->dane.flags;
|
|
s->min_proto_version = ctx->min_proto_version;
|
|
s->max_proto_version = ctx->max_proto_version;
|
|
s->mode = ctx->mode;
|
|
s->max_cert_list = ctx->max_cert_list;
|
|
s->max_early_data = ctx->max_early_data;
|
|
s->recv_max_early_data = ctx->recv_max_early_data;
|
|
s->num_tickets = ctx->num_tickets;
|
|
s->pha_enabled = ctx->pha_enabled;
|
|
|
|
/* Shallow copy of the ciphersuites stack */
|
|
s->tls13_ciphersuites = sk_SSL_CIPHER_dup(ctx->tls13_ciphersuites);
|
|
if (s->tls13_ciphersuites == NULL)
|
|
goto err;
|
|
|
|
/*
|
|
* Earlier library versions used to copy the pointer to the CERT, not
|
|
* its contents; only when setting new parameters for the per-SSL
|
|
* copy, ssl_cert_new would be called (and the direct reference to
|
|
* the per-SSL_CTX settings would be lost, but those still were
|
|
* indirectly accessed for various purposes, and for that reason they
|
|
* used to be known as s->ctx->default_cert). Now we don't look at the
|
|
* SSL_CTX's CERT after having duplicated it once.
|
|
*/
|
|
s->cert = ssl_cert_dup(ctx->cert);
|
|
if (s->cert == NULL)
|
|
goto err;
|
|
|
|
RECORD_LAYER_set_read_ahead(&s->rlayer, ctx->read_ahead);
|
|
s->msg_callback = ctx->msg_callback;
|
|
s->msg_callback_arg = ctx->msg_callback_arg;
|
|
s->verify_mode = ctx->verify_mode;
|
|
s->not_resumable_session_cb = ctx->not_resumable_session_cb;
|
|
s->record_padding_cb = ctx->record_padding_cb;
|
|
s->record_padding_arg = ctx->record_padding_arg;
|
|
s->block_padding = ctx->block_padding;
|
|
s->sid_ctx_length = ctx->sid_ctx_length;
|
|
if (!ossl_assert(s->sid_ctx_length <= sizeof(s->sid_ctx)))
|
|
goto err;
|
|
memcpy(&s->sid_ctx, &ctx->sid_ctx, sizeof(s->sid_ctx));
|
|
s->verify_callback = ctx->default_verify_callback;
|
|
s->generate_session_id = ctx->generate_session_id;
|
|
|
|
s->param = X509_VERIFY_PARAM_new();
|
|
if (s->param == NULL)
|
|
goto err;
|
|
X509_VERIFY_PARAM_inherit(s->param, ctx->param);
|
|
s->quiet_shutdown = ctx->quiet_shutdown;
|
|
|
|
s->ext.max_fragment_len_mode = ctx->ext.max_fragment_len_mode;
|
|
s->max_send_fragment = ctx->max_send_fragment;
|
|
s->split_send_fragment = ctx->split_send_fragment;
|
|
s->max_pipelines = ctx->max_pipelines;
|
|
if (s->max_pipelines > 1)
|
|
RECORD_LAYER_set_read_ahead(&s->rlayer, 1);
|
|
if (ctx->default_read_buf_len > 0)
|
|
SSL_set_default_read_buffer_len(s, ctx->default_read_buf_len);
|
|
|
|
SSL_CTX_up_ref(ctx);
|
|
s->ctx = ctx;
|
|
s->ext.debug_cb = 0;
|
|
s->ext.debug_arg = NULL;
|
|
s->ext.ticket_expected = 0;
|
|
s->ext.status_type = ctx->ext.status_type;
|
|
s->ext.status_expected = 0;
|
|
s->ext.ocsp.ids = NULL;
|
|
s->ext.ocsp.exts = NULL;
|
|
s->ext.ocsp.resp = NULL;
|
|
s->ext.ocsp.resp_len = 0;
|
|
SSL_CTX_up_ref(ctx);
|
|
s->session_ctx = ctx;
|
|
#ifndef OPENSSL_NO_EC
|
|
if (ctx->ext.ecpointformats) {
|
|
s->ext.ecpointformats =
|
|
OPENSSL_memdup(ctx->ext.ecpointformats,
|
|
ctx->ext.ecpointformats_len);
|
|
if (!s->ext.ecpointformats)
|
|
goto err;
|
|
s->ext.ecpointformats_len =
|
|
ctx->ext.ecpointformats_len;
|
|
}
|
|
#endif
|
|
if (ctx->ext.supportedgroups) {
|
|
s->ext.supportedgroups =
|
|
OPENSSL_memdup(ctx->ext.supportedgroups,
|
|
ctx->ext.supportedgroups_len
|
|
* sizeof(*ctx->ext.supportedgroups));
|
|
if (!s->ext.supportedgroups)
|
|
goto err;
|
|
s->ext.supportedgroups_len = ctx->ext.supportedgroups_len;
|
|
}
|
|
|
|
#ifndef OPENSSL_NO_NEXTPROTONEG
|
|
s->ext.npn = NULL;
|
|
#endif
|
|
|
|
if (s->ctx->ext.alpn) {
|
|
s->ext.alpn = OPENSSL_malloc(s->ctx->ext.alpn_len);
|
|
if (s->ext.alpn == NULL)
|
|
goto err;
|
|
memcpy(s->ext.alpn, s->ctx->ext.alpn, s->ctx->ext.alpn_len);
|
|
s->ext.alpn_len = s->ctx->ext.alpn_len;
|
|
}
|
|
|
|
s->verified_chain = NULL;
|
|
s->verify_result = X509_V_OK;
|
|
|
|
s->default_passwd_callback = ctx->default_passwd_callback;
|
|
s->default_passwd_callback_userdata = ctx->default_passwd_callback_userdata;
|
|
|
|
s->method = ctx->method;
|
|
|
|
s->key_update = SSL_KEY_UPDATE_NONE;
|
|
|
|
s->allow_early_data_cb = ctx->allow_early_data_cb;
|
|
s->allow_early_data_cb_data = ctx->allow_early_data_cb_data;
|
|
|
|
if (!s->method->ssl_new(s))
|
|
goto err;
|
|
|
|
s->server = (ctx->method->ssl_accept == ssl_undefined_function) ? 0 : 1;
|
|
|
|
if (!SSL_clear(s))
|
|
goto err;
|
|
|
|
if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data))
|
|
goto err;
|
|
|
|
#ifndef OPENSSL_NO_PSK
|
|
s->psk_client_callback = ctx->psk_client_callback;
|
|
s->psk_server_callback = ctx->psk_server_callback;
|
|
#endif
|
|
s->psk_find_session_cb = ctx->psk_find_session_cb;
|
|
s->psk_use_session_cb = ctx->psk_use_session_cb;
|
|
|
|
s->async_cb = ctx->async_cb;
|
|
s->async_cb_arg = ctx->async_cb_arg;
|
|
|
|
s->job = NULL;
|
|
|
|
#ifndef OPENSSL_NO_CT
|
|
if (!SSL_set_ct_validation_callback(s, ctx->ct_validation_callback,
|
|
ctx->ct_validation_callback_arg))
|
|
goto err;
|
|
#endif
|
|
|
|
return s;
|
|
err:
|
|
SSL_free(s);
|
|
SSLerr(SSL_F_SSL_NEW, ERR_R_MALLOC_FAILURE);
|
|
return NULL;
|
|
}
|
|
|
|
int SSL_is_dtls(const SSL *s)
|
|
{
|
|
return SSL_IS_DTLS(s) ? 1 : 0;
|
|
}
|
|
|
|
int SSL_up_ref(SSL *s)
|
|
{
|
|
int i;
|
|
|
|
if (CRYPTO_UP_REF(&s->references, &i, s->lock) <= 0)
|
|
return 0;
|
|
|
|
REF_PRINT_COUNT("SSL", s);
|
|
REF_ASSERT_ISNT(i < 2);
|
|
return ((i > 1) ? 1 : 0);
|
|
}
|
|
|
|
int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx,
|
|
unsigned int sid_ctx_len)
|
|
{
|
|
if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) {
|
|
SSLerr(SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT,
|
|
SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
|
|
return 0;
|
|
}
|
|
ctx->sid_ctx_length = sid_ctx_len;
|
|
memcpy(ctx->sid_ctx, sid_ctx, sid_ctx_len);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int SSL_set_session_id_context(SSL *ssl, const unsigned char *sid_ctx,
|
|
unsigned int sid_ctx_len)
|
|
{
|
|
if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) {
|
|
SSLerr(SSL_F_SSL_SET_SESSION_ID_CONTEXT,
|
|
SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG);
|
|
return 0;
|
|
}
|
|
ssl->sid_ctx_length = sid_ctx_len;
|
|
memcpy(ssl->sid_ctx, sid_ctx, sid_ctx_len);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int SSL_CTX_set_generate_session_id(SSL_CTX *ctx, GEN_SESSION_CB cb)
|
|
{
|
|
CRYPTO_THREAD_write_lock(ctx->lock);
|
|
ctx->generate_session_id = cb;
|
|
CRYPTO_THREAD_unlock(ctx->lock);
|
|
return 1;
|
|
}
|
|
|
|
int SSL_set_generate_session_id(SSL *ssl, GEN_SESSION_CB cb)
|
|
{
|
|
CRYPTO_THREAD_write_lock(ssl->lock);
|
|
ssl->generate_session_id = cb;
|
|
CRYPTO_THREAD_unlock(ssl->lock);
|
|
return 1;
|
|
}
|
|
|
|
int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id,
|
|
unsigned int id_len)
|
|
{
|
|
/*
|
|
* A quick examination of SSL_SESSION_hash and SSL_SESSION_cmp shows how
|
|
* we can "construct" a session to give us the desired check - i.e. to
|
|
* find if there's a session in the hash table that would conflict with
|
|
* any new session built out of this id/id_len and the ssl_version in use
|
|
* by this SSL.
|
|
*/
|
|
SSL_SESSION r, *p;
|
|
|
|
if (id_len > sizeof(r.session_id))
|
|
return 0;
|
|
|
|
r.ssl_version = ssl->version;
|
|
r.session_id_length = id_len;
|
|
memcpy(r.session_id, id, id_len);
|
|
|
|
CRYPTO_THREAD_read_lock(ssl->session_ctx->lock);
|
|
p = lh_SSL_SESSION_retrieve(ssl->session_ctx->sessions, &r);
|
|
CRYPTO_THREAD_unlock(ssl->session_ctx->lock);
|
|
return (p != NULL);
|
|
}
|
|
|
|
int SSL_CTX_set_purpose(SSL_CTX *s, int purpose)
|
|
{
|
|
return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
|
|
}
|
|
|
|
int SSL_set_purpose(SSL *s, int purpose)
|
|
{
|
|
return X509_VERIFY_PARAM_set_purpose(s->param, purpose);
|
|
}
|
|
|
|
int SSL_CTX_set_trust(SSL_CTX *s, int trust)
|
|
{
|
|
return X509_VERIFY_PARAM_set_trust(s->param, trust);
|
|
}
|
|
|
|
int SSL_set_trust(SSL *s, int trust)
|
|
{
|
|
return X509_VERIFY_PARAM_set_trust(s->param, trust);
|
|
}
|
|
|
|
int SSL_set1_host(SSL *s, const char *hostname)
|
|
{
|
|
/* If a hostname is provided and parses as an IP address,
|
|
* treat it as such. */
|
|
if (hostname && X509_VERIFY_PARAM_set1_ip_asc(s->param, hostname) == 1)
|
|
return 1;
|
|
|
|
return X509_VERIFY_PARAM_set1_host(s->param, hostname, 0);
|
|
}
|
|
|
|
int SSL_add1_host(SSL *s, const char *hostname)
|
|
{
|
|
/* If a hostname is provided and parses as an IP address,
|
|
* treat it as such. */
|
|
if (hostname)
|
|
{
|
|
ASN1_OCTET_STRING *ip;
|
|
char *old_ip;
|
|
|
|
ip = a2i_IPADDRESS(hostname);
|
|
if (ip) {
|
|
/* We didn't want it; only to check if it *is* an IP address */
|
|
ASN1_OCTET_STRING_free(ip);
|
|
|
|
old_ip = X509_VERIFY_PARAM_get1_ip_asc(s->param);
|
|
if (old_ip)
|
|
{
|
|
OPENSSL_free(old_ip);
|
|
/* There can be only one IP address */
|
|
return 0;
|
|
}
|
|
|
|
return X509_VERIFY_PARAM_set1_ip_asc(s->param, hostname);
|
|
}
|
|
}
|
|
|
|
return X509_VERIFY_PARAM_add1_host(s->param, hostname, 0);
|
|
}
|
|
|
|
void SSL_set_hostflags(SSL *s, unsigned int flags)
|
|
{
|
|
X509_VERIFY_PARAM_set_hostflags(s->param, flags);
|
|
}
|
|
|
|
const char *SSL_get0_peername(SSL *s)
|
|
{
|
|
return X509_VERIFY_PARAM_get0_peername(s->param);
|
|
}
|
|
|
|
int SSL_CTX_dane_enable(SSL_CTX *ctx)
|
|
{
|
|
return dane_ctx_enable(&ctx->dane);
|
|
}
|
|
|
|
unsigned long SSL_CTX_dane_set_flags(SSL_CTX *ctx, unsigned long flags)
|
|
{
|
|
unsigned long orig = ctx->dane.flags;
|
|
|
|
ctx->dane.flags |= flags;
|
|
return orig;
|
|
}
|
|
|
|
unsigned long SSL_CTX_dane_clear_flags(SSL_CTX *ctx, unsigned long flags)
|
|
{
|
|
unsigned long orig = ctx->dane.flags;
|
|
|
|
ctx->dane.flags &= ~flags;
|
|
return orig;
|
|
}
|
|
|
|
int SSL_dane_enable(SSL *s, const char *basedomain)
|
|
{
|
|
SSL_DANE *dane = &s->dane;
|
|
|
|
if (s->ctx->dane.mdmax == 0) {
|
|
SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_CONTEXT_NOT_DANE_ENABLED);
|
|
return 0;
|
|
}
|
|
if (dane->trecs != NULL) {
|
|
SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_DANE_ALREADY_ENABLED);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Default SNI name. This rejects empty names, while set1_host below
|
|
* accepts them and disables host name checks. To avoid side-effects with
|
|
* invalid input, set the SNI name first.
|
|
*/
|
|
if (s->ext.hostname == NULL) {
|
|
if (!SSL_set_tlsext_host_name(s, basedomain)) {
|
|
SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Primary RFC6125 reference identifier */
|
|
if (!X509_VERIFY_PARAM_set1_host(s->param, basedomain, 0)) {
|
|
SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN);
|
|
return -1;
|
|
}
|
|
|
|
dane->mdpth = -1;
|
|
dane->pdpth = -1;
|
|
dane->dctx = &s->ctx->dane;
|
|
dane->trecs = sk_danetls_record_new_null();
|
|
|
|
if (dane->trecs == NULL) {
|
|
SSLerr(SSL_F_SSL_DANE_ENABLE, ERR_R_MALLOC_FAILURE);
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
unsigned long SSL_dane_set_flags(SSL *ssl, unsigned long flags)
|
|
{
|
|
unsigned long orig = ssl->dane.flags;
|
|
|
|
ssl->dane.flags |= flags;
|
|
return orig;
|
|
}
|
|
|
|
unsigned long SSL_dane_clear_flags(SSL *ssl, unsigned long flags)
|
|
{
|
|
unsigned long orig = ssl->dane.flags;
|
|
|
|
ssl->dane.flags &= ~flags;
|
|
return orig;
|
|
}
|
|
|
|
int SSL_get0_dane_authority(SSL *s, X509 **mcert, EVP_PKEY **mspki)
|
|
{
|
|
SSL_DANE *dane = &s->dane;
|
|
|
|
if (!DANETLS_ENABLED(dane) || s->verify_result != X509_V_OK)
|
|
return -1;
|
|
if (dane->mtlsa) {
|
|
if (mcert)
|
|
*mcert = dane->mcert;
|
|
if (mspki)
|
|
*mspki = (dane->mcert == NULL) ? dane->mtlsa->spki : NULL;
|
|
}
|
|
return dane->mdpth;
|
|
}
|
|
|
|
int SSL_get0_dane_tlsa(SSL *s, uint8_t *usage, uint8_t *selector,
|
|
uint8_t *mtype, unsigned const char **data, size_t *dlen)
|
|
{
|
|
SSL_DANE *dane = &s->dane;
|
|
|
|
if (!DANETLS_ENABLED(dane) || s->verify_result != X509_V_OK)
|
|
return -1;
|
|
if (dane->mtlsa) {
|
|
if (usage)
|
|
*usage = dane->mtlsa->usage;
|
|
if (selector)
|
|
*selector = dane->mtlsa->selector;
|
|
if (mtype)
|
|
*mtype = dane->mtlsa->mtype;
|
|
if (data)
|
|
*data = dane->mtlsa->data;
|
|
if (dlen)
|
|
*dlen = dane->mtlsa->dlen;
|
|
}
|
|
return dane->mdpth;
|
|
}
|
|
|
|
SSL_DANE *SSL_get0_dane(SSL *s)
|
|
{
|
|
return &s->dane;
|
|
}
|
|
|
|
int SSL_dane_tlsa_add(SSL *s, uint8_t usage, uint8_t selector,
|
|
uint8_t mtype, unsigned const char *data, size_t dlen)
|
|
{
|
|
return dane_tlsa_add(&s->dane, usage, selector, mtype, data, dlen);
|
|
}
|
|
|
|
int SSL_CTX_dane_mtype_set(SSL_CTX *ctx, const EVP_MD *md, uint8_t mtype,
|
|
uint8_t ord)
|
|
{
|
|
return dane_mtype_set(&ctx->dane, md, mtype, ord);
|
|
}
|
|
|
|
int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm)
|
|
{
|
|
return X509_VERIFY_PARAM_set1(ctx->param, vpm);
|
|
}
|
|
|
|
int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm)
|
|
{
|
|
return X509_VERIFY_PARAM_set1(ssl->param, vpm);
|
|
}
|
|
|
|
X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx)
|
|
{
|
|
return ctx->param;
|
|
}
|
|
|
|
X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl)
|
|
{
|
|
return ssl->param;
|
|
}
|
|
|
|
void SSL_certs_clear(SSL *s)
|
|
{
|
|
ssl_cert_clear_certs(s->cert);
|
|
}
|
|
|
|
void SSL_free(SSL *s)
|
|
{
|
|
int i;
|
|
|
|
if (s == NULL)
|
|
return;
|
|
CRYPTO_DOWN_REF(&s->references, &i, s->lock);
|
|
REF_PRINT_COUNT("SSL", s);
|
|
if (i > 0)
|
|
return;
|
|
REF_ASSERT_ISNT(i < 0);
|
|
|
|
X509_VERIFY_PARAM_free(s->param);
|
|
dane_final(&s->dane);
|
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data);
|
|
|
|
RECORD_LAYER_release(&s->rlayer);
|
|
|
|
/* Ignore return value */
|
|
ssl_free_wbio_buffer(s);
|
|
|
|
BIO_free_all(s->wbio);
|
|
s->wbio = NULL;
|
|
BIO_free_all(s->rbio);
|
|
s->rbio = NULL;
|
|
|
|
BUF_MEM_free(s->init_buf);
|
|
|
|
/* add extra stuff */
|
|
sk_SSL_CIPHER_free(s->cipher_list);
|
|
sk_SSL_CIPHER_free(s->cipher_list_by_id);
|
|
sk_SSL_CIPHER_free(s->tls13_ciphersuites);
|
|
sk_SSL_CIPHER_free(s->peer_ciphers);
|
|
|
|
/* Make the next call work :-) */
|
|
if (s->session != NULL) {
|
|
ssl_clear_bad_session(s);
|
|
SSL_SESSION_free(s->session);
|
|
}
|
|
SSL_SESSION_free(s->psksession);
|
|
OPENSSL_free(s->psksession_id);
|
|
|
|
clear_ciphers(s);
|
|
|
|
ssl_cert_free(s->cert);
|
|
OPENSSL_free(s->shared_sigalgs);
|
|
/* Free up if allocated */
|
|
|
|
OPENSSL_free(s->ext.hostname);
|
|
SSL_CTX_free(s->session_ctx);
|
|
#ifndef OPENSSL_NO_EC
|
|
OPENSSL_free(s->ext.ecpointformats);
|
|
OPENSSL_free(s->ext.peer_ecpointformats);
|
|
#endif /* OPENSSL_NO_EC */
|
|
OPENSSL_free(s->ext.supportedgroups);
|
|
OPENSSL_free(s->ext.peer_supportedgroups);
|
|
sk_X509_EXTENSION_pop_free(s->ext.ocsp.exts, X509_EXTENSION_free);
|
|
#ifndef OPENSSL_NO_OCSP
|
|
sk_OCSP_RESPID_pop_free(s->ext.ocsp.ids, OCSP_RESPID_free);
|
|
#endif
|
|
#ifndef OPENSSL_NO_CT
|
|
SCT_LIST_free(s->scts);
|
|
OPENSSL_free(s->ext.scts);
|
|
#endif
|
|
OPENSSL_free(s->ext.ocsp.resp);
|
|
OPENSSL_free(s->ext.alpn);
|
|
OPENSSL_free(s->ext.tls13_cookie);
|
|
if (s->clienthello != NULL)
|
|
OPENSSL_free(s->clienthello->pre_proc_exts);
|
|
OPENSSL_free(s->clienthello);
|
|
OPENSSL_free(s->pha_context);
|
|
EVP_MD_CTX_free(s->pha_dgst);
|
|
|
|
sk_X509_NAME_pop_free(s->ca_names, X509_NAME_free);
|
|
sk_X509_NAME_pop_free(s->client_ca_names, X509_NAME_free);
|
|
|
|
sk_X509_pop_free(s->verified_chain, X509_free);
|
|
|
|
if (s->method != NULL)
|
|
s->method->ssl_free(s);
|
|
|
|
SSL_CTX_free(s->ctx);
|
|
|
|
ASYNC_WAIT_CTX_free(s->waitctx);
|
|
|
|
#if !defined(OPENSSL_NO_NEXTPROTONEG)
|
|
OPENSSL_free(s->ext.npn);
|
|
#endif
|
|
|
|
#ifndef OPENSSL_NO_SRTP
|
|
sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles);
|
|
#endif
|
|
|
|
CRYPTO_THREAD_lock_free(s->lock);
|
|
|
|
OPENSSL_free(s);
|
|
}
|
|
|
|
void SSL_set0_rbio(SSL *s, BIO *rbio)
|
|
{
|
|
BIO_free_all(s->rbio);
|
|
s->rbio = rbio;
|
|
}
|
|
|
|
void SSL_set0_wbio(SSL *s, BIO *wbio)
|
|
{
|
|
/*
|
|
* If the output buffering BIO is still in place, remove it
|
|
*/
|
|
if (s->bbio != NULL)
|
|
s->wbio = BIO_pop(s->wbio);
|
|
|
|
BIO_free_all(s->wbio);
|
|
s->wbio = wbio;
|
|
|
|
/* Re-attach |bbio| to the new |wbio|. */
|
|
if (s->bbio != NULL)
|
|
s->wbio = BIO_push(s->bbio, s->wbio);
|
|
}
|
|
|
|
void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio)
|
|
{
|
|
/*
|
|
* For historical reasons, this function has many different cases in
|
|
* ownership handling.
|
|
*/
|
|
|
|
/* If nothing has changed, do nothing */
|
|
if (rbio == SSL_get_rbio(s) && wbio == SSL_get_wbio(s))
|
|
return;
|
|
|
|
/*
|
|
* If the two arguments are equal then one fewer reference is granted by the
|
|
* caller than we want to take
|
|
*/
|
|
if (rbio != NULL && rbio == wbio)
|
|
BIO_up_ref(rbio);
|
|
|
|
/*
|
|
* If only the wbio is changed only adopt one reference.
|
|
*/
|
|
if (rbio == SSL_get_rbio(s)) {
|
|
SSL_set0_wbio(s, wbio);
|
|
return;
|
|
}
|
|
/*
|
|
* There is an asymmetry here for historical reasons. If only the rbio is
|
|
* changed AND the rbio and wbio were originally different, then we only
|
|
* adopt one reference.
|
|
*/
|
|
if (wbio == SSL_get_wbio(s) && SSL_get_rbio(s) != SSL_get_wbio(s)) {
|
|
SSL_set0_rbio(s, rbio);
|
|
return;
|
|
}
|
|
|
|
/* Otherwise, adopt both references. */
|
|
SSL_set0_rbio(s, rbio);
|
|
SSL_set0_wbio(s, wbio);
|
|
}
|
|
|
|
BIO *SSL_get_rbio(const SSL *s)
|
|
{
|
|
return s->rbio;
|
|
}
|
|
|
|
BIO *SSL_get_wbio(const SSL *s)
|
|
{
|
|
if (s->bbio != NULL) {
|
|
/*
|
|
* If |bbio| is active, the true caller-configured BIO is its
|
|
* |next_bio|.
|
|
*/
|
|
return BIO_next(s->bbio);
|
|
}
|
|
return s->wbio;
|
|
}
|
|
|
|
int SSL_get_fd(const SSL *s)
|
|
{
|
|
return SSL_get_rfd(s);
|
|
}
|
|
|
|
int SSL_get_rfd(const SSL *s)
|
|
{
|
|
int ret = -1;
|
|
BIO *b, *r;
|
|
|
|
b = SSL_get_rbio(s);
|
|
r = BIO_find_type(b, BIO_TYPE_DESCRIPTOR);
|
|
if (r != NULL)
|
|
BIO_get_fd(r, &ret);
|
|
return ret;
|
|
}
|
|
|
|
int SSL_get_wfd(const SSL *s)
|
|
{
|
|
int ret = -1;
|
|
BIO *b, *r;
|
|
|
|
b = SSL_get_wbio(s);
|
|
r = BIO_find_type(b, BIO_TYPE_DESCRIPTOR);
|
|
if (r != NULL)
|
|
BIO_get_fd(r, &ret);
|
|
return ret;
|
|
}
|
|
|
|
#ifndef OPENSSL_NO_SOCK
|
|
int SSL_set_fd(SSL *s, int fd)
|
|
{
|
|
int ret = 0;
|
|
BIO *bio = NULL;
|
|
|
|
bio = BIO_new(BIO_s_socket());
|
|
|
|
if (bio == NULL) {
|
|
SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
|
|
goto err;
|
|
}
|
|
BIO_set_fd(bio, fd, BIO_NOCLOSE);
|
|
SSL_set_bio(s, bio, bio);
|
|
#ifndef OPENSSL_NO_KTLS
|
|
/*
|
|
* The new socket is created successfully regardless of ktls_enable.
|
|
* ktls_enable doesn't change any functionality of the socket, except
|
|
* changing the setsockopt to enable the processing of ktls_start.
|
|
* Thus, it is not a problem to call it for non-TLS sockets.
|
|
*/
|
|
ktls_enable(fd);
|
|
#endif /* OPENSSL_NO_KTLS */
|
|
ret = 1;
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
int SSL_set_wfd(SSL *s, int fd)
|
|
{
|
|
BIO *rbio = SSL_get_rbio(s);
|
|
|
|
if (rbio == NULL || BIO_method_type(rbio) != BIO_TYPE_SOCKET
|
|
|| (int)BIO_get_fd(rbio, NULL) != fd) {
|
|
BIO *bio = BIO_new(BIO_s_socket());
|
|
|
|
if (bio == NULL) {
|
|
SSLerr(SSL_F_SSL_SET_WFD, ERR_R_BUF_LIB);
|
|
return 0;
|
|
}
|
|
BIO_set_fd(bio, fd, BIO_NOCLOSE);
|
|
SSL_set0_wbio(s, bio);
|
|
#ifndef OPENSSL_NO_KTLS
|
|
/*
|
|
* The new socket is created successfully regardless of ktls_enable.
|
|
* ktls_enable doesn't change any functionality of the socket, except
|
|
* changing the setsockopt to enable the processing of ktls_start.
|
|
* Thus, it is not a problem to call it for non-TLS sockets.
|
|
*/
|
|
ktls_enable(fd);
|
|
#endif /* OPENSSL_NO_KTLS */
|
|
} else {
|
|
BIO_up_ref(rbio);
|
|
SSL_set0_wbio(s, rbio);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int SSL_set_rfd(SSL *s, int fd)
|
|
{
|
|
BIO *wbio = SSL_get_wbio(s);
|
|
|
|
if (wbio == NULL || BIO_method_type(wbio) != BIO_TYPE_SOCKET
|
|
|| ((int)BIO_get_fd(wbio, NULL) != fd)) {
|
|
BIO *bio = BIO_new(BIO_s_socket());
|
|
|
|
if (bio == NULL) {
|
|
SSLerr(SSL_F_SSL_SET_RFD, ERR_R_BUF_LIB);
|
|
return 0;
|
|
}
|
|
BIO_set_fd(bio, fd, BIO_NOCLOSE);
|
|
SSL_set0_rbio(s, bio);
|
|
} else {
|
|
BIO_up_ref(wbio);
|
|
SSL_set0_rbio(s, wbio);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
/* return length of latest Finished message we sent, copy to 'buf' */
|
|
size_t SSL_get_finished(const SSL *s, void *buf, size_t count)
|
|
{
|
|
size_t ret = 0;
|
|
|
|
ret = s->s3.tmp.finish_md_len;
|
|
if (count > ret)
|
|
count = ret;
|
|
memcpy(buf, s->s3.tmp.finish_md, count);
|
|
return ret;
|
|
}
|
|
|
|
/* return length of latest Finished message we expected, copy to 'buf' */
|
|
size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count)
|
|
{
|
|
size_t ret = 0;
|
|
|
|
ret = s->s3.tmp.peer_finish_md_len;
|
|
if (count > ret)
|
|
count = ret;
|
|
memcpy(buf, s->s3.tmp.peer_finish_md, count);
|
|
return ret;
|
|
}
|
|
|
|
int SSL_get_verify_mode(const SSL *s)
|
|
{
|
|
return s->verify_mode;
|
|
}
|
|
|
|
int SSL_get_verify_depth(const SSL *s)
|
|
{
|
|
return X509_VERIFY_PARAM_get_depth(s->param);
|
|
}
|
|
|
|
int (*SSL_get_verify_callback(const SSL *s)) (int, X509_STORE_CTX *) {
|
|
return s->verify_callback;
|
|
}
|
|
|
|
int SSL_CTX_get_verify_mode(const SSL_CTX *ctx)
|
|
{
|
|
return ctx->verify_mode;
|
|
}
|
|
|
|
int SSL_CTX_get_verify_depth(const SSL_CTX *ctx)
|
|
{
|
|
return X509_VERIFY_PARAM_get_depth(ctx->param);
|
|
}
|
|
|
|
int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx)) (int, X509_STORE_CTX *) {
|
|
return ctx->default_verify_callback;
|
|
}
|
|
|
|
void SSL_set_verify(SSL *s, int mode,
|
|
int (*callback) (int ok, X509_STORE_CTX *ctx))
|
|
{
|
|
s->verify_mode = mode;
|
|
if (callback != NULL)
|
|
s->verify_callback = callback;
|
|
}
|
|
|
|
void SSL_set_verify_depth(SSL *s, int depth)
|
|
{
|
|
X509_VERIFY_PARAM_set_depth(s->param, depth);
|
|
}
|
|
|
|
void SSL_set_read_ahead(SSL *s, int yes)
|
|
{
|
|
RECORD_LAYER_set_read_ahead(&s->rlayer, yes);
|
|
}
|
|
|
|
int SSL_get_read_ahead(const SSL *s)
|
|
{
|
|
return RECORD_LAYER_get_read_ahead(&s->rlayer);
|
|
}
|
|
|
|
int SSL_pending(const SSL *s)
|
|
{
|
|
size_t pending = s->method->ssl_pending(s);
|
|
|
|
/*
|
|
* SSL_pending cannot work properly if read-ahead is enabled
|
|
* (SSL_[CTX_]ctrl(..., SSL_CTRL_SET_READ_AHEAD, 1, NULL)), and it is
|
|
* impossible to fix since SSL_pending cannot report errors that may be
|
|
* observed while scanning the new data. (Note that SSL_pending() is
|
|
* often used as a boolean value, so we'd better not return -1.)
|
|
*
|
|
* SSL_pending also cannot work properly if the value >INT_MAX. In that case
|
|
* we just return INT_MAX.
|
|
*/
|
|
return pending < INT_MAX ? (int)pending : INT_MAX;
|
|
}
|
|
|
|
int SSL_has_pending(const SSL *s)
|
|
{
|
|
/*
|
|
* Similar to SSL_pending() but returns a 1 to indicate that we have
|
|
* unprocessed data available or 0 otherwise (as opposed to the number of
|
|
* bytes available). Unlike SSL_pending() this will take into account
|
|
* read_ahead data. A 1 return simply indicates that we have unprocessed
|
|
* data. That data may not result in any application data, or we may fail
|
|
* to parse the records for some reason.
|
|
*/
|
|
if (RECORD_LAYER_processed_read_pending(&s->rlayer))
|
|
return 1;
|
|
|
|
return RECORD_LAYER_read_pending(&s->rlayer);
|
|
}
|
|
|
|
X509 *SSL_get1_peer_certificate(const SSL *s)
|
|
{
|
|
X509 *r = SSL_get0_peer_certificate(s);
|
|
|
|
if (r != NULL)
|
|
X509_up_ref(r);
|
|
|
|
return r;
|
|
}
|
|
|
|
X509 *SSL_get0_peer_certificate(const SSL *s)
|
|
{
|
|
if ((s == NULL) || (s->session == NULL))
|
|
return NULL;
|
|
else
|
|
return s->session->peer;
|
|
}
|
|
|
|
STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s)
|
|
{
|
|
STACK_OF(X509) *r;
|
|
|
|
if ((s == NULL) || (s->session == NULL))
|
|
r = NULL;
|
|
else
|
|
r = s->session->peer_chain;
|
|
|
|
/*
|
|
* If we are a client, cert_chain includes the peer's own certificate; if
|
|
* we are a server, it does not.
|
|
*/
|
|
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Now in theory, since the calling process own 't' it should be safe to
|
|
* modify. We need to be able to read f without being hassled
|
|
*/
|
|
int SSL_copy_session_id(SSL *t, const SSL *f)
|
|
{
|
|
int i;
|
|
/* Do we need to to SSL locking? */
|
|
if (!SSL_set_session(t, SSL_get_session(f))) {
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* what if we are setup for one protocol version but want to talk another
|
|
*/
|
|
if (t->method != f->method) {
|
|
t->method->ssl_free(t);
|
|
t->method = f->method;
|
|
if (t->method->ssl_new(t) == 0)
|
|
return 0;
|
|
}
|
|
|
|
CRYPTO_UP_REF(&f->cert->references, &i, f->cert->lock);
|
|
ssl_cert_free(t->cert);
|
|
t->cert = f->cert;
|
|
if (!SSL_set_session_id_context(t, f->sid_ctx, (int)f->sid_ctx_length)) {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Fix this so it checks all the valid key/cert options */
|
|
int SSL_CTX_check_private_key(const SSL_CTX *ctx)
|
|
{
|
|
if ((ctx == NULL) || (ctx->cert->key->x509 == NULL)) {
|
|
SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY, SSL_R_NO_CERTIFICATE_ASSIGNED);
|
|
return 0;
|
|
}
|
|
if (ctx->cert->key->privatekey == NULL) {
|
|
SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
|
|
return 0;
|
|
}
|
|
return X509_check_private_key
|
|
(ctx->cert->key->x509, ctx->cert->key->privatekey);
|
|
}
|
|
|
|
/* Fix this function so that it takes an optional type parameter */
|
|
int SSL_check_private_key(const SSL *ssl)
|
|
{
|
|
if (ssl == NULL) {
|
|
SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
if (ssl->cert->key->x509 == NULL) {
|
|
SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY, SSL_R_NO_CERTIFICATE_ASSIGNED);
|
|
return 0;
|
|
}
|
|
if (ssl->cert->key->privatekey == NULL) {
|
|
SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
|
|
return 0;
|
|
}
|
|
return X509_check_private_key(ssl->cert->key->x509,
|
|
ssl->cert->key->privatekey);
|
|
}
|
|
|
|
int SSL_waiting_for_async(SSL *s)
|
|
{
|
|
if (s->job)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SSL_get_all_async_fds(SSL *s, OSSL_ASYNC_FD *fds, size_t *numfds)
|
|
{
|
|
ASYNC_WAIT_CTX *ctx = s->waitctx;
|
|
|
|
if (ctx == NULL)
|
|
return 0;
|
|
return ASYNC_WAIT_CTX_get_all_fds(ctx, fds, numfds);
|
|
}
|
|
|
|
int SSL_get_changed_async_fds(SSL *s, OSSL_ASYNC_FD *addfd, size_t *numaddfds,
|
|
OSSL_ASYNC_FD *delfd, size_t *numdelfds)
|
|
{
|
|
ASYNC_WAIT_CTX *ctx = s->waitctx;
|
|
|
|
if (ctx == NULL)
|
|
return 0;
|
|
return ASYNC_WAIT_CTX_get_changed_fds(ctx, addfd, numaddfds, delfd,
|
|
numdelfds);
|
|
}
|
|
|
|
int SSL_CTX_set_async_callback(SSL_CTX *ctx, SSL_async_callback_fn callback)
|
|
{
|
|
ctx->async_cb = callback;
|
|
return 1;
|
|
}
|
|
|
|
int SSL_CTX_set_async_callback_arg(SSL_CTX *ctx, void *arg)
|
|
{
|
|
ctx->async_cb_arg = arg;
|
|
return 1;
|
|
}
|
|
|
|
int SSL_set_async_callback(SSL *s, SSL_async_callback_fn callback)
|
|
{
|
|
s->async_cb = callback;
|
|
return 1;
|
|
}
|
|
|
|
int SSL_set_async_callback_arg(SSL *s, void *arg)
|
|
{
|
|
s->async_cb_arg = arg;
|
|
return 1;
|
|
}
|
|
|
|
int SSL_get_async_status(SSL *s, int *status)
|
|
{
|
|
ASYNC_WAIT_CTX *ctx = s->waitctx;
|
|
|
|
if (ctx == NULL)
|
|
return 0;
|
|
*status = ASYNC_WAIT_CTX_get_status(ctx);
|
|
return 1;
|
|
}
|
|
|
|
int SSL_accept(SSL *s)
|
|
{
|
|
if (s->handshake_func == NULL) {
|
|
/* Not properly initialized yet */
|
|
SSL_set_accept_state(s);
|
|
}
|
|
|
|
return SSL_do_handshake(s);
|
|
}
|
|
|
|
int SSL_connect(SSL *s)
|
|
{
|
|
if (s->handshake_func == NULL) {
|
|
/* Not properly initialized yet */
|
|
SSL_set_connect_state(s);
|
|
}
|
|
|
|
return SSL_do_handshake(s);
|
|
}
|
|
|
|
long SSL_get_default_timeout(const SSL *s)
|
|
{
|
|
return s->method->get_timeout();
|
|
}
|
|
|
|
static int ssl_async_wait_ctx_cb(void *arg)
|
|
{
|
|
SSL *s = (SSL *)arg;
|
|
|
|
return s->async_cb(s, s->async_cb_arg);
|
|
}
|
|
|
|
static int ssl_start_async_job(SSL *s, struct ssl_async_args *args,
|
|
int (*func) (void *))
|
|
{
|
|
int ret;
|
|
if (s->waitctx == NULL) {
|
|
s->waitctx = ASYNC_WAIT_CTX_new();
|
|
if (s->waitctx == NULL)
|
|
return -1;
|
|
if (s->async_cb != NULL
|
|
&& !ASYNC_WAIT_CTX_set_callback
|
|
(s->waitctx, ssl_async_wait_ctx_cb, s))
|
|
return -1;
|
|
}
|
|
switch (ASYNC_start_job(&s->job, s->waitctx, &ret, func, args,
|
|
sizeof(struct ssl_async_args))) {
|
|
case ASYNC_ERR:
|
|
s->rwstate = SSL_NOTHING;
|
|
SSLerr(SSL_F_SSL_START_ASYNC_JOB, SSL_R_FAILED_TO_INIT_ASYNC);
|
|
return -1;
|
|
case ASYNC_PAUSE:
|
|
s->rwstate = SSL_ASYNC_PAUSED;
|
|
return -1;
|
|
case ASYNC_NO_JOBS:
|
|
s->rwstate = SSL_ASYNC_NO_JOBS;
|
|
return -1;
|
|
case ASYNC_FINISH:
|
|
s->job = NULL;
|
|
return ret;
|
|
default:
|
|
s->rwstate = SSL_NOTHING;
|
|
SSLerr(SSL_F_SSL_START_ASYNC_JOB, ERR_R_INTERNAL_ERROR);
|
|
/* Shouldn't happen */
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static int ssl_io_intern(void *vargs)
|
|
{
|
|
struct ssl_async_args *args;
|
|
SSL *s;
|
|
void *buf;
|
|
size_t num;
|
|
|
|
args = (struct ssl_async_args *)vargs;
|
|
s = args->s;
|
|
buf = args->buf;
|
|
num = args->num;
|
|
switch (args->type) {
|
|
case READFUNC:
|
|
return args->f.func_read(s, buf, num, &s->asyncrw);
|
|
case WRITEFUNC:
|
|
return args->f.func_write(s, buf, num, &s->asyncrw);
|
|
case OTHERFUNC:
|
|
return args->f.func_other(s);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
|
|
{
|
|
if (s->handshake_func == NULL) {
|
|
SSLerr(SSL_F_SSL_READ_INTERNAL, SSL_R_UNINITIALIZED);
|
|
return -1;
|
|
}
|
|
|
|
if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
|
|
s->rwstate = SSL_NOTHING;
|
|
return 0;
|
|
}
|
|
|
|
if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY
|
|
|| s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY) {
|
|
SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
|
return 0;
|
|
}
|
|
/*
|
|
* If we are a client and haven't received the ServerHello etc then we
|
|
* better do that
|
|
*/
|
|
ossl_statem_check_finish_init(s, 0);
|
|
|
|
if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
|
|
struct ssl_async_args args;
|
|
int ret;
|
|
|
|
args.s = s;
|
|
args.buf = buf;
|
|
args.num = num;
|
|
args.type = READFUNC;
|
|
args.f.func_read = s->method->ssl_read;
|
|
|
|
ret = ssl_start_async_job(s, &args, ssl_io_intern);
|
|
*readbytes = s->asyncrw;
|
|
return ret;
|
|
} else {
|
|
return s->method->ssl_read(s, buf, num, readbytes);
|
|
}
|
|
}
|
|
|
|
int SSL_read(SSL *s, void *buf, int num)
|
|
{
|
|
int ret;
|
|
size_t readbytes;
|
|
|
|
if (num < 0) {
|
|
SSLerr(SSL_F_SSL_READ, SSL_R_BAD_LENGTH);
|
|
return -1;
|
|
}
|
|
|
|
ret = ssl_read_internal(s, buf, (size_t)num, &readbytes);
|
|
|
|
/*
|
|
* The cast is safe here because ret should be <= INT_MAX because num is
|
|
* <= INT_MAX
|
|
*/
|
|
if (ret > 0)
|
|
ret = (int)readbytes;
|
|
|
|
return ret;
|
|
}
|
|
|
|
int SSL_read_ex(SSL *s, void *buf, size_t num, size_t *readbytes)
|
|
{
|
|
int ret = ssl_read_internal(s, buf, num, readbytes);
|
|
|
|
if (ret < 0)
|
|
ret = 0;
|
|
return ret;
|
|
}
|
|
|
|
int SSL_read_early_data(SSL *s, void *buf, size_t num, size_t *readbytes)
|
|
{
|
|
int ret;
|
|
|
|
if (!s->server) {
|
|
SSLerr(SSL_F_SSL_READ_EARLY_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
|
return SSL_READ_EARLY_DATA_ERROR;
|
|
}
|
|
|
|
switch (s->early_data_state) {
|
|
case SSL_EARLY_DATA_NONE:
|
|
if (!SSL_in_before(s)) {
|
|
SSLerr(SSL_F_SSL_READ_EARLY_DATA,
|
|
ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
|
return SSL_READ_EARLY_DATA_ERROR;
|
|
}
|
|
/* fall through */
|
|
|
|
case SSL_EARLY_DATA_ACCEPT_RETRY:
|
|
s->early_data_state = SSL_EARLY_DATA_ACCEPTING;
|
|
ret = SSL_accept(s);
|
|
if (ret <= 0) {
|
|
/* NBIO or error */
|
|
s->early_data_state = SSL_EARLY_DATA_ACCEPT_RETRY;
|
|
return SSL_READ_EARLY_DATA_ERROR;
|
|
}
|
|
/* fall through */
|
|
|
|
case SSL_EARLY_DATA_READ_RETRY:
|
|
if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
|
|
s->early_data_state = SSL_EARLY_DATA_READING;
|
|
ret = SSL_read_ex(s, buf, num, readbytes);
|
|
/*
|
|
* State machine will update early_data_state to
|
|
* SSL_EARLY_DATA_FINISHED_READING if we get an EndOfEarlyData
|
|
* message
|
|
*/
|
|
if (ret > 0 || (ret <= 0 && s->early_data_state
|
|
!= SSL_EARLY_DATA_FINISHED_READING)) {
|
|
s->early_data_state = SSL_EARLY_DATA_READ_RETRY;
|
|
return ret > 0 ? SSL_READ_EARLY_DATA_SUCCESS
|
|
: SSL_READ_EARLY_DATA_ERROR;
|
|
}
|
|
} else {
|
|
s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
|
|
}
|
|
*readbytes = 0;
|
|
return SSL_READ_EARLY_DATA_FINISH;
|
|
|
|
default:
|
|
SSLerr(SSL_F_SSL_READ_EARLY_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
|
return SSL_READ_EARLY_DATA_ERROR;
|
|
}
|
|
}
|
|
|
|
int SSL_get_early_data_status(const SSL *s)
|
|
{
|
|
return s->ext.early_data;
|
|
}
|
|
|
|
static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
|
|
{
|
|
if (s->handshake_func == NULL) {
|
|
SSLerr(SSL_F_SSL_PEEK_INTERNAL, SSL_R_UNINITIALIZED);
|
|
return -1;
|
|
}
|
|
|
|
if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
|
|
return 0;
|
|
}
|
|
if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
|
|
struct ssl_async_args args;
|
|
int ret;
|
|
|
|
args.s = s;
|
|
args.buf = buf;
|
|
args.num = num;
|
|
args.type = READFUNC;
|
|
args.f.func_read = s->method->ssl_peek;
|
|
|
|
ret = ssl_start_async_job(s, &args, ssl_io_intern);
|
|
*readbytes = s->asyncrw;
|
|
return ret;
|
|
} else {
|
|
return s->method->ssl_peek(s, buf, num, readbytes);
|
|
}
|
|
}
|
|
|
|
int SSL_peek(SSL *s, void *buf, int num)
|
|
{
|
|
int ret;
|
|
size_t readbytes;
|
|
|
|
if (num < 0) {
|
|
SSLerr(SSL_F_SSL_PEEK, SSL_R_BAD_LENGTH);
|
|
return -1;
|
|
}
|
|
|
|
ret = ssl_peek_internal(s, buf, (size_t)num, &readbytes);
|
|
|
|
/*
|
|
* The cast is safe here because ret should be <= INT_MAX because num is
|
|
* <= INT_MAX
|
|
*/
|
|
if (ret > 0)
|
|
ret = (int)readbytes;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int SSL_peek_ex(SSL *s, void *buf, size_t num, size_t *readbytes)
|
|
{
|
|
int ret = ssl_peek_internal(s, buf, num, readbytes);
|
|
|
|
if (ret < 0)
|
|
ret = 0;
|
|
return ret;
|
|
}
|
|
|
|
int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
|
|
{
|
|
if (s->handshake_func == NULL) {
|
|
SSLerr(SSL_F_SSL_WRITE_INTERNAL, SSL_R_UNINITIALIZED);
|
|
return -1;
|
|
}
|
|
|
|
if (s->shutdown & SSL_SENT_SHUTDOWN) {
|
|
s->rwstate = SSL_NOTHING;
|
|
SSLerr(SSL_F_SSL_WRITE_INTERNAL, SSL_R_PROTOCOL_IS_SHUTDOWN);
|
|
return -1;
|
|
}
|
|
|
|
if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY
|
|
|| s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY
|
|
|| s->early_data_state == SSL_EARLY_DATA_READ_RETRY) {
|
|
SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
|
return 0;
|
|
}
|
|
/* If we are a client and haven't sent the Finished we better do that */
|
|
ossl_statem_check_finish_init(s, 1);
|
|
|
|
if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
|
|
int ret;
|
|
struct ssl_async_args args;
|
|
|
|
args.s = s;
|
|
args.buf = (void *)buf;
|
|
args.num = num;
|
|
args.type = WRITEFUNC;
|
|
args.f.func_write = s->method->ssl_write;
|
|
|
|
ret = ssl_start_async_job(s, &args, ssl_io_intern);
|
|
*written = s->asyncrw;
|
|
return ret;
|
|
} else {
|
|
return s->method->ssl_write(s, buf, num, written);
|
|
}
|
|
}
|
|
|
|
ossl_ssize_t SSL_sendfile(SSL *s, int fd, off_t offset, size_t size, int flags)
|
|
{
|
|
ossl_ssize_t ret;
|
|
|
|
if (s->handshake_func == NULL) {
|
|
SSLerr(SSL_F_SSL_SENDFILE, SSL_R_UNINITIALIZED);
|
|
return -1;
|
|
}
|
|
|
|
if (s->shutdown & SSL_SENT_SHUTDOWN) {
|
|
s->rwstate = SSL_NOTHING;
|
|
SSLerr(SSL_F_SSL_SENDFILE, SSL_R_PROTOCOL_IS_SHUTDOWN);
|
|
return -1;
|
|
}
|
|
|
|
if (!BIO_get_ktls_send(s->wbio)) {
|
|
SSLerr(SSL_F_SSL_SENDFILE, SSL_R_UNINITIALIZED);
|
|
return -1;
|
|
}
|
|
|
|
/* If we have an alert to send, lets send it */
|
|
if (s->s3.alert_dispatch) {
|
|
ret = (ossl_ssize_t)s->method->ssl_dispatch_alert(s);
|
|
if (ret <= 0) {
|
|
/* SSLfatal() already called if appropriate */
|
|
return ret;
|
|
}
|
|
/* if it went, fall through and send more stuff */
|
|
}
|
|
|
|
s->rwstate = SSL_WRITING;
|
|
if (BIO_flush(s->wbio) <= 0) {
|
|
if (!BIO_should_retry(s->wbio)) {
|
|
s->rwstate = SSL_NOTHING;
|
|
} else {
|
|
#ifdef EAGAIN
|
|
set_sys_error(EAGAIN);
|
|
#endif
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
#ifdef OPENSSL_NO_KTLS
|
|
ERR_raise_data(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR,
|
|
"can't call ktls_sendfile(), ktls disabled");
|
|
return -1;
|
|
#else
|
|
ret = ktls_sendfile(SSL_get_wfd(s), fd, offset, size, flags);
|
|
if (ret < 0) {
|
|
#if defined(EAGAIN) && defined(EINTR) && defined(EBUSY)
|
|
if ((get_last_sys_error() == EAGAIN) ||
|
|
(get_last_sys_error() == EINTR) ||
|
|
(get_last_sys_error() == EBUSY))
|
|
BIO_set_retry_write(s->wbio);
|
|
else
|
|
#endif
|
|
SSLerr(SSL_F_SSL_SENDFILE, SSL_R_UNINITIALIZED);
|
|
return ret;
|
|
}
|
|
s->rwstate = SSL_NOTHING;
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
int SSL_write(SSL *s, const void *buf, int num)
|
|
{
|
|
int ret;
|
|
size_t written;
|
|
|
|
if (num < 0) {
|
|
SSLerr(SSL_F_SSL_WRITE, SSL_R_BAD_LENGTH);
|
|
return -1;
|
|
}
|
|
|
|
ret = ssl_write_internal(s, buf, (size_t)num, &written);
|
|
|
|
/*
|
|
* The cast is safe here because ret should be <= INT_MAX because num is
|
|
* <= INT_MAX
|
|
*/
|
|
if (ret > 0)
|
|
ret = (int)written;
|
|
|
|
return ret;
|
|
}
|
|
|
|
int SSL_write_ex(SSL *s, const void *buf, size_t num, size_t *written)
|
|
{
|
|
int ret = ssl_write_internal(s, buf, num, written);
|
|
|
|
if (ret < 0)
|
|
ret = 0;
|
|
return ret;
|
|
}
|
|
|
|
int SSL_write_early_data(SSL *s, const void *buf, size_t num, size_t *written)
|
|
{
|
|
int ret, early_data_state;
|
|
size_t writtmp;
|
|
uint32_t partialwrite;
|
|
|
|
switch (s->early_data_state) {
|
|
case SSL_EARLY_DATA_NONE:
|
|
if (s->server
|
|
|| !SSL_in_before(s)
|
|
|| ((s->session == NULL || s->session->ext.max_early_data == 0)
|
|
&& (s->psk_use_session_cb == NULL))) {
|
|
SSLerr(SSL_F_SSL_WRITE_EARLY_DATA,
|
|
ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
|
return 0;
|
|
}
|
|
/* fall through */
|
|
|
|
case SSL_EARLY_DATA_CONNECT_RETRY:
|
|
s->early_data_state = SSL_EARLY_DATA_CONNECTING;
|
|
ret = SSL_connect(s);
|
|
if (ret <= 0) {
|
|
/* NBIO or error */
|
|
s->early_data_state = SSL_EARLY_DATA_CONNECT_RETRY;
|
|
return 0;
|
|
}
|
|
/* fall through */
|
|
|
|
case SSL_EARLY_DATA_WRITE_RETRY:
|
|
s->early_data_state = SSL_EARLY_DATA_WRITING;
|
|
/*
|
|
* We disable partial write for early data because we don't keep track
|
|
* of how many bytes we've written between the SSL_write_ex() call and
|
|
* the flush if the flush needs to be retried)
|
|
*/
|
|
partialwrite = s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE;
|
|
s->mode &= ~SSL_MODE_ENABLE_PARTIAL_WRITE;
|
|
ret = SSL_write_ex(s, buf, num, &writtmp);
|
|
s->mode |= partialwrite;
|
|
if (!ret) {
|
|
s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
|
|
return ret;
|
|
}
|
|
s->early_data_state = SSL_EARLY_DATA_WRITE_FLUSH;
|
|
/* fall through */
|
|
|
|
case SSL_EARLY_DATA_WRITE_FLUSH:
|
|
/* The buffering BIO is still in place so we need to flush it */
|
|
if (statem_flush(s) != 1)
|
|
return 0;
|
|
*written = num;
|
|
s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
|
|
return 1;
|
|
|
|
case SSL_EARLY_DATA_FINISHED_READING:
|
|
case SSL_EARLY_DATA_READ_RETRY:
|
|
early_data_state = s->early_data_state;
|
|
/* We are a server writing to an unauthenticated client */
|
|
s->early_data_state = SSL_EARLY_DATA_UNAUTH_WRITING;
|
|
ret = SSL_write_ex(s, buf, num, written);
|
|
/* The buffering BIO is still in place */
|
|
if (ret)
|
|
(void)BIO_flush(s->wbio);
|
|
s->early_data_state = early_data_state;
|
|
return ret;
|
|
|
|
default:
|
|
SSLerr(SSL_F_SSL_WRITE_EARLY_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int SSL_shutdown(SSL *s)
|
|
{
|
|
/*
|
|
* Note that this function behaves differently from what one might
|
|
* expect. Return values are 0 for no success (yet), 1 for success; but
|
|
* calling it once is usually not enough, even if blocking I/O is used
|
|
* (see ssl3_shutdown).
|
|
*/
|
|
|
|
if (s->handshake_func == NULL) {
|
|
SSLerr(SSL_F_SSL_SHUTDOWN, SSL_R_UNINITIALIZED);
|
|
return -1;
|
|
}
|
|
|
|
if (!SSL_in_init(s)) {
|
|
if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
|
|
struct ssl_async_args args;
|
|
|
|
args.s = s;
|
|
args.type = OTHERFUNC;
|
|
args.f.func_other = s->method->ssl_shutdown;
|
|
|
|
return ssl_start_async_job(s, &args, ssl_io_intern);
|
|
} else {
|
|
return s->method->ssl_shutdown(s);
|
|
}
|
|
} else {
|
|
SSLerr(SSL_F_SSL_SHUTDOWN, SSL_R_SHUTDOWN_WHILE_IN_INIT);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int SSL_key_update(SSL *s, int updatetype)
|
|
{
|
|
/*
|
|
* TODO(TLS1.3): How will applications know whether TLSv1.3 has been
|
|
* negotiated, and that it is appropriate to call SSL_key_update() instead
|
|
* of SSL_renegotiate().
|
|
*/
|
|
if (!SSL_IS_TLS13(s)) {
|
|
SSLerr(SSL_F_SSL_KEY_UPDATE, SSL_R_WRONG_SSL_VERSION);
|
|
return 0;
|
|
}
|
|
|
|
if (updatetype != SSL_KEY_UPDATE_NOT_REQUESTED
|
|
&& updatetype != SSL_KEY_UPDATE_REQUESTED) {
|
|
SSLerr(SSL_F_SSL_KEY_UPDATE, SSL_R_INVALID_KEY_UPDATE_TYPE);
|
|
return 0;
|
|
}
|
|
|
|
if (!SSL_is_init_finished(s)) {
|
|
SSLerr(SSL_F_SSL_KEY_UPDATE, SSL_R_STILL_IN_INIT);
|
|
return 0;
|
|
}
|
|
|
|
ossl_statem_set_in_init(s, 1);
|
|
s->key_update = updatetype;
|
|
return 1;
|
|
}
|
|
|
|
int SSL_get_key_update_type(const SSL *s)
|
|
{
|
|
return s->key_update;
|
|
}
|
|
|
|
int SSL_renegotiate(SSL *s)
|
|
{
|
|
if (SSL_IS_TLS13(s)) {
|
|
SSLerr(SSL_F_SSL_RENEGOTIATE, SSL_R_WRONG_SSL_VERSION);
|
|
return 0;
|
|
}
|
|
|
|
if ((s->options & SSL_OP_NO_RENEGOTIATION)) {
|
|
SSLerr(SSL_F_SSL_RENEGOTIATE, SSL_R_NO_RENEGOTIATION);
|
|
return 0;
|
|
}
|
|
|
|
s->renegotiate = 1;
|
|
s->new_session = 1;
|
|
|
|
return s->method->ssl_renegotiate(s);
|
|
}
|
|
|
|
int SSL_renegotiate_abbreviated(SSL *s)
|
|
{
|
|
if (SSL_IS_TLS13(s)) {
|
|
SSLerr(SSL_F_SSL_RENEGOTIATE_ABBREVIATED, SSL_R_WRONG_SSL_VERSION);
|
|
return 0;
|
|
}
|
|
|
|
if ((s->options & SSL_OP_NO_RENEGOTIATION)) {
|
|
SSLerr(SSL_F_SSL_RENEGOTIATE_ABBREVIATED, SSL_R_NO_RENEGOTIATION);
|
|
return 0;
|
|
}
|
|
|
|
s->renegotiate = 1;
|
|
s->new_session = 0;
|
|
|
|
return s->method->ssl_renegotiate(s);
|
|
}
|
|
|
|
int SSL_renegotiate_pending(const SSL *s)
|
|
{
|
|
/*
|
|
* becomes true when negotiation is requested; false again once a
|
|
* handshake has finished
|
|
*/
|
|
return (s->renegotiate != 0);
|
|
}
|
|
|
|
int SSL_new_session_ticket(SSL *s)
|
|
{
|
|
if (SSL_in_init(s) || SSL_IS_FIRST_HANDSHAKE(s) || !s->server
|
|
|| !SSL_IS_TLS13(s))
|
|
return 0;
|
|
s->ext.extra_tickets_expected++;
|
|
return 1;
|
|
}
|
|
|
|
long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
|
|
{
|
|
long l;
|
|
|
|
switch (cmd) {
|
|
case SSL_CTRL_GET_READ_AHEAD:
|
|
return RECORD_LAYER_get_read_ahead(&s->rlayer);
|
|
case SSL_CTRL_SET_READ_AHEAD:
|
|
l = RECORD_LAYER_get_read_ahead(&s->rlayer);
|
|
RECORD_LAYER_set_read_ahead(&s->rlayer, larg);
|
|
return l;
|
|
|
|
case SSL_CTRL_SET_MSG_CALLBACK_ARG:
|
|
s->msg_callback_arg = parg;
|
|
return 1;
|
|
|
|
case SSL_CTRL_MODE:
|
|
return (s->mode |= larg);
|
|
case SSL_CTRL_CLEAR_MODE:
|
|
return (s->mode &= ~larg);
|
|
case SSL_CTRL_GET_MAX_CERT_LIST:
|
|
return (long)s->max_cert_list;
|
|
case SSL_CTRL_SET_MAX_CERT_LIST:
|
|
if (larg < 0)
|
|
return 0;
|
|
l = (long)s->max_cert_list;
|
|
s->max_cert_list = (size_t)larg;
|
|
return l;
|
|
case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
|
|
if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
|
|
return 0;
|
|
#ifndef OPENSSL_NO_KTLS
|
|
if (s->wbio != NULL && BIO_get_ktls_send(s->wbio))
|
|
return 0;
|
|
#endif /* OPENSSL_NO_KTLS */
|
|
s->max_send_fragment = larg;
|
|
if (s->max_send_fragment < s->split_send_fragment)
|
|
s->split_send_fragment = s->max_send_fragment;
|
|
return 1;
|
|
case SSL_CTRL_SET_SPLIT_SEND_FRAGMENT:
|
|
if ((size_t)larg > s->max_send_fragment || larg == 0)
|
|
return 0;
|
|
s->split_send_fragment = larg;
|
|
return 1;
|
|
case SSL_CTRL_SET_MAX_PIPELINES:
|
|
if (larg < 1 || larg > SSL_MAX_PIPELINES)
|
|
return 0;
|
|
s->max_pipelines = larg;
|
|
if (larg > 1)
|
|
RECORD_LAYER_set_read_ahead(&s->rlayer, 1);
|
|
return 1;
|
|
case SSL_CTRL_GET_RI_SUPPORT:
|
|
return s->s3.send_connection_binding;
|
|
case SSL_CTRL_CERT_FLAGS:
|
|
return (s->cert->cert_flags |= larg);
|
|
case SSL_CTRL_CLEAR_CERT_FLAGS:
|
|
return (s->cert->cert_flags &= ~larg);
|
|
|
|
case SSL_CTRL_GET_RAW_CIPHERLIST:
|
|
if (parg) {
|
|
if (s->s3.tmp.ciphers_raw == NULL)
|
|
return 0;
|
|
*(unsigned char **)parg = s->s3.tmp.ciphers_raw;
|
|
return (int)s->s3.tmp.ciphers_rawlen;
|
|
} else {
|
|
return TLS_CIPHER_LEN;
|
|
}
|
|
case SSL_CTRL_GET_EXTMS_SUPPORT:
|
|
if (!s->session || SSL_in_init(s) || ossl_statem_get_in_handshake(s))
|
|
return -1;
|
|
if (s->session->flags & SSL_SESS_FLAG_EXTMS)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
case SSL_CTRL_SET_MIN_PROTO_VERSION:
|
|
return ssl_check_allowed_versions(larg, s->max_proto_version)
|
|
&& ssl_set_version_bound(s->ctx->method->version, (int)larg,
|
|
&s->min_proto_version);
|
|
case SSL_CTRL_GET_MIN_PROTO_VERSION:
|
|
return s->min_proto_version;
|
|
case SSL_CTRL_SET_MAX_PROTO_VERSION:
|
|
return ssl_check_allowed_versions(s->min_proto_version, larg)
|
|
&& ssl_set_version_bound(s->ctx->method->version, (int)larg,
|
|
&s->max_proto_version);
|
|
case SSL_CTRL_GET_MAX_PROTO_VERSION:
|
|
return s->max_proto_version;
|
|
default:
|
|
return s->method->ssl_ctrl(s, cmd, larg, parg);
|
|
}
|
|
}
|
|
|
|
long SSL_callback_ctrl(SSL *s, int cmd, void (*fp) (void))
|
|
{
|
|
switch (cmd) {
|
|
case SSL_CTRL_SET_MSG_CALLBACK:
|
|
s->msg_callback = (void (*)
|
|
(int write_p, int version, int content_type,
|
|
const void *buf, size_t len, SSL *ssl,
|
|
void *arg))(fp);
|
|
return 1;
|
|
|
|
default:
|
|
return s->method->ssl_callback_ctrl(s, cmd, fp);
|
|
}
|
|
}
|
|
|
|
LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx)
|
|
{
|
|
return ctx->sessions;
|
|
}
|
|
|
|
long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
|
|
{
|
|
long l;
|
|
/* For some cases with ctx == NULL perform syntax checks */
|
|
if (ctx == NULL) {
|
|
switch (cmd) {
|
|
case SSL_CTRL_SET_GROUPS_LIST:
|
|
return tls1_set_groups_list(ctx, NULL, NULL, parg);
|
|
case SSL_CTRL_SET_SIGALGS_LIST:
|
|
case SSL_CTRL_SET_CLIENT_SIGALGS_LIST:
|
|
return tls1_set_sigalgs_list(NULL, parg, 0);
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
switch (cmd) {
|
|
case SSL_CTRL_GET_READ_AHEAD:
|
|
return ctx->read_ahead;
|
|
case SSL_CTRL_SET_READ_AHEAD:
|
|
l = ctx->read_ahead;
|
|
ctx->read_ahead = larg;
|
|
return l;
|
|
|
|
case SSL_CTRL_SET_MSG_CALLBACK_ARG:
|
|
ctx->msg_callback_arg = parg;
|
|
return 1;
|
|
|
|
case SSL_CTRL_GET_MAX_CERT_LIST:
|
|
return (long)ctx->max_cert_list;
|
|
case SSL_CTRL_SET_MAX_CERT_LIST:
|
|
if (larg < 0)
|
|
return 0;
|
|
l = (long)ctx->max_cert_list;
|
|
ctx->max_cert_list = (size_t)larg;
|
|
return l;
|
|
|
|
case SSL_CTRL_SET_SESS_CACHE_SIZE:
|
|
if (larg < 0)
|
|
return 0;
|
|
l = (long)ctx->session_cache_size;
|
|
ctx->session_cache_size = (size_t)larg;
|
|
return l;
|
|
case SSL_CTRL_GET_SESS_CACHE_SIZE:
|
|
return (long)ctx->session_cache_size;
|
|
case SSL_CTRL_SET_SESS_CACHE_MODE:
|
|
l = ctx->session_cache_mode;
|
|
ctx->session_cache_mode = larg;
|
|
return l;
|
|
case SSL_CTRL_GET_SESS_CACHE_MODE:
|
|
return ctx->session_cache_mode;
|
|
|
|
case SSL_CTRL_SESS_NUMBER:
|
|
return lh_SSL_SESSION_num_items(ctx->sessions);
|
|
case SSL_CTRL_SESS_CONNECT:
|
|
return tsan_load(&ctx->stats.sess_connect);
|
|
case SSL_CTRL_SESS_CONNECT_GOOD:
|
|
return tsan_load(&ctx->stats.sess_connect_good);
|
|
case SSL_CTRL_SESS_CONNECT_RENEGOTIATE:
|
|
return tsan_load(&ctx->stats.sess_connect_renegotiate);
|
|
case SSL_CTRL_SESS_ACCEPT:
|
|
return tsan_load(&ctx->stats.sess_accept);
|
|
case SSL_CTRL_SESS_ACCEPT_GOOD:
|
|
return tsan_load(&ctx->stats.sess_accept_good);
|
|
case SSL_CTRL_SESS_ACCEPT_RENEGOTIATE:
|
|
return tsan_load(&ctx->stats.sess_accept_renegotiate);
|
|
case SSL_CTRL_SESS_HIT:
|
|
return tsan_load(&ctx->stats.sess_hit);
|
|
case SSL_CTRL_SESS_CB_HIT:
|
|
return tsan_load(&ctx->stats.sess_cb_hit);
|
|
case SSL_CTRL_SESS_MISSES:
|
|
return tsan_load(&ctx->stats.sess_miss);
|
|
case SSL_CTRL_SESS_TIMEOUTS:
|
|
return tsan_load(&ctx->stats.sess_timeout);
|
|
case SSL_CTRL_SESS_CACHE_FULL:
|
|
return tsan_load(&ctx->stats.sess_cache_full);
|
|
case SSL_CTRL_MODE:
|
|
return (ctx->mode |= larg);
|
|
case SSL_CTRL_CLEAR_MODE:
|
|
return (ctx->mode &= ~larg);
|
|
case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
|
|
if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
|
|
return 0;
|
|
ctx->max_send_fragment = larg;
|
|
if (ctx->max_send_fragment < ctx->split_send_fragment)
|
|
ctx->split_send_fragment = ctx->max_send_fragment;
|
|
return 1;
|
|
case SSL_CTRL_SET_SPLIT_SEND_FRAGMENT:
|
|
if ((size_t)larg > ctx->max_send_fragment || larg == 0)
|
|
return 0;
|
|
ctx->split_send_fragment = larg;
|
|
return 1;
|
|
case SSL_CTRL_SET_MAX_PIPELINES:
|
|
if (larg < 1 || larg > SSL_MAX_PIPELINES)
|
|
return 0;
|
|
ctx->max_pipelines = larg;
|
|
return 1;
|
|
case SSL_CTRL_CERT_FLAGS:
|
|
return (ctx->cert->cert_flags |= larg);
|
|
case SSL_CTRL_CLEAR_CERT_FLAGS:
|
|
return (ctx->cert->cert_flags &= ~larg);
|
|
case SSL_CTRL_SET_MIN_PROTO_VERSION:
|
|
return ssl_check_allowed_versions(larg, ctx->max_proto_version)
|
|
&& ssl_set_version_bound(ctx->method->version, (int)larg,
|
|
&ctx->min_proto_version);
|
|
case SSL_CTRL_GET_MIN_PROTO_VERSION:
|
|
return ctx->min_proto_version;
|
|
case SSL_CTRL_SET_MAX_PROTO_VERSION:
|
|
return ssl_check_allowed_versions(ctx->min_proto_version, larg)
|
|
&& ssl_set_version_bound(ctx->method->version, (int)larg,
|
|
&ctx->max_proto_version);
|
|
case SSL_CTRL_GET_MAX_PROTO_VERSION:
|
|
return ctx->max_proto_version;
|
|
default:
|
|
return ctx->method->ssl_ctx_ctrl(ctx, cmd, larg, parg);
|
|
}
|
|
}
|
|
|
|
long SSL_CTX_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp) (void))
|
|
{
|
|
switch (cmd) {
|
|
case SSL_CTRL_SET_MSG_CALLBACK:
|
|
ctx->msg_callback = (void (*)
|
|
(int write_p, int version, int content_type,
|
|
const void *buf, size_t len, SSL *ssl,
|
|
void *arg))(fp);
|
|
return 1;
|
|
|
|
default:
|
|
return ctx->method->ssl_ctx_callback_ctrl(ctx, cmd, fp);
|
|
}
|
|
}
|
|
|
|
int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b)
|
|
{
|
|
if (a->id > b->id)
|
|
return 1;
|
|
if (a->id < b->id)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
int ssl_cipher_ptr_id_cmp(const SSL_CIPHER *const *ap,
|
|
const SSL_CIPHER *const *bp)
|
|
{
|
|
if ((*ap)->id > (*bp)->id)
|
|
return 1;
|
|
if ((*ap)->id < (*bp)->id)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
/** return a STACK of the ciphers available for the SSL and in order of
|
|
* preference */
|
|
STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s)
|
|
{
|
|
if (s != NULL) {
|
|
if (s->cipher_list != NULL) {
|
|
return s->cipher_list;
|
|
} else if ((s->ctx != NULL) && (s->ctx->cipher_list != NULL)) {
|
|
return s->ctx->cipher_list;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
STACK_OF(SSL_CIPHER) *SSL_get_client_ciphers(const SSL *s)
|
|
{
|
|
if ((s == NULL) || !s->server)
|
|
return NULL;
|
|
return s->peer_ciphers;
|
|
}
|
|
|
|
STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s)
|
|
{
|
|
STACK_OF(SSL_CIPHER) *sk = NULL, *ciphers;
|
|
int i;
|
|
|
|
ciphers = SSL_get_ciphers(s);
|
|
if (!ciphers)
|
|
return NULL;
|
|
if (!ssl_set_client_disabled(s))
|
|
return NULL;
|
|
for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
|
|
const SSL_CIPHER *c = sk_SSL_CIPHER_value(ciphers, i);
|
|
if (!ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED, 0)) {
|
|
if (!sk)
|
|
sk = sk_SSL_CIPHER_new_null();
|
|
if (!sk)
|
|
return NULL;
|
|
if (!sk_SSL_CIPHER_push(sk, c)) {
|
|
sk_SSL_CIPHER_free(sk);
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
return sk;
|
|
}
|
|
|
|
/** return a STACK of the ciphers available for the SSL and in order of
|
|
* algorithm id */
|
|
STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s)
|
|
{
|
|
if (s != NULL) {
|
|
if (s->cipher_list_by_id != NULL) {
|
|
return s->cipher_list_by_id;
|
|
} else if ((s->ctx != NULL) && (s->ctx->cipher_list_by_id != NULL)) {
|
|
return s->ctx->cipher_list_by_id;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/** The old interface to get the same thing as SSL_get_ciphers() */
|
|
const char *SSL_get_cipher_list(const SSL *s, int n)
|
|
{
|
|
const SSL_CIPHER *c;
|
|
STACK_OF(SSL_CIPHER) *sk;
|
|
|
|
if (s == NULL)
|
|
return NULL;
|
|
sk = SSL_get_ciphers(s);
|
|
if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= n))
|
|
return NULL;
|
|
c = sk_SSL_CIPHER_value(sk, n);
|
|
if (c == NULL)
|
|
return NULL;
|
|
return c->name;
|
|
}
|
|
|
|
/** return a STACK of the ciphers available for the SSL_CTX and in order of
|
|
* preference */
|
|
STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx)
|
|
{
|
|
if (ctx != NULL)
|
|
return ctx->cipher_list;
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Distinguish between ciphers controlled by set_ciphersuite() and
|
|
* set_cipher_list() when counting.
|
|
*/
|
|
static int cipher_list_tls12_num(STACK_OF(SSL_CIPHER) *sk)
|
|
{
|
|
int i, num = 0;
|
|
const SSL_CIPHER *c;
|
|
|
|
if (sk == NULL)
|
|
return 0;
|
|
for (i = 0; i < sk_SSL_CIPHER_num(sk); ++i) {
|
|
c = sk_SSL_CIPHER_value(sk, i);
|
|
if (c->min_tls >= TLS1_3_VERSION)
|
|
continue;
|
|
num++;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
/** specify the ciphers to be used by default by the SSL_CTX */
|
|
int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str)
|
|
{
|
|
STACK_OF(SSL_CIPHER) *sk;
|
|
|
|
sk = ssl_create_cipher_list(ctx->method, ctx->tls13_ciphersuites,
|
|
&ctx->cipher_list, &ctx->cipher_list_by_id, str,
|
|
ctx->cert);
|
|
/*
|
|
* ssl_create_cipher_list may return an empty stack if it was unable to
|
|
* find a cipher matching the given rule string (for example if the rule
|
|
* string specifies a cipher which has been disabled). This is not an
|
|
* error as far as ssl_create_cipher_list is concerned, and hence
|
|
* ctx->cipher_list and ctx->cipher_list_by_id has been updated.
|
|
*/
|
|
if (sk == NULL)
|
|
return 0;
|
|
else if (cipher_list_tls12_num(sk) == 0) {
|
|
SSLerr(SSL_F_SSL_CTX_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/** specify the ciphers to be used by the SSL */
|
|
int SSL_set_cipher_list(SSL *s, const char *str)
|
|
{
|
|
STACK_OF(SSL_CIPHER) *sk;
|
|
|
|
sk = ssl_create_cipher_list(s->ctx->method, s->tls13_ciphersuites,
|
|
&s->cipher_list, &s->cipher_list_by_id, str,
|
|
s->cert);
|
|
/* see comment in SSL_CTX_set_cipher_list */
|
|
if (sk == NULL)
|
|
return 0;
|
|
else if (cipher_list_tls12_num(sk) == 0) {
|
|
SSLerr(SSL_F_SSL_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
char *SSL_get_shared_ciphers(const SSL *s, char *buf, int size)
|
|
{
|
|
char *p;
|
|
STACK_OF(SSL_CIPHER) *clntsk, *srvrsk;
|
|
const SSL_CIPHER *c;
|
|
int i;
|
|
|
|
if (!s->server
|
|
|| s->peer_ciphers == NULL
|
|
|| size < 2)
|
|
return NULL;
|
|
|
|
p = buf;
|
|
clntsk = s->peer_ciphers;
|
|
srvrsk = SSL_get_ciphers(s);
|
|
if (clntsk == NULL || srvrsk == NULL)
|
|
return NULL;
|
|
|
|
if (sk_SSL_CIPHER_num(clntsk) == 0 || sk_SSL_CIPHER_num(srvrsk) == 0)
|
|
return NULL;
|
|
|
|
for (i = 0; i < sk_SSL_CIPHER_num(clntsk); i++) {
|
|
int n;
|
|
|
|
c = sk_SSL_CIPHER_value(clntsk, i);
|
|
|