dradis-calculator_cvss 3.21.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -59
  3. data/CHANGELOG.template +12 -0
  4. data/README.md +1 -1
  5. data/app/assets/javascripts/dradis/plugins/calculators/cvss/calculator.js.coffee +38 -8
  6. data/app/assets/javascripts/dradis/plugins/calculators/cvss/manifests/application.js +3 -0
  7. data/app/assets/javascripts/dradis/plugins/calculators/cvss/manifests/tylium.js +3 -0
  8. data/app/assets/javascripts/dradis/plugins/calculators/cvss/vendor/cvsscalc30_helptext.js +156 -0
  9. data/app/assets/javascripts/dradis/plugins/calculators/cvss/vendor/cvsscalc31.js +753 -0
  10. data/app/assets/javascripts/dradis/plugins/calculators/cvss/vendor/cvsscalc31_helptext.js +157 -0
  11. data/app/assets/stylesheets/dradis/plugins/calculators/cvss/_version_switch.scss +47 -0
  12. data/app/assets/stylesheets/dradis/plugins/calculators/cvss/manifests/application.css.scss +3 -2
  13. data/app/assets/stylesheets/dradis/plugins/calculators/cvss/manifests/tylium.scss +2 -0
  14. data/app/controllers/dradis/plugins/calculators/cvss/issues_controller.rb +1 -1
  15. data/app/models/dradis/plugins/calculators/cvss/v3.rb +1 -1
  16. data/app/views/dradis/plugins/calculators/cvss/_addons_menu.html.erb +1 -1
  17. data/app/views/dradis/plugins/calculators/cvss/_version_switch.html.erb +10 -0
  18. data/app/views/dradis/plugins/calculators/cvss/base/_base.html.erb +30 -30
  19. data/app/views/dradis/plugins/calculators/cvss/base/_environmental.html.erb +53 -53
  20. data/app/views/dradis/plugins/calculators/cvss/base/_temporal.html.erb +17 -17
  21. data/app/views/dradis/plugins/calculators/cvss/base/index.html.erb +7 -6
  22. data/app/views/dradis/plugins/calculators/cvss/issues/_show-content.html.erb +3 -1
  23. data/app/views/dradis/plugins/calculators/cvss/issues/_show-tabs.html.erb +3 -1
  24. data/app/views/dradis/plugins/calculators/cvss/issues/edit.html.erb +5 -2
  25. data/dradis-calculator_cvss.gemspec +2 -2
  26. data/lib/dradis/plugins/calculators/cvss/engine.rb +7 -2
  27. data/lib/dradis/plugins/calculators/cvss/gem_version.rb +2 -2
  28. metadata +16 -9
