@@ -107,7 +107,7 @@ module JCAModel {
107107 bindingset [ name]
108108 predicate key_agreement_names ( string name ) {
109109 name .toUpperCase ( )
110- .matches ( [ "DH" , "EDH" , "ECDH" , "X25519" , "X448" , "ML-KEM%" , "XDH" ] .toUpperCase ( ) )
110+ .matches ( [ "DH" , "EDH" , "ECDH" , "ECMQV" , " X25519", "X448" , "ML-KEM%" , "XDH" ] .toUpperCase ( ) )
111111 }
112112
113113 bindingset [ name]
@@ -265,6 +265,9 @@ module JCAModel {
265265 type = Crypto:: ECDH ( ) and
266266 name .toUpperCase ( ) in [ "ECDH" , "X25519" , "X448" , "XDH" ]
267267 or
268+ type = Crypto:: ECMQV ( ) and
269+ name .toUpperCase ( ) = "ECMQV"
270+ or
268271 type = Crypto:: OtherKeyAgreementType ( ) and
269272 name .toUpperCase ( ) .matches ( "ML-KEM%" )
270273 }
@@ -1876,7 +1879,16 @@ module JCAModel {
18761879
18771880 override Crypto:: ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm ( ) { none ( ) }
18781881
1879- override Crypto:: PaddingAlgorithmInstance getPaddingAlgorithm ( ) { none ( ) }
1882+ override Crypto:: PaddingAlgorithmInstance getPaddingAlgorithm ( ) {
1883+ result = this
1884+ }
1885+
1886+ override predicate shouldHaveModeOfOperation ( ) { none ( ) }
1887+
1888+ override predicate shouldHavePaddingScheme ( ) {
1889+ // Only RSA-based signatures have a meaningful padding concept (PSS or PKCS1v1.5)
1890+ signature_name_to_type_known ( KeyOpAlg:: TAsymmetricCipher ( KeyOpAlg:: RSA ( ) ) , super .getValue ( ) )
1891+ }
18801892 }
18811893
18821894 class SignatureHashAlgorithmInstance extends Crypto:: HashAlgorithmInstance instanceof SignatureStringLiteralAlgorithmInstance
@@ -1895,6 +1907,201 @@ module JCAModel {
18951907 override int getFixedDigestLength ( ) { result = digestLength }
18961908 }
18971909
1910+ /**
1911+ * Determines if a signature algorithm name implies PSS padding.
1912+ */
1913+ bindingset [ name]
1914+ private predicate signatureImpliesPss ( string name ) {
1915+ name .toUpperCase ( ) .matches ( "%RSASSA-PSS%" ) or
1916+ name .toUpperCase ( ) .matches ( "%WITHRSA%MGF1%" ) or
1917+ name .toUpperCase ( ) .matches ( "%WITHRSA/PSS%" )
1918+ }
1919+
1920+ /**
1921+ * Base class for PSS padding derived from signature algorithm names.
1922+ * Provides getPaddingType() on PaddingAlgorithmInstance to break the non-monotonic
1923+ * recursion that would occur if the derived PssPaddingAlgorithmInstance class
1924+ * defined getPaddingType() itself (since PssPaddingAlgorithmInstance's charpred
1925+ * calls getPaddingType()).
1926+ * Follows the same two-class pattern used for OAEP:
1927+ * CipherStringLiteralPaddingAlgorithmInstance → OaepPaddingAlgorithmInstance.
1928+ */
1929+ private class SignaturePssPaddingBase extends SignatureStringLiteralAlgorithmInstance ,
1930+ Crypto:: PaddingAlgorithmInstance instanceof SignatureStringLiteral
1931+ {
1932+ SignaturePssPaddingBase ( ) { signatureImpliesPss ( super .getValue ( ) ) }
1933+
1934+ override string getRawPaddingAlgorithmName ( ) { result = "PSS" }
1935+
1936+ override KeyOpAlg:: PaddingSchemeType getPaddingType ( ) { result instanceof KeyOpAlg:: PSS }
1937+ }
1938+
1939+ /**
1940+ * A PSS padding algorithm instance derived from a signature algorithm literal.
1941+ * Extends PssPaddingAlgorithmInstance (whose charpred evaluates through
1942+ * SignaturePssPaddingBase.getPaddingType()) to produce MD and MGF1Hash edges.
1943+ *
1944+ * For name-implied PSS (e.g., "SHA256withRSAandMGF1"), the same literal element
1945+ * is also a SignatureHashAlgorithmInstance, so `result = this` yields the hash.
1946+ * For bare "RSASSA-PSS", `result = this` has no result (this is not a
1947+ * HashAlgorithmInstance), so the graph falls back to self-referencing (unknown).
1948+ * When a PSSParameterSpec is connected via setParameter(), the explicit hash
1949+ * from the spec is used instead.
1950+ */
1951+ class SignaturePssPaddingAlgorithmInstance extends Crypto:: PssPaddingAlgorithmInstance ,
1952+ SignaturePssPaddingBase instanceof SignatureStringLiteral
1953+ {
1954+ override Crypto:: HashAlgorithmInstance getHashAlgorithm ( ) {
1955+ // Name-implied hash (e.g., SHA256withRSAandMGF1 → SHA-256)
1956+ result = this
1957+ or
1958+ // Explicit PSS hash from PSSParameterSpec via Signature.setParameter()
1959+ exists ( PSSParameterSpecInstantiation spec |
1960+ pssSpecForSignatureLiteral ( spec , this ) and
1961+ result .( PSSParameterSpecDigestHashAlgorithmInstance ) .getSpec ( ) = spec
1962+ )
1963+ }
1964+
1965+ override Crypto:: HashAlgorithmInstance getMgf1HashAlgorithm ( ) {
1966+ // Name-implied MGF1 hash (defaults to same hash as digest)
1967+ result = this
1968+ or
1969+ // Explicit MGF1 hash from PSSParameterSpec via Signature.setParameter()
1970+ exists ( PSSParameterSpecInstantiation spec |
1971+ pssSpecForSignatureLiteral ( spec , this ) and
1972+ result .( PSSParameterSpecMgf1HashAlgorithmInstance ) .getSpec ( ) = spec
1973+ )
1974+ }
1975+ }
1976+
1977+ /**
1978+ * A PSSParameterSpec instantiation, e.g.,
1979+ * new PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 32, 1)
1980+ */
1981+ class PSSParameterSpecInstantiation extends ClassInstanceExpr {
1982+ PSSParameterSpecInstantiation ( ) {
1983+ this .getConstructedType ( ) .hasQualifiedName ( "java.security.spec" , "PSSParameterSpec" )
1984+ }
1985+
1986+ /** Gets the digest algorithm name argument (arg 0). */
1987+ Expr getDigestAlgorithmArg ( ) {
1988+ result = this .getArgument ( 0 )
1989+ }
1990+
1991+ /** Gets the MGF algorithm name argument (arg 1). */
1992+ Expr getMgfAlgorithmArg ( ) {
1993+ result = this .getArgument ( 1 )
1994+ }
1995+
1996+ /** Gets the salt length argument (arg 3). */
1997+ Expr getSaltLengthArg ( ) {
1998+ result = this .getArgument ( 3 )
1999+ }
2000+
2001+ /** Gets the MGF parameter spec argument (arg 2), e.g., MGF1ParameterSpec.SHA256. */
2002+ Expr getMgfSpecArg ( ) {
2003+ result = this .getArgument ( 2 )
2004+ }
2005+ }
2006+
2007+ /**
2008+ * A static field access on `java.security.spec.MGF1ParameterSpec`, e.g.,
2009+ * `MGF1ParameterSpec.SHA256`. These fields represent well-known MGF1 hash
2010+ * algorithm configurations.
2011+ */
2012+ class MGF1ParameterSpecFieldAccess extends FieldAccess {
2013+ MGF1ParameterSpecFieldAccess ( ) {
2014+ this .getField ( )
2015+ .getDeclaringType ( )
2016+ .hasQualifiedName ( "java.security.spec" , "MGF1ParameterSpec" ) and
2017+ this .getField ( ) .isStatic ( )
2018+ }
2019+
2020+ /** Gets the hash algorithm name corresponding to this MGF1 field. */
2021+ string getHashAlgorithmName ( ) {
2022+ this .getField ( ) .getName ( ) = "SHA1" and result = "SHA-1"
2023+ or
2024+ this .getField ( ) .getName ( ) = "SHA224" and result = "SHA-224"
2025+ or
2026+ this .getField ( ) .getName ( ) = "SHA256" and result = "SHA-256"
2027+ or
2028+ this .getField ( ) .getName ( ) = "SHA384" and result = "SHA-384"
2029+ or
2030+ this .getField ( ) .getName ( ) = "SHA512" and result = "SHA-512"
2031+ or
2032+ this .getField ( ) .getName ( ) = "SHA512_224" and result = "SHA-512/224"
2033+ or
2034+ this .getField ( ) .getName ( ) = "SHA512_256" and result = "SHA-512/256"
2035+ }
2036+ }
2037+
2038+ /**
2039+ * A hash algorithm instance for the digest algorithm argument (arg 0) of a
2040+ * PSSParameterSpec instantiation, e.g., "SHA-256" in:
2041+ * new PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 32, 1)
2042+ *
2043+ * Type resolution delegates to hash_name_to_type_known from Standardization.
2044+ */
2045+ class PSSParameterSpecDigestHashAlgorithmInstance extends Crypto:: HashAlgorithmInstance
2046+ instanceof JavaConstant
2047+ {
2048+ PSSParameterSpecInstantiation spec ;
2049+
2050+ PSSParameterSpecDigestHashAlgorithmInstance ( ) {
2051+ this = spec .getDigestAlgorithmArg ( ) and
2052+ // Only instantiate when the value resolves to a known hash type
2053+ exists ( hash_name_to_type_known ( super .getValue ( ) , _) )
2054+ }
2055+
2056+ /** Gets the PSSParameterSpec this digest hash belongs to. */
2057+ PSSParameterSpecInstantiation getSpec ( ) { result = spec }
2058+
2059+ override string getRawHashAlgorithmName ( ) { result = super .getValue ( ) }
2060+
2061+ override Crypto:: THashType getHashType ( ) {
2062+ result = hash_name_to_type_known ( super .getValue ( ) , _)
2063+ }
2064+
2065+ override int getFixedDigestLength ( ) {
2066+ exists ( hash_name_to_type_known ( super .getValue ( ) , result ) )
2067+ }
2068+ }
2069+
2070+ /**
2071+ * A hash algorithm instance for the MGF1 parameter spec argument (arg 2) of a
2072+ * PSSParameterSpec instantiation, e.g., MGF1ParameterSpec.SHA256 in:
2073+ * new PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 32, 1)
2074+ *
2075+ * The field name is normalized to a standard hash algorithm name (e.g.,
2076+ * SHA256 -> SHA-256), then type resolution delegates to hash_name_to_type_known.
2077+ */
2078+ class PSSParameterSpecMgf1HashAlgorithmInstance extends Crypto:: HashAlgorithmInstance
2079+ instanceof MGF1ParameterSpecFieldAccess
2080+ {
2081+ PSSParameterSpecInstantiation spec ;
2082+ string normalizedName ;
2083+
2084+ PSSParameterSpecMgf1HashAlgorithmInstance ( ) {
2085+ this = spec .getMgfSpecArg ( ) and
2086+ normalizedName = super .getHashAlgorithmName ( ) and
2087+ // Only instantiate when the normalized name resolves to a known hash type
2088+ exists ( hash_name_to_type_known ( normalizedName , _) )
2089+ }
2090+
2091+ /** Gets the PSSParameterSpec this MGF1 hash belongs to. */
2092+ PSSParameterSpecInstantiation getSpec ( ) { result = spec }
2093+
2094+ override string getRawHashAlgorithmName ( ) { result = super .getField ( ) .getName ( ) }
2095+
2096+ override Crypto:: THashType getHashType ( ) {
2097+ result = hash_name_to_type_known ( normalizedName , _)
2098+ }
2099+
2100+ override int getFixedDigestLength ( ) {
2101+ exists ( hash_name_to_type_known ( normalizedName , result ) )
2102+ }
2103+ }
2104+
18982105 class SignatureInitCall extends MethodCall {
18992106 SignatureInitCall ( ) {
19002107 this .getCallee ( ) .hasQualifiedName ( "java.security" , "Signature" , [ "initSign" , "initVerify" ] )
@@ -1906,6 +2113,21 @@ module JCAModel {
19062113 }
19072114 }
19082115
2116+ /**
2117+ * A call to `Signature.setParameter(AlgorithmParameterSpec)`, used to
2118+ * configure algorithm parameters such as PSSParameterSpec on a Signature instance.
2119+ */
2120+ class SignatureSetParameterCall extends MethodCall {
2121+ SignatureSetParameterCall ( ) {
2122+ this .getMethod ( )
2123+ .hasQualifiedName ( "java.security" , "Signature" , "setParameter" ) and
2124+ this .getMethod ( ) .getParameterType ( 0 ) .( RefType ) .hasQualifiedName ( "java.security.spec" , "AlgorithmParameterSpec" )
2125+ }
2126+
2127+ /** Gets the AlgorithmParameterSpec argument. */
2128+ Expr getParameterSpecArg ( ) { result = this .getArgument ( 0 ) }
2129+ }
2130+
19092131 class SignatureOperationCall extends MethodCall {
19102132 SignatureOperationCall ( ) {
19112133 this .getMethod ( ) .hasQualifiedName ( "java.security" , "Signature" , [ "update" , "sign" , "verify" ] )
@@ -1970,7 +2192,6 @@ module JCAModel {
19702192 }
19712193
19722194 override Crypto:: AlgorithmValueConsumer getHashAlgorithmValueConsumer ( ) {
1973- // TODO: RSASSA-PSS literal sets hashes differently, through a ParameterSpec
19742195 result = this .getInstantiationCall ( ) .getAlgorithmArg ( )
19752196 }
19762197
@@ -1997,6 +2218,61 @@ module JCAModel {
19972218 GetInstanceInitUseFlowAnalysis< SignatureGetInstanceCall , SignatureInitCall ,
19982219 SignatureOperationCall > ;
19992220
2221+ /**
2222+ * Flow from `Signature.getInstance()` return value to `Signature.setParameter()` qualifier.
2223+ * Used to connect a signature algorithm literal to its PSSParameterSpec configuration.
2224+ */
2225+ module SignatureToSetParameterConfig implements DataFlow:: ConfigSig {
2226+ predicate isSource ( DataFlow:: Node src ) { src .asExpr ( ) instanceof SignatureGetInstanceCall }
2227+
2228+ predicate isSink ( DataFlow:: Node sink ) {
2229+ exists ( SignatureSetParameterCall c | sink .asExpr ( ) = c .getQualifier ( ) )
2230+ }
2231+ }
2232+
2233+ module SignatureToSetParameterFlow = DataFlow:: Global< SignatureToSetParameterConfig > ;
2234+
2235+ /**
2236+ * Flow from `PSSParameterSpec` instantiation to `Signature.setParameter()` argument.
2237+ */
2238+ module PSSSpecToSetParameterConfig implements DataFlow:: ConfigSig {
2239+ predicate isSource ( DataFlow:: Node src ) {
2240+ src .asExpr ( ) instanceof PSSParameterSpecInstantiation
2241+ }
2242+
2243+ predicate isSink ( DataFlow:: Node sink ) {
2244+ exists ( SignatureSetParameterCall c | sink .asExpr ( ) = c .getParameterSpecArg ( ) )
2245+ }
2246+ }
2247+
2248+ module PSSSpecToSetParameterFlow = DataFlow:: Global< PSSSpecToSetParameterConfig > ;
2249+
2250+ /**
2251+ * Connects a PSSParameterSpec instantiation to the signature PSS padding literal
2252+ * for which it provides configuration, via `Signature.setParameter()`.
2253+ *
2254+ * The connection requires:
2255+ * 1. The padding literal flows (via its consumer) to a `Signature.getInstance()` call
2256+ * 2. That getInstance call flows to a `Signature.setParameter()` qualifier
2257+ * 3. The PSSParameterSpec flows to the same setParameter's argument
2258+ */
2259+ private predicate pssSpecForSignatureLiteral (
2260+ PSSParameterSpecInstantiation spec , SignaturePssPaddingAlgorithmInstance literal
2261+ ) {
2262+ exists (
2263+ SignatureSetParameterCall setParam ,
2264+ SignatureGetInstanceCall getInstance ,
2265+ SignatureGetInstanceAlgorithmValueConsumer consumer
2266+ |
2267+ consumer = literal .getConsumer ( ) and
2268+ consumer = getInstance .getAlgorithmArg ( ) and
2269+ SignatureToSetParameterFlow:: flow ( DataFlow:: exprNode ( getInstance ) ,
2270+ DataFlow:: exprNode ( setParam .getQualifier ( ) ) ) and
2271+ PSSSpecToSetParameterFlow:: flow ( DataFlow:: exprNode ( spec ) ,
2272+ DataFlow:: exprNode ( setParam .getParameterSpecArg ( ) ) )
2273+ )
2274+ }
2275+
20002276 /*
20012277 * Elliptic Curves (EC)
20022278 */
0 commit comments