/*
* Copyright 2012-2023 The OpenSSL Project Authors. 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 "ssl_local.h"
#include <openssl/conf.h>
#include <openssl/objects.h>
#include <openssl/decoder.h>
#include <openssl/core_dispatch.h>
#include "internal/nelem.h"
/*
* structure holding name tables. This is used for permitted elements in lists
* such as TLSv1.
*/
typedef struct {
const char *name;
int namelen;
unsigned int name_flags;
uint64_t option_value;
} ssl_flag_tbl;
/* Switch table: use for single command line switches like no_tls2 */
typedef struct {
uint64_t option_value;
unsigned int name_flags;
} ssl_switch_tbl;
/* Sense of name is inverted e.g. "TLSv1" will clear SSL_OP_NO_TLSv1 */
#define SSL_TFLAG_INV 0x1
/* Mask for type of flag referred to */
#define SSL_TFLAG_TYPE_MASK 0xf00
/* Flag is for options */
#define SSL_TFLAG_OPTION 0x000
/* Flag is for cert_flags */
#define SSL_TFLAG_CERT 0x100
/* Flag is for verify mode */
#define SSL_TFLAG_VFY 0x200
/* Option can only be used for clients */
#define SSL_TFLAG_CLIENT SSL_CONF_FLAG_CLIENT
/* Option can only be used for servers */
#define SSL_TFLAG_SERVER SSL_CONF_FLAG_SERVER
#define SSL_TFLAG_BOTH (SSL_TFLAG_CLIENT|SSL_TFLAG_SERVER)
#define SSL_FLAG_TBL(str, flag) \
{str, (int)(sizeof(str) - 1), SSL_TFLAG_BOTH, flag}
#define SSL_FLAG_TBL_SRV(str, flag) \
{str, (int)(sizeof(str) - 1), SSL_TFLAG_SERVER, flag}
#define SSL_FLAG_TBL_CLI(str, flag) \
{str, (int)(sizeof(str) - 1), SSL_TFLAG_CLIENT, flag}
#define SSL_FLAG_TBL_INV(str, flag) \
{str, (int)(sizeof(str) - 1), SSL_TFLAG_INV|SSL_TFLAG_BOTH, flag}
#define SSL_FLAG_TBL_SRV_INV(str, flag) \
{str, (int)(sizeof(str) - 1), SSL_TFLAG_INV|SSL_TFLAG_SERVER, flag}
#define SSL_FLAG_TBL_CERT(str, flag) \
{str, (int)(sizeof(str) - 1), SSL_TFLAG_CERT|SSL_TFLAG_BOTH, flag}
#define SSL_FLAG_VFY_CLI(str, flag) \
{str, (int)(sizeof(str) - 1), SSL_TFLAG_VFY | SSL_TFLAG_CLIENT, flag}
#define SSL_FLAG_VFY_SRV(str, flag) \
{str, (int)(sizeof(str) - 1), SSL_TFLAG_VFY | SSL_TFLAG_SERVER, flag}
/*
* Opaque structure containing SSL configuration context.
*/
struct ssl_conf_ctx_st {
/*
* Various flags indicating (among other things) which options we will
* recognise.
*/
unsigned int flags;
/* Prefix and length of commands */
char *prefix;
size_t prefixlen;
/* SSL_CTX or SSL structure to perform operations on */
SSL_CTX *ctx;
SSL *ssl;
/* Pointer to SSL or SSL_CTX options field or NULL if none */
uint64_t *poptions;
/* Certificate filenames for each type */
char *cert_filename[SSL_PKEY_NUM];
/* Pointer to SSL or SSL_CTX cert_flags or NULL if none */
uint32_t *pcert_flags;
/* Pointer to SSL or SSL_CTX verify_mode or NULL if none */
uint32_t *pvfy_flags;
/* Pointer to SSL or SSL_CTX min_version field or NULL if none */
int *min_version;
/* Pointer to SSL or SSL_CTX max_version field or NULL if none */
int *max_version;
/* Current flag table being worked on */
const ssl_flag_tbl *tbl;
/* Size of table */
size_t ntbl;
/* Client CA names */
STACK_OF(X509_NAME) *canames;
};
static void ssl_set_option(SSL_CONF_CTX *cctx, unsigned int name_flags,
uint64_t option_value, int onoff)
{
uint32_t *pflags;
if (cctx->poptions == NULL)
return;
if (name_flags & SSL_TFLAG_INV)
onoff ^= 1;
switch (name_flags & SSL_TFLAG_TYPE_MASK) {
case SSL_TFLAG_CERT:
pflags = cctx->pcert_flags;
break;
case SSL_TFLAG_VFY:
pflags = cctx->pvfy_flags;
break;
case SSL_TFLAG_OPTION:
if (onoff)
*cctx->poptions |= option_value;
else
*cctx->poptions &= ~option_value;
return;
default:
return;
}
if (onoff)
*pflags |= option_value;
else
*pflags &= ~option_value;
}
static int ssl_match_option(SSL_CONF_CTX *cctx, const ssl_flag_tbl *tbl,
const char *name, int namelen, int onoff)
{
/* If name not relevant for context skip */
if (!(cctx->flags & tbl->name_flags & SSL_TFLAG_BOTH))
return 0;
if (namelen == -1) {
if (strcmp(tbl->name, name))
return 0;
} else if (tbl->namelen != namelen
|| OPENSSL