@@ -0,0 +1,753 @@
1
+ /* Copyright (c) 2019, FIRST.ORG, INC.
2
+ * All rights reserved.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
5
+ * following conditions are met:
6
+ * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
7
+ * disclaimer.
8
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
9
+ * following disclaimer in the documentation and/or other materials provided with the distribution.
10
+ * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
11
+ * products derived from this software without specific prior written permission.
12
+ *
13
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
14
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
16
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
18
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
19
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20
+ */
21
+
22
+ /* This JavaScript contains two main functions. Both take CVSS metric values and calculate CVSS scores for Base,
23
+ * Temporal and Environmental metric groups, their associated severity ratings, and an overall Vector String.
24
+ *
25
+ * Use CVSS31.calculateCVSSFromMetrics if you wish to pass metric values as individual parameters.
26
+ * Use CVSS31.calculateCVSSFromVector if you wish to pass metric values as a single Vector String.
27
+ *
28
+ * Changelog
29
+ *
30
+ * 2019-06-01 Darius Wiles Updates for CVSS version 3.1:
31
+ *
32
+ * 1) The CVSS31.roundUp1 function now performs rounding using integer arithmetic to
33
+ * eliminate problems caused by tiny errors introduced during JavaScript math
34
+ * operations. Thanks to Stanislav Kontar of Red Hat for suggesting and testing
35
+ * various implementations.
36
+ *
37
+ * 2) Environmental formulas changed to prevent the Environmental Score decreasing when
38
+ * the value of an Environmental metric is raised. The problem affected a small
39
+ * percentage of CVSS v3.0 metrics. The change is to the modifiedImpact
40
+ * formula, but only affects scores where the Modified Scope is Changed (or the
41
+ * Scope is Changed if Modified Scope is Not Defined).
42
+ *
43
+ * 3) The JavaScript object containing everything in this file has been renamed from
44
+ * "CVSS" to "CVSS31" to allow both objects to be included without causing a
45
+ * naming conflict.
46
+ *
47
+ * 4) Variable names and code order have changed to more closely reflect the formulas
48
+ * in the CVSS v3.1 Specification Document.
49
+ *
50
+ * 5) A successful call to calculateCVSSFromMetrics now returns sub-formula values.
51
+ *
52
+ * Note that some sets of metrics will produce different scores between CVSS v3.0 and
53
+ * v3.1 as a result of changes 1 and 2. See the explanation of changes between these
54
+ * two standards in the CVSS v3.1 User Guide for more details.
55
+ *
56
+ * 2018-02-15 Darius Wiles Added a missing pair of parentheses in the Environmental score, specifically
57
+ * in the code setting envScore in the main clause (not the else clause). It was changed
58
+ * from "min (...), 10" to "min ((...), 10)". This correction does not alter any final
59
+ * Environmental scores.
60
+ *
61
+ * 2015-08-04 Darius Wiles Added CVSS.generateXMLFromMetrics and CVSS.generateXMLFromVector functions to return
62
+ * XML string representations of: a set of metric values; or a Vector String respectively.
63
+ * Moved all constants and functions to an object named "CVSS" to
64
+ * reduce the chance of conflicts in global variables when this file is combined with
65
+ * other JavaScript code. This will break all existing code that uses this file until
66
+ * the string "CVSS." is prepended to all references. The "Exploitability" metric has been
67
+ * renamed "Exploit Code Maturity" in the specification, so the same change has been made
68
+ * in the code in this file.
69
+ *
70
+ * 2015-04-24 Darius Wiles Environmental formula modified to eliminate undesirable behavior caused by subtle
71
+ * differences in rounding between Temporal and Environmental formulas that often
72
+ * caused the latter to be 0.1 lower than than the former when all Environmental
73
+ * metrics are "Not defined". Also added a RoundUp1 function to simplify formulas.
74
+ *
75
+ * 2015-04-09 Darius Wiles Added calculateCVSSFromVector function, license information, cleaned up code and improved
76
+ * comments.
77
+ *
78
+ * 2014-12-12 Darius Wiles Initial release for CVSS 3.0 Preview 2.
79
+ */
80
+
81
+ // Constants used in the formula. They are not declared as "const" to avoid problems in older browsers.
82
+
83
+ var CVSS31 = {};
84
+
85
+ CVSS31.CVSSVersionIdentifier = "CVSS:3.1";
86
+ CVSS31.exploitabilityCoefficient = 8.22;
87
+ CVSS31.scopeCoefficient = 1.08;
88
+
89
+ // A regular expression to validate that a CVSS 3.1 vector string is well formed. It checks metrics and metric
90
+ // values. It does not check that a metric is specified more than once and it does not check that all base
91
+ // metrics are present. These checks need to be performed separately.
92
+
93
+ CVSS31.vectorStringRegex_31 = /^CVSS:3\.1\/((AV:[NALP]|AC:[LH]|PR:[UNLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XUNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])\/)*(AV:[NALP]|AC:[LH]|PR:[UNLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XUNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])$/;
94
+
95
+
96
+ // Associative arrays mapping each metric value to the constant defined in the CVSS scoring formula in the CVSS v3.1
97
+ // specification.
98
+
99
+ CVSS31.Weight = {
100
+ AV: { N: 0.85, A: 0.62, L: 0.55, P: 0.2},
101
+ AC: { H: 0.44, L: 0.77},
102
+ PR: { U: {N: 0.85, L: 0.62, H: 0.27}, // These values are used if Scope is Unchanged
103
+ C: {N: 0.85, L: 0.68, H: 0.5}}, // These values are used if Scope is Changed
104
+ UI: { N: 0.85, R: 0.62},
105
+ S: { U: 6.42, C: 7.52}, // Note: not defined as constants in specification
106
+ CIA: { N: 0, L: 0.22, H: 0.56}, // C, I and A have the same weights
107
+
108
+ E: { X: 1, U: 0.91, P: 0.94, F: 0.97, H: 1},
109
+ RL: { X: 1, O: 0.95, T: 0.96, W: 0.97, U: 1},
110
+ RC: { X: 1, U: 0.92, R: 0.96, C: 1},
111
+
112
+ CIAR: { X: 1, L: 0.5, M: 1, H: 1.5} // CR, IR and AR have the same weights
113
+ };
114
+
115
+
116
+ // Severity rating bands, as defined in the CVSS v3.1 specification.
117
+
118
+ CVSS31.severityRatings = [ { name: "None", bottom: 0.0, top: 0.0},
119
+ { name: "Low", bottom: 0.1, top: 3.9},
120
+ { name: "Medium", bottom: 4.0, top: 6.9},
121
+ { name: "High", bottom: 7.0, top: 8.9},
122
+ { name: "Critical", bottom: 9.0, top: 10.0} ];
123
+
124
+
125
+
126
+
127
+ /* ** CVSS31.calculateCVSSFromMetrics **
128
+ *
129
+ * Takes Base, Temporal and Environmental metric values as individual parameters. Their values are in the short format
130
+ * defined in the CVSS v3.1 standard definition of the Vector String. For example, the AttackComplexity parameter
131
+ * should be either "H" or "L".
132
+ *
133
+ * Returns Base, Temporal and Environmental scores, severity ratings, and an overall Vector String. All Base metrics
134
+ * are required to generate this output. All Temporal and Environmental metric values are optional. Any that are not
135
+ * passed default to "X" ("Not Defined").
136
+ *
137
+ * The output is an object which always has a property named "success".
138
+ *
139
+ * If no errors are encountered, success is Boolean "true", and the following other properties are defined containing
140
+ * scores, severities and a vector string:
141
+ * baseMetricScore, baseSeverity,
142
+ * temporalMetricScore, temporalSeverity,
143
+ * environmentalMetricScore, environmentalSeverity,
144
+ * vectorString
145
+ *
146
+ * The following properties are also defined, and contain sub-formula values:
147
+ * baseISS, baseImpact, baseExploitability,
148
+ * environmentalMISS, environmentalModifiedImpact, environmentalModifiedExploitability
149
+ *
150
+ *
151
+ * If errors are encountered, success is Boolean "false", and the following other properties are defined:
152
+ * errorType - a string indicating the error. Either:
153
+ * "MissingBaseMetric", if at least one Base metric has not been defined; or
154
+ * "UnknownMetricValue", if at least one metric value is invalid.
155
+ * errorMetrics - an array of strings representing the metrics at fault. The strings are abbreviated versions of the
156
+ * metrics, as defined in the CVSS v3.1 standard definition of the Vector String.
157
+ */
158
+ CVSS31.calculateCVSSFromMetrics = function (
159
+ AttackVector, AttackComplexity, PrivilegesRequired, UserInteraction, Scope, Confidentiality, Integrity, Availability,
160
+ ExploitCodeMaturity, RemediationLevel, ReportConfidence,
161
+ ConfidentialityRequirement, IntegrityRequirement, AvailabilityRequirement,
162
+ ModifiedAttackVector, ModifiedAttackComplexity, ModifiedPrivilegesRequired, ModifiedUserInteraction, ModifiedScope,
163
+ ModifiedConfidentiality, ModifiedIntegrity, ModifiedAvailability) {
164
+
165
+ // If input validation fails, this array is populated with strings indicating which metrics failed validation.
166
+ var badMetrics = [];
167
+
168
+ // ENSURE ALL BASE METRICS ARE DEFINED
169
+ //
170
+ // We need values for all Base Score metrics to calculate scores.
171
+ // If any Base Score parameters are undefined, create an array of missing metrics and return it with an error.
172
+
173
+ if (typeof AttackVector === "undefined" || AttackVector === "") { badMetrics.push("AV"); }
174
+ if (typeof AttackComplexity === "undefined" || AttackComplexity === "") { badMetrics.push("AC"); }
175
+ if (typeof PrivilegesRequired === "undefined" || PrivilegesRequired === "") { badMetrics.push("PR"); }
176
+ if (typeof UserInteraction === "undefined" || UserInteraction === "") { badMetrics.push("UI"); }
177
+ if (typeof Scope === "undefined" || Scope === "") { badMetrics.push("S"); }
178
+ if (typeof Confidentiality === "undefined" || Confidentiality === "") { badMetrics.push("C"); }
179
+ if (typeof Integrity === "undefined" || Integrity === "") { badMetrics.push("I"); }
180
+ if (typeof Availability === "undefined" || Availability === "") { badMetrics.push("A"); }
181
+
182
+ if (badMetrics.length > 0) {
183
+ return { success: false, errorType: "MissingBaseMetric", errorMetrics: badMetrics };
184
+ }
185
+
186
+
187
+ // STORE THE METRIC VALUES THAT WERE PASSED AS PARAMETERS
188
+ //
189
+ // Temporal and Environmental metrics are optional, so set them to "X" ("Not Defined") if no value was passed.
190
+
191
+ var AV = AttackVector;
192
+ var AC = AttackComplexity;
193
+ var PR = PrivilegesRequired;
194
+ var UI = UserInteraction;
195
+ var S = Scope;
196
+ var C = Confidentiality;
197
+ var I = Integrity;
198
+ var A = Availability;
199
+
200
+ var E = ExploitCodeMaturity || "X";
201
+ var RL = RemediationLevel || "X";
202
+ var RC = ReportConfidence || "X";
203
+
204
+ var CR = ConfidentialityRequirement || "X";
205
+ var IR = IntegrityRequirement || "X";
206
+ var AR = AvailabilityRequirement || "X";
207
+ var MAV = ModifiedAttackVector || "X";
208
+ var MAC = ModifiedAttackComplexity || "X";
209
+ var MPR = ModifiedPrivilegesRequired || "X";
210
+ var MUI = ModifiedUserInteraction || "X";
211
+ var MS = ModifiedScope || "X";
212
+ var MC = ModifiedConfidentiality || "X";
213
+ var MI = ModifiedIntegrity || "X";
214
+ var MA = ModifiedAvailability || "X";
215
+
216
+
217
+ // CHECK VALIDITY OF METRIC VALUES
218
+ //
219
+ // Use the Weight object to ensure that, for every metric, the metric value passed is valid.
220
+ // If any invalid values are found, create an array of their metrics and return it with an error.
221
+ //
222
+ // The Privileges Required (PR) weight depends on Scope, but when checking the validity of PR we must not assume
223
+ // that the given value for Scope is valid. We therefore always look at the weights for Unchanged Scope when
224
+ // performing this check. The same applies for validation of Modified Privileges Required (MPR).
225
+ //
226
+ // The Weights object does not contain "X" ("Not Defined") values for Environmental metrics because we replace them
227
+ // with their Base metric equivalents later in the function. For example, an MAV of "X" will be replaced with the
228
+ // value given for AV. We therefore need to explicitly allow a value of "X" for Environmental metrics.
229
+
230
+ if (!CVSS31.Weight.AV.hasOwnProperty(AV)) { badMetrics.push("AV"); }
231
+ if (!CVSS31.Weight.AC.hasOwnProperty(AC)) { badMetrics.push("AC"); }
232
+ if (!CVSS31.Weight.PR.U.hasOwnProperty(PR)) { badMetrics.push("PR"); }
233
+ if (!CVSS31.Weight.UI.hasOwnProperty(UI)) { badMetrics.push("UI"); }
234
+ if (!CVSS31.Weight.S.hasOwnProperty(S)) { badMetrics.push("S"); }
235
+ if (!CVSS31.Weight.CIA.hasOwnProperty(C)) { badMetrics.push("C"); }
236
+ if (!CVSS31.Weight.CIA.hasOwnProperty(I)) { badMetrics.push("I"); }
237
+ if (!CVSS31.Weight.CIA.hasOwnProperty(A)) { badMetrics.push("A"); }
238
+
239
+ if (!CVSS31.Weight.E.hasOwnProperty(E)) { badMetrics.push("E"); }
240
+ if (!CVSS31.Weight.RL.hasOwnProperty(RL)) { badMetrics.push("RL"); }
241
+ if (!CVSS31.Weight.RC.hasOwnProperty(RC)) { badMetrics.push("RC"); }
242
+
243
+ if (!(CR === "X" || CVSS31.Weight.CIAR.hasOwnProperty(CR))) { badMetrics.push("CR"); }
244
+ if (!(IR === "X" || CVSS31.Weight.CIAR.hasOwnProperty(IR))) { badMetrics.push("IR"); }
245
+ if (!(AR === "X" || CVSS31.Weight.CIAR.hasOwnProperty(AR))) { badMetrics.push("AR"); }
246
+ if (!(MAV === "X" || CVSS31.Weight.AV.hasOwnProperty(MAV))) { badMetrics.push("MAV"); }
247
+ if (!(MAC === "X" || CVSS31.Weight.AC.hasOwnProperty(MAC))) { badMetrics.push("MAC"); }
248
+ if (!(MPR === "X" || CVSS31.Weight.PR.U.hasOwnProperty(MPR))) { badMetrics.push("MPR"); }
249
+ if (!(MUI === "X" || CVSS31.Weight.UI.hasOwnProperty(MUI))) { badMetrics.push("MUI"); }
250
+ if (!(MS === "X" || CVSS31.Weight.S.hasOwnProperty(MS))) { badMetrics.push("MS"); }
251
+ if (!(MC === "X" || CVSS31.Weight.CIA.hasOwnProperty(MC))) { badMetrics.push("MC"); }
252
+ if (!(MI === "X" || CVSS31.Weight.CIA.hasOwnProperty(MI))) { badMetrics.push("MI"); }
253
+ if (!(MA === "X" || CVSS31.Weight.CIA.hasOwnProperty(MA))) { badMetrics.push("MA"); }
254
+
255
+ if (badMetrics.length > 0) {
256
+ return { success: false, errorType: "UnknownMetricValue", errorMetrics: badMetrics };
257
+ }
258
+
259
+
260
+
261
+ // GATHER WEIGHTS FOR ALL METRICS
262
+
263
+ var metricWeightAV = CVSS31.Weight.AV [AV];
264
+ var metricWeightAC = CVSS31.Weight.AC [AC];
265
+ var metricWeightPR = CVSS31.Weight.PR [S][PR]; // PR depends on the value of Scope (S).
266
+ var metricWeightUI = CVSS31.Weight.UI [UI];
267
+ var metricWeightS = CVSS31.Weight.S [S];
268
+ var metricWeightC = CVSS31.Weight.CIA [C];
269
+ var metricWeightI = CVSS31.Weight.CIA [I];
270
+ var metricWeightA = CVSS31.Weight.CIA [A];
271
+
272
+ var metricWeightE = CVSS31.Weight.E [E];
273
+ var metricWeightRL = CVSS31.Weight.RL [RL];
274
+ var metricWeightRC = CVSS31.Weight.RC [RC];
275
+
276
+ // For metrics that are modified versions of Base Score metrics, e.g. Modified Attack Vector, use the value of
277
+ // the Base Score metric if the modified version value is "X" ("Not Defined").
278
+ var metricWeightCR = CVSS31.Weight.CIAR [CR];
279
+ var metricWeightIR = CVSS31.Weight.CIAR [IR];
280
+ var metricWeightAR = CVSS31.Weight.CIAR [AR];
281
+ var metricWeightMAV = CVSS31.Weight.AV [MAV !== "X" ? MAV : AV];
282
+ var metricWeightMAC = CVSS31.Weight.AC [MAC !== "X" ? MAC : AC];
283
+ var metricWeightMPR = CVSS31.Weight.PR [MS !== "X" ? MS : S] [MPR !== "X" ? MPR : PR]; // Depends on MS.
284
+ var metricWeightMUI = CVSS31.Weight.UI [MUI !== "X" ? MUI : UI];
285
+ var metricWeightMS = CVSS31.Weight.S [MS !== "X" ? MS : S];
286
+ var metricWeightMC = CVSS31.Weight.CIA [MC !== "X" ? MC : C];
287
+ var metricWeightMI = CVSS31.Weight.CIA [MI !== "X" ? MI : I];
288
+ var metricWeightMA = CVSS31.Weight.CIA [MA !== "X" ? MA : A];
289
+
290
+
291
+
292
+ // CALCULATE THE CVSS BASE SCORE
293
+
294
+ var iss; /* Impact Sub-Score */
295
+ var impact;
296
+ var exploitability;
297
+ var baseScore;
298
+
299
+ iss = (1 - ((1 - metricWeightC) * (1 - metricWeightI) * (1 - metricWeightA)));
300
+
301
+ if (S === 'U') {
302
+ impact = metricWeightS * iss;
303
+ } else {
304
+ impact = metricWeightS * (iss - 0.029) - 3.25 * Math.pow(iss - 0.02, 15);
305
+ }
306
+
307
+ exploitability = CVSS31.exploitabilityCoefficient * metricWeightAV * metricWeightAC * metricWeightPR * metricWeightUI;
308
+
309
+ if (impact <= 0) {
310
+ baseScore = 0;
311
+ } else {
312
+ if (S === 'U') {
313
+ baseScore = CVSS31.roundUp1(Math.min((exploitability + impact), 10));
314
+ } else {
315
+ baseScore = CVSS31.roundUp1(Math.min(CVSS31.scopeCoefficient * (exploitability + impact), 10));
316
+ }
317
+ }
318
+
319
+
320
+ // CALCULATE THE CVSS TEMPORAL SCORE
321
+
322
+ var temporalScore = CVSS31.roundUp1(baseScore * metricWeightE * metricWeightRL * metricWeightRC);
323
+
324
+
325
+ // CALCULATE THE CVSS ENVIRONMENTAL SCORE
326
+ //
327
+ // - modifiedExploitability recalculates the Base Score Exploitability sub-score using any modified values from the
328
+ // Environmental metrics group in place of the values specified in the Base Score, if any have been defined.
329
+ // - modifiedImpact recalculates the Base Score Impact sub-score using any modified values from the
330
+ // Environmental metrics group in place of the values specified in the Base Score, and any additional weightings
331
+ // given in the Environmental metrics group.
332
+
333
+ var miss; /* Modified Impact Sub-Score */
334
+ var modifiedImpact;
335
+ var envScore;
336
+ var modifiedExploitability;
337
+
338
+ miss = Math.min (1 -
339
+ ( (1 - metricWeightMC * metricWeightCR) *
340
+ (1 - metricWeightMI * metricWeightIR) *
341
+ (1 - metricWeightMA * metricWeightAR)), 0.915);
342
+
343
+ if (MS === "U" ||
344
+ (MS === "X" && S === "U")) {
345
+ modifiedImpact = metricWeightMS * miss;
346
+ } else {
347
+ modifiedImpact = metricWeightMS * (miss - 0.029) - 3.25 * Math.pow(miss * 0.9731 - 0.02, 13);
348
+ }
349
+
350
+ modifiedExploitability = CVSS31.exploitabilityCoefficient * metricWeightMAV * metricWeightMAC * metricWeightMPR * metricWeightMUI;
351
+
352
+ if (modifiedImpact <= 0) {
353
+ envScore = 0;
354
+ } else if (MS === "U" || (MS === "X" && S === "U")) {
355
+ envScore = CVSS31.roundUp1(CVSS31.roundUp1(Math.min((modifiedImpact + modifiedExploitability), 10)) *
356
+ metricWeightE * metricWeightRL * metricWeightRC);
357
+ } else {
358
+ envScore = CVSS31.roundUp1(CVSS31.roundUp1(Math.min(CVSS31.scopeCoefficient * (modifiedImpact + modifiedExploitability), 10)) *
359
+ metricWeightE * metricWeightRL * metricWeightRC);
360
+ }
361
+
362
+
363
+ // CONSTRUCT THE VECTOR STRING
364
+
365
+ var vectorString =
366
+ CVSS31.CVSSVersionIdentifier +
367
+ "/AV:" + AV +
368
+ "/AC:" + AC +
369
+ "/PR:" + PR +
370
+ "/UI:" + UI +
371
+ "/S:" + S +
372
+ "/C:" + C +
373
+ "/I:" + I +
374
+ "/A:" + A;
375
+
376
+ if (E !== "X") {vectorString = vectorString + "/E:" + E;}
377
+ if (RL !== "X") {vectorString = vectorString + "/RL:" + RL;}
378
+ if (RC !== "X") {vectorString = vectorString + "/RC:" + RC;}
379
+
380
+ if (CR !== "X") {vectorString = vectorString + "/CR:" + CR;}
381
+ if (IR !== "X") {vectorString = vectorString + "/IR:" + IR;}
382
+ if (AR !== "X") {vectorString = vectorString + "/AR:" + AR;}
383
+ if (MAV !== "X") {vectorString = vectorString + "/MAV:" + MAV;}
384
+ if (MAC !== "X") {vectorString = vectorString + "/MAC:" + MAC;}
385
+ if (MPR !== "X") {vectorString = vectorString + "/MPR:" + MPR;}
386
+ if (MUI !== "X") {vectorString = vectorString + "/MUI:" + MUI;}
387
+ if (MS !== "X") {vectorString = vectorString + "/MS:" + MS;}
388
+ if (MC !== "X") {vectorString = vectorString + "/MC:" + MC;}
389
+ if (MI !== "X") {vectorString = vectorString + "/MI:" + MI;}
390
+ if (MA !== "X") {vectorString = vectorString + "/MA:" + MA;}
391
+
392
+
393
+ // Return an object containing the scores for all three metric groups, and an overall vector string.
394
+ // Sub-formula values are also included.
395
+
396
+ return {
397
+ success: true,
398
+
399
+ baseMetricScore: baseScore.toFixed(1),
400
+ baseSeverity: CVSS31.severityRating( baseScore.toFixed(1) ),
401
+ baseISS: iss,
402
+ baseImpact: impact,
403
+ baseExploitability: exploitability,
404
+
405
+ temporalMetricScore: temporalScore.toFixed(1),
406
+ temporalSeverity: CVSS31.severityRating( temporalScore.toFixed(1) ),
407
+
408
+ environmentalMetricScore: envScore.toFixed(1),
409
+ environmentalSeverity: CVSS31.severityRating( envScore.toFixed(1) ),
410
+ environmentalMISS: miss,
411
+ environmentalModifiedImpact: modifiedImpact,
412
+ environmentalModifiedExploitability: modifiedExploitability,
413
+
414
+ vectorString: vectorString
415
+ };
416
+ };
417
+
418
+
419
+
420
+
421
+ /* ** CVSS31.calculateCVSSFromVector **
422
+ *
423
+ * Takes Base, Temporal and Environmental metric values as a single string in the Vector String format defined
424
+ * in the CVSS v3.1 standard definition of the Vector String.
425
+ *
426
+ * Returns Base, Temporal and Environmental scores, severity ratings, and an overall Vector String. All Base metrics
427
+ * are required to generate this output. All Temporal and Environmental metric values are optional. Any that are not
428
+ * passed default to "X" ("Not Defined").
429
+ *
430
+ * See the comment for the CVSS31.calculateCVSSFromMetrics function for details on the function output. In addition to
431
+ * the error conditions listed for that function, this function can also return:
432
+ * "MalformedVectorString", if the Vector String passed does not conform to the format in the standard; or
433
+ * "MultipleDefinitionsOfMetric", if the Vector String is well formed but defines the same metric (or metrics),
434
+ * more than once.
435
+ */
436
+ CVSS31.calculateCVSSFromVector = function ( vectorString ) {
437
+
438
+ var metricValues = {
439
+ AV: undefined, AC: undefined, PR: undefined, UI: undefined, S: undefined,
440
+ C: undefined, I: undefined, A: undefined,
441
+ E: undefined, RL: undefined, RC: undefined,
442
+ CR: undefined, IR: undefined, AR: undefined,
443
+ MAV: undefined, MAC: undefined, MPR: undefined, MUI: undefined, MS: undefined,
444
+ MC: undefined, MI: undefined, MA: undefined
445
+ };
446
+
447
+ // If input validation fails, this array is populated with strings indicating which metrics failed validation.
448
+ var badMetrics = [];
449
+
450
+ if (!CVSS31.vectorStringRegex_31.test(vectorString)) {
451
+ return { success: false, errorType: "MalformedVectorString" };
452
+ }
453
+
454
+ var metricNameValue = vectorString.substring(CVSS31.CVSSVersionIdentifier.length).split("/");
455
+
456
+ for (var i in metricNameValue) {
457
+ if (metricNameValue.hasOwnProperty(i)) {
458
+
459
+ var singleMetric = metricNameValue[i].split(":");
460
+
461
+ if (typeof metricValues[singleMetric[0]] === "undefined") {
462
+ metricValues[singleMetric[0]] = singleMetric[1];
463
+ } else {
464
+ badMetrics.push(singleMetric[0]);
465
+ }
466
+ }
467
+ }
468
+
469
+ if (badMetrics.length > 0) {
470
+ return { success: false, errorType: "MultipleDefinitionsOfMetric", errorMetrics: badMetrics };
471
+ }
472
+
473
+ return CVSS31.calculateCVSSFromMetrics (
474
+ metricValues.AV, metricValues.AC, metricValues.PR, metricValues.UI, metricValues.S,
475
+ metricValues.C, metricValues.I, metricValues.A,
476
+ metricValues.E, metricValues.RL, metricValues.RC,
477
+ metricValues.CR, metricValues.IR, metricValues.AR,
478
+ metricValues.MAV, metricValues.MAC, metricValues.MPR, metricValues.MUI, metricValues.MS,
479
+ metricValues.MC, metricValues.MI, metricValues.MA);
480
+ };
481
+
482
+
483
+
484
+
485
+ /* ** CVSS31.roundUp1 **
486
+ *
487
+ * Rounds up its parameter to 1 decimal place and returns the result.
488
+ *
489
+ * Standard JavaScript errors thrown when arithmetic operations are performed on non-numbers will be returned if the
490
+ * given input is not a number.
491
+ *
492
+ * Implementation note: Tiny representation errors in floating point numbers makes rounding complex. For example,
493
+ * consider calculating Math.ceil((1-0.58)*100) by hand. It can be simplified to Math.ceil(0.42*100), then
494
+ * Math.ceil(42), and finally 42. Most JavaScript implementations give 43. The problem is that, on many systems,
495
+ * 1-0.58 = 0.42000000000000004, and the tiny error is enough to push ceil up to the next integer. The implementation
496
+ * below avoids such problems by performing the rounding using integers. The input is first multiplied by 100,000
497
+ * and rounded to the nearest integer to consider 6 decimal places of accuracy, so 0.000001 results in 0.0, but
498
+ * 0.000009 results in 0.1.
499
+ *
500
+ * A more elegant solution may be possible, but the following gives answers consistent with results from an arbitrary
501
+ * precision library.
502
+ */
503
+ CVSS31.roundUp1 = function Roundup (input) {
504
+ var int_input = Math.round(input * 100000);
505
+
506
+ if (int_input % 10000 === 0) {
507
+ return int_input / 100000;
508
+ } else {
509
+ return (Math.floor(int_input / 10000) + 1) / 10;
510
+ }
511
+ };
512
+
513
+
514
+
515
+ /* ** CVSS31.severityRating **
516
+ *
517
+ * Given a CVSS score, returns the name of the severity rating as defined in the CVSS standard.
518
+ * The input needs to be a number between 0.0 to 10.0, to one decimal place of precision.
519
+ *
520
+ * The following error values may be returned instead of a severity rating name:
521
+ * NaN (JavaScript "Not a Number") - if the input is not a number.
522
+ * undefined - if the input is a number that is not within the range of any defined severity rating.
523
+ */
524
+ CVSS31.severityRating = function (score) {
525
+ var severityRatingLength = CVSS31.severityRatings.length;
526
+
527
+ var validatedScore = Number(score);
528
+
529
+ if (isNaN(validatedScore)) {
530
+ return validatedScore;
531
+ }
532
+
533
+ for (var i = 0; i < severityRatingLength; i++) {
534
+ if (score >= CVSS31.severityRatings[i].bottom && score <= CVSS31.severityRatings[i].top) {
535
+ return CVSS31.severityRatings[i].name;
536
+ }
537
+ }
538
+
539
+ return undefined;
540
+ };
541
+
542
+
543
+
544
+ ///////////////////////////////////////////////////////////////////////////
545
+ // DATA AND FUNCTIONS FOR CREATING AN XML REPRESENTATION OF A CVSS SCORE //
546
+ ///////////////////////////////////////////////////////////////////////////
547
+
548
+ // A mapping between abbreviated metric values and the string used in the XML representation.
549
+ // For example, a Remediation Level (RL) abbreviated metric value of "W" maps to "WORKAROUND".
550
+ // For brevity, every Base metric shares its definition with its equivalent Environmental metric. This is possible
551
+ // because the metric values are same between these groups, except that the latter have an additional metric value
552
+ // of "NOT_DEFINED".
553
+
554
+ CVSS31.XML_MetricNames = {
555
+ E: { X: "NOT_DEFINED", U: "UNPROVEN", P: "PROOF_OF_CONCEPT", F: "FUNCTIONAL", H: "HIGH"},
556
+ RL: { X: "NOT_DEFINED", O: "OFFICIAL_FIX", T: "TEMPORARY_FIX", W: "WORKAROUND", U: "UNAVAILABLE"},
557
+ RC: { X: "NOT_DEFINED", U: "UNKNOWN", R: "REASONABLE", C: "CONFIRMED"},
558
+
559
+ CIAR: { X: "NOT_DEFINED", L: "LOW", M: "MEDIUM", H: "HIGH"}, // CR, IR and AR use the same values
560
+ MAV: { N: "NETWORK", A: "ADJACENT_NETWORK", L: "LOCAL", P: "PHYSICAL", X: "NOT_DEFINED" },
561
+ MAC: { H: "HIGH", L: "LOW", X: "NOT_DEFINED" },
562
+ MPR: { N: "NONE", L: "LOW", H: "HIGH", X: "NOT_DEFINED" },
563
+ MUI: { N: "NONE", R: "REQUIRED", X: "NOT_DEFINED" },
564
+ MS: { U: "UNCHANGED", C: "CHANGED", X: "NOT_DEFINED" },
565
+ MCIA: { N: "NONE", L: "LOW", H: "HIGH", X: "NOT_DEFINED" } // C, I and A use the same values
566
+ };
567
+
568
+
569
+
570
+ /* ** CVSS31.generateXMLFromMetrics **
571
+ *
572
+ * Takes Base, Temporal and Environmental metric values as individual parameters. Their values are in the short format
573
+ * defined in the CVSS v3.1 standard definition of the Vector String. For example, the AttackComplexity parameter
574
+ * should be either "H" or "L".
575
+ *
576
+ * Returns a single string containing the metric values in XML form. All Base metrics are required to generate this
577
+ * output. All Temporal and Environmental metric values are optional. Any that are not passed will be represented in
578
+ * the XML as NOT_DEFINED. The function returns a string for simplicity. It is arguably better to return the XML as
579
+ * a DOM object, but at the time of writing this leads to complexity due to older browsers using different JavaScript
580
+ * interfaces to do this. Also for simplicity, all Temporal and Environmental metrics are included in the string,
581
+ * even though those with a value of "Not Defined" do not need to be included.
582
+ *
583
+ * The output of this function is an object which always has a property named "success".
584
+ *
585
+ * If no errors are encountered, success is Boolean "true", and the "xmlString" property contains the XML string
586
+ * representation.
587
+ *
588
+ * If errors are encountered, success is Boolean "false", and other properties are defined as per the
589
+ * CVSS31.calculateCVSSFromMetrics function. Refer to the comment for that function for more details.
590
+ */
591
+ CVSS31.generateXMLFromMetrics = function (
592
+ AttackVector, AttackComplexity, PrivilegesRequired, UserInteraction, Scope, Confidentiality, Integrity, Availability,
593
+ ExploitCodeMaturity, RemediationLevel, ReportConfidence,
594
+ ConfidentialityRequirement, IntegrityRequirement, AvailabilityRequirement,
595
+ ModifiedAttackVector, ModifiedAttackComplexity, ModifiedPrivilegesRequired, ModifiedUserInteraction, ModifiedScope,
596
+ ModifiedConfidentiality, ModifiedIntegrity, ModifiedAvailability) {
597
+
598
+ // A string containing the XML we wish to output, with placeholders for the CVSS metrics we will substitute for
599
+ // their values, based on the inputs passed to this function.
600
+ var xmlTemplate =
601
+ '<?xml version="1.0" encoding="UTF-8"?>\n' +
602
+ '<cvssv3.1 xmlns="https://www.first.org/cvss/cvss-v3.1.xsd"\n' +
603
+ ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n' +
604
+ ' xsi:schemaLocation="https://www.first.org/cvss/cvss-v3.1.xsd https://www.first.org/cvss/cvss-v3.1.xsd"\n' +
605
+ ' >\n' +
606
+ '\n' +
607
+ ' <base_metrics>\n' +
608
+ ' <attack-vector>__AttackVector__</attack-vector>\n' +
609
+ ' <attack-complexity>__AttackComplexity__</attack-complexity>\n' +
610
+ ' <privileges-required>__PrivilegesRequired__</privileges-required>\n' +
611
+ ' <user-interaction>__UserInteraction__</user-interaction>\n' +
612
+ ' <scope>__Scope__</scope>\n' +
613
+ ' <confidentiality-impact>__Confidentiality__</confidentiality-impact>\n' +
614
+ ' <integrity-impact>__Integrity__</integrity-impact>\n' +
615
+ ' <availability-impact>__Availability__</availability-impact>\n' +
616
+ ' <base-score>__BaseScore__</base-score>\n' +
617
+ ' <base-severity>__BaseSeverityRating__</base-severity>\n' +
618
+ ' </base_metrics>\n' +
619
+ '\n' +
620
+ ' <temporal_metrics>\n' +
621
+ ' <exploit-code-maturity>__ExploitCodeMaturity__</exploit-code-maturity>\n' +
622
+ ' <remediation-level>__RemediationLevel__</remediation-level>\n' +
623
+ ' <report-confidence>__ReportConfidence__</report-confidence>\n' +
624
+ ' <temporal-score>__TemporalScore__</temporal-score>\n' +
625
+ ' <temporal-severity>__TemporalSeverityRating__</temporal-severity>\n' +
626
+ ' </temporal_metrics>\n' +
627
+ '\n' +
628
+ ' <environmental_metrics>\n' +
629
+ ' <confidentiality-requirement>__ConfidentialityRequirement__</confidentiality-requirement>\n' +
630
+ ' <integrity-requirement>__IntegrityRequirement__</integrity-requirement>\n' +
631
+ ' <availability-requirement>__AvailabilityRequirement__</availability-requirement>\n' +
632
+ ' <modified-attack-vector>__ModifiedAttackVector__</modified-attack-vector>\n' +
633
+ ' <modified-attack-complexity>__ModifiedAttackComplexity__</modified-attack-complexity>\n' +
634
+ ' <modified-privileges-required>__ModifiedPrivilegesRequired__</modified-privileges-required>\n' +
635
+ ' <modified-user-interaction>__ModifiedUserInteraction__</modified-user-interaction>\n' +
636
+ ' <modified-scope>__ModifiedScope__</modified-scope>\n' +
637
+ ' <modified-confidentiality-impact>__ModifiedConfidentiality__</modified-confidentiality-impact>\n' +
638
+ ' <modified-integrity-impact>__ModifiedIntegrity__</modified-integrity-impact>\n' +
639
+ ' <modified-availability-impact>__ModifiedAvailability__</modified-availability-impact>\n' +
640
+ ' <environmental-score>__EnvironmentalScore__</environmental-score>\n' +
641
+ ' <environmental-severity>__EnvironmentalSeverityRating__</environmental-severity>\n' +
642
+ ' </environmental_metrics>\n' +
643
+ '\n' +
644
+ '</cvssv3.1>\n';
645
+
646
+
647
+ // Call CVSS31.calculateCVSSFromMetrics to validate all the parameters and generate scores and severity ratings.
648
+ // If that function returns an error, immediately return it to the caller of this function.
649
+ var result = CVSS31.calculateCVSSFromMetrics (
650
+ AttackVector, AttackComplexity, PrivilegesRequired, UserInteraction, Scope, Confidentiality, Integrity, Availability,
651
+ ExploitCodeMaturity, RemediationLevel, ReportConfidence,
652
+ ConfidentialityRequirement, IntegrityRequirement, AvailabilityRequirement,
653
+ ModifiedAttackVector, ModifiedAttackComplexity, ModifiedPrivilegesRequired, ModifiedUserInteraction, ModifiedScope,
654
+ ModifiedConfidentiality, ModifiedIntegrity, ModifiedAvailability);
655
+
656
+ if (result.success !== true) {
657
+ return result;
658
+ }
659
+
660
+ var xmlOutput = xmlTemplate;
661
+ xmlOutput = xmlOutput.replace ("__AttackVector__", CVSS31.XML_MetricNames["MAV"][AttackVector]);
662
+ xmlOutput = xmlOutput.replace ("__AttackComplexity__", CVSS31.XML_MetricNames["MAC"][AttackComplexity]);
663
+ xmlOutput = xmlOutput.replace ("__PrivilegesRequired__", CVSS31.XML_MetricNames["MPR"][PrivilegesRequired]);
664
+ xmlOutput = xmlOutput.replace ("__UserInteraction__", CVSS31.XML_MetricNames["MUI"][UserInteraction]);
665
+ xmlOutput = xmlOutput.replace ("__Scope__", CVSS31.XML_MetricNames["MS"][Scope]);
666
+ xmlOutput = xmlOutput.replace ("__Confidentiality__", CVSS31.XML_MetricNames["MCIA"][Confidentiality]);
667
+ xmlOutput = xmlOutput.replace ("__Integrity__", CVSS31.XML_MetricNames["MCIA"][Integrity]);
668
+ xmlOutput = xmlOutput.replace ("__Availability__", CVSS31.XML_MetricNames["MCIA"][Availability]);
669
+ xmlOutput = xmlOutput.replace ("__BaseScore__", result.baseMetricScore);
670
+ xmlOutput = xmlOutput.replace ("__BaseSeverityRating__", result.baseSeverity);
671
+
672
+ xmlOutput = xmlOutput.replace ("__ExploitCodeMaturity__", CVSS31.XML_MetricNames["E"][ExploitCodeMaturity || "X"]);
673
+ xmlOutput = xmlOutput.replace ("__RemediationLevel__", CVSS31.XML_MetricNames["RL"][RemediationLevel || "X"]);
674
+ xmlOutput = xmlOutput.replace ("__ReportConfidence__", CVSS31.XML_MetricNames["RC"][ReportConfidence || "X"]);
675
+ xmlOutput = xmlOutput.replace ("__TemporalScore__", result.temporalMetricScore);
676
+ xmlOutput = xmlOutput.replace ("__TemporalSeverityRating__", result.temporalSeverity);
677
+
678
+ xmlOutput = xmlOutput.replace ("__ConfidentialityRequirement__", CVSS31.XML_MetricNames["CIAR"][ConfidentialityRequirement || "X"]);
679
+ xmlOutput = xmlOutput.replace ("__IntegrityRequirement__", CVSS31.XML_MetricNames["CIAR"][IntegrityRequirement || "X"]);
680
+ xmlOutput = xmlOutput.replace ("__AvailabilityRequirement__", CVSS31.XML_MetricNames["CIAR"][AvailabilityRequirement || "X"]);
681
+ xmlOutput = xmlOutput.replace ("__ModifiedAttackVector__", CVSS31.XML_MetricNames["MAV"][ModifiedAttackVector || "X"]);
682
+ xmlOutput = xmlOutput.replace ("__ModifiedAttackComplexity__", CVSS31.XML_MetricNames["MAC"][ModifiedAttackComplexity || "X"]);
683
+ xmlOutput = xmlOutput.replace ("__ModifiedPrivilegesRequired__", CVSS31.XML_MetricNames["MPR"][ModifiedPrivilegesRequired || "X"]);
684
+ xmlOutput = xmlOutput.replace ("__ModifiedUserInteraction__", CVSS31.XML_MetricNames["MUI"][ModifiedUserInteraction || "X"]);
685
+ xmlOutput = xmlOutput.replace ("__ModifiedScope__", CVSS31.XML_MetricNames["MS"][ModifiedScope || "X"]);
686
+ xmlOutput = xmlOutput.replace ("__ModifiedConfidentiality__", CVSS31.XML_MetricNames["MCIA"][ModifiedConfidentiality || "X"]);
687
+ xmlOutput = xmlOutput.replace ("__ModifiedIntegrity__", CVSS31.XML_MetricNames["MCIA"][ModifiedIntegrity || "X"]);
688
+ xmlOutput = xmlOutput.replace ("__ModifiedAvailability__", CVSS31.XML_MetricNames["MCIA"][ModifiedAvailability || "X"]);
689
+ xmlOutput = xmlOutput.replace ("__EnvironmentalScore__", result.environmentalMetricScore);
690
+ xmlOutput = xmlOutput.replace ("__EnvironmentalSeverityRating__", result.environmentalSeverity);
691
+
692
+ return { success: true, xmlString: xmlOutput };
693
+ };
694
+
695
+
696
+
697
+ /* ** CVSS31.generateXMLFromVector **
698
+ *
699
+ * Takes Base, Temporal and Environmental metric values as a single string in the Vector String format defined
700
+ * in the CVSS v3.1 standard definition of the Vector String.
701
+ *
702
+ * Returns an XML string representation of this input. See the comment for CVSS31.generateXMLFromMetrics for more
703
+ * detail on inputs, return values and errors. In addition to the error conditions listed for that function, this
704
+ * function can also return:
705
+ * "MalformedVectorString", if the Vector String passed is does not conform to the format in the standard; or
706
+ * "MultipleDefinitionsOfMetric", if the Vector String is well formed but defines the same metric (or metrics),
707
+ * more than once.
708
+ */
709
+ CVSS31.generateXMLFromVector = function ( vectorString ) {
710
+
711
+ var metricValues = {
712
+ AV: undefined, AC: undefined, PR: undefined, UI: undefined, S: undefined,
713
+ C: undefined, I: undefined, A: undefined,
714
+ E: undefined, RL: undefined, RC: undefined,
715
+ CR: undefined, IR: undefined, AR: undefined,
716
+ MAV: undefined, MAC: undefined, MPR: undefined, MUI: undefined, MS: undefined,
717
+ MC: undefined, MI: undefined, MA: undefined
718
+ };
719
+
720
+ // If input validation fails, this array is populated with strings indicating which metrics failed validation.
721
+ var badMetrics = [];
722
+
723
+ if (!CVSS31.vectorStringRegex_31.test(vectorString)) {
724
+ return { success: false, errorType: "MalformedVectorString" };
725
+ }
726
+
727
+ var metricNameValue = vectorString.substring(CVSS31.CVSSVersionIdentifier.length).split("/");
728
+
729
+ for (var i in metricNameValue) {
730
+ if (metricNameValue.hasOwnProperty(i)) {
731
+
732
+ var singleMetric = metricNameValue[i].split(":");
733
+
734
+ if (typeof metricValues[singleMetric[0]] === "undefined") {
735
+ metricValues[singleMetric[0]] = singleMetric[1];
736
+ } else {
737
+ badMetrics.push(singleMetric[0]);
738
+ }
739
+ }
740
+ }
741
+
742
+ if (badMetrics.length > 0) {
743
+ return { success: false, errorType: "MultipleDefinitionsOfMetric", errorMetrics: badMetrics };
744
+ }
745
+
746
+ return CVSS31.generateXMLFromMetrics (
747
+ metricValues.AV, metricValues.AC, metricValues.PR, metricValues.UI, metricValues.S,
748
+ metricValues.C, metricValues.I, metricValues.A,
749
+ metricValues.E, metricValues.RL, metricValues.RC,
750
+ metricValues.CR, metricValues.IR, metricValues.AR,
751
+ metricValues.MAV, metricValues.MAC, metricValues.MPR, metricValues.MUI, metricValues.MS,
752
+ metricValues.MC, metricValues.MI, metricValues.MA);
753
+ };