cvss.c
Go to the documentation of this file.
/* SPDX-FileCopyrightText: 2012-2023 Greenbone AG
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "cvss.h"
#include <glib.h>
#include <math.h>
#include <strings.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "libgvm base"
/* Static Headers. */
static double
get_cvss_score_from_base_metrics_v3 (const char *);
static double
get_cvss_score_from_metrics_v4 (const char *);
/* CVSS v2. */
// clang-format off
#define AV_NETWORK 1.0
#define AV_ADJACENT_NETWORK 0.646
#define AV_LOCAL 0.395
#define AC_LOW 0.71
#define AC_MEDIUM 0.61
#define AC_HIGH 0.35
#define Au_MULTIPLE_INSTANCES 0.45
#define Au_SINGLE_INSTANCE 0.56
#define Au_NONE 0.704
#define C_NONE 0.0
#define C_PARTIAL 0.275
#define C_COMPLETE 0.660
#define I_NONE 0.0
#define I_PARTIAL 0.275
#define I_COMPLETE 0.660
#define A_NONE 0.0
#define A_PARTIAL 0.275
#define A_COMPLETE 0.660
// clang-format on
enum base_metrics
{
A,
I,
C,
Au,
AC,
AV
};
struct impact_item
{
const char *name;
double nvalue;
};
struct cvss
{
double conf_impact;
double integ_impact;
double avail_impact;
double access_vector;
double access_complexity;
double authentication;
};
static const struct impact_item impact_map[][3] = {
[A] =
{
{"N", A_NONE},
{"P", A_PARTIAL},
{"C", A_COMPLETE},
},
[I] =
{
{"N", I_NONE},
{"P", I_PARTIAL},
{"C", I_COMPLETE},
},
[C] =
{
{"N", C_NONE},
{"P", C_PARTIAL},
{"C", C_COMPLETE},
},
[Au] =
{
{"N", Au_NONE},
{"M", Au_MULTIPLE_INSTANCES},
{"S", Au_SINGLE_INSTANCE},
},
[AV] =
{
{"N", AV_NETWORK},
{"A", AV_ADJACENT_NETWORK},
{"L", AV_LOCAL},
},
[AC] =
{
{"L", AC_LOW},
{"M", AC_MEDIUM},
{"H", AC_HIGH},
},
};
// CVSS 4.0
typedef enum
{
// Base (11 metrics)
CVSS4_AV,
CVSS4_AC,
CVSS4_AT,
CVSS4_PR,
CVSS4_UI,
CVSS4_VC,
CVSS4_VI,
CVSS4_VA,
CVSS4_SC,
CVSS4_SI,
CVSS4_SA,
// Threat (1 metric)
CVSS4_E,
// Environmental (14 metrics)
CVSS4_CR,
CVSS4_IR,
CVSS4_AR,
CVSS4_MAV,
CVSS4_MAC,
CVSS4_MAT,
CVSS4_MPR,
CVSS4_MUI,
CVSS4_MVC,
CVSS4_MVI,
CVSS4_MVA,
CVSS4_MSC,
CVSS4_MSI,
CVSS4_MSA,
// Supplemental (6 metrics)
CVSS4_S,
CVSS4_AU,
CVSS4_R,
CVSS4_V,
CVSS4_RE,
CVSS4_U,
// Maximum number
CVSS4_METRICS_MAX,
} cvss4_metric_t;
#define CVSS_METRICS_STR_BLANK "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
#define CVSS_MACROVECTOR_BLANK "XXXXXX"
typedef struct
{
const char *metric_str;
const cvss4_metric_t metric;
const char *values;
} cvss4_metric_def_t;
static cvss4_metric_def_t cvss4_metric_defs[] = {
// Base (11 metrics)
{"AV", CVSS4_AV, "NALP"},
{"AC", CVSS4_AC, "LH"},
{"AT", CVSS4_AT, "NP"},
{"PR", CVSS4_PR, "NLH"},
{"UI", CVSS4_UI, "NPA"},
{"VC", CVSS4_VC, "HLN"},
{"VI", CVSS4_VI, "HLN"},
{"VA", CVSS4_VA, "HLN"},
{"SC", CVSS4_SC, "HLN"},
{"SI", CVSS4_SI, "HLNS"},
{"SA", CVSS4_SA, "HLNS"},
// Threat (1 metric)
{"E", CVSS4_E, "XAPU"},
// Environmental (14 metrics)
{"CR", CVSS4_CR, "XHML"},
{"IR", CVSS4_IR, "XHML"},
{"AR", CVSS4_AR, "XHML"},
{"MAV", CVSS4_MAV, "XNALP"},
{"MAC", CVSS4_MAC, "XLH"},
{"MAT", CVSS4_MAT, "XNP"},
{"MPR", CVSS4_MPR, "XNLH"},
{"MUI", CVSS4_MUI, "XNPA"},
{"MVC", CVSS4_MVC, "XHLN"},
{"MVI", CVSS4_MVI, "XHLN"},
{"MVA", CVSS4_MVA, "XHLN"},
{"MSC", CVSS4_MSC, "XHLN"},
{"MSI", CVSS4_MSI, "XHLNS"},
{"MSA", CVSS4_MSA, "XHLNS"},
// Supplemental (6 metrics)
{"S", CVSS4_S, "XNP"},
{"AU", CVSS4_AU, "XNY"},
{"R", CVSS4_R, "XAUI"},
{"V", CVSS4_V, "XDC"},
{"RE", CVSS4_RE, "XLMH"},
{"U", CVSS4_U, "XCGAR"}, // Abbreviated to first letters
// Max number / array terminator
{NULL, CVSS4_METRICS_MAX, NULL}};
typedef struct
{
const char *vector;
double score;
} cvss4_macrovector_mapping_t;
static const cvss4_macrovector_mapping_t cvss4_macrovector_mappings[] = {
{"000000", 10}, {"000001", 9.9}, {"000010", 9.8}, {"000011", 9.5},
{"000020", 9.5}, {"000021", 9.2}, {"000100", 10}, {"000101", 9.6},
{"000110", 9.3}, {"000111", 8.7}, {"000120", 9.1}, {"000121", 8.1},
{"000200", 9.3}, {"000201", 9}, {"000210", 8.9}, {"000211", 8},
{"000220", 8.1}, {"000221", 6.8}, {"001000", 9.8}, {"001001", 9.5},
{"001010", 9.5}, {"001011", 9.2}, {"001020", 9}, {"001021", 8.4},
{"001100", 9.3}, {"001101", 9.2}, {"001110", 8.9}, {"001111", 8.1},
{"001120", 8.1}, {"001121", 6.5}, {"001200", 8.8}, {"001201", 8},
{"001210", 7.8}, {"001211", 7}, {"001220", 6.9}, {"001221", 4.8},
{"002001", 9.2}, {"002011", 8.2}, {"002021", 7.2}, {"002101", 7.9},
{"002111", 6.9}, {"002121", 5}, {"002201", 6.9}, {"002211", 5.5},
{"002221", 2.7}, {"010000", 9.9}, {"010001", 9.7}, {"010010", 9.5},
{"010011", 9.2}, {"010020", 9.2}, {"010021", 8.5}, {"010100", 9.5},
{"010101", 9.1}, {"010110", 9}, {"010111", 8.3}, {"010120", 8.4},
{"010121", 7.1}, {"010200", 9.2}, {"010201", 8.1}, {"010210", 8.2},
{"010211", 7.1}, {"010220", 7.2}, {"010221", 5.3}, {"011000", 9.5},
{"011001", 9.3}, {"011010", 9.2}, {"011011", 8.5}, {"011020", 8.5},
{"011021", 7.3}, {"011100", 9.2}, {"011101", 8.2}, {"011110", 8},
{"011111", 7.2}, {"011120", 7}, {"011121", 5.9}, {"011200", 8.4},
{"011201", 7}, {"011210", 7.1}, {"011211", 5.2}, {"011220", 5},
{"011221", 3}, {"012001", 8.6}, {"012011", 7.5}, {"012021", 5.2},
{"012101", 7.1}, {"012111", 5.2}, {"012121", 2.9}, {"012201", 6.3},
{"012211", 2.9}, {"012221", 1.7}, {"100000", 9.8}, {"100001", 9.5},
{"100010", 9.4}, {"100011", 8.7}, {"100020", 9.1}, {"100021", 8.1},
{"100100", 9.4}, {"100101", 8.9}, {"100110", 8.6}, {"100111", 7.4},
{"100120", 7.7}, {"100121", 6.4}, {"100200", 8.7}, {"100201", 7.5},
{"100210", 7.4}, {"100211", 6.3}, {"100220", 6.3}, {"100221", 4.9},
{"101000", 9.4}, {"101001", 8.9}, {"101010", 8.8}, {"101011", 7.7},
{"101020", 7.6}, {"101021", 6.7}, {"101100", 8.6}, {"101101", 7.6},
{"101110", 7.4}, {"101111", 5.8}, {"101120", 5.9}, {"101121", 5},
{"101200", 7.2}, {"101201", 5.7}, {"101210", 5.7}, {"101211", 5.2},
{"101220", 5.2}, {"101221", 2.5}, {"102001", 8.3}, {"102011", 7},
{"102021", 5.4}, {"102101", 6.5}, {"102111", 5.8}, {"102121", 2.6},
{"102201", 5.3}, {"102211", 2.1}, {"102221", 1.3}, {"110000", 9.5},
{"110001", 9}, {"110010", 8.8}, {"110011", 7.6}, {"110020", 7.6},
{"110021", 7}, {"110100", 9}, {"110101", 7.7}, {"110110", 7.5},
{"110111", 6.2}, {"110120", 6.1}, {"110121", 5.3}, {"110200", 7.7},
{"110201", 6.6}, {"110210", 6.8}, {"110211", 5.9}, {"110220", 5.2},
{"110221", 3}, {"111000", 8.9}, {"111001", 7.8}, {"111010", 7.6},
{"111011", 6.7}, {"111020", 6.2}, {"111021", 5.8}, {"111100", 7.4},
{"111101", 5.9}, {"111110", 5.7}, {"111111", 5.7}, {"111120", 4.7},
{"111121", 2.3}, {"111200", 6.1}, {"111201", 5.2}, {"111210", 5.7},
{"111211", 2.9}, {"111220", 2.4}, {"111221", 1.6}, {"112001", 7.1},
{"112011", 5.9}, {"112021", 3}, {"112101", 5.8}, {"112111", 2.6},
{"112121", 1.5}, {"112201", 2.3}, {"112211", 1.3}, {"112221", 0.6},
{"200000", 9.3}, {"200001", 8.7}, {"200010", 8.6}, {"200011", 7.2},
{"200020", 7.5}, {"200021", 5.8}, {"200100", 8.6}, {"200101", 7.4},
{"200110", 7.4}, {"200111", 6.1}, {"200120", 5.6}, {"200121", 3.4},
{"200200", 7}, {"200201", 5.4}, {"200210", 5.2}, {"200211", 4},
{"200220", 4}, {"200221", 2.2}, {"201000", 8.5}, {"201001", 7.5},
{"201010", 7.4}, {"201011", 5.5}, {"201020", 6.2}, {"201021", 5.1},
{"201100", 7.2}, {"201101", 5.7}, {"201110", 5.5}, {"201111", 4.1},
{"201120", 4.6}, {"201121", 1.9}, {"201200", 5.3}, {"201201", 3.6},
{"201210", 3.4}, {"201211", 1.9}, {"201220", 1.9}, {"201221", 0.8},
{"202001", 6.4}, {"202011", 5.1}, {"202021", 2}, {"202101", 4.7},
{"202111", 2.1}, {"202121", 1.1}, {"202201", 2.4}, {"202211", 0.9},
{"202221", 0.4}, {"210000", 8.8}, {"210001", 7.5}, {"210010", 7.3},
{"210011", 5.3}, {"210020", 6}, {"210021", 5}, {"210100", 7.3},
{"210101", 5.5}, {"210110", 5.9}, {"210111", 4}, {"210120", 4.1},
{"210121", 2}, {"210200", 5.4}, {"210201", 4.3}, {"210210", 4.5},
{"210211", 2.2}, {"210220", 2}, {"210221", 1.1}, {"211000", 7.5},
{"211001", 5.5}, {"211010", 5.8}, {"211011", 4.5}, {"211020", 4},
{"211021", 2.1}, {"211100", 6.1}, {"211101", 5.1}, {"211110", 4.8},
{"211111", 1.8}, {"211120", 2}, {"211121", 0.9}, {"211200", 4.6},
{"211201", 1.8}, {"211210", 1.7}, {"211211", 0.7}, {"211220", 0.8},
{"211221", 0.2}, {"212001", 5.3}, {"212011", 2.4}, {"212021", 1.4},
{"212101", 2.4}, {"212111", 1.2}, {"212121", 0.5}, {"212201", 1},
{"212211", 0.3}, {"212221", 0.1}, {NULL, 0.0}};
static GHashTable *cvss4_macrovector_table = NULL;
static int
toenum (const char *str, enum base_metrics *res)
{
int rc = 0; /* let's be optimistic */
if (g_strcmp0 (str, "A") == 0)
*res = A;
else if (g_strcmp0 (str, "I") == 0)
*res = I;
else if (g_strcmp0 (str, "C") == 0)
*res = C;
else if (g_strcmp0 (str, "Au") == 0)
*res = Au;
else if (g_strcmp0 (str, "AU") == 0)
*res = Au;
else if (g_strcmp0 (str, "AV") == 0)
*res = AV;
else if (g_strcmp0 (str, "AC") == 0)
*res = AC;
else
rc = -1;
return rc;
}
static double
get_impact_subscore (const struct cvss *cvss)
{
return 10.41
* (1
- (1 - cvss->conf_impact) * (1 - cvss->integ_impact)
* (1 - cvss->avail_impact));
}
static double
get_exploitability_subscore (const struct cvss *cvss)
{
return 20 * cvss->access_vector * cvss->access_complexity
* cvss->authentication;
}
static inline int
set_impact_from_str (const char *value, enum base_metrics metric,
struct cvss *cvss)
{
int i;
for (i = 0; i < 3; i++)
{
const struct impact_item *impact;
impact = &impact_map[metric][i];
if (g_strcmp0 (impact->name, value) == 0)
{
switch (metric)
{
case A:
cvss->avail_impact = impact->nvalue;
break;
case I:
cvss->integ_impact = impact->nvalue;
break;
case C:
cvss->conf_impact = impact->nvalue;
break;
case Au:
cvss->authentication = impact->nvalue;
break;
case AV:
cvss->access_vector = impact->nvalue;
break;
case AC:
cvss->access_complexity = impact->nvalue;
break;
default:
return -1;
}
return 0;
}
}
return -1;
}
static double
__get_cvss_score (struct cvss *cvss)
{
double impact = 1.176;
double impact_sub;
double exploitability_sub;
impact_sub = get_impact_subscore (cvss);
exploitability_sub = get_exploitability_subscore (cvss);
if (impact_sub < 0.1)
impact = 0.0;
return (((0.6 * impact_sub) + (0.4 * exploitability_sub) - 1.5) * impact)
+ 0.0;
}
double
get_cvss_score_from_base_metrics (const char *cvss_str)
{
struct cvss cvss;
char *token, *base_str, *base_metrics;
if (cvss_str == NULL)
return -1.0;
if (g_str_has_prefix (cvss_str, "CVSS:3.1/")
|| g_str_has_prefix (cvss_str, "CVSS:3.0/"))
return get_cvss_score_from_base_metrics_v3 (cvss_str
+ strlen ("CVSS:3.X/"));
if (g_str_has_prefix (cvss_str, "CVSS:4.0/"))
return get_cvss_score_from_metrics_v4 (cvss_str + strlen ("CVSS:4.X/"));
memset (&cvss, 0x00, sizeof (struct cvss));
base_str = base_metrics = g_strdup_printf ("%s/", cvss_str);
while ((token = strchr (base_metrics, '/')) != NULL)
{
char *token2 = strtok (base_metrics, ":");
char *metric_name = token2;
char *metric_value;
enum base_metrics mval;
int rc;
*token++ = '\0';
if (metric_name == NULL)
goto ret_err;
metric_value = strtok (NULL, ":");
if (metric_value == NULL)
goto ret_err;
rc = toenum (metric_name, &mval);
if (rc)
goto ret_err;
if (set_impact_from_str (metric_value, mval, &cvss))
goto ret_err;
base_metrics = token;
}
g_free (base_str);
return __get_cvss_score (&cvss);
ret_err:
g_free (base_str);
return (double) -1;
}
/* CVSS v3. */
static double
roundup (double cvss)
{
int trim;
/* "Roundup returns the smallest number, specified to 1 decimal place,
* that is equal to or higher than its input. For example, Roundup (4.02)
* returns 4.1; and Roundup (4.00) returns 4.0." */
/* 3.020000000 => 3.1 */
/* 3.000000001 => 3.0 */
/* 5.299996 => 5.3 */
/* 5.500320 => 5.6 */
trim = round (cvss * 100000);
if ((trim % 10000) == 0)
return ((double) trim) / 100000;
return (floor (trim / 10000) + 1) / 10.0;
}
static double
v3_impact (const char *value)
{
if (strcasecmp (value, "N") == 0)
return 0.0;
if (strcasecmp (value, "L") == 0)
return 0.22;
if (strcasecmp (value, "H") == 0)
return 0.56;
return -1.0;
}
static double
get_cvss_score_from_base_metrics_v3 (const char *cvss_str)
{
gchar **split, **point;
int scope_changed;
double impact_conf, impact_integ, impact_avail;
double vector, complexity, privilege, user;
double isc_base, impact, exploitability, base;
/* https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator
* https://www.first.org/cvss/v3.1/specification-document
* https://www.first.org/cvss/v3.0/specification-document */
scope_changed = -1;
impact_conf = -1.0;
impact_integ = -1.0;
impact_avail = -1.0;
vector = -1.0;
complexity = -1.0;
privilege = -1.0;
user = -1.0;
/* AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N */
split = g_strsplit (cvss_str, "/", 0);
point = split;
while (*point)
{
/* Scope. */
if (strncasecmp ("S:", *point, 2) == 0)
{
if (strcasecmp (*point + 2, "U") == 0)
scope_changed = 0;
else if (strcasecmp (*point + 2, "C") == 0)
scope_changed = 1;
}
/* Confidentiality. */
if (strncasecmp ("C:", *point, 2) == 0)
impact_conf = v3_impact (*point + 2);
/* Integrity. */
if (strncasecmp ("I:", *point, 2) == 0)
impact_integ = v3_impact (*point + 2);
/* Availability. */
if (strncasecmp ("A:", *point, 2) == 0)
impact_avail = v3_impact (*point + 2);
/* Attack Vector. */
if (strncasecmp ("AV:", *point, 3) == 0)
{
if (strcasecmp (*point + 3, "N") == 0)
vector = 0.85;
else if (strcasecmp (*point + 3, "A") == 0)
vector = 0.62;
else if (strcasecmp (*point + 3, "L") == 0)
vector = 0.55;
else if (strcasecmp (*point + 3, "P") == 0)
vector = 0.2;
}
/* Attack Complexity. */
if (strncasecmp ("AC:", *point, 3) == 0)
{
if (strcasecmp (*point + 3, "L") == 0)
complexity = 0.77;
else if (strcasecmp (*point + 3, "H") == 0)
complexity = 0.44;
}
/* Privileges Required. */
if (strncasecmp ("PR:", *point, 3) == 0)
{
if (strcasecmp (*point + 3, "N") == 0)
privilege = 0.85;
else if (strcasecmp (*point + 3, "L") == 0)
privilege = 0.62;
else if (strcasecmp (*point + 3, "H") == 0)
privilege = 0.27;
else
privilege = -1.0;
}
/* User Interaction. */
if (strncasecmp ("UI:", *point, 3) == 0)
{
if (strcasecmp (*point + 3, "N") == 0)
user = 0.85;
else if (strcasecmp (*point + 3, "R") == 0)
user = 0.62;
}
point++;
}
g_strfreev (split);
/* All of the base metrics are required. */
if (scope_changed == -1 || impact_conf == -1.0 || impact_integ == -1.0
|| impact_avail == -1.0 || vector == -1.0 || complexity == -1.0
|| privilege == -1.0 || user == -1.0)
return -1.0;
/* Privileges Required has a special case for S:C. */
if (scope_changed && privilege == 0.62)
privilege = 0.68;
else if (scope_changed && privilege == 0.27)
privilege = 0.5;
/* Impact. */
isc_base = 1 - ((1 - impact_conf) * (1 - impact_integ) * (1 - impact_avail));
if (scope_changed)
impact = 7.52 * (isc_base - 0.029) - 3.25 * pow ((isc_base - 0.02), 15);
else
impact = 6.42 * isc_base;
if (impact <= 0)
return 0.0;
/* Exploitability. */
exploitability = 8.22 * vector * complexity * privilege * user;
/* Final. */
if (scope_changed)
base = 1.08 * (impact + exploitability);
else
base = impact + exploitability;
if (base > 10.0)
return 10.0;
return roundup (base);
}
static void
cvss4_init_macrovector_table ()
{
if (cvss4_macrovector_table)
return;
int index = 0;
cvss4_macrovector_table = g_hash_table_new (g_str_hash, g_str_equal);
while (cvss4_macrovector_mappings[index].vector != NULL)
{
g_hash_table_insert (cvss4_macrovector_table,
(gpointer) cvss4_macrovector_mappings[index].vector,
(gpointer) &cvss4_macrovector_mappings[index].score);
index++;
}
}
static inline double
cvss4_macrovector_score (const char *vector)
{
double *score_ptr;
cvss4_init_macrovector_table ();
score_ptr = g_hash_table_lookup (cvss4_macrovector_table, vector);
if (score_ptr)
return *score_ptr;
return -1.0;
}
static char
cvss4_m (const char *simplified_vec, cvss4_metric_t metric)
{
char selected = simplified_vec[metric];
// If E=X it will default to the worst case i.e. E=A
if (metric == CVSS4_E && selected == 'X')
return 'A';
// If CR=X, IR=X or AR=X they will default to the worst case
// i.e. CR=H, IR=H and AR=H
if ((metric == CVSS4_CR || metric == CVSS4_IR || metric == CVSS4_AR)
&& selected == 'X')
return 'H';
// All other environmental metrics just overwrite base score values,
// so if they’re not defined just use the base score value.
if (metric >= CVSS4_AV && metric <= CVSS4_SA)
{
char modified_selected = simplified_vec[metric - CVSS4_AV + CVSS4_MAV];
if (modified_selected != 'X')
return modified_selected;
}
return selected;
}
static gchar *
simplify_cvss4_vector (const char *cvss_str)
{
gchar **split_cvss_str, **split_cvss_point;
gboolean valid = TRUE;
gchar *vec = NULL;
cvss4_metric_t metric;
if (cvss_str == NULL || strcmp (cvss_str, "") == 0)
return NULL;
vec = g_strdup (CVSS_METRICS_STR_BLANK);
split_cvss_str = g_strsplit (cvss_str, "/", -1);
split_cvss_point = split_cvss_str;
while (valid && *split_cvss_point)
{
if (strcmp (*split_cvss_point, "") == 0)
{
split_cvss_point++;
continue;
}
gchar **split_component = g_strsplit (*split_cvss_point, ":", 2);
const gchar *metric_str = split_component[0], *value = split_component[1];
valid = FALSE;
if (value == NULL)
{
g_debug ("%s: value for metric %s missing", __func__, metric_str);
break;
}
else if (strcasecmp (metric_str, "U") == 0)
{
// Special case for the Provider Urgency metric
if (strcasecmp (value, "Red") && strcasecmp (value, "Amber")
&& strcasecmp (value, "Green") && strcasecmp (value, "Clear")
&& strcasecmp (value, "X"))
{
g_debug ("%s: value for metric %s must be one of"
" 'Red', 'Amber', 'Green', 'Clear', 'X'",
__func__, metric_str);
break;
}
else
valid = TRUE;
}
else if (strlen (value) != 1)
{
g_debug ("%s: value for metric %s must be 1 character", __func__,
metric_str);
break;
}
cvss4_metric_def_t *metric_def = &cvss4_metric_defs[0];
while (metric_def->metric_str)
{
if (strcasecmp (metric_str, metric_def->metric_str) == 0)
{
char value_char = g_ascii_toupper (value[0]);
// Reject duplicate metrics
if (vec[metric_def->metric] != 'X')
{
g_debug ("%s: duplicate metric %s", __func__, metric_str);
break;
}
// Set the metric in the simplified vector
if (strchr (metric_def->values, value_char))
{
valid = TRUE;
vec[metric_def->metric] = value_char;
}
else
{
g_debug ("%s: invalid metric: %s:%c", __func__, metric_str,
value_char);
}
break;
}
metric_def++;
}
split_cvss_point++;
g_strfreev (split_component);
}
g_strfreev (split_cvss_str);
for (metric = CVSS4_AV; valid && metric <= CVSS4_SA; metric++)
{
if (vec[metric] == 'X')
{
g_debug ("%s: mandatory metric %s is undefined", __func__,
cvss4_metric_defs[metric].metric_str);
valid = FALSE;
}
}
if (!valid)
{
g_debug ("%s: vector %s is invalid", __func__, cvss_str);
g_free (vec);
return NULL;
}
return vec;
}
static gchar *
cvss4_vector_expand (const char *vec)
{
cvss4_metric_t metric;
GString *str = g_string_new ("CVSS:4.0");
for (metric = 0; metric < CVSS4_METRICS_MAX; metric++)
{
const char *expanded_value;
if (vec[metric] == 'X')
continue;
cvss4_metric_def_t def = cvss4_metric_defs[metric];
if (metric == CVSS4_U)
{
switch (vec[metric])
{
case 'R':
expanded_value = "Red";
break;
case 'A':
expanded_value = "Amber";
break;
case 'G':
expanded_value = "Green";
break;
case 'C':
expanded_value = "Clear";
break;
default:
expanded_value = NULL;
}
}
else
expanded_value = NULL;
if (expanded_value)
g_string_append_printf (str, "/%s:%s", def.metric_str, expanded_value);
else
g_string_append_printf (str, "/%s:%c", def.metric_str, vec[metric]);
}
return g_string_free (str, FALSE);
}
static inline gchar *
cvss4_macrovector (const char *vec)
{
gchar *macrovector;
if (vec == NULL)
return NULL;
macrovector = g_strdup (CVSS_MACROVECTOR_BLANK);
// EQ1: 0-AV:N and PR:N and UI:N
// 1-(AV:N or PR:N or UI:N) and not (AV:N and PR:N and UI:N) and not AV:P
// 2-AV:P or not(AV:N or PR:N or UI:N)
char av = cvss4_m (vec, CVSS4_AV);
char pr = cvss4_m (vec, CVSS4_PR);
char ui = cvss4_m (vec, CVSS4_UI);
if (av == 'N' && pr == 'N' && ui == 'N')
macrovector[0] = '0';
else if ((av == 'N' || pr == 'N' || ui == 'N') && !(av == 'P'))
macrovector[0] = '1';
else
macrovector[0] = '2';
// EQ2: 0-(AC:L and AT:N)
// 1-(not(AC:L and AT:N))
char ac = cvss4_m (vec, CVSS4_AC);
char at = cvss4_m (vec, CVSS4_AT);
if (ac == 'L' && at == 'N')
macrovector[1] = '0';
else
macrovector[1] = '1';
// EQ3: 0-(VC:H and VI:H)
// 1-(not(VC:H and VI:H) and (VC:H or VI:H or VA:H))
// 2-not (VC:H or VI:H or VA:H)
char vc = cvss4_m (vec, CVSS4_VC);
char vi = cvss4_m (vec, CVSS4_VI);
char va = cvss4_m (vec, CVSS4_VA);
if (vc == 'H' && vi == 'H')
macrovector[2] = '0';
else if (vc == 'H' || vi == 'H' || va == 'H')
macrovector[2] = '1';
else
macrovector[2] = '2';
// EQ4: 0-(MSI:S or MSA:S)
// 1-not (MSI:S or MSA:S) and (SC:H or SI:H or SA:H)
// 2-not (MSI:S or MSA:S) and not (SC:H or SI:H or SA:H)
//
// "Effective" SI and SA are the same as MSI and MSA for the purposes of
// checking for the "Safety" value.
char sc = cvss4_m (vec, CVSS4_SC);
char si = cvss4_m (vec, CVSS4_SI);
char sa = cvss4_m (vec, CVSS4_SA);
if (si == 'S' || sa == 'S')
macrovector[3] = '0';
else if (sc == 'H' || si == 'H' || sa == 'H')
macrovector[3] = '1';
else
macrovector[3] = '2';
// EQ5: 0-E:A
// 1-E:P
// 2-E:U
char e = cvss4_m (vec, CVSS4_E);
if (e == 'A')
macrovector[4] = '0';
else if (e == 'P')
macrovector[4] = '1';
else
macrovector[4] = '2';
// EQ6: 0-(CR:H and VC:H) or (IR:H and VI:H) or (AR:H and VA:H)
// 1-not[(CR:H and VC:H) or (IR:H and VI:H) or (AR:H and VA:H)]
char cr = cvss4_m (vec, CVSS4_CR);
char ir = cvss4_m (vec, CVSS4_IR);
char ar = cvss4_m (vec, CVSS4_AR);
if ((cr == 'H' && vc == 'H') || (ir == 'H' && vi == 'H')
|| (ar == 'H' && va == 'H'))
macrovector[5] = '0';
else
macrovector[5] = '1';
return macrovector;
}
static void
cvss4_maximal_scoring_differences (const char *macrovector,
double *available_distance_eq1,
double *available_distance_eq2,
double *available_distance_eq3eq6,
double *available_distance_eq4,
double *available_distance_eq5)
{
double value = cvss4_macrovector_score (macrovector);
double score_eq1_next_lower_macro, score_eq2_next_lower_macro;
double score_eq3eq6_next_lower_macro;
double score_eq4_next_lower_macro, score_eq5_next_lower_macro;
// Next lower macrovector for EQ1 only exists if EQ1 is 0 or 1.
if (macrovector[0] <= '1')
{
gchar *eq1_next_lower_macro = g_strdup (macrovector);
eq1_next_lower_macro[0]++;
score_eq1_next_lower_macro =
cvss4_macrovector_score (eq1_next_lower_macro);
g_free (eq1_next_lower_macro);
}
else
score_eq1_next_lower_macro = -1.0;
// Next lower macrovector for EQ2 only exists if EQ2 is 0.
if (macrovector[1] == '0')
{
gchar *eq2_next_lower_macro = g_strdup (macrovector);
eq2_next_lower_macro[1]++;
score_eq2_next_lower_macro =
cvss4_macrovector_score (eq2_next_lower_macro);
}
else
score_eq2_next_lower_macro = -1.0;
// Next lower macrovector for EQ3.
if ((macrovector[2] == '0' || macrovector[2] == '1') && macrovector[5] == '1')
{
gchar *eq3eq6_next_lower_macro = g_strdup (macrovector);
eq3eq6_next_lower_macro[2]++;
score_eq3eq6_next_lower_macro =
cvss4_macrovector_score (eq3eq6_next_lower_macro);
g_free (eq3eq6_next_lower_macro);
}
else if (macrovector[2] == '1' && macrovector[5] == '0')
{
gchar *eq3eq6_next_lower_macro = g_strdup (macrovector);
eq3eq6_next_lower_macro[5]++;
score_eq3eq6_next_lower_macro =
cvss4_macrovector_score (eq3eq6_next_lower_macro);
g_free (eq3eq6_next_lower_macro);
}
else if (macrovector[2] == '0' && macrovector[5] == '0')
{
gchar *eq3eq6_next_lower_macro_left = g_strdup (macrovector);
eq3eq6_next_lower_macro_left[5]++;
gchar *eq3eq6_next_lower_macro_right = g_strdup (macrovector);
eq3eq6_next_lower_macro_right[2]++;
double score_eq3eq6_next_lower_macro_left =
cvss4_macrovector_score (eq3eq6_next_lower_macro_left);
double score_eq3eq6_next_lower_macro_right =
cvss4_macrovector_score (eq3eq6_next_lower_macro_right);
if (score_eq3eq6_next_lower_macro_left
> score_eq3eq6_next_lower_macro_right)
score_eq3eq6_next_lower_macro = score_eq3eq6_next_lower_macro_left;
else
score_eq3eq6_next_lower_macro = score_eq3eq6_next_lower_macro_right;
g_free (eq3eq6_next_lower_macro_left);
g_free (eq3eq6_next_lower_macro_right);
}
else
score_eq3eq6_next_lower_macro = -1.0;
// Next lower macrovector for EQ4 only exists if EQ4 is 0 or 1.
if (macrovector[3] <= '1')
{
gchar *eq4_next_lower_macro = g_strdup (macrovector);
eq4_next_lower_macro[3]++;
score_eq4_next_lower_macro =
cvss4_macrovector_score (eq4_next_lower_macro);
g_free (eq4_next_lower_macro);
}
else
score_eq4_next_lower_macro = -1.0;
// Next lower macrovector for EQ5 only exists if EQ5 is 0 or 1.
if (macrovector[4] <= '1')
{
gchar *eq5_next_lower_macro = g_strdup (macrovector);
eq5_next_lower_macro[4]++;
score_eq5_next_lower_macro =
cvss4_macrovector_score (eq5_next_lower_macro);
g_free (eq5_next_lower_macro);
}
else
score_eq5_next_lower_macro = -1.0;
if (value != -1.0)
{
*available_distance_eq1 = score_eq1_next_lower_macro != -1.0
? value - score_eq1_next_lower_macro
: -1.0;
*available_distance_eq2 = score_eq2_next_lower_macro != -1.0
? value - score_eq2_next_lower_macro
: -1.0;
*available_distance_eq3eq6 = score_eq3eq6_next_lower_macro != -1.0
? value - score_eq3eq6_next_lower_macro
: -1.0;
*available_distance_eq4 = score_eq4_next_lower_macro != -1.0
? value - score_eq4_next_lower_macro
: -1.0;
*available_distance_eq5 = score_eq5_next_lower_macro != -1.0
? value - score_eq5_next_lower_macro
: -1.0;
}
else
{
*available_distance_eq1 = -1.0;
*available_distance_eq2 = -1.0;
*available_distance_eq3eq6 = -1.0;
*available_distance_eq4 = -1.0;
*available_distance_eq5 = -1.0;
}
}
static gchar **
cvss4_max_vectors (const char *macrovector)
{
const char **eq1_maxes, **eq2_maxes, **eq3eq6_maxes;
const char *eq4_max, *eq5_max;
gchar **ret;
// EQ1
static const char *eq1_maxes_0[] = {"AV:N/PR:N/UI:N/", NULL};
static const char *eq1_maxes_1[] = {"AV:A/PR:N/UI:N/", "AV:N/PR:L/UI:N/",
"AV:N/PR:N/UI:P/", NULL};
static const char *eq1_maxes_2[] = {"AV:P/PR:N/UI:N/", "AV:A/PR:L/UI:P/",
NULL};
if (macrovector[0] == '0')
eq1_maxes = eq1_maxes_0;
else if (macrovector[0] == '1')
eq1_maxes = eq1_maxes_1;
else
eq1_maxes = eq1_maxes_2;
// EQ2
static const char *eq2_maxes_0[] = {"AC:L/AT:N/", NULL};
static const char *eq2_maxes_1[] = {"AC:H/AT:N/", "AC:L/AT:P/", NULL};
if (macrovector[1] == '0')
eq2_maxes = eq2_maxes_0;
else
eq2_maxes = eq2_maxes_1;
// EQ3+EQ6
static const char *eq3eq6_maxes_00[] = {"VC:H/VI:H/VA:H/CR:H/IR:H/AR:H/",
NULL};
static const char *eq3eq6_maxes_01[] = {
"VC:H/VI:H/VA:L/CR:M/IR:M/AR:H/", "VC:H/VI:H/VA:H/CR:M/IR:M/AR:M/", NULL};
static const char *eq3eq6_maxes_10[] = {
"VC:L/VI:H/VA:H/CR:H/IR:H/AR:H/", "VC:H/VI:L/VA:H/CR:H/IR:H/AR:H/", NULL};
static const char *eq3eq6_maxes_11[] = {
"VC:L/VI:H/VA:L/CR:H/IR:M/AR:H/", "VC:L/VI:H/VA:H/CR:H/IR:M/AR:M/",
"VC:H/VI:L/VA:H/CR:M/IR:H/AR:M/", "VC:H/VI:L/VA:L/CR:M/IR:H/AR:H/",
"VC:L/VI:L/VA:H/CR:H/IR:H/AR:M/", NULL};
static const char *eq3eq6_maxes_21[] = {"VC:L/VI:L/VA:L/CR:H/IR:H/AR:H/",
NULL};
if ((macrovector[2] == '0'))
{
if (macrovector[5] == '0')
eq3eq6_maxes = eq3eq6_maxes_00;
else
eq3eq6_maxes = eq3eq6_maxes_01;
}
else if ((macrovector[2] == '1'))
{
if (macrovector[5] == '0')
eq3eq6_maxes = eq3eq6_maxes_10;
else
eq3eq6_maxes = eq3eq6_maxes_11;
}
else
eq3eq6_maxes = eq3eq6_maxes_21;
// EQ4
if (macrovector[3] == '0')
eq4_max = "SC:H/SI:S/SA:S/";
else if (macrovector[3] == '1')
eq4_max = "SC:H/SI:H/SA:H/";
else
eq4_max = "SC:L/SI:L/SA:L/";
// EQ5
if (macrovector[4] == '0')
eq5_max = "E:A/";
else if (macrovector[4] == '1')
eq5_max = "E:P/";
else
eq5_max = "E:U/";
GPtrArray *max_vectors = g_ptr_array_new ();
const char **eq1_max, **eq2_max, **eq3eq6_max;
for (eq1_max = eq1_maxes; *eq1_max != NULL; eq1_max++)
{
for (eq2_max = eq2_maxes; *eq2_max != NULL; eq2_max++)
{
for (eq3eq6_max = eq3eq6_maxes; *eq3eq6_max != NULL; eq3eq6_max++)
{
gchar *full_vector =
g_strdup_printf ("%s%s%s%s%s", *eq1_max, *eq2_max, *eq3eq6_max,
eq4_max, eq5_max);
gchar *vector = simplify_cvss4_vector (full_vector);
if (vector == NULL)
g_warning ("%s: generated vector %s is invalid", __func__,
full_vector);
else
g_ptr_array_add (max_vectors, vector);
g_free (full_vector);
}
}
}
g_ptr_array_add (max_vectors, NULL);
ret = (gchar **) max_vectors->pdata;
g_ptr_array_free (max_vectors, FALSE);
return ret;
}
static double
cvss4_metric_level (cvss4_metric_t metric, char value)
{
switch (metric)
{
case CVSS4_AV:
switch (value)
{
case 'N':
return 0.0;
case 'A':
return 0.1;
case 'L':
return 0.2;
case 'P':
return 0.3;
default:
return -99.0;
}
break;
case CVSS4_PR:
switch (value)
{
case 'N':
return 0.0;
case 'L':
return 0.1;
case 'H':
return 0.2;
default:
return -99.0;
}
break;
case CVSS4_UI:
switch (value)
{
case 'N':
return 0.0;
case 'P':
return 0.1;
case 'A':
return 0.2;
default:
return -99.0;
}
break;
case CVSS4_AC:
switch (value)
{
case 'L':
return 0.0;
case 'H':
return 0.1;
default:
return -99.0;
}
break;
case CVSS4_AT:
switch (value)
{
case 'N':
return 0.0;
case 'P':
return 0.1;
default:
return -99.0;
}
break;
case CVSS4_VC:
case CVSS4_VI:
case CVSS4_VA:
switch (value)
{
case 'H':
return 0.0;
case 'L':
return 0.1;
case 'N':
return 0.2;
default:
return -99.0;
}
break;
case CVSS4_SC:
case CVSS4_SI:
case CVSS4_SA:
switch (value)
{
case 'S':
return 0.0;
case 'H':
return 0.1;
case 'L':
return 0.2;
case 'N':
return 0.3;
default:
return -99.0;
}
break;
case CVSS4_CR:
case CVSS4_IR:
case CVSS4_AR:
switch (value)
{
case 'H':
return 0.0;
case 'M':
return 0.1;
case 'L':
return 0.2;
default:
return -99.0;
}
break;
// The Exploit Maturity metric is included in the reference implementation
// but never used
/*
case CVSS4_E:
switch (value)
{
case 'A': return 0.0;
case 'P': return 0.1;
case 'U': return 0.2;
}
break;
*/
default:
return -99.0;
}
}
static inline double
cvss4_severity_distance (cvss4_metric_t metric, const char *vec,
const char *max_vec)
{
return cvss4_metric_level (metric, cvss4_m (vec, metric))
- cvss4_metric_level (metric, max_vec[metric]);
}
static void
cvss4_current_severity_distances (const char *vec, const char *macrovector,
double *current_severity_distance_eq1,
double *current_severity_distance_eq2,
double *current_severity_distance_eq3eq6,
double *current_severity_distance_eq4,
double *current_severity_distance_eq5)
{
double severity_distance_AV, severity_distance_PR, severity_distance_UI;
double severity_distance_AC, severity_distance_AT;
double severity_distance_VC, severity_distance_VI, severity_distance_VA;
double severity_distance_SC, severity_distance_SI, severity_distance_SA;
double severity_distance_CR, severity_distance_IR, severity_distance_AR;
severity_distance_AV = severity_distance_PR = severity_distance_UI = -99.0;
severity_distance_AC = severity_distance_AT = -99.0;
severity_distance_VC = severity_distance_VI = severity_distance_VA = -99.0;
severity_distance_SC = severity_distance_SI = severity_distance_SA = -99.0;
severity_distance_CR = severity_distance_IR = severity_distance_AR = -99.0;
char **max_vectors, **max_vec;
max_vectors = cvss4_max_vectors (macrovector);
for (max_vec = max_vectors; *max_vec != NULL; max_vec++)
{
severity_distance_AV = cvss4_severity_distance (CVSS4_AV, vec, *max_vec);
severity_distance_PR = cvss4_severity_distance (CVSS4_PR, vec, *max_vec);
severity_distance_UI = cvss4_severity_distance (CVSS4_UI, vec, *max_vec);
severity_distance_AC = cvss4_severity_distance (CVSS4_AC, vec, *max_vec);
severity_distance_AT = cvss4_severity_distance (CVSS4_AT, vec, *max_vec);
severity_distance_VC = cvss4_severity_distance (CVSS4_VC, vec, *max_vec);
severity_distance_VI = cvss4_severity_distance (CVSS4_VI, vec, *max_vec);
severity_distance_VA = cvss4_severity_distance (CVSS4_VA, vec, *max_vec);
severity_distance_SC = cvss4_severity_distance (CVSS4_SC, vec, *max_vec);
severity_distance_SI = cvss4_severity_distance (CVSS4_SI, vec, *max_vec);
severity_distance_SA = cvss4_severity_distance (CVSS4_SA, vec, *max_vec);
severity_distance_CR = cvss4_severity_distance (CVSS4_CR, vec, *max_vec);
severity_distance_IR = cvss4_severity_distance (CVSS4_IR, vec, *max_vec);
severity_distance_AR = cvss4_severity_distance (CVSS4_AR, vec, *max_vec);
if (severity_distance_AV < 0.0 || severity_distance_PR < 0.0
|| severity_distance_UI < 0.0 || severity_distance_AC < 0.0
|| severity_distance_AT < 0.0 || severity_distance_VC < 0.0
|| severity_distance_VI < 0.0 || severity_distance_VA < 0.0
|| severity_distance_SC < 0.0 || severity_distance_SI < 0.0
|| severity_distance_SA < 0.0 || severity_distance_CR < 0.0
|| severity_distance_IR < 0.0 || severity_distance_AR < 0.0)
continue;
g_debug ("%s AV:%0.1f PR:%0.1f UI:%0.1f |"
" AC:%0.1f AT:%0.1f |"
" VC:%0.1f VI:%0.1f VA:%0.1f |"
" SC:%0.1f SI:%0.1f SA:%0.1f |"
" CR:%0.1f IR:%0.1f AR:%0.1f",
__func__, severity_distance_AV, severity_distance_PR,
severity_distance_UI, severity_distance_AC, severity_distance_AT,
severity_distance_VC, severity_distance_VI, severity_distance_VA,
severity_distance_SC, severity_distance_SI, severity_distance_SA,
severity_distance_CR, severity_distance_IR,
severity_distance_AR);
break;
}
gchar *max_vec_expanded = cvss4_vector_expand (*max_vec);
g_debug ("%s: max_vec: %s", __func__, max_vec_expanded);
g_free (max_vec_expanded);
g_strfreev (max_vectors);
*current_severity_distance_eq1 =
severity_distance_AV + severity_distance_PR + severity_distance_UI;
*current_severity_distance_eq2 = severity_distance_AC + severity_distance_AT;
*current_severity_distance_eq3eq6 =
severity_distance_VC + severity_distance_VI + severity_distance_VA
+ severity_distance_CR + severity_distance_IR + severity_distance_AR;
*current_severity_distance_eq4 =
severity_distance_SC + severity_distance_SI + severity_distance_SA;
*current_severity_distance_eq5 = 0.0;
}
static void
cvss4_max_severities (const char *macrovector, double *max_severity_eq1,
double *max_severity_eq2, double *max_severity_eq3eq6,
double *max_severity_eq4)
{
switch (macrovector[0])
{
case '0':
*max_severity_eq1 = 0.1;
break;
case '1':
*max_severity_eq1 = 0.4;
break;
case '2':
*max_severity_eq1 = 0.5;
break;
default:
*max_severity_eq1 = -99.0;
}
switch (macrovector[1])
{
case '0':
*max_severity_eq2 = 0.1;
break;
case '1':
*max_severity_eq2 = 0.2;
break;
default:
*max_severity_eq2 = -99.0;
}
switch (macrovector[2])
{
case '0':
if (macrovector[5] == '0')
*max_severity_eq3eq6 = 0.7;
else
*max_severity_eq3eq6 = 0.6;
break;
case '1':
*max_severity_eq3eq6 = 0.8;
break;
case '2':
*max_severity_eq3eq6 = 1.0;
break;
default:
*max_severity_eq3eq6 = -99.0;
}
switch (macrovector[3])
{
case '0':
*max_severity_eq4 = 0.6;
break;
case '1':
*max_severity_eq4 = 0.5;
break;
case '2':
*max_severity_eq4 = 0.4;
break;
default:
*max_severity_eq4 = -99.0;
}
}
static double
get_cvss_score_from_metrics_v4 (const char *cvss_str)
{
char *vec = NULL;
char *macrovector = NULL;
double available_distance_eq1, available_distance_eq2;
double available_distance_eq3eq6;
double available_distance_eq4, available_distance_eq5;
double current_severity_distance_eq1, current_severity_distance_eq2;
double current_severity_distance_eq3eq6;
double current_severity_distance_eq4, current_severity_distance_eq5;
double max_severity_eq1, max_severity_eq2, max_severity_eq3eq6;
double max_severity_eq4;
double mean_distance, value;
int n_existing_lower = 0;
// Convert vector to simplified, enum-indexed string
g_debug ("%s: CVSS string: %s", __func__, cvss_str);
vec = simplify_cvss4_vector (cvss_str);
g_debug ("%s: simplified vector: %s", __func__, vec);
if (vec == NULL)
return -1.0;
// Calculate macrovector
macrovector = cvss4_macrovector (vec);
value = cvss4_macrovector_score (macrovector);
g_debug ("%s: macrovector: %s, value: %0.1f", __func__, macrovector, value);
if (macrovector == NULL || value == -1.0)
{
g_free (vec);
return -1.0;
}
// Calculate maximum distances
cvss4_maximal_scoring_differences (
macrovector, &available_distance_eq1, &available_distance_eq2,
&available_distance_eq3eq6, &available_distance_eq4,
&available_distance_eq5);
g_debug ("%s: maximal scoring diffs:"
" EQ1:%0.1f EQ2:%0.1f EQ3+EQ6:%0.1f EQ5:%0.1f EQ6:%0.1f",
__func__, available_distance_eq1, available_distance_eq2,
available_distance_eq3eq6, available_distance_eq4,
available_distance_eq5);
// Calculate current severity distances
cvss4_current_severity_distances (
vec, macrovector, &current_severity_distance_eq1,
&current_severity_distance_eq2, &current_severity_distance_eq3eq6,
&current_severity_distance_eq4, &current_severity_distance_eq5);
g_debug ("%s: current severity distances:"
"EQ1:%0.1f EQ2:%0.1f EQ3+EQ6:%0.1f EQ4:%0.1f EQ5:%0.1f",
__func__, current_severity_distance_eq1,
current_severity_distance_eq2, current_severity_distance_eq3eq6,
current_severity_distance_eq4, current_severity_distance_eq5);
// Get MaxSeverity
cvss4_max_severities (macrovector, &max_severity_eq1, &max_severity_eq2,
&max_severity_eq3eq6, &max_severity_eq4);
g_free (vec);
g_free (macrovector);
// Calculate mean distances
mean_distance = 0.0;
if (available_distance_eq1 >= 0.0)
{
n_existing_lower++;
double percent_to_next_severity =
(current_severity_distance_eq1) / max_severity_eq1;
mean_distance += (available_distance_eq1 * percent_to_next_severity);
}
if (available_distance_eq2 >= 0.0)
{
n_existing_lower++;
double percent_to_next_severity =
(current_severity_distance_eq2) / max_severity_eq2;
mean_distance += (available_distance_eq2 * percent_to_next_severity);
}
if (available_distance_eq3eq6 >= 0.0)
{
n_existing_lower++;
double percent_to_next_severity =
(current_severity_distance_eq3eq6) / max_severity_eq3eq6;
mean_distance += (available_distance_eq3eq6 * percent_to_next_severity);
}
if (available_distance_eq4 >= 0.0)
{
n_existing_lower++;
double percent_to_next_severity =
(current_severity_distance_eq4) / max_severity_eq4;
mean_distance += (available_distance_eq4 * percent_to_next_severity);
}
if (available_distance_eq5 >= 0.0)
{
// For EQ5 the percentage is always 0
n_existing_lower++;
}
mean_distance = mean_distance / n_existing_lower;
// Get and adjust macrovector score
value = value - mean_distance;
if (value < 0.0)
value = 0.0;
else if (value > 10.0)
value = 10.0;
return round (value * 10.0) / 10.0;
}
cvss4_current_severity_distances
static void cvss4_current_severity_distances(const char *vec, const char *macrovector, double *current_severity_distance_eq1, double *current_severity_distance_eq2, double *current_severity_distance_eq3eq6, double *current_severity_distance_eq4, double *current_severity_distance_eq5)
Calculate current severity distances for given CVSS 4.0 vector.
Definition cvss.c:1600
C_COMPLETE
#define C_COMPLETE
Definition cvss.c:122
cvss4_metric_t
cvss4_metric_t
CVSS 4.0 metrics.
Definition cvss.c:219
CVSS4_PR
@ CVSS4_PR
Definition cvss.c:224
CVSS4_VA
@ CVSS4_VA
Definition cvss.c:228
CVSS4_V
@ CVSS4_V
Definition cvss.c:253
CVSS4_AV
@ CVSS4_AV
Definition cvss.c:221
CVSS4_MSA
@ CVSS4_MSA
Definition cvss.c:248
CVSS4_MAC
@ CVSS4_MAC
Definition cvss.c:239
CVSS4_MSC
@ CVSS4_MSC
Definition cvss.c:246
CVSS4_E
@ CVSS4_E
Definition cvss.c:233
CVSS4_RE
@ CVSS4_RE
Definition cvss.c:254
CVSS4_U
@ CVSS4_U
Definition cvss.c:255
CVSS4_MAV
@ CVSS4_MAV
Definition cvss.c:238
CVSS4_AR
@ CVSS4_AR
Definition cvss.c:237
CVSS4_R
@ CVSS4_R
Definition cvss.c:252
CVSS4_SA
@ CVSS4_SA
Definition cvss.c:231
CVSS4_S
@ CVSS4_S
Definition cvss.c:250
CVSS4_VI
@ CVSS4_VI
Definition cvss.c:227
CVSS4_MPR
@ CVSS4_MPR
Definition cvss.c:241
CVSS4_UI
@ CVSS4_UI
Definition cvss.c:225
CVSS4_VC
@ CVSS4_VC
Definition cvss.c:226
CVSS4_SC
@ CVSS4_SC
Definition cvss.c:229
CVSS4_AU
@ CVSS4_AU
Definition cvss.c:251
CVSS4_MSI
@ CVSS4_MSI
Definition cvss.c:247
CVSS4_MVC
@ CVSS4_MVC
Definition cvss.c:243
CVSS4_MUI
@ CVSS4_MUI
Definition cvss.c:242
CVSS4_MAT
@ CVSS4_MAT
Definition cvss.c:240
CVSS4_AT
@ CVSS4_AT
Definition cvss.c:223
CVSS4_AC
@ CVSS4_AC
Definition cvss.c:222
CVSS4_CR
@ CVSS4_CR
Definition cvss.c:235
CVSS4_MVI
@ CVSS4_MVI
Definition cvss.c:244
CVSS4_METRICS_MAX
@ CVSS4_METRICS_MAX
Definition cvss.c:257
CVSS4_MVA
@ CVSS4_MVA
Definition cvss.c:245
CVSS4_SI
@ CVSS4_SI
Definition cvss.c:230
CVSS4_IR
@ CVSS4_IR
Definition cvss.c:236
cvss4_init_macrovector_table
static void cvss4_init_macrovector_table()
Initialize the CVSS 4.0 macrovector lookup table.
Definition cvss.c:840
set_impact_from_str
static int set_impact_from_str(const char *value, enum base_metrics metric, struct cvss *cvss)
Set impact score from string representation.
Definition cvss.c:504
AV_LOCAL
#define AV_LOCAL
Definition cvss.c:101
get_exploitability_subscore
static double get_exploitability_subscore(const struct cvss *cvss)
Calculate Exploitability Sub Score.
Definition cvss.c:488
Au_SINGLE_INSTANCE
#define Au_SINGLE_INSTANCE
Definition cvss.c:114
cvss4_macrovector_score
static double cvss4_macrovector_score(const char *vector)
Get the CVSS 4.0 score for a given macrovector string.
Definition cvss.c:865
A_PARTIAL
#define A_PARTIAL
Definition cvss.c:135
CVSS_MACROVECTOR_BLANK
#define CVSS_MACROVECTOR_BLANK
Blank simplified CVSS 4.0 macrovector string.
Definition cvss.c:268
toenum
static int toenum(const char *str, enum base_metrics *res)
Determine base metric enumeration from a string.
Definition cvss.c:438
C_NONE
#define C_NONE
ConfidentialityImpact (C) Constants.
Definition cvss.c:120
I_PARTIAL
#define I_PARTIAL
Definition cvss.c:128
cvss4_metric_defs
static cvss4_metric_def_t cvss4_metric_defs[]
String to enum mappings and allowed values for CVSS 4.0 metrics.
Definition cvss.c:294
v3_impact
static double v3_impact(const char *value)
Get impact.
Definition cvss.c:677
AV_NETWORK
#define AV_NETWORK
AccessVector (AV) Constants.
Definition cvss.c:99
cvss4_macrovector_mappings
static const cvss4_macrovector_mapping_t cvss4_macrovector_mappings[]
CVSS 4.0 macrovector mappings.
Definition cvss.c:350
cvss4_macrovector_table
static GHashTable * cvss4_macrovector_table
Hashtable for quick lookup of CVSS macrovector scores.
Definition cvss.c:427
C_PARTIAL
#define C_PARTIAL
Definition cvss.c:121
cvss4_m
static char cvss4_m(const char *simplified_vec, cvss4_metric_t metric)
Get the effective value of a metric in a simplified CVSS4 vector.
Definition cvss.c:888
CVSS_METRICS_STR_BLANK
#define CVSS_METRICS_STR_BLANK
Blank simplified CVSS 4.0 metrics string.
Definition cvss.c:263
A_COMPLETE
#define A_COMPLETE
Definition cvss.c:136
cvss4_macrovector
static gchar * cvss4_macrovector(const char *vec)
Calculate CVSS 4.0 macrovector from a simplified vector.
Definition cvss.c:1095
simplify_cvss4_vector
static gchar * simplify_cvss4_vector(const char *cvss_str)
Simplify CVSS 4.0 base vector so metrics can be indexed by enum.
Definition cvss.c:929
cvss4_vector_expand
static gchar * cvss4_vector_expand(const char *vec)
Expands a simplified CVSS 4.0 vector into its full string form.
Definition cvss.c:1046
Au_MULTIPLE_INSTANCES
#define Au_MULTIPLE_INSTANCES
Authentication (Au) Constants.
Definition cvss.c:113
get_impact_subscore
static double get_impact_subscore(const struct cvss *cvss)
Calculate Impact Sub Score.
Definition cvss.c:471
AC_LOW
#define AC_LOW
AccessComplexity (AC) Constants.
Definition cvss.c:106
I_NONE
#define I_NONE
IntegrityImpact (I) Constants.
Definition cvss.c:127
get_cvss_score_from_metrics_v4
static double get_cvss_score_from_metrics_v4(const char *)
Calculate CVSS 4.0 Score.
Definition cvss.c:1766
impact_map
static const struct impact_item impact_map[][3]
Definition cvss.c:174
cvss4_metric_level
static double cvss4_metric_level(cvss4_metric_t metric, char value)
Get the index of a CVSS 4.0 metric value for severity distances.
Definition cvss.c:1439
base_metrics
base_metrics
CVSS v2 Base metrics.
Definition cvss.c:143
AC
@ AC
Definition cvss.c:148
A
@ A
Definition cvss.c:144
C
@ C
Definition cvss.c:146
Au
@ Au
Definition cvss.c:147
I
@ I
Definition cvss.c:145
AV
@ AV
Definition cvss.c:149
get_cvss_score_from_base_metrics_v3
static double get_cvss_score_from_base_metrics_v3(const char *)
Calculate CVSS Score.
Definition cvss.c:696
A_NONE
#define A_NONE
AvailabilityImpact (A) Constants.
Definition cvss.c:134
get_cvss_score_from_base_metrics
double get_cvss_score_from_base_metrics(const char *cvss_str)
Calculate CVSS Score.
Definition cvss.c:585
cvss4_max_severities
static void cvss4_max_severities(const char *macrovector, double *max_severity_eq1, double *max_severity_eq2, double *max_severity_eq3eq6, double *max_severity_eq4)
Get the max severity values for a CVSS 4.0 macrovector.
Definition cvss.c:1693
__get_cvss_score
static double __get_cvss_score(struct cvss *cvss)
Final CVSS score computation helper.
Definition cvss.c:561
I_COMPLETE
#define I_COMPLETE
Definition cvss.c:129
cvss4_severity_distance
static double cvss4_severity_distance(cvss4_metric_t metric, const char *vec, const char *max_vec)
Calculate severity distance for a metric in two CVSS 4.0 vectors.
Definition cvss.c:1581
AC_MEDIUM
#define AC_MEDIUM
Definition cvss.c:107
AV_ADJACENT_NETWORK
#define AV_ADJACENT_NETWORK
Definition cvss.c:100
roundup
static double roundup(double cvss)
Round final score as in spec.
Definition cvss.c:650
cvss4_max_vectors
static gchar ** cvss4_max_vectors(const char *macrovector)
Composes a list of max vectors for the given CVSS 4.0 macrovector.
Definition cvss.c:1328
AC_HIGH
#define AC_HIGH
Definition cvss.c:108
cvss4_maximal_scoring_differences
static void cvss4_maximal_scoring_differences(const char *macrovector, double *available_distance_eq1, double *available_distance_eq2, double *available_distance_eq3eq6, double *available_distance_eq4, double *available_distance_eq5)
Calulate the maximal scoring differences from a CVSS 4.0 macrovector.
Definition cvss.c:1193
Au_NONE
#define Au_NONE
Definition cvss.c:115
cvss.h
Protos for CVSS utility functions.
strings.h
String utilities.
cvss4_macrovector_mapping_t
Key-Value mappings of CVSS 4.0 macrovectors to scores.
Definition cvss.c:338
cvss4_macrovector_mapping_t::vector
const char * vector
Definition cvss.c:339
cvss4_macrovector_mapping_t::score
double score
Definition cvss.c:340
cvss4_metric_def_t
String to enum mapping and allowed values for a CVSS 4.0 metric.
Definition cvss.c:278
cvss4_metric_def_t::metric_str
const char * metric_str
Definition cvss.c:279
cvss4_metric_def_t::values
const char * values
Definition cvss.c:281
cvss4_metric_def_t::metric
const cvss4_metric_t metric
Definition cvss.c:280
cvss
Describe a CVSS metrics.
Definition cvss.c:165
cvss::integ_impact
double integ_impact
Definition cvss.c:167
cvss::access_vector
double access_vector
Definition cvss.c:169
cvss::avail_impact
double avail_impact
Definition cvss.c:168
cvss::authentication
double authentication
Definition cvss.c:171
cvss::access_complexity
double access_complexity
Definition cvss.c:170
cvss::conf_impact
double conf_impact
Definition cvss.c:166
impact_item
Describe a CVSS impact element.
Definition cvss.c:156
impact_item::name
const char * name
Definition cvss.c:157
impact_item::nvalue
double nvalue
Definition cvss.c:158