%% %% This is file `cvss.sty', %% generated with the docstrip utility. %% %% The original source files were: %% %% cvss.dtx (with options: `package') %% ---------------------------------------------------------------- %% cvss --- A package to compute and display CVSS base scores %% E-mail: pierre@vivegnis.be %% Released under the LaTeX Project Public License v1.3c or later %% See http://www.latex-project.org/lppl.txt %% ---------------------------------------------------------------- %% \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{cvss}[2022/12/02 v1.1.0 ] % \begin{syntax} % \end{function} % \begin{syntax} % \cs{cvssLevel} \Arg{CVSS string} % \end{syntax} % \begin{syntax} % \cs{cvssLevelpretty} \Arg{CVSS string} % \end{syntax} % \begin{syntax} % \cs{cvssTag} \Arg{CVSS string} % \end{syntax} % \begin{syntax} % \cs{category} \Arg{CVSS score} % \end{syntax} %%\category{9.9} \RequirePackage{expl3} \RequirePackage[skins]{tcolorbox} \tcbuselibrary{xparse} \RequirePackage{xstring} \RequirePackage{hyperref} \def\scoreLow{0.1} \def\scoreMed{4.0} \def\scoreHigh{7.0} \def\scoreCrit{9.0} \definecolor{color@cvss@None}{RGB}{83, 170, 51} \definecolor{color@cvss@Low}{RGB}{255, 203, 13} \definecolor{color@cvss@Medium}{RGB}{249, 160, 9} \definecolor{color@cvss@High}{RGB}{223, 61, 3} \definecolor{color@cvss@Critical}{RGB}{204, 5, 0} \ExplSyntaxOn \cs_new:Npn \__CVSS_roundup:n #1 { \fp_eval:n { ceil(#1,1) } \fp_compare:nT { ceil(#1,1)=ceil(#1,0) } {.0} } \msg_new:nnn { CVSS } { invalid-option }{ Value~'#2'~invalid~for~#1~#3.} \msg_new:nnn { CVSS } { invalid-structure } { CVSS~metric~#1~is~not~correct~(#2)~#3.} \msg_new:nnn { CVSS } { invalid-length } { CVSS~vector~"#1"~is~badly~formatted~#2.} \msg_new:nnn { CVSS } { wrong-version } { Wrong~CVSS~version~(#2)~#3.} \cs_new:Npn \__CVSS_parseAV:n #1 { \str_case_e:nnF {#1} { { N } { 0.85 } % Network { A } { 0.62 } % Adjacent { L } { 0.55 } % Local { P } { 0.2 } % Physical } { \msg_error:nnxxx { CVSS } { invalid-option } { parseAV } {#1} {\msg_line_context:} } } \cs_new:Npn \__CVSS_parseAC:n #1 { \str_case_e:nnF {#1} { { H } { 0.44 } % High { L } { 0.77 } % Low } { \msg_error:nnxxx { CVSS } { invalid-option } { parseAC } {#1} {\msg_line_context:} } } \cs_new:Npn \__CVSS_parsePRScopeUnchanged:n #1 { \str_case_e:nnF {#1} { { N } { 0.85 } % None { L } { 0.62 } % Low { H } { 0.27 } % High } { \msg_error:nnxxx { CVSS } { invalid-option } { parsePRScopeUnchanged } {#1} {\msg_line_context:} } } \cs_new:Npn \__CVSS_parsePRScopeChanged:n #1 { \str_case_e:nnF {#1} { { N } { 0.85 } % None { L } { 0.68 } % Low { H } { 0.50 } % High } { \msg_error:nnxxx { CVSS } { invalid-option } { parsePRScopeChanged } {#1} {\msg_line_context:} } } \cs_new:Npn \__CVSS_parsePR:nn #1#2 { % #1 Privilege Required % #2 Scope \str_case_e:nnF {#2} { { U } { \exp_args:Ne \__CVSS_parsePRScopeUnchanged:n {#1} } { C } { \exp_args:Ne \__CVSS_parsePRScopeChanged:n {#1} } } { \msg_error:nnxxx { CVSS } { invalid-option } { parsePR } {#1} {\msg_line_context:} } } \cs_new:Npn \__CVSS_parseUI:n #1 { \str_case_e:nnF {#1} { { N } { 0.85 } % None { R } { 0.62 } % Required } { \msg_error:nnxxx { CVSS } { invalid-option } { parseUI } {#1} {\msg_line_context:} } } \cs_new:Npn \__CVSS_parseCIA:n #1 { \str_case_e:nnF {#1} { { H } { 0.56 } { L } { 0.22 } { N } { 0.00 } } { \msg_error:nnxxx { CVSS } { invalid-option } { parseCIA } {#1} {\msg_line_context:} } } \cs_new:Npn \__CVSS_calcISS:nnn #1#2#3 { % #1 Confidentiality Impact %High H, Low L, None N % #2 Integrity Impact %High H, Low L, None N % #3 Availability Impact %High H, Low L, None N 1 - ( (1 - (\__CVSS_parseCIA:n {#1})) * (1 - (\__CVSS_parseCIA:n {#2})) * (1 - (\__CVSS_parseCIA:n {#3})) ) } \cs_new:Npn \__CVSS_calcImpact:nn #1#2 { % #1 = Scope % #2 = ISS % Scope Unchanged 6.42 × ISS % Scope Changed 7.52 × [ISS-0.029] - 3.25 × [ISS-0.02]15 \str_case_e:nnF {#1} { { U } { \fp_eval:n { 6.42 * (#2) } } % Scope UNCHANGED { C } { \fp_eval:n { 7.52 * ( (#2) - 0.029 ) - 3.25 * ( (#2) - 0.02 )^15 } } % Scope CHANGED } { \msg_error:nnxxx { CVSS } { invalid-option } { calcISC } {#1} {\msg_line_context:} } }% \cs_new:Npn \__CVSS_calcExploitability:nnnnn #1#2#3#4#5 { % #1 Attack Vector % #2 Attack Complexity % #3 Privileges Required % #4 User Interaction % #5 Scope % 8.22 × AttackVector × AttackComplexity × PrivilegeRequired × UserInteraction 8.22 * (\__CVSS_parseAV:n {#1}) * (\__CVSS_parseAC:n {#2}) * (\__CVSS_parsePR:nn {#3}{#5}) * (\__CVSS_parseUI:n {#4})% } \cs_new:Npn \__CVSS_cvssBaseScore:nnnnnnnn #1#2#3#4#5#6#7#8 { % #1 Attack Vector %Network N, Adjacent A, Local L, Physical P % #2 Attack Complexity %Low L, High H % #3 Privileges Required %None N, Low L, High H % #4 User Interaction %None N, Required R % #5 Scope %Unchanged U, Changed C % #6 Confidentiality Impact %High H, Low L, None N % #7 Integrity Impact %High H, Low L, None N % #8 Availability Impact %High H, Low L, None N % \fp_compare:nTF { \exp_args:Ne \__CVSS_calcImpact:nn {#5}{\exp_args:Ne \__CVSS_calcISS:nnn {#6}{#7}{#8}} <= 0 } % IF ISC <=0 { % ISC <=0 0.0 }{ % ISC > 0 \str_case_e:nnF {#5} { { U } { % SCOPE UNCHANGED \fp_eval:n { \__CVSS_roundup:n { min( ((\__CVSS_calcImpact:nn {#5}{\__CVSS_calcISS:nnn {#6}{#7}{#8}}) + (\__CVSS_calcExploitability:nnnnn {#1}{#2}{#3}{#4}{#5})), 10) } }% } { C } { % SCOPE CHANGED \fp_eval:n { \__CVSS_roundup:n { min( (1.08 * ((\__CVSS_calcImpact:nn {#5}{\__CVSS_calcISS:nnn {#6}{#7}{#8}}) + (\__CVSS_calcExploitability:nnnnn {#1}{#2}{#3}{#4}{#5}))), 10) } }% } } { \msg_error:nnxxx { CVSS } { invalid-option } { parseScope } {#1} {\msg_line_context:} } }% } \NewExpandableDocumentCommand \cvssScore { m }{% % Check that there are 44 chars \int_compare:nNnTF { \str_count_ignore_spaces:n {#1} } = {44}{}{ \msg_error:nnxx{CVSS}{invalid-length}{#1}{\msg_line_context:} } % Check CVSS: value \str_if_eq:eeTF {\str_range:nnn {#1} {1} {5}} {CVSS:} {} { \msg_error:nnxxx{CVSS}{invalid-structure}{AV}{\str_range:nnn {#1} {1} {5}}{\msg_line_context:} } % Check 3.1 value \str_if_eq:eeTF {\str_range:nnn {#1} {6} {8}} {3.1} {} { \msg_error:nnxxx{CVSS}{wrong-version}{3.1}{\str_range:nnn {#1} {6} {8}}{\msg_line_context:} } % Check 3.1 value \str_if_eq:eeTF {\str_range:nnn {#1} {9} {9}} {/} {} { \msg_error:nnxxx{CVSS}{wrong-version}{/}{\str_range:nnn {#1} {9} {9}}{\msg_line_context:} } % Check AV value \str_if_eq:eeTF {\str_range:nnn {#1} {10} {12}} {AV:} {} { \msg_error:nnxxx{CVSS}{invalid-structure}{AV}{\str_range:nnn {#1} {10} {12}}{\msg_line_context:} } % Check AC value \str_if_eq:eeTF {\str_range:nnn {#1} {14} {17}} {/AC:} {} { \msg_error:nnxxx{CVSS}{invalid-structure}{AC}{\str_range:nnn {#1} {14} {17}}{\msg_line_context:} } % Check PR value \str_if_eq:eeTF {\str_range:nnn {#1} {19} {22}} {/PR:} {} { \msg_error:nnxxx{CVSS}{invalid-structure}{PR}{\str_range:nnn {#1} {19} {22}}{\msg_line_context:} } % Check UI value \str_if_eq:eeTF {\str_range:nnn {#1} {24} {27}} {/UI:} {} { \msg_error:nnxxx{CVSS}{invalid-structure}{UI}{\str_range:nnn {#1} {24} {27}}{\msg_line_context:} } % Check S value \str_if_eq:eeTF {\str_range:nnn {#1} {29} {31}} {/S:} {} { \msg_error:nnxxx{CVSS}{invalid-structure}{S}{\str_range:nnn {#1} {29} {31}}{\msg_line_context:} } % Check I value \str_if_eq:eeTF {\str_range:nnn {#1} {33} {35}} {/C:} {} { \msg_error:nnxxx{CVSS}{invalid-structure}{C}{\str_range:nnn {#1} {33} {35}}{\msg_line_context:} } % Check I value \str_if_eq:eeTF {\str_range:nnn {#1} {37} {39}} {/I:} {} { \msg_error:nnxxx{CVSS}{invalid-structure}{I}{\str_range:nnn {#1} {37} {39}}{\msg_line_context:} } % Check A value \str_if_eq:eeTF {\str_range:nnn {#1} {41} {43}} {/A:} {} { \msg_error:nnxxx{CVSS}{invalid-structure}{A}{\str_range:nnn {#1} {41} {43}}{\msg_line_context:} } \exp_args:Ne \__CVSS_cvssBaseScore:nnnnnnnn { \str_use:N \str_item_ignore_spaces:nn { #1 }{ 13 } } { \str_use:N \str_item_ignore_spaces:nn { #1 }{ 18 } } { \str_use:N \str_item_ignore_spaces:nn { #1 }{ 23 } } { \str_use:N \str_item_ignore_spaces:nn { #1 }{ 28 } } { \str_use:N \str_item_ignore_spaces:nn { #1 }{ 32 } } { \str_use:N \str_item_ignore_spaces:nn { #1 }{ 36 } } { \str_use:N \str_item_ignore_spaces:nn { #1 }{ 40 } } { \str_use:N \str_item_ignore_spaces:nn { #1 }{ 44 } } }% \ExplSyntaxOff \ExplSyntaxOn \NewExpandableDocumentCommand \category { m }{% \fp_compare:nNnTF {#1}<{\scoreLow}{None} { \fp_compare:nNnTF{#1}<{\scoreMed}{Low} { \fp_compare:nNnTF{#1}<{\scoreHigh}{Medium} { \fp_compare:nNnTF{#1}<{\scoreCrit}{High} {Critical} }% }% }% }% \ExplSyntaxOff \newcommand{\cvssScorepretty}[1]{% \def\CVSScategory{\category{\cvssScore{#1}}}% \textcolor{color@cvss@\CVSScategory}{\cvssScore{#1}}% }% \newcommand{\cvssLevel}[1]{% \def\CVSSscore{\cvssScore{#1}}% \category{\CVSSscore}% }% \newcommand{\cvssLevelpretty}[1]{% \def\CVSScategory{\category{\cvssScore{#1}}}% \textcolor{color@cvss@\CVSScategory}{\CVSScategory}% }% \DeclareTotalTCBox{\cvssFrame}{m}{ enhanced,nobeforeafter, tcbox raise base, boxrule=0.4pt, top=0mm,bottom=0mm,right=1mm,left=1mm, arc=1pt, boxsep=2pt, colframe=color@cvss@#1, colback=tcbcolframe, coltext=black, }{#1}% \MakeRobust\cvssFrame \newcommand{\cvssTag}[1]{% \def\CVSSscore{\cvssScore{#1}}% \cvssFrame{\category{\CVSSscore}}% }% \newcommand{\cvssPrint}[1]{% \def\CVSSscore{\cvssScore{#1}} \cvssFrame{\category{\CVSSscore}} \quad \CVSSscore \quad% \href{https://www.first.org/cvss/calculator/3.1\##1}{#1} }% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% Copyright (C) 2022 by Pierre VIVEGNIS %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License (LPPL), either %% version 1.3c of this license or (at your option) any later %% version. The latest version of this license is in the file: %% %% http://www.latex-project.org/lppl.txt %% %% This work is "maintained" (as per LPPL maintenance status) by %% Pierre VIVEGNIS. %% %% This work consists of the file cvss.dtx %% and the derived files cvss.ins, %% cvss.pdf and %% cvss.sty. %% %% %% End of file `cvss.sty'.