%%
%% This is file `cvss.ins',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% cvss.dtx  (with options: `install')
%% ----------------------------------------------------------------
%% 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
%% ----------------------------------------------------------------
%% 
\input docstrip.tex
\keepsilent
\askforoverwritefalse
\preamble
----------------------------------------------------------------
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
----------------------------------------------------------------

\endpreamble
\postamble

Copyright (C) 2022 by Pierre VIVEGNIS <pierre@vivegnis.be>

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.

\endpostamble
\usedir{tex/latex/cvss}
\generate{
  \file{\jobname.sty}{\from{\jobname.dtx}{package}}
}
\endbatchfile
 %   \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 <pierre@vivegnis.be>
%% 
%% 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.ins'.
