Merge pull request #12852 from egregius313/egregius313/java/webgoat/model-jwsheader

Java: Model `io.jsonwebtoken.SigningKeyResolverAdapter` and `io.jsonwebtoken.JwsHeader`
This commit is contained in:
Edward Minnix III
2023-05-08 10:57:34 -04:00
committed by GitHub
9 changed files with 156 additions and 1 deletions

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Added models for the `io.jsonwebtoken` library.

View File

@@ -0,0 +1,15 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: summaryModel
data:
- ["io.jsonwebtoken", "JwsHeader", True, "getAlgorithm", "", "", "Argument[this].SyntheticField[io.jsonwebtoken.JwsHeader.algorithm]", "ReturnValue", "taint", "manual"]
- ["io.jsonwebtoken", "JwsHeader", True, "setAlgorithm", "", "", "Argument[0]", "Argument[this].SyntheticField[io.jsonwebtoken.JwsHeader.algorithm]", "taint", "manual"]
- ["io.jsonwebtoken", "JwsHeader", True, "getKeyId", "", "", "Argument[this].SyntheticField[io.jsonwebtoken.JwsHeader.keyId]", "ReturnValue", "taint", "manual"]
- ["io.jsonwebtoken", "JwsHeader", True, "setKeyId", "", "", "Argument[0]", "Argument[this].SyntheticField[io.jsonwebtoken.JwsHeader.keyId]", "taint", "manual"]
- addsTo:
pack: codeql/java-all
extensible: sourceModel
data:
- ["io.jsonwebtoken", "SigningKeyResolver", True, "resolveSigningKey", "", "", "Parameter[0]", "remote", "manual"]
- ["io.jsonwebtoken", "SigningKeyResolverAdapter", True, "resolveSigningKeyBytes", "", "", "Parameter[0]", "remote", "manual"]

View File

@@ -18,6 +18,7 @@ private module Frameworks {
private import semmle.code.java.frameworks.ApacheHttp
private import semmle.code.java.frameworks.guava.Guava
private import semmle.code.java.frameworks.Guice
private import semmle.code.java.frameworks.IoJsonWebToken
private import semmle.code.java.frameworks.jackson.JacksonSerializability
private import semmle.code.java.frameworks.Properties
private import semmle.code.java.frameworks.Protobuf

View File

@@ -0,0 +1,11 @@
/** Predicates and classes to reason about the `io.jsonwebtoken` library. */
import java
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.FlowSteps
private class JwsHeaderFieldsInheritTaint extends DataFlow::SyntheticFieldContent,
TaintInheritingContent
{
JwsHeaderFieldsInheritTaint() { this.getField().matches("io.jsonwebtoken.JwsHeader.%") }
}

View File

@@ -0,0 +1,34 @@
import java.security.Key;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.SigningKeyResolverAdapter;
public class JwsSigningKeyResolverAdapter extends SigningKeyResolverAdapter {
private void sink(Object o) {
}
@Override
public Key resolveSigningKey(JwsHeader header, Claims claims) {
final String keyId = header.getKeyId();
String example = "example:" + keyId;
sink(example); // $ hasRemoteTaintFlow
return null;
}
@Override
public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
final String keyId = header.getKeyId();
String example = "example:" + keyId;
sink(example); // $ hasRemoteTaintFlow
final String algorithm = header.getAlgorithm();
sink("algo:" + algorithm); // $ hasRemoteTaintFlow
final String random = (String)header.get("random");
sink("random:" + random) ; // $ hasRemoteTaintFlow
return new byte[0];
}
}

View File

@@ -1 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/akka-2.6.x
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/akka-2.6.x:${testdir}/../../../stubs/jwtk-jjwt-0.11.2

View File

@@ -22,5 +22,11 @@ package io.jsonwebtoken;
* @since 0.1
*/
public interface JwsHeader<T extends JwsHeader<T>> extends Header<T> {
String getAlgorithm();
void setAlgorithm(String algorithm);
String getKeyId();
void setKeyId(String keyId);
}

View File

@@ -48,5 +48,7 @@ import java.security.Key;
* @since 0.4
*/
public interface SigningKeyResolver {
public Key resolveSigningKey(JwsHeader header, Claims claims);
public Key resolveSigningKey(JwsHeader header, String plaintext);
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2014 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken;
import java.security.Key;
import io.jsonwebtoken.SigningKeyResolver;
import io.jsonwebtoken.JwsHeader;
/**
* An <a href="http://en.wikipedia.org/wiki/Adapter_pattern">Adapter</a> implementation of the
* {@link SigningKeyResolver} interface that allows subclasses to process only the type of JWS body that
* is known/expected for a particular case.
*
* <p>The {@link #resolveSigningKey(JwsHeader, Claims)} and {@link #resolveSigningKey(JwsHeader, String)} method
* implementations delegate to the
* {@link #resolveSigningKeyBytes(JwsHeader, Claims)} and {@link #resolveSigningKeyBytes(JwsHeader, String)} methods
* respectively. The latter two methods simply throw exceptions: they represent scenarios expected by
* calling code in known situations, and it is expected that you override the implementation in those known situations;
* non-overridden *KeyBytes methods indicates that the JWS input was unexpected.</p>
*
* <p>If either {@link #resolveSigningKey(JwsHeader, String)} or {@link #resolveSigningKey(JwsHeader, Claims)}
* are not overridden, one (or both) of the *KeyBytes variants must be overridden depending on your expected
* use case. You do not have to override any method that does not represent an expected condition.</p>
*
* @since 0.4
*/
public class SigningKeyResolverAdapter implements SigningKeyResolver {
@Override
public Key resolveSigningKey(JwsHeader header, Claims claims) {
return null;
}
@Override
public Key resolveSigningKey(JwsHeader header, String plaintext) {
return null;
}
/**
* Convenience method invoked by {@link #resolveSigningKey(JwsHeader, Claims)} that obtains the necessary signing
* key bytes. This implementation simply throws an exception: if the JWS parsed is a Claims JWS, you must
* override this method or the {@link #resolveSigningKey(JwsHeader, Claims)} method instead.
*
* <p><b>NOTE:</b> You cannot override this method when validating RSA signatures. If you expect RSA signatures,
* you must override the {@link #resolveSigningKey(JwsHeader, Claims)} method instead.</p>
*
* @param header the parsed {@link JwsHeader}
* @param claims the parsed {@link Claims}
* @return the signing key bytes to use to verify the JWS signature.
*/
public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
return new byte[0];
}
/**
* Convenience method invoked by {@link #resolveSigningKey(JwsHeader, String)} that obtains the necessary signing
* key bytes. This implementation simply throws an exception: if the JWS parsed is a plaintext JWS, you must
* override this method or the {@link #resolveSigningKey(JwsHeader, String)} method instead.
*
* @param header the parsed {@link JwsHeader}
* @param payload the parsed String plaintext payload
* @return the signing key bytes to use to verify the JWS signature.
*/
public byte[] resolveSigningKeyBytes(JwsHeader header, String payload) {
return new byte[0];
}
}