Merge branch 'main' into redsun82/go-internal-tests

This commit is contained in:
Paolo Tranquilli
2025-06-30 17:38:59 +02:00
committed by GitHub
4305 changed files with 240105 additions and 119777 deletions

4
.github/copilot-instructions.md vendored Normal file
View File

@@ -0,0 +1,4 @@
When reviewing code:
* do not review changes in files with `.expected` extension (they are automatically ensured to be correct).
* in `.ql` and `.qll` files, do not try to review the code itself as you don't understand the programming language
well enough to make comments in these languages. You can still check for typos or comment improvements.

View File

@@ -16,7 +16,6 @@ on:
- "shared/**/*.qll" - "shared/**/*.qll"
- "!**/experimental/**" - "!**/experimental/**"
- "!ql/**" - "!ql/**"
- "!rust/**"
- ".github/workflows/check-change-note.yml" - ".github/workflows/check-change-note.yml"
jobs: jobs:

View File

@@ -0,0 +1,23 @@
name: Check overlay annotations
on:
push:
branches:
- main
- 'rc/*'
pull_request:
branches:
- main
- 'rc/*'
permissions:
contents: read
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check overlay annotations
run: python config/add-overlay-annotations.py --check java

View File

@@ -53,7 +53,7 @@ jobs:
- name: Create database - name: Create database
run: | run: |
"${CODEQL}" database create \ "${CODEQL}" database create \
--search-path "${{ github.workspace }}" --search-path "${{ github.workspace }}" \
--threads 4 \ --threads 4 \
--language ql --source-root "${{ github.workspace }}/repo" \ --language ql --source-root "${{ github.workspace }}/repo" \
"${{ runner.temp }}/database" "${{ runner.temp }}/database"

View File

@@ -9,7 +9,7 @@ repos:
- id: trailing-whitespace - id: trailing-whitespace
exclude: /test/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$ exclude: /test/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$
- id: end-of-file-fixer - id: end-of-file-fixer
exclude: /test/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$ exclude: Cargo.lock$|/test/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$
- repo: https://github.com/pre-commit/mirrors-clang-format - repo: https://github.com/pre-commit/mirrors-clang-format
rev: v17.0.6 rev: v17.0.6
@@ -20,7 +20,7 @@ repos:
rev: 25.1.0 rev: 25.1.0
hooks: hooks:
- id: black - id: black
files: ^(misc/codegen/.*|misc/scripts/models-as-data/bulk_generate_mad)\.py$ files: ^(misc/codegen/.*|misc/scripts/models-as-data/.*)\.py$
- repo: local - repo: local
hooks: hooks:

920
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,8 +11,3 @@ members = [
"rust/autobuild", "rust/autobuild",
] ]
exclude = ["mad-generation-build"] exclude = ["mad-generation-build"]
[patch.crates-io]
# patch for build script bug preventing bazel build
# see https://github.com/rust-lang/rustc_apfloat/pull/17
rustc_apfloat = { git = "https://github.com/redsun82/rustc_apfloat.git", rev = "32968f16ef1b082243f9bf43a3fbd65c381b3e27" }

View File

@@ -37,7 +37,7 @@ bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True
# the versions there are canonical, the versions here are used for CI in github/codeql, as well as for the vendoring of dependencies. # the versions there are canonical, the versions here are used for CI in github/codeql, as well as for the vendoring of dependencies.
RUST_EDITION = "2024" RUST_EDITION = "2024"
RUST_VERSION = "1.85.0" RUST_VERSION = "1.86.0"
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust") rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain( rust.toolchain(
@@ -71,11 +71,11 @@ use_repo(
tree_sitter_extractors_deps = use_extension("//misc/bazel/3rdparty:tree_sitter_extractors_extension.bzl", "r") tree_sitter_extractors_deps = use_extension("//misc/bazel/3rdparty:tree_sitter_extractors_extension.bzl", "r")
use_repo( use_repo(
tree_sitter_extractors_deps, tree_sitter_extractors_deps,
"vendor_ts__anyhow-1.0.97", "vendor_ts__anyhow-1.0.98",
"vendor_ts__argfile-0.2.1", "vendor_ts__argfile-0.2.1",
"vendor_ts__chalk-ir-0.100.0", "vendor_ts__chalk-ir-0.103.0",
"vendor_ts__chrono-0.4.40", "vendor_ts__chrono-0.4.41",
"vendor_ts__clap-4.5.35", "vendor_ts__clap-4.5.40",
"vendor_ts__dunce-1.0.5", "vendor_ts__dunce-1.0.5",
"vendor_ts__either-1.15.0", "vendor_ts__either-1.15.0",
"vendor_ts__encoding-0.2.33", "vendor_ts__encoding-0.2.33",
@@ -87,33 +87,33 @@ use_repo(
"vendor_ts__lazy_static-1.5.0", "vendor_ts__lazy_static-1.5.0",
"vendor_ts__mustache-0.9.0", "vendor_ts__mustache-0.9.0",
"vendor_ts__num-traits-0.2.19", "vendor_ts__num-traits-0.2.19",
"vendor_ts__num_cpus-1.16.0", "vendor_ts__num_cpus-1.17.0",
"vendor_ts__proc-macro2-1.0.94", "vendor_ts__proc-macro2-1.0.95",
"vendor_ts__quote-1.0.40", "vendor_ts__quote-1.0.40",
"vendor_ts__ra_ap_base_db-0.0.273", "vendor_ts__ra_ap_base_db-0.0.288",
"vendor_ts__ra_ap_cfg-0.0.273", "vendor_ts__ra_ap_cfg-0.0.288",
"vendor_ts__ra_ap_hir-0.0.273", "vendor_ts__ra_ap_hir-0.0.288",
"vendor_ts__ra_ap_hir_def-0.0.273", "vendor_ts__ra_ap_hir_def-0.0.288",
"vendor_ts__ra_ap_hir_expand-0.0.273", "vendor_ts__ra_ap_hir_expand-0.0.288",
"vendor_ts__ra_ap_hir_ty-0.0.273", "vendor_ts__ra_ap_hir_ty-0.0.288",
"vendor_ts__ra_ap_ide_db-0.0.273", "vendor_ts__ra_ap_ide_db-0.0.288",
"vendor_ts__ra_ap_intern-0.0.273", "vendor_ts__ra_ap_intern-0.0.288",
"vendor_ts__ra_ap_load-cargo-0.0.273", "vendor_ts__ra_ap_load-cargo-0.0.288",
"vendor_ts__ra_ap_parser-0.0.273", "vendor_ts__ra_ap_parser-0.0.288",
"vendor_ts__ra_ap_paths-0.0.273", "vendor_ts__ra_ap_paths-0.0.288",
"vendor_ts__ra_ap_project_model-0.0.273", "vendor_ts__ra_ap_project_model-0.0.288",
"vendor_ts__ra_ap_span-0.0.273", "vendor_ts__ra_ap_span-0.0.288",
"vendor_ts__ra_ap_stdx-0.0.273", "vendor_ts__ra_ap_stdx-0.0.288",
"vendor_ts__ra_ap_syntax-0.0.273", "vendor_ts__ra_ap_syntax-0.0.288",
"vendor_ts__ra_ap_vfs-0.0.273", "vendor_ts__ra_ap_vfs-0.0.288",
"vendor_ts__rand-0.9.0", "vendor_ts__rand-0.9.1",
"vendor_ts__rayon-1.10.0", "vendor_ts__rayon-1.10.0",
"vendor_ts__regex-1.11.1", "vendor_ts__regex-1.11.1",
"vendor_ts__serde-1.0.219", "vendor_ts__serde-1.0.219",
"vendor_ts__serde_json-1.0.140", "vendor_ts__serde_json-1.0.140",
"vendor_ts__serde_with-3.12.0", "vendor_ts__serde_with-3.13.0",
"vendor_ts__syn-2.0.100", "vendor_ts__syn-2.0.103",
"vendor_ts__toml-0.8.20", "vendor_ts__toml-0.8.23",
"vendor_ts__tracing-0.1.41", "vendor_ts__tracing-0.1.41",
"vendor_ts__tracing-flame-0.2.0", "vendor_ts__tracing-flame-0.2.0",
"vendor_ts__tracing-subscriber-0.3.19", "vendor_ts__tracing-subscriber-0.3.19",

View File

@@ -2,7 +2,7 @@ import runs_on
import pytest import pytest
from query_suites import * from query_suites import *
well_known_query_suites = ['actions-code-quality.qls', 'actions-security-and-quality.qls', 'actions-security-extended.qls', 'actions-code-scanning.qls'] well_known_query_suites = ['actions-code-quality.qls', 'actions-code-quality-extended.qls', 'actions-security-and-quality.qls', 'actions-security-extended.qls', 'actions-code-scanning.qls']
@runs_on.posix @runs_on.posix
@pytest.mark.parametrize("query_suite", well_known_query_suites) @pytest.mark.parametrize("query_suite", well_known_query_suites)

View File

@@ -1,3 +1,11 @@
## 0.4.12
### Minor Analysis Improvements
* Fixed performance issues in the parsing of Bash scripts in workflow files,
which led to out-of-disk errors when analysing certain workflow files with
complex interpolations of shell commands or quoted strings.
## 0.4.11 ## 0.4.11
No user-facing changes. No user-facing changes.

View File

@@ -1,6 +0,0 @@
---
category: minorAnalysis
---
* Fixed performance issues in the parsing of Bash scripts in workflow files,
which led to out-of-disk errors when analysing certain workflow files with
complex interpolations of shell commands or quoted strings.

View File

@@ -0,0 +1,7 @@
## 0.4.12
### Minor Analysis Improvements
* Fixed performance issues in the parsing of Bash scripts in workflow files,
which led to out-of-disk errors when analysing certain workflow files with
complex interpolations of shell commands or quoted strings.

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 0.4.11 lastReleaseVersion: 0.4.12

View File

@@ -214,6 +214,10 @@ private module OutputClobberingConfig implements DataFlow::ConfigSig {
) )
) )
} }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
} }
/** Tracks flow of unsafe user input that is used to construct and evaluate an environment variable. */ /** Tracks flow of unsafe user input that is used to construct and evaluate an environment variable. */

View File

@@ -16,6 +16,10 @@ private module RequestForgeryConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) { sink instanceof RequestForgerySink } predicate isSink(DataFlow::Node sink) { sink instanceof RequestForgerySink }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
} }
/** Tracks flow of unsafe user input that is used to construct and evaluate a system command. */ /** Tracks flow of unsafe user input that is used to construct and evaluate a system command. */

View File

@@ -15,6 +15,10 @@ private module SecretExfiltrationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) { sink instanceof SecretExfiltrationSink } predicate isSink(DataFlow::Node sink) { sink instanceof SecretExfiltrationSink }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
} }
/** Tracks flow of unsafe user input that is used in a context where it may lead to a secret exfiltration. */ /** Tracks flow of unsafe user input that is used in a context where it may lead to a secret exfiltration. */

View File

@@ -1,5 +1,5 @@
name: codeql/actions-all name: codeql/actions-all
version: 0.4.12-dev version: 0.4.13-dev
library: true library: true
warnOnImplicitThis: true warnOnImplicitThis: true
dependencies: dependencies:

View File

@@ -1,3 +1,7 @@
## 0.6.4
No user-facing changes.
## 0.6.3 ## 0.6.3
No user-facing changes. No user-facing changes.

View File

@@ -24,6 +24,10 @@ private module MyConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { predicate isSink(DataFlow::Node sink) {
sink instanceof CodeInjectionSink and not madSink(sink, "code-injection") sink instanceof CodeInjectionSink and not madSink(sink, "code-injection")
} }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
} }
module MyFlow = TaintTracking::Global<MyConfig>; module MyFlow = TaintTracking::Global<MyConfig>;

View File

@@ -34,6 +34,10 @@ private module MyConfig implements DataFlow::ConfigSig {
isSink(node) and isSink(node) and
set instanceof DataFlow::FieldContent set instanceof DataFlow::FieldContent
} }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
} }
module MyFlow = TaintTracking::Global<MyConfig>; module MyFlow = TaintTracking::Global<MyConfig>;

View File

@@ -25,6 +25,10 @@ private module MyConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { predicate isSink(DataFlow::Node sink) {
exists(CompositeAction c | c.getAnOutputExpr() = sink.asExpr()) exists(CompositeAction c | c.getAnOutputExpr() = sink.asExpr())
} }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
} }
module MyFlow = TaintTracking::Global<MyConfig>; module MyFlow = TaintTracking::Global<MyConfig>;

View File

@@ -24,6 +24,10 @@ private module MyConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { predicate isSink(DataFlow::Node sink) {
sink instanceof CodeInjectionSink and not madSink(sink, "code-injection") sink instanceof CodeInjectionSink and not madSink(sink, "code-injection")
} }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
} }
module MyFlow = TaintTracking::Global<MyConfig>; module MyFlow = TaintTracking::Global<MyConfig>;

View File

@@ -34,6 +34,10 @@ private module MyConfig implements DataFlow::ConfigSig {
isSink(node) and isSink(node) and
set instanceof DataFlow::FieldContent set instanceof DataFlow::FieldContent
} }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
} }
module MyFlow = TaintTracking::Global<MyConfig>; module MyFlow = TaintTracking::Global<MyConfig>;

View File

@@ -25,6 +25,10 @@ private module MyConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { predicate isSink(DataFlow::Node sink) {
exists(ReusableWorkflow w | w.getAnOutputExpr() = sink.asExpr()) exists(ReusableWorkflow w | w.getAnOutputExpr() = sink.asExpr())
} }
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
} }
module MyFlow = TaintTracking::Global<MyConfig>; module MyFlow = TaintTracking::Global<MyConfig>;

View File

@@ -0,0 +1,3 @@
## 0.6.4
No user-facing changes.

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 0.6.3 lastReleaseVersion: 0.6.4

View File

@@ -0,0 +1,3 @@
- queries: .
- apply: code-quality-extended-selectors.yml
from: codeql/suite-helpers

View File

@@ -1,5 +1,5 @@
name: codeql/actions-queries name: codeql/actions-queries
version: 0.6.4-dev version: 0.6.5-dev
library: false library: false
warnOnImplicitThis: true warnOnImplicitThis: true
groups: [actions, queries] groups: [actions, queries]

View File

@@ -0,0 +1,274 @@
# This script is used to annotate .qll files without any existing overlay annotations
# with overlay[local?] and overlay[caller?] annotations. Maintenance of overlay annotations
# in annotated files will be handled by QL-for-QL queries.
# It will walk the directory tree and annotate most .qll files, skipping only
# some specific cases (e.g., empty files, files that configure dataflow for queries).
# The script takes a list of languages and processes the corresponding directories.
# If the optional --check argument is provided, the script checks for missing annotations,
# but does not modify any files.
# Usage: python3 add-overlay-annotations.py [--check] <language1> <language2> ...
# The script will modify the files in place and print the changes made.
# The script is designed to be run from the root of the repository.
#!/usr/bin/python3
import sys
import os
import re
from difflib import context_diff
OVERLAY_PATTERN = re.compile(r'overlay\[[a-zA-Z?_-]+\]')
def has_overlay_annotations(lines):
'''
Check whether the given lines contain any overlay[...] annotations.
'''
return any(OVERLAY_PATTERN.search(line) for line in lines)
def is_line_comment(line):
return line.startswith("//") or (line.startswith("/*") and line.endswith("*/"))
def find_file_level_module_declaration(lines):
'''
Returns the index of the existing file-level module declaration if one
exists. Returns None otherwise.
'''
comment = False
for i, line in enumerate(lines):
trimmed = line.strip()
if is_line_comment(trimmed):
continue
elif trimmed.startswith("/*"):
comment = True
elif comment and trimmed.endswith("*/"):
comment = False
elif not comment and trimmed.endswith("module;"):
return i
return None
def is_file_module_qldoc(i, lines):
'''
Assuming a qldoc ended on line i, determine if it belongs to the implicit
file-level module. If it is followed by another qldoc or imports, then it
does and if it is followed by any other non-empty, non-comment lines, then
we assume that is a declaration of some kind and the qldoc is attached to
that declaration.
'''
comment = False
for line in lines[i+1:]:
trimmed = line.strip()
if trimmed.startswith("import ") or trimmed.startswith("private import ") or trimmed.startswith("/**"):
return True
elif is_line_comment(trimmed) or not trimmed:
continue
elif trimmed.startswith("/*"):
comment = True
elif comment and trimmed.endswith("*/"):
comment = False
elif not comment and trimmed:
return False
return True
def find_file_module_qldoc_declaration(lines):
'''
Returns the index of last line of the implicit file module qldoc if one
exists. Returns None otherwise.
'''
qldoc = False
comment = False
for i, line in enumerate(lines):
trimmed = line.strip()
if trimmed.startswith("//"):
continue
elif (qldoc or trimmed.startswith("/**")) and trimmed.endswith("*/"):
# a qldoc just ended; determine if it belongs to the implicit file module
if is_file_module_qldoc(i, lines):
return i
else:
return None
elif trimmed.startswith("/**"):
qldoc = True
elif trimmed.startswith("/*"):
comment = True
elif comment and trimmed.endswith("*/"):
comment = False
elif (not qldoc and not comment) and trimmed:
return None
return None
def only_comments(lines):
'''
Returns true if the lines contain only comments and empty lines.
'''
comment = False
for line in lines:
trimmed = line.strip()
if not trimmed or is_line_comment(trimmed):
continue
elif trimmed.startswith("/*"):
comment = True
elif comment and trimmed.endswith("*/"):
comment = False
elif comment:
continue
elif trimmed:
return False
return True
def insert_toplevel_maybe_local_annotation(filename, lines):
'''
Find a suitable place to insert an overlay[local?] annotation at the top of the file.
Returns a pair consisting of description and the modified lines or None if no overlay
annotation is necessary (e.g., for files that only contain comments).
'''
if only_comments(lines):
return None
i = find_file_level_module_declaration(lines)
if not i == None:
out_lines = lines[:i]
out_lines.append("overlay[local?]\n")
out_lines.extend(lines[i:])
return (f"Annotating \"{filename}\" via existing file-level module statement", out_lines)
i = find_file_module_qldoc_declaration(lines)
if not i == None:
out_lines = lines[:i+1]
out_lines.append("overlay[local?]\n")
out_lines.append("module;\n")
out_lines.extend(lines[i+1:])
return (f"Annotating \"{filename}\" which has a file-level module qldoc", out_lines)
out_lines = ["overlay[local?]\n", "module;\n", "\n"] + lines
return (f"Annotating \"{filename}\" without file-level module qldoc", out_lines)
def insert_overlay_caller_annotations(lines):
'''
Mark pragma[inline] predicates as overlay[caller?] if they are not declared private.
'''
out_lines = []
for i, line in enumerate(lines):
trimmed = line.strip()
if trimmed == "pragma[inline]":
if i + 1 < len(lines) and not "private" in lines[i+1]:
whitespace = line[0: line.find(trimmed)]
out_lines.append(f"{whitespace}overlay[caller?]\n")
out_lines.append(line)
return out_lines
def annotate_as_appropriate(filename, lines):
'''
Insert new overlay[...] annotations according to heuristics in files without existing
overlay annotations.
Returns None if no annotations are needed. Otherwise, returns a pair consisting of a
string describing the action taken and the modified content as a list of lines.
'''
if has_overlay_annotations(lines):
return None
# These simple heuristics filter out those .qll files that we no _not_ want to annotate
# as overlay[local?]. It is not clear that these heuristics are exactly what we want,
# but they seem to work well enough for now (as determined by speed and accuracy numbers).
if (filename.endswith("Test.qll") or
((filename.endswith("Query.qll") or filename.endswith("Config.qll")) and
any("implements DataFlow::ConfigSig" in line for line in lines))):
return None
elif not any(line for line in lines if line.strip()):
return None
lines = insert_overlay_caller_annotations(lines)
return insert_toplevel_maybe_local_annotation(filename, lines)
def process_single_file(write, filename):
'''
Process a single file, annotating it as appropriate.
If write is set, the changes are written back to the file.
Returns True if the file requires changes.
'''
with open(filename) as f:
old = [line for line in f]
annotate_result = annotate_as_appropriate(filename, old)
if annotate_result is None:
return False
if not write:
return True
new = annotate_result[1]
diff = context_diff(old, new, fromfile=filename, tofile=filename)
diff = [line for line in diff]
if diff:
print(annotate_result[0])
for line in diff:
print(line.rstrip())
with open(filename, "w") as out_file:
for line in new:
out_file.write(line)
return True
if len(sys.argv) > 1 and sys.argv[1] == "--check":
check = True
langs = sys.argv[2:]
else:
check = False
langs = sys.argv[1:]
dirs = []
for lang in langs:
if lang in ["cpp", "go", "csharp", "java", "javascript", "python", "ruby", "rust", "swift"]:
dirs.append(f"{lang}/ql/lib")
else:
raise Exception(f"Unknown language \"{lang}\".")
if dirs:
dirs.append("shared")
missingAnnotations = []
for roots in dirs:
for dirpath, dirnames, filenames in os.walk(roots):
for filename in filenames:
if filename.endswith(".qll") and not dirpath.endswith("tutorial"):
path = os.path.join(dirpath, filename)
res = process_single_file(not check, path)
if check and res:
missingAnnotations.append(path)
if len(missingAnnotations) > 0:
print("The following files have no overlay annotations:")
for path in missingAnnotations[:10]:
print("- " + path)
if len(missingAnnotations) > 10:
print("and " + str(len(missingAnnotations) - 10) + " additional files.")
print()
print("Please manually add overlay annotations or use the config/add-overlay-annotations.py script to automatically add sensible default overlay annotations.")
exit(1)

View File

@@ -11,6 +11,7 @@
"/*- Diagnostic messages -*/", "/*- Diagnostic messages -*/",
"/*- Diagnostic messages: severity -*/", "/*- Diagnostic messages: severity -*/",
"/*- Source location prefix -*/", "/*- Source location prefix -*/",
"/*- Database metadata -*/",
"/*- Lines of code -*/", "/*- Lines of code -*/",
"/*- Configuration files with key value pairs -*/", "/*- Configuration files with key value pairs -*/",
"/*- YAML -*/", "/*- YAML -*/",
@@ -31,4 +32,4 @@
"/*- Python dbscheme -*/", "/*- Python dbscheme -*/",
"/*- Empty location -*/" "/*- Empty location -*/"
] ]
} }

View File

@@ -8,9 +8,9 @@ needs_an_re = re.compile(r'^(?!Unary)[AEIOU]') # Name requiring "an" instead of
start_qldoc_re = re.compile(r'^\s*/\*\*') # Start of a QLDoc comment start_qldoc_re = re.compile(r'^\s*/\*\*') # Start of a QLDoc comment
end_qldoc_re = re.compile(r'\*/\s*$') # End of a QLDoc comment end_qldoc_re = re.compile(r'\*/\s*$') # End of a QLDoc comment
blank_qldoc_line_re = re.compile(r'^\s*\*\s*$') # A line in a QLDoc comment with only the '*' blank_qldoc_line_re = re.compile(r'^\s*\*\s*$') # A line in a QLDoc comment with only the '*'
instruction_class_re = re.compile(r'^class (?P<name>[A-aa-z0-9]+)Instruction\s') # Declaration of an `Instruction` class instruction_class_re = re.compile(r'^class (?P<name>[A-Za-z0-9]+)Instruction\s') # Declaration of an `Instruction` class
opcode_base_class_re = re.compile(r'^abstract class (?P<name>[A-aa-z0-9]+)Opcode\s') # Declaration of an `Opcode` base class opcode_base_class_re = re.compile(r'^abstract class (?P<name>[A-Za-z0-9]+)Opcode\s') # Declaration of an `Opcode` base class
opcode_class_re = re.compile(r'^ class (?P<name>[A-aa-z0-9]+)\s') # Declaration of an `Opcode` class opcode_class_re = re.compile(r'^ class (?P<name>[A-Za-z0-9]+)\s') # Declaration of an `Opcode` class
script_dir = path.realpath(path.dirname(__file__)) script_dir = path.realpath(path.dirname(__file__))
instruction_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll')) instruction_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll'))

View File

@@ -0,0 +1,14 @@
class BuiltinType extends @builtintype {
string toString() { none() }
}
from BuiltinType type, string name, int kind, int kind_new, int size, int sign, int alignment
where
builtintypes(type, name, kind, size, sign, alignment) and
if
type instanceof @complex_fp16 or
type instanceof @complex_std_bfloat16 or
type instanceof @complex_std_float16
then kind_new = 2
else kind_new = kind
select type, name, kind_new, size, sign, alignment

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Introduce new complex 16-bit floating-point types
compatibility: backwards
builtintypes.rel: run builtintypes.qlo

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Add a predicate `getAnAttribute` to `Namespace`
compatibility: full
namespaceattributes.rel: delete

View File

@@ -0,0 +1,9 @@
class BuiltinType extends @builtintype {
string toString() { none() }
}
from BuiltinType id, string name, int kind, int new_kind, int size, int sign, int alignment
where
builtintypes(id, name, kind, size, sign, alignment) and
if kind = 63 then /* @errortype */ new_kind = 1 else new_kind = kind
select id, name, new_kind, size, sign, alignment

View File

@@ -0,0 +1,9 @@
class Type extends @type {
string toString() { none() }
}
from Type type, string name, int kind, int new_kind, Type type_id
where
derivedtypes(type, name, kind, type_id) and
if kind = 11 then /* @gnu_vector */ new_kind = 5 else new_kind = kind
select type, name, new_kind, type_id

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
description: Arm scalable vector type support
compatibility: backwards
builtintypes.rel: run builtintypes.qlo
derivedtypes.rel: run derivedtypes.qlo
tupleelements.rel: delete

View File

@@ -0,0 +1,161 @@
class Accessible extends @accessible {
string toString() { none() }
}
class Container extends @container {
string toString() { none() }
}
class Expr extends @expr {
string toString() { none() }
}
class Initialiser extends @initialiser {
string toString() { none() }
}
class Location extends @location_default {
string toString() { none() }
}
class Stmt extends @stmt {
string toString() { none() }
}
predicate isLocationDefault(Location l) {
diagnostics(_, _, _, _, _, l)
or
macroinvocations(_, _, l, _)
or
fun_decls(_, _, _, _, l)
or
var_decls(_, _, _, _, l)
or
type_decls(_, _, l)
or
namespace_decls(_, _, l, _)
or
namespace_decls(_, _, _, l)
or
usings(_, _, l, _)
or
static_asserts(_, _, _, l, _)
or
enumconstants(_, _, _, _, _, l)
or
concept_templates(_, _, l)
or
attributes(_, _, _, _, l)
or
attribute_args(_, _, _, _, l)
or
derivations(_, _, _, _, l)
or
frienddecls(_, _, _, l)
or
comments(_, _, l)
or
namequalifiers(_, _, _, l)
or
lambda_capture(_, _, _, _, _, _, l)
or
preprocdirects(_, _, l)
or
xmllocations(_, l)
or
locations_default(l, _, 0, 0, 0, 0) // For containers.
}
predicate isLocationExpr(Location l) {
initialisers(_, _, _, l)
or
exprs(_, _, l)
}
predicate isLocationStmt(Location l) { stmts(_, _, l) }
newtype TExprOrStmtLocation =
TExprLocation(Location l, Container c, int startLine, int startColumn, int endLine, int endColumn) {
isLocationExpr(l) and
(isLocationDefault(l) or isLocationStmt(l)) and
locations_default(l, c, startLine, startColumn, endLine, endColumn)
} or
TStmtLocation(Location l, Container c, int startLine, int startColumn, int endLine, int endColumn) {
isLocationStmt(l) and
(isLocationDefault(l) or isLocationExpr(l)) and
locations_default(l, c, startLine, startColumn, endLine, endColumn)
}
module Fresh = QlBuiltins::NewEntity<TExprOrStmtLocation>;
class NewLocationBase = @location_default or Fresh::EntityId;
class NewLocation extends NewLocationBase {
string toString() { none() }
}
query predicate new_locations_default(
NewLocation l, Container c, int startLine, int startColumn, int endLine, int endColumn
) {
isLocationDefault(l) and
locations_default(l, c, startLine, startColumn, endLine, endColumn)
}
query predicate new_locations_expr(
NewLocation l, Container c, int startLine, int startColumn, int endLine, int endColumn
) {
exists(Location l_old |
isLocationExpr(l_old) and
locations_default(l_old, c, startLine, startColumn, endLine, endColumn)
|
if not isLocationDefault(l_old) and not isLocationStmt(l)
then l = l_old
else l = Fresh::map(TExprLocation(l_old, c, startLine, startColumn, endLine, endColumn))
)
}
query predicate new_locations_stmt(
NewLocation l, Container c, int startLine, int startColumn, int endLine, int endColumn
) {
exists(Location l_old |
isLocationStmt(l_old) and
locations_default(l_old, c, startLine, startColumn, endLine, endColumn)
|
if not isLocationDefault(l_old) and not isLocationExpr(l)
then l = l_old
else l = Fresh::map(TStmtLocation(l_old, c, startLine, startColumn, endLine, endColumn))
)
}
query predicate new_exprs(Expr e, int kind, NewLocation l) {
exists(Location l_old, Container c, int startLine, int startColumn, int endLine, int endColumn |
exprs(e, kind, l_old) and
locations_default(l_old, c, startLine, startColumn, endLine, endColumn)
|
if not isLocationDefault(l_old) and not isLocationStmt(l)
then l = l_old
else l = Fresh::map(TExprLocation(l_old, c, startLine, startColumn, endLine, endColumn))
)
}
query predicate new_initialisers(Initialiser i, Accessible v, Expr e, NewLocation l) {
exists(Location l_old, Container c, int startLine, int startColumn, int endLine, int endColumn |
initialisers(i, v, e, l_old) and
locations_default(l_old, c, startLine, startColumn, endLine, endColumn)
|
if not isLocationDefault(l_old) and not isLocationStmt(l)
then l = l_old
else l = Fresh::map(TExprLocation(l_old, c, startLine, startColumn, endLine, endColumn))
)
}
query predicate new_stmts(Stmt s, int kind, NewLocation l) {
exists(Location l_old, Container c, int startLine, int startColumn, int endLine, int endColumn |
stmts(s, kind, l_old) and
locations_default(l_old, c, startLine, startColumn, endLine, endColumn)
|
if not isLocationDefault(l_old) and not isLocationExpr(l)
then l = l_old
else l = Fresh::map(TStmtLocation(l_old, c, startLine, startColumn, endLine, endColumn))
)
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
description: Merge location tables
compatibility: partial
locations_default.rel: run downgrades.ql new_locations_default
locations_expr.rel: run downgrades.ql new_locations_expr
locations_stmt.rel: run downgrades.ql new_locations_stmt
exprs.rel: run downgrades.ql new_exprs
initialisers.rel: run downgrades.ql new_initialisers
stmts.rel: run downgrades.ql new_stmts

View File

@@ -2,7 +2,7 @@ import runs_on
import pytest import pytest
from query_suites import * from query_suites import *
well_known_query_suites = ['cpp-code-quality.qls', 'cpp-security-and-quality.qls', 'cpp-security-extended.qls', 'cpp-code-scanning.qls'] well_known_query_suites = ['cpp-code-quality.qls', 'cpp-code-quality-extended.qls', 'cpp-security-and-quality.qls', 'cpp-security-extended.qls', 'cpp-code-scanning.qls']
@runs_on.posix @runs_on.posix
@pytest.mark.parametrize("query_suite", well_known_query_suites) @pytest.mark.parametrize("query_suite", well_known_query_suites)

View File

@@ -1,3 +1,20 @@
## 5.2.0
### Deprecated APIs
* The `ThrowingFunction` class (`semmle.code.cpp.models.interfaces.Throwing`) has been deprecated. Please use the `AlwaysSehThrowingFunction` class instead.
### New Features
* Added a predicate `getAnAttribute` to `Namespace` to retrieve a namespace attribute.
* The Microsoft-specific `__leave` statement is now supported.
* A new class `LeaveStmt` extending `JumpStmt` was added to represent `__leave` statements.
* Added a predicate `hasParameterList` to `LambdaExpression` to capture whether a lambda has an explicitly specified parameter list.
### Bug Fixes
* `resolveTypedefs` now properly resolves typedefs for `ArrayType`s.
## 5.1.0 ## 5.1.0
### New Features ### New Features

View File

@@ -1,4 +0,0 @@
---
category: deprecated
---
* The `ThrowingFunction` class (`semmle.code.cpp.models.interfaces.Throwing`) has been deprecated. Please use the `AlwaysSehThrowingFunction` class instead.

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* Added a predicate `hasParameterList` to `LambdaExpression` to capture whether a lambda has an explicitly specified parameter list.

View File

@@ -1,5 +0,0 @@
---
category: feature
---
* The Microsoft-specific `__leave` statement is now supported.
* A new class `LeaveStmt` extending `JumpStmt` was added to represent `__leave` statements.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added `sql-injection` sink models for the Oracle Call Interface (OCI) database library functions `OCIStmtPrepare` and `OCIStmtPrepare2`.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added support for `__fp16 _Complex` and `__bf16 _Complex` types

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* The `UnknownDefaultLocation`, `UnknownExprLocation`, and `UnknownStmtLocation` classes have been deprecated. Use `UnknownLocation` instead.

View File

@@ -0,0 +1,16 @@
## 5.2.0
### Deprecated APIs
* The `ThrowingFunction` class (`semmle.code.cpp.models.interfaces.Throwing`) has been deprecated. Please use the `AlwaysSehThrowingFunction` class instead.
### New Features
* Added a predicate `getAnAttribute` to `Namespace` to retrieve a namespace attribute.
* The Microsoft-specific `__leave` statement is now supported.
* A new class `LeaveStmt` extending `JumpStmt` was added to represent `__leave` statements.
* Added a predicate `hasParameterList` to `LambdaExpression` to capture whether a lambda has an explicitly specified parameter list.
### Bug Fixes
* `resolveTypedefs` now properly resolves typedefs for `ArrayType`s.

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 5.1.0 lastReleaseVersion: 5.2.0

View File

@@ -8,12 +8,14 @@ module CryptoInput implements InputSig<Language::Location> {
class LocatableElement = Language::Locatable; class LocatableElement = Language::Locatable;
class UnknownLocation = Language::UnknownDefaultLocation; class UnknownLocation = Language::UnknownLocation;
LocatableElement dfn_to_element(DataFlow::Node node) { LocatableElement dfn_to_element(DataFlow::Node node) {
result = node.asExpr() or result = node.asExpr() or
result = node.asParameter() or result = node.asParameter() or
result = node.asVariable() result = node.asVariable() or
result = node.asDefiningArgument()
// TODO: do we need asIndirectExpr()?
} }
string locationToFileBaseNameAndLineNumberString(Location location) { string locationToFileBaseNameAndLineNumberString(Location location) {
@@ -54,7 +56,7 @@ module ArtifactFlowConfig implements DataFlow::ConfigSig {
module ArtifactFlow = DataFlow::Global<ArtifactFlowConfig>; module ArtifactFlow = DataFlow::Global<ArtifactFlowConfig>;
/** /**
* Artifact output to node input configuration * An artifact output to node input configuration
*/ */
abstract class AdditionalFlowInputStep extends DataFlow::Node { abstract class AdditionalFlowInputStep extends DataFlow::Node {
abstract DataFlow::Node getOutput(); abstract DataFlow::Node getOutput();
@@ -89,9 +91,8 @@ module GenericDataSourceFlowConfig implements DataFlow::ConfigSig {
module GenericDataSourceFlow = TaintTracking::Global<GenericDataSourceFlowConfig>; module GenericDataSourceFlow = TaintTracking::Global<GenericDataSourceFlowConfig>;
private class ConstantDataSource extends Crypto::GenericConstantSourceInstance instanceof Literal { private class ConstantDataSource extends Crypto::GenericConstantSourceInstance instanceof OpenSslGenericSourceCandidateLiteral
ConstantDataSource() { this instanceof OpenSSLGenericSourceCandidateLiteral } {
override DataFlow::Node getOutputNode() { result.asExpr() = this } override DataFlow::Node getOutputNode() { result.asExpr() = this }
override predicate flowsTo(Crypto::FlowAwareElement other) { override predicate flowsTo(Crypto::FlowAwareElement other) {

View File

@@ -12,13 +12,15 @@ private import PaddingAlgorithmInstance
* overlap with the known algorithm constants. * overlap with the known algorithm constants.
* Padding consumers (specific padding consumers) are excluded from the set of sinks. * Padding consumers (specific padding consumers) are excluded from the set of sinks.
*/ */
module KnownOpenSSLAlgorithmToAlgorithmValueConsumerConfig implements DataFlow::ConfigSig { module KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof KnownOpenSSLAlgorithmConstant source.asExpr() instanceof KnownOpenSslAlgorithmExpr and
// No need to flow direct operations to AVCs
not source.asExpr() instanceof OpenSslDirectAlgorithmOperationCall
} }
predicate isSink(DataFlow::Node sink) { predicate isSink(DataFlow::Node sink) {
exists(OpenSSLAlgorithmValueConsumer c | exists(OpenSslAlgorithmValueConsumer c |
c.getInputNode() = sink and c.getInputNode() = sink and
// exclude padding algorithm consumers, since // exclude padding algorithm consumers, since
// these consumers take in different constant values // these consumers take in different constant values
@@ -43,11 +45,11 @@ module KnownOpenSSLAlgorithmToAlgorithmValueConsumerConfig implements DataFlow::
} }
} }
module KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow = module KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow =
DataFlow::Global<KnownOpenSSLAlgorithmToAlgorithmValueConsumerConfig>; DataFlow::Global<KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig>;
module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataFlow::ConfigSig { module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof OpenSSLPaddingLiteral } predicate isSource(DataFlow::Node source) { source.asExpr() instanceof OpenSslPaddingLiteral }
predicate isSink(DataFlow::Node sink) { predicate isSink(DataFlow::Node sink) {
exists(PaddingAlgorithmValueConsumer c | c.getInputNode() = sink) exists(PaddingAlgorithmValueConsumer c | c.getInputNode() = sink)
@@ -58,11 +60,11 @@ module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataF
} }
} }
module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow = module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow =
DataFlow::Global<RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>; DataFlow::Global<RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>;
class OpenSSLAlgorithmAdditionalFlowStep extends AdditionalFlowInputStep { class OpenSslAlgorithmAdditionalFlowStep extends AdditionalFlowInputStep {
OpenSSLAlgorithmAdditionalFlowStep() { exists(AlgorithmPassthroughCall c | c.getInNode() = this) } OpenSslAlgorithmAdditionalFlowStep() { exists(AlgorithmPassthroughCall c | c.getInNode() = this) }
override DataFlow::Node getOutput() { override DataFlow::Node getOutput() {
exists(AlgorithmPassthroughCall c | c.getInNode() = this and c.getOutNode() = result) exists(AlgorithmPassthroughCall c | c.getInNode() = this and c.getOutNode() = result)
@@ -112,11 +114,11 @@ class CopyAndDupAlgorithmPassthroughCall extends AlgorithmPassthroughCall {
override DataFlow::Node getOutNode() { result = outNode } override DataFlow::Node getOutNode() { result = outNode }
} }
class NIDToPointerPassthroughCall extends AlgorithmPassthroughCall { class NidToPointerPassthroughCall extends AlgorithmPassthroughCall {
DataFlow::Node inNode; DataFlow::Node inNode;
DataFlow::Node outNode; DataFlow::Node outNode;
NIDToPointerPassthroughCall() { NidToPointerPassthroughCall() {
this.getTarget().getName() in ["OBJ_nid2obj", "OBJ_nid2ln", "OBJ_nid2sn"] and this.getTarget().getName() in ["OBJ_nid2obj", "OBJ_nid2ln", "OBJ_nid2sn"] and
inNode.asExpr() = this.getArgument(0) and inNode.asExpr() = this.getArgument(0) and
outNode.asExpr() = this outNode.asExpr() = this
@@ -148,11 +150,11 @@ class PointerToPointerPassthroughCall extends AlgorithmPassthroughCall {
override DataFlow::Node getOutNode() { result = outNode } override DataFlow::Node getOutNode() { result = outNode }
} }
class PointerToNIDPassthroughCall extends AlgorithmPassthroughCall { class PointerToNidPassthroughCall extends AlgorithmPassthroughCall {
DataFlow::Node inNode; DataFlow::Node inNode;
DataFlow::Node outNode; DataFlow::Node outNode;
PointerToNIDPassthroughCall() { PointerToNidPassthroughCall() {
this.getTarget().getName() in ["OBJ_obj2nid", "OBJ_ln2nid", "OBJ_sn2nid", "OBJ_txt2nid"] and this.getTarget().getName() in ["OBJ_obj2nid", "OBJ_ln2nid", "OBJ_sn2nid", "OBJ_txt2nid"] and
( (
inNode.asIndirectExpr() = this.getArgument(0) inNode.asIndirectExpr() = this.getArgument(0)

View File

@@ -5,68 +5,68 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
private import AlgToAVCFlow private import AlgToAVCFlow
private import codeql.quantum.experimental.Standardization::Types::KeyOpAlg as KeyOpAlg
/** /**
* Given a `KnownOpenSSLBlockModeAlgorithmConstant`, converts this to a block family type. * Given a `KnownOpenSslBlockModeAlgorithmExpr`, converts this to a block family type.
* Does not bind if there is no mapping (no mapping to 'unknown' or 'other'). * Does not bind if there is no mapping (no mapping to 'unknown' or 'other').
*/ */
predicate knownOpenSSLConstantToBlockModeFamilyType( predicate knownOpenSslConstantToBlockModeFamilyType(
KnownOpenSSLBlockModeAlgorithmConstant e, Crypto::TBlockCipherModeOfOperationType type KnownOpenSslBlockModeAlgorithmExpr e, KeyOpAlg::ModeOfOperationType type
) { ) {
exists(string name | exists(string name |
name = e.getNormalizedName() and name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
( (
name.matches("CBC") and type instanceof Crypto::CBC name = "CBC" and type instanceof KeyOpAlg::CBC
or or
name.matches("CFB%") and type instanceof Crypto::CFB name = "CFB%" and type instanceof KeyOpAlg::CFB
or or
name.matches("CTR") and type instanceof Crypto::CTR name = "CTR" and type instanceof KeyOpAlg::CTR
or or
name.matches("GCM") and type instanceof Crypto::GCM name = "GCM" and type instanceof KeyOpAlg::GCM
or or
name.matches("OFB") and type instanceof Crypto::OFB name = "OFB" and type instanceof KeyOpAlg::OFB
or or
name.matches("XTS") and type instanceof Crypto::XTS name = "XTS" and type instanceof KeyOpAlg::XTS
or or
name.matches("CCM") and type instanceof Crypto::CCM name = "CCM" and type instanceof KeyOpAlg::CCM
or or
name.matches("GCM") and type instanceof Crypto::GCM name = "CCM" and type instanceof KeyOpAlg::CCM
or or
name.matches("CCM") and type instanceof Crypto::CCM name = "ECB" and type instanceof KeyOpAlg::ECB
or
name.matches("ECB") and type instanceof Crypto::ECB
) )
) )
} }
class KnownOpenSSLBlockModeConstantAlgorithmInstance extends OpenSSLAlgorithmInstance, class KnownOpenSslBlockModeConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
Crypto::ModeOfOperationAlgorithmInstance instanceof KnownOpenSSLBlockModeAlgorithmConstant Crypto::ModeOfOperationAlgorithmInstance instanceof KnownOpenSslBlockModeAlgorithmExpr
{ {
OpenSSLAlgorithmValueConsumer getterCall; OpenSslAlgorithmValueConsumer getterCall;
KnownOpenSSLBlockModeConstantAlgorithmInstance() { KnownOpenSslBlockModeConstantAlgorithmInstance() {
// Two possibilities: // Two possibilities:
// 1) The source is a literal and flows to a getter, then we know we have an instance // 1) The source is a literal and flows to a getter, then we know we have an instance
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that // 2) The source is a KnownOpenSslAlgorithm is call, and we know we have an instance immediately from that
// Possibility 1: // Possibility 1:
this instanceof Literal and this instanceof OpenSslAlgorithmLiteral and
exists(DataFlow::Node src, DataFlow::Node sink | exists(DataFlow::Node src, DataFlow::Node sink |
// Sink is an argument to a CipherGetterCall // Sink is an argument to a CipherGetterCall
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and sink = getterCall.getInputNode() and
// Source is `this` // Source is `this`
src.asExpr() = this and src.asExpr() = this and
// This traces to a getter // This traces to a getter
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink) KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
) )
or or
// Possibility 2: // Possibility 2:
this instanceof DirectAlgorithmValueConsumer and getterCall = this this instanceof OpenSslAlgorithmCall and
getterCall = this
} }
override Crypto::TBlockCipherModeOfOperationType getModeType() { override KeyOpAlg::ModeOfOperationType getModeType() {
knownOpenSSLConstantToBlockModeFamilyType(this, result) knownOpenSslConstantToBlockModeFamilyType(this, result)
or or
not knownOpenSSLConstantToBlockModeFamilyType(this, _) and result = Crypto::OtherMode() not knownOpenSslConstantToBlockModeFamilyType(this, _) and result = KeyOpAlg::OtherMode()
} }
// NOTE: I'm not going to attempt to parse out the mode specific part, so returning // NOTE: I'm not going to attempt to parse out the mode specific part, so returning
@@ -77,5 +77,5 @@ class KnownOpenSSLBlockModeConstantAlgorithmInstance extends OpenSSLAlgorithmIns
result = this.(Call).getTarget().getName() result = this.(Call).getTarget().getName()
} }
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall } override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
} }

View File

@@ -10,14 +10,14 @@ private import AlgToAVCFlow
private import BlockAlgorithmInstance private import BlockAlgorithmInstance
/** /**
* Given a `KnownOpenSSLCipherAlgorithmConstant`, converts this to a cipher family type. * Given a `KnownOpenSslCipherAlgorithmExpr`, converts this to a cipher family type.
* Does not bind if there is no mapping (no mapping to 'unknown' or 'other'). * Does not bind if there is no mapping (no mapping to 'unknown' or 'other').
*/ */
predicate knownOpenSSLConstantToCipherFamilyType( predicate knownOpenSslConstantToCipherFamilyType(
KnownOpenSSLCipherAlgorithmConstant e, Crypto::KeyOpAlg::TAlgorithm type KnownOpenSslCipherAlgorithmExpr e, Crypto::KeyOpAlg::TAlgorithm type
) { ) {
exists(string name | exists(string name |
name = e.getNormalizedName() and name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
( (
name.matches("AES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::AES()) name.matches("AES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::AES())
or or
@@ -33,9 +33,9 @@ predicate knownOpenSSLConstantToCipherFamilyType(
or or
name.matches("CAST5%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::CAST5()) name.matches("CAST5%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::CAST5())
or or
name.matches("2DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DoubleDES()) name.matches("2DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DOUBLE_DES())
or or
name.matches("3DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::TripleDES()) name.matches("3DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::TRIPLE_DES())
or or
name.matches("DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DES()) name.matches("DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DES())
or or
@@ -64,28 +64,29 @@ predicate knownOpenSSLConstantToCipherFamilyType(
) )
} }
class KnownOpenSSLCipherConstantAlgorithmInstance extends OpenSSLAlgorithmInstance, class KnownOpenSslCipherConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
Crypto::KeyOperationAlgorithmInstance instanceof KnownOpenSSLCipherAlgorithmConstant Crypto::KeyOperationAlgorithmInstance instanceof KnownOpenSslCipherAlgorithmExpr
{ {
OpenSSLAlgorithmValueConsumer getterCall; OpenSslAlgorithmValueConsumer getterCall;
KnownOpenSSLCipherConstantAlgorithmInstance() { KnownOpenSslCipherConstantAlgorithmInstance() {
// Two possibilities: // Two possibilities:
// 1) The source is a literal and flows to a getter, then we know we have an instance // 1) The source is a literal and flows to a getter, then we know we have an instance
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that // 2) The source is a KnownOpenSslAlgorithm is call, and we know we have an instance immediately from that
// Possibility 1: // Possibility 1:
this instanceof Literal and this instanceof OpenSslAlgorithmLiteral and
exists(DataFlow::Node src, DataFlow::Node sink | exists(DataFlow::Node src, DataFlow::Node sink |
// Sink is an argument to a CipherGetterCall // Sink is an argument to a CipherGetterCall
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and sink = getterCall.getInputNode() and
// Source is `this` // Source is `this`
src.asExpr() = this and src.asExpr() = this and
// This traces to a getter // This traces to a getter
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink) KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
) )
or or
// Possibility 2: // Possibility 2:
this instanceof DirectAlgorithmValueConsumer and getterCall = this this instanceof OpenSslAlgorithmCall and
getterCall = this
} }
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() { override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() {
@@ -109,17 +110,17 @@ class KnownOpenSSLCipherConstantAlgorithmInstance extends OpenSSLAlgorithmInstan
} }
override int getKeySizeFixed() { override int getKeySizeFixed() {
this.(KnownOpenSSLCipherAlgorithmConstant).getExplicitKeySize() = result this.(KnownOpenSslCipherAlgorithmExpr).getExplicitKeySize() = result
} }
override Crypto::KeyOpAlg::Algorithm getAlgorithmType() { override KeyOpAlg::AlgorithmType getAlgorithmType() {
knownOpenSSLConstantToCipherFamilyType(this, result) knownOpenSslConstantToCipherFamilyType(this, result)
or or
not knownOpenSSLConstantToCipherFamilyType(this, _) and not knownOpenSslConstantToCipherFamilyType(this, _) and
result = Crypto::KeyOpAlg::TUnknownKeyOperationAlgorithmType() result = Crypto::KeyOpAlg::TUnknownKeyOperationAlgorithmType()
} }
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall } override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() { override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
// TODO: trace to any key size initializer, symmetric and asymmetric // TODO: trace to any key size initializer, symmetric and asymmetric

View File

@@ -6,31 +6,32 @@ private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgor
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
private import AlgToAVCFlow private import AlgToAVCFlow
class KnownOpenSSLEllipticCurveConstantAlgorithmInstance extends OpenSSLAlgorithmInstance, class KnownOpenSslEllipticCurveConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
Crypto::EllipticCurveInstance instanceof KnownOpenSSLEllipticCurveAlgorithmConstant Crypto::EllipticCurveInstance instanceof KnownOpenSslEllipticCurveAlgorithmExpr
{ {
OpenSSLAlgorithmValueConsumer getterCall; OpenSslAlgorithmValueConsumer getterCall;
KnownOpenSSLEllipticCurveConstantAlgorithmInstance() { KnownOpenSslEllipticCurveConstantAlgorithmInstance() {
// Two possibilities: // Two possibilities:
// 1) The source is a literal and flows to a getter, then we know we have an instance // 1) The source is a literal and flows to a getter, then we know we have an instance
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that // 2) The source is a KnownOpenSslAlgorithm is call, and we know we have an instance immediately from that
// Possibility 1: // Possibility 1:
this instanceof Literal and this instanceof OpenSslAlgorithmLiteral and
exists(DataFlow::Node src, DataFlow::Node sink | exists(DataFlow::Node src, DataFlow::Node sink |
// Sink is an argument to a CipherGetterCall // Sink is an argument to a CipherGetterCall
sink = getterCall.getInputNode() and sink = getterCall.getInputNode() and
// Source is `this` // Source is `this`
src.asExpr() = this and src.asExpr() = this and
// This traces to a getter // This traces to a getter
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink) KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
) )
or or
// Possibility 2: // Possibility 2:
this instanceof DirectAlgorithmValueConsumer and getterCall = this this instanceof OpenSslAlgorithmCall and
getterCall = this
} }
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall } override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
override string getRawEllipticCurveName() { override string getRawEllipticCurveName() {
result = this.(Literal).getValue().toString() result = this.(Literal).getValue().toString()
@@ -38,16 +39,22 @@ class KnownOpenSSLEllipticCurveConstantAlgorithmInstance extends OpenSSLAlgorith
result = this.(Call).getTarget().getName() result = this.(Call).getTarget().getName()
} }
override Crypto::TEllipticCurveType getEllipticCurveType() { override Crypto::EllipticCurveFamilyType getEllipticCurveFamilyType() {
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _, result) if
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _,
_)
then
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _,
result)
else result = Crypto::OtherEllipticCurveType()
} }
override string getParsedEllipticCurveName() { override string getParsedEllipticCurveName() {
result = this.(KnownOpenSSLEllipticCurveAlgorithmConstant).getNormalizedName() result = this.(KnownOpenSslAlgorithmExpr).getNormalizedName()
} }
override int getKeySize() { override int getKeySize() {
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.(KnownOpenSSLEllipticCurveAlgorithmConstant) Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.(KnownOpenSslAlgorithmExpr)
.getNormalizedName(), result, _) .getNormalizedName(), result, _)
} }
} }

View File

@@ -5,75 +5,76 @@ private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgor
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
private import AlgToAVCFlow private import AlgToAVCFlow
predicate knownOpenSSLConstantToHashFamilyType( predicate knownOpenSslConstantToHashFamilyType(
KnownOpenSSLHashAlgorithmConstant e, Crypto::THashType type KnownOpenSslHashAlgorithmExpr e, Crypto::THashType type
) { ) {
exists(string name | exists(string name |
name = e.getNormalizedName() and name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
( (
name.matches("BLAKE2B") and type instanceof Crypto::BLAKE2B name = "BLAKE2B" and type instanceof Crypto::BLAKE2B
or or
name.matches("BLAKE2S") and type instanceof Crypto::BLAKE2S name = "BLAKE2S" and type instanceof Crypto::BLAKE2S
or or
name.matches("GOST%") and type instanceof Crypto::GOSTHash name.matches("GOST%") and type instanceof Crypto::GOST_HASH
or or
name.matches("MD2") and type instanceof Crypto::MD2 name = "MD2" and type instanceof Crypto::MD2
or or
name.matches("MD4") and type instanceof Crypto::MD4 name = "MD4" and type instanceof Crypto::MD4
or or
name.matches("MD5") and type instanceof Crypto::MD5 name = "MD5" and type instanceof Crypto::MD5
or or
name.matches("MDC2") and type instanceof Crypto::MDC2 name = "MDC2" and type instanceof Crypto::MDC2
or or
name.matches("POLY1305") and type instanceof Crypto::POLY1305 name = "POLY1305" and type instanceof Crypto::POLY1305
or or
name.matches(["SHA", "SHA1"]) and type instanceof Crypto::SHA1 name.matches(["SHA", "SHA1"]) and type instanceof Crypto::SHA1
or or
name.matches("SHA+%") and not name.matches(["SHA1", "SHA3-"]) and type instanceof Crypto::SHA2 name.matches("SHA_%") and not name.matches(["SHA1", "SHA3-"]) and type instanceof Crypto::SHA2
or or
name.matches("SHA3-%") and type instanceof Crypto::SHA3 name.matches("SHA3-%") and type instanceof Crypto::SHA3
or or
name.matches(["SHAKE"]) and type instanceof Crypto::SHAKE name = "SHAKE" and type instanceof Crypto::SHAKE
or or
name.matches("SM3") and type instanceof Crypto::SM3 name = "SM3" and type instanceof Crypto::SM3
or or
name.matches("RIPEMD160") and type instanceof Crypto::RIPEMD160 name = "RIPEMD160" and type instanceof Crypto::RIPEMD160
or or
name.matches("WHIRLPOOL") and type instanceof Crypto::WHIRLPOOL name = "WHIRLPOOL" and type instanceof Crypto::WHIRLPOOL
) )
) )
} }
class KnownOpenSSLHashConstantAlgorithmInstance extends OpenSSLAlgorithmInstance, class KnownOpenSslHashConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
Crypto::HashAlgorithmInstance instanceof KnownOpenSSLHashAlgorithmConstant Crypto::HashAlgorithmInstance instanceof KnownOpenSslHashAlgorithmExpr
{ {
OpenSSLAlgorithmValueConsumer getterCall; OpenSslAlgorithmValueConsumer getterCall;
KnownOpenSSLHashConstantAlgorithmInstance() { KnownOpenSslHashConstantAlgorithmInstance() {
// Two possibilities: // Two possibilities:
// 1) The source is a literal and flows to a getter, then we know we have an instance // 1) The source is a literal and flows to a getter, then we know we have an instance
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that // 2) The source is a KnownOpenSslAlgorithm is call, and we know we have an instance immediately from that
// Possibility 1: // Possibility 1:
this instanceof Literal and this instanceof OpenSslAlgorithmLiteral and
exists(DataFlow::Node src, DataFlow::Node sink | exists(DataFlow::Node src, DataFlow::Node sink |
// Sink is an argument to a CipherGetterCall // Sink is an argument to a CipherGetterCall
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and sink = getterCall.getInputNode() and
// Source is `this` // Source is `this`
src.asExpr() = this and src.asExpr() = this and
// This traces to a getter // This traces to a getter
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink) KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
) )
or or
// Possibility 2: // Possibility 2:
this instanceof DirectAlgorithmValueConsumer and getterCall = this this instanceof OpenSslAlgorithmCall and
getterCall = this
} }
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall } override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
override Crypto::THashType getHashFamily() { override Crypto::THashType getHashFamily() {
knownOpenSSLConstantToHashFamilyType(this, result) knownOpenSslConstantToHashFamilyType(this, result)
or or
not knownOpenSSLConstantToHashFamilyType(this, _) and result = Crypto::OtherHashType() not knownOpenSslConstantToHashFamilyType(this, _) and result = Crypto::OtherHashType()
} }
override string getRawHashAlgorithmName() { override string getRawHashAlgorithmName() {
@@ -83,6 +84,6 @@ class KnownOpenSSLHashConstantAlgorithmInstance extends OpenSSLAlgorithmInstance
} }
override int getFixedDigestLength() { override int getFixedDigestLength() {
this.(KnownOpenSSLHashAlgorithmConstant).getExplicitDigestLength() = result this.(KnownOpenSslHashAlgorithmExpr).getExplicitDigestLength() = result
} }
} }

View File

@@ -5,11 +5,11 @@ private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgor
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
private import AlgToAVCFlow private import AlgToAVCFlow
predicate knownOpenSSLConstantToKeyAgreementFamilyType( predicate knownOpenSslConstantToKeyAgreementFamilyType(
KnownOpenSSLKeyAgreementAlgorithmConstant e, Crypto::TKeyAgreementType type KnownOpenSslKeyAgreementAlgorithmExpr e, Crypto::TKeyAgreementType type
) { ) {
exists(string name | exists(string name |
name = e.getNormalizedName() and name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
( (
name = "ECDH" and type = Crypto::ECDH() name = "ECDH" and type = Crypto::ECDH()
or or
@@ -22,36 +22,37 @@ predicate knownOpenSSLConstantToKeyAgreementFamilyType(
) )
} }
class KnownOpenSSLHashConstantAlgorithmInstance extends OpenSSLAlgorithmInstance, class KnownOpenSslKeyAgreementConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
Crypto::KeyAgreementAlgorithmInstance instanceof KnownOpenSSLKeyAgreementAlgorithmConstant Crypto::KeyAgreementAlgorithmInstance instanceof KnownOpenSslKeyAgreementAlgorithmExpr
{ {
OpenSSLAlgorithmValueConsumer getterCall; OpenSslAlgorithmValueConsumer getterCall;
KnownOpenSSLHashConstantAlgorithmInstance() { KnownOpenSslKeyAgreementConstantAlgorithmInstance() {
// Two possibilities: // Two possibilities:
// 1) The source is a literal and flows to a getter, then we know we have an instance // 1) The source is a literal and flows to a getter, then we know we have an instance
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that // 2) The source is a KnownOpenSslAlgorithm is call, and we know we have an instance immediately from that
// Possibility 1: // Possibility 1:
this instanceof Literal and this instanceof OpenSslAlgorithmLiteral and
exists(DataFlow::Node src, DataFlow::Node sink | exists(DataFlow::Node src, DataFlow::Node sink |
// Sink is an argument to a CipherGetterCall // Sink is an argument to a CipherGetterCall
sink = getterCall.getInputNode() and sink = getterCall.getInputNode() and
// Source is `this` // Source is `this`
src.asExpr() = this and src.asExpr() = this and
// This traces to a getter // This traces to a getter
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink) KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
) )
or or
// Possibility 2: // Possibility 2:
this instanceof DirectAlgorithmValueConsumer and getterCall = this this instanceof OpenSslAlgorithmCall and
getterCall = this
} }
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall } override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
override Crypto::TKeyAgreementType getKeyAgreementType() { override Crypto::TKeyAgreementType getKeyAgreementType() {
knownOpenSSLConstantToKeyAgreementFamilyType(this, result) knownOpenSslConstantToKeyAgreementFamilyType(this, result)
or or
not knownOpenSSLConstantToKeyAgreementFamilyType(this, _) and not knownOpenSslConstantToKeyAgreementFamilyType(this, _) and
result = Crypto::OtherKeyAgreementType() result = Crypto::OtherKeyAgreementType()
} }

View File

@@ -1,79 +1,44 @@
import cpp import cpp
import experimental.quantum.OpenSSL.GenericSourceCandidateLiteral import experimental.quantum.OpenSSL.GenericSourceCandidateLiteral
predicate resolveAlgorithmFromExpr(Expr e, string normalizedName, string algType) { predicate resolveAlgorithmFromExpr(
resolveAlgorithmFromCall(e, normalizedName, algType) KnownOpenSslAlgorithmExpr e, string normalizedName, string algType
or ) {
resolveAlgorithmFromLiteral(e, normalizedName, algType) normalizedName = e.getNormalizedName() and
} algType = e.getAlgType()
class KnownOpenSSLAlgorithmConstant extends Expr {
KnownOpenSSLAlgorithmConstant() { resolveAlgorithmFromExpr(this, _, _) }
string getNormalizedName() { resolveAlgorithmFromExpr(this, result, _) }
string getAlgType() { resolveAlgorithmFromExpr(this, _, result) }
}
class KnownOpenSSLCipherAlgorithmConstant extends KnownOpenSSLAlgorithmConstant {
string algType;
KnownOpenSSLCipherAlgorithmConstant() {
resolveAlgorithmFromExpr(this, _, algType) and
algType.matches("%ENCRYPTION")
}
int getExplicitKeySize() {
exists(string name |
name = this.getNormalizedName() and
resolveAlgorithmFromExpr(this, name, algType) and
result = name.regexpCapture(".*-(\\d*)", 1).toInt()
)
}
}
class KnownOpenSSLPaddingAlgorithmConstant extends KnownOpenSSLAlgorithmConstant {
KnownOpenSSLPaddingAlgorithmConstant() {
exists(string algType |
resolveAlgorithmFromExpr(this, _, algType) and
algType.matches("%PADDING")
)
}
}
class KnownOpenSSLBlockModeAlgorithmConstant extends KnownOpenSSLAlgorithmConstant {
KnownOpenSSLBlockModeAlgorithmConstant() { resolveAlgorithmFromExpr(this, _, "BLOCK_MODE") }
}
class KnownOpenSSLHashAlgorithmConstant extends KnownOpenSSLAlgorithmConstant {
KnownOpenSSLHashAlgorithmConstant() { resolveAlgorithmFromExpr(this, _, "HASH") }
int getExplicitDigestLength() {
exists(string name |
name = this.getNormalizedName() and
resolveAlgorithmFromExpr(this, name, "HASH") and
result = name.regexpCapture(".*-(\\d*)$", 1).toInt()
)
}
}
class KnownOpenSSLEllipticCurveAlgorithmConstant extends KnownOpenSSLAlgorithmConstant {
KnownOpenSSLEllipticCurveAlgorithmConstant() {
resolveAlgorithmFromExpr(this, _, "ELLIPTIC_CURVE")
}
}
class KnownOpenSSLSignatureAlgorithmConstant extends KnownOpenSSLAlgorithmConstant {
KnownOpenSSLSignatureAlgorithmConstant() { resolveAlgorithmFromExpr(this, _, "SIGNATURE") }
}
class KnownOpenSSLKeyAgreementAlgorithmConstant extends KnownOpenSSLAlgorithmConstant {
KnownOpenSSLKeyAgreementAlgorithmConstant() { resolveAlgorithmFromExpr(this, _, "KEY_AGREEMENT") }
} }
/** /**
* Resolves a call to a 'direct algorithm getter', e.g., EVP_MD5() * An expression that resolves to a known OpenSsl algorithm constant.
* This approach to fetching algorithms was used in OpenSSL 1.0.2. * This can be a literal, a call to a known OpenSsl algorithm constant getter,
* or a call to an operation that directly operates on a known algorithm.
*/
abstract class KnownOpenSslAlgorithmExpr extends Expr {
abstract string getNormalizedName();
abstract string getAlgType();
}
class OpenSslAlgorithmLiteral extends KnownOpenSslAlgorithmExpr instanceof Literal {
string normalizedName;
string algType;
OpenSslAlgorithmLiteral() { resolveAlgorithmFromLiteral(this, normalizedName, algType) }
override string getNormalizedName() { result = normalizedName }
override string getAlgType() { result = algType }
}
/**
* A call to either an OpenSsl algorithm constant 'getter', e.g., EVP_MD5()
* or call to an operation that directly operates on a known algorithm, e.g., AES_encrypt
*/
abstract class OpenSslAlgorithmCall extends KnownOpenSslAlgorithmExpr instanceof Call { }
/**
* A call to a 'direct algorithm getter', e.g., EVP_MD5()
* This approach to fetching algorithms was used in OpenSsl 1.0.2.
* The strategy for resolving these calls is to parse the target name * The strategy for resolving these calls is to parse the target name
* and resolve the name as though it were a known literal. * and resolve the name as though it were a known literal.
* There are a few exceptions where the name doesn't directly match the * There are a few exceptions where the name doesn't directly match the
@@ -81,15 +46,134 @@ class KnownOpenSSLKeyAgreementAlgorithmConstant extends KnownOpenSSLAlgorithmCon
* set of aliases. E.g., EVP_dss() and EVP_dss1() needed such mappings * set of aliases. E.g., EVP_dss() and EVP_dss1() needed such mappings
* alias = "dss" and target = "dsa" * alias = "dss" and target = "dsa"
* or * or
* alias = "dss1" and target = "dsaWithSHA1" * alias = "dss1" and target = "dsaWithSHA1"
*/ */
predicate resolveAlgorithmFromCall(Call c, string normalized, string algType) { class OpenSslDirectAlgorithmFetchCall extends OpenSslAlgorithmCall {
exists(string name, string parsedTargetName | string normalizedName;
parsedTargetName = string algType;
c.getTarget().getName().replaceAll("EVP_", "").toLowerCase().replaceAll("_", "-") and
name = resolveAlgorithmAlias(parsedTargetName) and OpenSslDirectAlgorithmFetchCall() {
knownOpenSSLAlgorithmLiteral(name, _, normalized, algType) //ASSUMPTION: these cases will have operands for the call
) not exists(this.(Call).getAnArgument()) and
exists(string name, string parsedTargetName |
parsedTargetName =
this.(Call).getTarget().getName().replaceAll("EVP_", "").toLowerCase().replaceAll("_", "-") and
name = resolveAlgorithmAlias(parsedTargetName) and
knownOpenSslAlgorithmLiteral(name, _, normalizedName, algType)
)
}
override string getNormalizedName() { result = normalizedName }
override string getAlgType() { result = algType }
}
/**
* A call to an OpenSsl operation that directly operates on a known algorithm.
* An algorithm construct is not generated for these calls, rather, the operation
* is directly performed, and the algorithm is inferred by the operation itself.
*/
class OpenSslDirectAlgorithmOperationCall extends OpenSslAlgorithmCall {
string normalizedName;
string algType;
OpenSslDirectAlgorithmOperationCall() {
//TODO: this set will have to be exhaustive, and for each operation
//further modeling will be necessary for each case to map the APIs operands
//ASSUMPTION: these cases must have operands for the call
exists(this.(Call).getAnArgument()) and
//TODO: Each case would be enumerated here. Will likely need an exhaustive mapping much like
// for known constants.
knownOpenSslAlgorithmOperationCall(this, normalizedName, algType)
}
override string getNormalizedName() { result = normalizedName }
override string getAlgType() { result = algType }
}
class KnownOpenSslCipherAlgorithmExpr extends Expr instanceof KnownOpenSslAlgorithmExpr {
string algType;
KnownOpenSslCipherAlgorithmExpr() {
algType = this.(KnownOpenSslAlgorithmExpr).getAlgType() and
algType.matches("%ENCRYPTION")
}
int getExplicitKeySize() {
exists(string name |
name = this.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
resolveAlgorithmFromExpr(this, name, algType) and
result = name.regexpCapture(".*-(\\d*)", 1).toInt()
)
}
}
class KnownOpenSslPaddingAlgorithmExpr extends Expr instanceof KnownOpenSslAlgorithmExpr {
KnownOpenSslPaddingAlgorithmExpr() {
exists(string algType |
resolveAlgorithmFromExpr(this, _, algType) and
algType.matches("%PADDING")
)
}
}
class KnownOpenSslBlockModeAlgorithmExpr extends Expr instanceof KnownOpenSslAlgorithmExpr {
KnownOpenSslBlockModeAlgorithmExpr() { resolveAlgorithmFromExpr(this, _, "BLOCK_MODE") }
}
class KnownOpenSslHashAlgorithmExpr extends Expr instanceof KnownOpenSslAlgorithmExpr {
KnownOpenSslHashAlgorithmExpr() { resolveAlgorithmFromExpr(this, _, "HASH") }
int getExplicitDigestLength() {
exists(string name |
name = this.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
resolveAlgorithmFromExpr(this, name, "HASH") and
result = name.regexpCapture(".*-(\\d*)$", 1).toInt()
)
}
}
class KnownOpenSslMacAlgorithmExpr extends Expr instanceof KnownOpenSslAlgorithmExpr {
KnownOpenSslMacAlgorithmExpr() { resolveAlgorithmFromExpr(this, _, "MAC") }
}
class KnownOpenSslHMacAlgorithmExpr extends Expr instanceof KnownOpenSslMacAlgorithmExpr {
KnownOpenSslHMacAlgorithmExpr() { resolveAlgorithmFromExpr(this, "HMAC", "MAC") }
/**
* Gets an explicit cipher algorithm for this MAC algorithm.
* This occurs when the MAC specifies the algorithm at the same time "HMAC-SHA-256"
*/
KnownOpenSslHashAlgorithmExpr getExplicitHashAlgorithm() { result = this }
}
class KnownOpenSslCMacAlgorithmExpr extends Expr instanceof KnownOpenSslMacAlgorithmExpr {
KnownOpenSslCMacAlgorithmExpr() { resolveAlgorithmFromExpr(this, "CMAC", "MAC") }
/**
* Gets an explicit cipher algorithm for this MAC algorithm.
* This occurs when the MAC specifies the algorithm at the same time "HMAC-SHA-256"
*/
KnownOpenSslCipherAlgorithmExpr getExplicitCipherAlgorithm() { result = this }
}
class KnownOpenSslEllipticCurveAlgorithmExpr extends Expr instanceof KnownOpenSslAlgorithmExpr {
KnownOpenSslEllipticCurveAlgorithmExpr() { resolveAlgorithmFromExpr(this, _, "ELLIPTIC_CURVE") }
}
class KnownOpenSslSignatureAlgorithmExpr extends Expr instanceof KnownOpenSslAlgorithmExpr {
KnownOpenSslSignatureAlgorithmExpr() { resolveAlgorithmFromExpr(this, _, "SIGNATURE") }
}
class KnownOpenSslKeyAgreementAlgorithmExpr extends Expr instanceof KnownOpenSslAlgorithmExpr {
KnownOpenSslKeyAgreementAlgorithmExpr() { resolveAlgorithmFromExpr(this, _, "KEY_AGREEMENT") }
}
predicate knownOpenSslAlgorithmOperationCall(Call c, string normalized, string algType) {
c.getTarget().getName() in ["EVP_RSA_gen", "RSA_generate_key_ex", "RSA_generate_key", "RSA_new"] and
normalized = "RSA" and
algType = "ASYMMETRIC_ENCRYPTION"
} }
/** /**
@@ -98,13 +182,13 @@ predicate resolveAlgorithmFromCall(Call c, string normalized, string algType) {
* If this predicate does not hold, then `e` can be interpreted as being of `UNKNOWN` type. * If this predicate does not hold, then `e` can be interpreted as being of `UNKNOWN` type.
*/ */
predicate resolveAlgorithmFromLiteral( predicate resolveAlgorithmFromLiteral(
OpenSSLGenericSourceCandidateLiteral e, string normalized, string algType OpenSslGenericSourceCandidateLiteral e, string normalized, string algType
) { ) {
knownOpenSSLAlgorithmLiteral(_, e.getValue().toInt(), normalized, algType) knownOpenSslAlgorithmLiteral(_, e.getValue().toInt(), normalized, algType)
or or
exists(string name | exists(string name |
name = resolveAlgorithmAlias(e.getValue()) and name = resolveAlgorithmAlias(e.getValue()) and
knownOpenSSLAlgorithmLiteral(name, _, normalized, algType) knownOpenSslAlgorithmLiteral(name, _, normalized, algType)
) )
} }
@@ -115,7 +199,7 @@ string resolveAlgorithmAlias(string name) {
result = getAlgorithmAlias(lower) result = getAlgorithmAlias(lower)
or or
// or the name is itself a known algorithm // or the name is itself a known algorithm
knownOpenSSLAlgorithmLiteral(lower, _, _, _) and result = lower knownOpenSslAlgorithmLiteral(lower, _, _, _) and result = lower
) )
} }
@@ -126,7 +210,8 @@ string getAlgorithmAlias(string alias) {
} }
/** /**
* Finds aliases of known alagorithms defined by users (through obj_name_add and various macros pointing to this function) * Holds for aliases of known algorithms defined by users
* (through obj_name_add and various macros pointing to this function).
* *
* The `target` and `alias` are converted to lowercase to be of a standard form. * The `target` and `alias` are converted to lowercase to be of a standard form.
*/ */
@@ -138,9 +223,9 @@ predicate customAliases(string target, string alias) {
} }
/** /**
* A hard-coded mapping of known algorithm aliases in OpenSSL. * Holds for a hard-coded mapping of known algorithm aliases in OpenSsl.
* This was derived by applying the same kind of logic foun din `customAliases` to the * This was derived by applying the same kind of logic foun din `customAliases` to the
* OpenSSL code base directly. * OpenSsl code base directly.
* *
* The `target` and `alias` are converted to lowercase to be of a standard form. * The `target` and `alias` are converted to lowercase to be of a standard form.
*/ */
@@ -247,7 +332,7 @@ predicate defaultAliases(string target, string alias) {
* `normalized` is the normalized name of the algorithm (e.g., "AES128" for "aes-128-cbc") * `normalized` is the normalized name of the algorithm (e.g., "AES128" for "aes-128-cbc")
* `algType` is the type of algorithm (e.g., "SYMMETRIC_ENCRYPTION") * `algType` is the type of algorithm (e.g., "SYMMETRIC_ENCRYPTION")
*/ */
predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized, string algType) { predicate knownOpenSslAlgorithmLiteral(string name, int nid, string normalized, string algType) {
name = "dhKeyAgreement" and nid = 28 and normalized = "DH" and algType = "KEY_AGREEMENT" name = "dhKeyAgreement" and nid = 28 and normalized = "DH" and algType = "KEY_AGREEMENT"
or or
name = "x9.42 dh" and nid = 29 and normalized = "DH" and algType = "KEY_AGREEMENT" name = "x9.42 dh" and nid = 29 and normalized = "DH" and algType = "KEY_AGREEMENT"
@@ -886,6 +971,8 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
or or
name = "id-alg-dh-sig-hmac-sha1" and nid = 325 and normalized = "DH" and algType = "KEY_AGREEMENT" name = "id-alg-dh-sig-hmac-sha1" and nid = 325 and normalized = "DH" and algType = "KEY_AGREEMENT"
or or
name = "id-alg-dh-sig-hmac-sha1" and nid = 325 and normalized = "HMAC" and algType = "MAC"
or
name = "aes-128-ofb" and nid = 420 and normalized = "AES-128" and algType = "SYMMETRIC_ENCRYPTION" name = "aes-128-ofb" and nid = 420 and normalized = "AES-128" and algType = "SYMMETRIC_ENCRYPTION"
or or
name = "aes-128-ofb" and nid = 420 and normalized = "OFB" and algType = "BLOCK_MODE" name = "aes-128-ofb" and nid = 420 and normalized = "OFB" and algType = "BLOCK_MODE"
@@ -1064,8 +1151,12 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
or or
name = "hmac-md5" and nid = 780 and normalized = "MD5" and algType = "HASH" name = "hmac-md5" and nid = 780 and normalized = "MD5" and algType = "HASH"
or or
name = "hmac-md5" and nid = 780 and normalized = "HMAC" and algType = "HASH"
or
name = "hmac-sha1" and nid = 781 and normalized = "SHA1" and algType = "HASH" name = "hmac-sha1" and nid = 781 and normalized = "SHA1" and algType = "HASH"
or or
name = "hmac-sha1" and nid = 781 and normalized = "HMAC" and algType = "MAC"
or
name = "md_gost94" and nid = 809 and normalized = "GOST94" and algType = "HASH" name = "md_gost94" and nid = 809 and normalized = "GOST94" and algType = "HASH"
or or
name = "gost94" and nid = 812 and normalized = "GOST94" and algType = "HASH" name = "gost94" and nid = 812 and normalized = "GOST94" and algType = "HASH"
@@ -1140,10 +1231,14 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
or or
name = "rc4-hmac-md5" and nid = 915 and normalized = "MD5" and algType = "HASH" name = "rc4-hmac-md5" and nid = 915 and normalized = "MD5" and algType = "HASH"
or or
name = "rc4-hmac-md5" and nid = 915 and normalized = "HMAC" and algType = "MAC"
or
name = "rc4-hmac-md5" and nid = 915 and normalized = "RC4" and algType = "SYMMETRIC_ENCRYPTION" name = "rc4-hmac-md5" and nid = 915 and normalized = "RC4" and algType = "SYMMETRIC_ENCRYPTION"
or or
name = "aes-128-cbc-hmac-sha1" and nid = 916 and normalized = "SHA1" and algType = "HASH" name = "aes-128-cbc-hmac-sha1" and nid = 916 and normalized = "SHA1" and algType = "HASH"
or or
name = "aes-128-cbc-hmac-sha1" and nid = 916 and normalized = "HMAC" and algType = "MAC"
or
name = "aes-128-cbc-hmac-sha1" and name = "aes-128-cbc-hmac-sha1" and
nid = 916 and nid = 916 and
normalized = "AES-128" and normalized = "AES-128" and
@@ -1153,6 +1248,8 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
or or
name = "aes-192-cbc-hmac-sha1" and nid = 917 and normalized = "SHA1" and algType = "HASH" name = "aes-192-cbc-hmac-sha1" and nid = 917 and normalized = "SHA1" and algType = "HASH"
or or
name = "aes-192-cbc-hmac-sha1" and nid = 917 and normalized = "HMAC" and algType = "MAC"
or
name = "aes-192-cbc-hmac-sha1" and name = "aes-192-cbc-hmac-sha1" and
nid = 917 and nid = 917 and
normalized = "AES-192" and normalized = "AES-192" and
@@ -1167,6 +1264,8 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
or or
name = "aes-256-cbc-hmac-sha1" and nid = 918 and normalized = "CBC" and algType = "BLOCK_MODE" name = "aes-256-cbc-hmac-sha1" and nid = 918 and normalized = "CBC" and algType = "BLOCK_MODE"
or or
name = "aes-256-cbc-hmac-sha1" and nid = 918 and normalized = "HMAC" and algType = "MAC"
or
name = "aes-128-cbc-hmac-sha256" and nid = 948 and normalized = "SHA-256" and algType = "HASH" name = "aes-128-cbc-hmac-sha256" and nid = 948 and normalized = "SHA-256" and algType = "HASH"
or or
name = "aes-128-cbc-hmac-sha256" and name = "aes-128-cbc-hmac-sha256" and
@@ -1178,6 +1277,8 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
or or
name = "aes-192-cbc-hmac-sha256" and nid = 949 and normalized = "SHA-256" and algType = "HASH" name = "aes-192-cbc-hmac-sha256" and nid = 949 and normalized = "SHA-256" and algType = "HASH"
or or
name = "aes-192-cbc-hmac-sha256" and nid = 949 and normalized = "HMAC" and algType = "MAC"
or
name = "aes-192-cbc-hmac-sha256" and name = "aes-192-cbc-hmac-sha256" and
nid = 949 and nid = 949 and
normalized = "AES-192" and normalized = "AES-192" and
@@ -1187,6 +1288,8 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
or or
name = "aes-256-cbc-hmac-sha256" and nid = 950 and normalized = "SHA-256" and algType = "HASH" name = "aes-256-cbc-hmac-sha256" and nid = 950 and normalized = "SHA-256" and algType = "HASH"
or or
name = "aes-256-cbc-hmac-sha256" and nid = 950 and normalized = "HMAC" and algType = "MAC"
or
name = "aes-256-cbc-hmac-sha256" and name = "aes-256-cbc-hmac-sha256" and
nid = 950 and nid = 950 and
normalized = "AES-256" and normalized = "AES-256" and
@@ -1226,6 +1329,11 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
normalized = "CAMELLIA-128" and normalized = "CAMELLIA-128" and
algType = "SYMMETRIC_ENCRYPTION" algType = "SYMMETRIC_ENCRYPTION"
or or
name = "camellia-128-cmac" and
nid = 964 and
normalized = "CMAC" and
algType = "MAC"
or
name = "camellia-192-gcm" and name = "camellia-192-gcm" and
nid = 965 and nid = 965 and
normalized = "CAMELLIA-192" and normalized = "CAMELLIA-192" and
@@ -1278,6 +1386,11 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
normalized = "CAMELLIA-256" and normalized = "CAMELLIA-256" and
algType = "SYMMETRIC_ENCRYPTION" algType = "SYMMETRIC_ENCRYPTION"
or or
name = "camellia-256-cmac" and
nid = 972 and
normalized = "CMAC" and
algType = "MAC"
or
name = "id-scrypt" and nid = 973 and normalized = "SCRYPT" and algType = "KEY_DERIVATION" name = "id-scrypt" and nid = 973 and normalized = "SCRYPT" and algType = "KEY_DERIVATION"
or or
name = "gost89-cnt-12" and name = "gost89-cnt-12" and
@@ -1291,11 +1404,13 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
or or
name = "md_gost12_512" and nid = 983 and normalized = "GOST" and algType = "HASH" name = "md_gost12_512" and nid = 983 and normalized = "GOST" and algType = "HASH"
or or
// TODO: re-evaluate: this is a signing algorithm using hashing and curves
name = "id-tc26-signwithdigest-gost3410-2012-256" and name = "id-tc26-signwithdigest-gost3410-2012-256" and
nid = 985 and nid = 985 and
normalized = "GOST34102012" and normalized = "GOST34102012" and
algType = "SYMMETRIC_ENCRYPTION" algType = "SYMMETRIC_ENCRYPTION"
or or
// TODO: re-evaluate: this is a signing algorithm using hashing and curves
name = "id-tc26-signwithdigest-gost3410-2012-512" and name = "id-tc26-signwithdigest-gost3410-2012-512" and
nid = 986 and nid = 986 and
normalized = "GOST34102012" and normalized = "GOST34102012" and
@@ -1304,22 +1419,42 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
name = "id-tc26-hmac-gost-3411-2012-256" and name = "id-tc26-hmac-gost-3411-2012-256" and
nid = 988 and nid = 988 and
normalized = "GOST34112012" and normalized = "GOST34112012" and
algType = "SYMMETRIC_ENCRYPTION" algType = "HASH"
or
name = "id-tc26-hmac-gost-3411-2012-256" and
nid = 988 and
normalized = "HMAC" and
algType = "MAC"
or or
name = "id-tc26-hmac-gost-3411-2012-512" and name = "id-tc26-hmac-gost-3411-2012-512" and
nid = 989 and nid = 989 and
normalized = "GOST34112012" and normalized = "GOST34112012" and
algType = "SYMMETRIC_ENCRYPTION" algType = "HASH"
or
name = "id-tc26-hmac-gost-3411-2012-512" and
nid = 989 and
normalized = "HMAC" and
algType = "MAC"
or or
name = "id-tc26-agreement-gost-3410-2012-256" and name = "id-tc26-agreement-gost-3410-2012-256" and
nid = 992 and nid = 992 and
normalized = "GOST34102012" and normalized = "GOST34102012" and
algType = "SYMMETRIC_ENCRYPTION" algType = "ELLIPTIC_CURVE"
or
name = "id-tc26-agreement-gost-3410-2012-256" and
nid = 992 and
normalized = "GOST34102012" and
algType = "KEY_AGREEMENT"
or or
name = "id-tc26-agreement-gost-3410-2012-512" and name = "id-tc26-agreement-gost-3410-2012-512" and
nid = 993 and nid = 993 and
normalized = "GOST34102012" and normalized = "GOST34102012" and
algType = "SYMMETRIC_ENCRYPTION" algType = "ELLIPTIC_CURVE"
or
name = "id-tc26-agreement-gost-3410-2012-512" and
nid = 993 and
normalized = "GOST34102012" and
algType = "KEY_AGREEMENT"
or or
name = "id-tc26-gost-3410-2012-512-constants" and name = "id-tc26-gost-3410-2012-512-constants" and
nid = 996 and nid = 996 and
@@ -1407,12 +1542,20 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
or or
name = "hmac-sha3-224" and nid = 1102 and normalized = "SHA3-224" and algType = "HASH" name = "hmac-sha3-224" and nid = 1102 and normalized = "SHA3-224" and algType = "HASH"
or or
name = "hmac-sha3-224" and nid = 1102 and normalized = "HMAC" and algType = "MAC"
or
name = "hmac-sha3-256" and nid = 1103 and normalized = "SHA3-256" and algType = "HASH" name = "hmac-sha3-256" and nid = 1103 and normalized = "SHA3-256" and algType = "HASH"
or or
name = "hmac-sha3-256" and nid = 1103 and normalized = "HMAC" and algType = "MAC"
or
name = "hmac-sha3-384" and nid = 1104 and normalized = "SHA3-384" and algType = "HASH" name = "hmac-sha3-384" and nid = 1104 and normalized = "SHA3-384" and algType = "HASH"
or or
name = "hmac-sha3-384" and nid = 1104 and normalized = "HMAC" and algType = "MAC"
or
name = "hmac-sha3-512" and nid = 1105 and normalized = "SHA3-512" and algType = "HASH" name = "hmac-sha3-512" and nid = 1105 and normalized = "SHA3-512" and algType = "HASH"
or or
name = "hmac-sha3-512" and nid = 1105 and normalized = "HMAC" and algType = "MAC"
or
name = "id-dsa-with-sha384" and nid = 1106 and normalized = "DSA" and algType = "SIGNATURE" name = "id-dsa-with-sha384" and nid = 1106 and normalized = "DSA" and algType = "SIGNATURE"
or or
name = "id-dsa-with-sha384" and nid = 1106 and normalized = "SHA-384" and algType = "HASH" name = "id-dsa-with-sha384" and nid = 1106 and normalized = "SHA-384" and algType = "HASH"
@@ -2180,34 +2323,67 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
normalized = "GOST" and normalized = "GOST" and
algType = "SYMMETRIC_ENCRYPTION" algType = "SYMMETRIC_ENCRYPTION"
or or
name = "hmac gost 34.11-2012 256 bit" and
nid = 988 and
normalized = "HMAC" and
algType = "MAC"
or
name = "hmac gost 34.11-2012 512 bit" and name = "hmac gost 34.11-2012 512 bit" and
nid = 989 and nid = 989 and
normalized = "GOST" and normalized = "GOST" and
algType = "SYMMETRIC_ENCRYPTION" algType = "SYMMETRIC_ENCRYPTION"
or or
name = "hmac gost 34.11-2012 512 bit" and
nid = 989 and
normalized = "HMAC" and
algType = "MAC"
or
name = "hmac gost 34.11-94" and name = "hmac gost 34.11-94" and
nid = 810 and nid = 810 and
normalized = "GOST" and normalized = "GOST" and
algType = "SYMMETRIC_ENCRYPTION" algType = "SYMMETRIC_ENCRYPTION"
or or
name = "hmac gost 34.11-94" and
nid = 810 and
normalized = "HMAC" and
algType = "MAC"
or
name = "hmacwithmd5" and nid = 797 and normalized = "MD5" and algType = "HASH" name = "hmacwithmd5" and nid = 797 and normalized = "MD5" and algType = "HASH"
or or
name = "hmacwithmd5" and nid = 797 and normalized = "HMAC" and algType = "MAC"
or
name = "hmacwithsha1" and nid = 163 and normalized = "SHA1" and algType = "HASH" name = "hmacwithsha1" and nid = 163 and normalized = "SHA1" and algType = "HASH"
or or
name = "hmacwithsha1" and nid = 163 and normalized = "HMAC" and algType = "MAC"
or
name = "hmacwithsha224" and nid = 798 and normalized = "SHA-224" and algType = "HASH" name = "hmacwithsha224" and nid = 798 and normalized = "SHA-224" and algType = "HASH"
or or
name = "hmacwithsha224" and nid = 798 and normalized = "HMAC" and algType = "MAC"
or
name = "hmacwithsha256" and nid = 799 and normalized = "SHA-256" and algType = "HASH" name = "hmacwithsha256" and nid = 799 and normalized = "SHA-256" and algType = "HASH"
or or
name = "hmacwithsha256" and nid = 799 and normalized = "HMAC" and algType = "MAC"
or
name = "hmacwithsha384" and nid = 800 and normalized = "SHA-384" and algType = "HASH" name = "hmacwithsha384" and nid = 800 and normalized = "SHA-384" and algType = "HASH"
or or
name = "hmacwithsha384" and nid = 800 and normalized = "HMAC" and algType = "MAC"
or
name = "hmacwithsha512" and nid = 801 and normalized = "SHA-512" and algType = "HASH" name = "hmacwithsha512" and nid = 801 and normalized = "SHA-512" and algType = "HASH"
or or
name = "hmacwithsha512" and nid = 801 and normalized = "HMAC" and algType = "MAC"
or
name = "hmacwithsha512-224" and nid = 1193 and normalized = "SHA-512-224" and algType = "HASH" name = "hmacwithsha512-224" and nid = 1193 and normalized = "SHA-512-224" and algType = "HASH"
or or
name = "hmacwithsha512-224" and nid = 1193 and normalized = "HMAC" and algType = "MAC"
or
name = "hmacwithsha512-256" and nid = 1194 and normalized = "SHA-512-256" and algType = "HASH" name = "hmacwithsha512-256" and nid = 1194 and normalized = "SHA-512-256" and algType = "HASH"
or or
name = "hmacwithsha512-256" and nid = 1194 and normalized = "HMAC" and algType = "MAC"
or
name = "hmacwithsm3" and nid = 1281 and normalized = "SM3" and algType = "HASH" name = "hmacwithsm3" and nid = 1281 and normalized = "SM3" and algType = "HASH"
or or
name = "hmacwithsm3" and nid = 1281 and normalized = "HMAC" and algType = "MAC"
or
name = "id-aes128-ccm" and name = "id-aes128-ccm" and
nid = 896 and nid = 896 and
normalized = "AES-128" and normalized = "AES-128" and
@@ -2457,12 +2633,20 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
or or
name = "id-hmacwithsha3-224" and nid = 1102 and normalized = "SHA3-224" and algType = "HASH" name = "id-hmacwithsha3-224" and nid = 1102 and normalized = "SHA3-224" and algType = "HASH"
or or
name = "id-hmacwithsha3-224" and nid = 1102 and normalized = "HMAC" and algType = "MAC"
or
name = "id-hmacwithsha3-256" and nid = 1103 and normalized = "SHA3-256" and algType = "HASH" name = "id-hmacwithsha3-256" and nid = 1103 and normalized = "SHA3-256" and algType = "HASH"
or or
name = "id-hmacwithsha3-256" and nid = 1103 and normalized = "HMAC" and algType = "MAC"
or
name = "id-hmacwithsha3-384" and nid = 1104 and normalized = "SHA3-384" and algType = "HASH" name = "id-hmacwithsha3-384" and nid = 1104 and normalized = "SHA3-384" and algType = "HASH"
or or
name = "id-hmacwithsha3-384" and nid = 1104 and normalized = "HMAC" and algType = "MAC"
or
name = "id-hmacwithsha3-512" and nid = 1105 and normalized = "SHA3-512" and algType = "HASH" name = "id-hmacwithsha3-512" and nid = 1105 and normalized = "SHA3-512" and algType = "HASH"
or or
name = "id-hmacwithsha3-512" and nid = 1105 and normalized = "HMAC" and algType = "MAC"
or
name = "id-regctrl" and nid = 313 and normalized = "CTR" and algType = "BLOCK_MODE" name = "id-regctrl" and nid = 313 and normalized = "CTR" and algType = "BLOCK_MODE"
or or
name = "id-smime-alg-3deswrap" and name = "id-smime-alg-3deswrap" and
@@ -2818,93 +3002,93 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
name = "ripemd160withrsa" and name = "ripemd160withrsa" and
nid = 119 and nid = 119 and
normalized = "RSA" and normalized = "RSA" and
algType = "ASYMMETRIC_ENCRYPTION" algType = "SIGNATURE"
or or
name = "ripemd160withrsa" and nid = 119 and normalized = "RIPEMD160" and algType = "HASH" name = "ripemd160withrsa" and nid = 119 and normalized = "RIPEMD160" and algType = "HASH"
or or
name = "rsa-md2" and nid = 7 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-md2" and nid = 7 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-md2" and nid = 7 and normalized = "MD2" and algType = "HASH" name = "rsa-md2" and nid = 7 and normalized = "MD2" and algType = "HASH"
or or
name = "rsa-md4" and nid = 396 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-md4" and nid = 396 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-md4" and nid = 396 and normalized = "MD4" and algType = "HASH" name = "rsa-md4" and nid = 396 and normalized = "MD4" and algType = "HASH"
or or
name = "rsa-md5" and nid = 8 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-md5" and nid = 8 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-md5" and nid = 8 and normalized = "MD5" and algType = "HASH" name = "rsa-md5" and nid = 8 and normalized = "MD5" and algType = "HASH"
or or
name = "rsa-mdc2" and nid = 96 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-mdc2" and nid = 96 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-mdc2" and nid = 96 and normalized = "MDC2" and algType = "HASH" name = "rsa-mdc2" and nid = 96 and normalized = "MDC2" and algType = "HASH"
or or
name = "rsa-np-md5" and nid = 104 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-np-md5" and nid = 104 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-np-md5" and nid = 104 and normalized = "MD5" and algType = "HASH" name = "rsa-np-md5" and nid = 104 and normalized = "MD5" and algType = "HASH"
or or
name = "rsa-ripemd160" and nid = 119 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-ripemd160" and nid = 119 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-ripemd160" and nid = 119 and normalized = "RIPEMD160" and algType = "HASH" name = "rsa-ripemd160" and nid = 119 and normalized = "RIPEMD160" and algType = "HASH"
or or
name = "rsa-sha" and nid = 42 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-sha" and nid = 42 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-sha" and nid = 42 and normalized = "SHA" and algType = "HASH" name = "rsa-sha" and nid = 42 and normalized = "SHA" and algType = "HASH"
or or
name = "rsa-sha1" and nid = 65 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-sha1" and nid = 65 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-sha1" and nid = 65 and normalized = "SHA1" and algType = "HASH" name = "rsa-sha1" and nid = 65 and normalized = "SHA1" and algType = "HASH"
or or
name = "rsa-sha1-2" and nid = 115 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-sha1-2" and nid = 115 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-sha1-2" and nid = 115 and normalized = "SHA1" and algType = "HASH" name = "rsa-sha1-2" and nid = 115 and normalized = "SHA1" and algType = "HASH"
or or
name = "rsa-sha224" and nid = 671 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-sha224" and nid = 671 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-sha224" and nid = 671 and normalized = "SHA-224" and algType = "HASH" name = "rsa-sha224" and nid = 671 and normalized = "SHA-224" and algType = "HASH"
or or
name = "rsa-sha256" and nid = 668 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-sha256" and nid = 668 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-sha256" and nid = 668 and normalized = "SHA-256" and algType = "HASH" name = "rsa-sha256" and nid = 668 and normalized = "SHA-256" and algType = "HASH"
or or
name = "rsa-sha3-224" and nid = 1116 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-sha3-224" and nid = 1116 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-sha3-224" and nid = 1116 and normalized = "SHA3-224" and algType = "HASH" name = "rsa-sha3-224" and nid = 1116 and normalized = "SHA3-224" and algType = "HASH"
or or
name = "rsa-sha3-256" and nid = 1117 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-sha3-256" and nid = 1117 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-sha3-256" and nid = 1117 and normalized = "SHA3-256" and algType = "HASH" name = "rsa-sha3-256" and nid = 1117 and normalized = "SHA3-256" and algType = "HASH"
or or
name = "rsa-sha3-384" and nid = 1118 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-sha3-384" and nid = 1118 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-sha3-384" and nid = 1118 and normalized = "SHA3-384" and algType = "HASH" name = "rsa-sha3-384" and nid = 1118 and normalized = "SHA3-384" and algType = "HASH"
or or
name = "rsa-sha3-512" and nid = 1119 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-sha3-512" and nid = 1119 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-sha3-512" and nid = 1119 and normalized = "SHA3-512" and algType = "HASH" name = "rsa-sha3-512" and nid = 1119 and normalized = "SHA3-512" and algType = "HASH"
or or
name = "rsa-sha384" and nid = 669 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-sha384" and nid = 669 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-sha384" and nid = 669 and normalized = "SHA-384" and algType = "HASH" name = "rsa-sha384" and nid = 669 and normalized = "SHA-384" and algType = "HASH"
or or
name = "rsa-sha512" and nid = 670 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-sha512" and nid = 670 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-sha512" and nid = 670 and normalized = "SHA-512" and algType = "HASH" name = "rsa-sha512" and nid = 670 and normalized = "SHA-512" and algType = "HASH"
or or
name = "rsa-sha512/224" and name = "rsa-sha512/224" and
nid = 1145 and nid = 1145 and
normalized = "RSA" and normalized = "RSA" and
algType = "ASYMMETRIC_ENCRYPTION" algType = "SIGNATURE"
or or
name = "rsa-sha512/224" and nid = 1145 and normalized = "SHA-512-224" and algType = "HASH" name = "rsa-sha512/224" and nid = 1145 and normalized = "SHA-512-224" and algType = "HASH"
or or
name = "rsa-sha512/256" and name = "rsa-sha512/256" and
nid = 1146 and nid = 1146 and
normalized = "RSA" and normalized = "RSA" and
algType = "ASYMMETRIC_ENCRYPTION" algType = "SIGNATURE"
or or
name = "rsa-sha512/256" and nid = 1146 and normalized = "SHA-512-256" and algType = "HASH" name = "rsa-sha512/256" and nid = 1146 and normalized = "SHA-512-256" and algType = "HASH"
or or
name = "rsa-sm3" and nid = 1144 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsa-sm3" and nid = 1144 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsa-sm3" and nid = 1144 and normalized = "SM3" and algType = "HASH" name = "rsa-sm3" and nid = 1144 and normalized = "SM3" and algType = "HASH"
or or
@@ -2928,52 +3112,52 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
normalized = "OAEP" and normalized = "OAEP" and
algType = "ASYMMETRIC_PADDING" algType = "ASYMMETRIC_PADDING"
or or
name = "rsasignature" and nid = 377 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsasignature" and nid = 377 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsassa-pss" and nid = 912 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsassa-pss" and nid = 912 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsassa-pss" and nid = 912 and normalized = "PSS" and algType = "ASYMMETRIC_PADDING" name = "rsassa-pss" and nid = 912 and normalized = "PSS" and algType = "ASYMMETRIC_PADDING"
or or
name = "rsassapss" and nid = 912 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "rsassapss" and nid = 912 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "rsassapss" and nid = 912 and normalized = "PSS" and algType = "ASYMMETRIC_PADDING" name = "rsassapss" and nid = 912 and normalized = "PSS" and algType = "SIGNATURE"
or or
name = "sha1withrsa" and nid = 115 and normalized = "RSA" and algType = "ASYMMETRIC_ENCRYPTION" name = "sha1withrsa" and nid = 115 and normalized = "RSA" and algType = "SIGNATURE"
or or
name = "sha1withrsa" and nid = 115 and normalized = "SHA1" and algType = "HASH" name = "sha1withrsa" and nid = 115 and normalized = "SHA1" and algType = "HASH"
or or
name = "sha1withrsaencryption" and name = "sha1withrsaencryption" and
nid = 65 and nid = 65 and
normalized = "RSA" and normalized = "RSA" and
algType = "ASYMMETRIC_ENCRYPTION" algType = "SIGNATURE"
or or
name = "sha1withrsaencryption" and nid = 65 and normalized = "SHA1" and algType = "HASH" name = "sha1withrsaencryption" and nid = 65 and normalized = "SHA1" and algType = "HASH"
or or
name = "sha224withrsaencryption" and name = "sha224withrsaencryption" and
nid = 671 and nid = 671 and
normalized = "RSA" and normalized = "RSA" and
algType = "ASYMMETRIC_ENCRYPTION" algType = "SIGNATURE"
or or
name = "sha224withrsaencryption" and nid = 671 and normalized = "SHA-224" and algType = "HASH" name = "sha224withrsaencryption" and nid = 671 and normalized = "SHA-224" and algType = "HASH"
or or
name = "sha256withrsaencryption" and name = "sha256withrsaencryption" and
nid = 668 and nid = 668 and
normalized = "RSA" and normalized = "RSA" and
algType = "ASYMMETRIC_ENCRYPTION" algType = "SIGNATURE"
or or
name = "sha256withrsaencryption" and nid = 668 and normalized = "SHA-256" and algType = "HASH" name = "sha256withrsaencryption" and nid = 668 and normalized = "SHA-256" and algType = "HASH"
or or
name = "sha384withrsaencryption" and name = "sha384withrsaencryption" and
nid = 669 and nid = 669 and
normalized = "RSA" and normalized = "RSA" and
algType = "ASYMMETRIC_ENCRYPTION" algType = "SIGNATURE"
or or
name = "sha384withrsaencryption" and nid = 669 and normalized = "SHA-384" and algType = "HASH" name = "sha384withrsaencryption" and nid = 669 and normalized = "SHA-384" and algType = "HASH"
or or
name = "sha512-224withrsaencryption" and name = "sha512-224withrsaencryption" and
nid = 1145 and nid = 1145 and
normalized = "RSA" and normalized = "RSA" and
algType = "ASYMMETRIC_ENCRYPTION" algType = "SIGNATURE"
or or
name = "sha512-224withrsaencryption" and name = "sha512-224withrsaencryption" and
nid = 1145 and nid = 1145 and
@@ -2983,7 +3167,7 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
name = "sha512-256withrsaencryption" and name = "sha512-256withrsaencryption" and
nid = 1146 and nid = 1146 and
normalized = "RSA" and normalized = "RSA" and
algType = "ASYMMETRIC_ENCRYPTION" algType = "SIGNATURE"
or or
name = "sha512-256withrsaencryption" and name = "sha512-256withrsaencryption" and
nid = 1146 and nid = 1146 and
@@ -2993,14 +3177,14 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
name = "sha512withrsaencryption" and name = "sha512withrsaencryption" and
nid = 670 and nid = 670 and
normalized = "RSA" and normalized = "RSA" and
algType = "ASYMMETRIC_ENCRYPTION" algType = "SIGNATURE"
or or
name = "sha512withrsaencryption" and nid = 670 and normalized = "SHA-512" and algType = "HASH" name = "sha512withrsaencryption" and nid = 670 and normalized = "SHA-512" and algType = "HASH"
or or
name = "shawithrsaencryption" and name = "shawithrsaencryption" and
nid = 42 and nid = 42 and
normalized = "RSA" and normalized = "RSA" and
algType = "ASYMMETRIC_ENCRYPTION" algType = "SIGNATURE"
or or
name = "shawithrsaencryption" and nid = 42 and normalized = "SHA" and algType = "HASH" name = "shawithrsaencryption" and nid = 42 and normalized = "SHA" and algType = "HASH"
or or
@@ -3017,7 +3201,11 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
name = "sm3withrsaencryption" and name = "sm3withrsaencryption" and
nid = 1144 and nid = 1144 and
normalized = "RSA" and normalized = "RSA" and
algType = "ASYMMETRIC_ENCRYPTION" algType = "SIGNATURE"
or or
name = "sm3withrsaencryption" and nid = 1144 and normalized = "SM3" and algType = "HASH" name = "sm3withrsaencryption" and nid = 1144 and normalized = "SM3" and algType = "HASH"
or
name = "hmac" and nid = 855 and normalized = "HMAC" and algType = "MAC"
or
name = "cmac" and nid = 894 and normalized = "CMAC" and algType = "MAC"
} }

View File

@@ -0,0 +1,68 @@
import cpp
private import experimental.quantum.Language
private import KnownAlgorithmConstants
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
private import AlgToAVCFlow
class KnownOpenSslMacConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
Crypto::MacAlgorithmInstance instanceof KnownOpenSslMacAlgorithmExpr
{
OpenSslAlgorithmValueConsumer getterCall;
KnownOpenSslMacConstantAlgorithmInstance() {
// Two possibilities:
// 1) The source is a literal and flows to a getter, then we know we have an instance
// 2) The source is a KnownOpenSslAlgorithm is call, and we know we have an instance immediately from that
// Possibility 1:
this instanceof OpenSslAlgorithmLiteral and
exists(DataFlow::Node src, DataFlow::Node sink |
// Sink is an argument to a CipherGetterCall
sink = getterCall.getInputNode() and
// Source is `this`
src.asExpr() = this and
// This traces to a getter
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
)
or
// Possibility 2:
this instanceof OpenSslAlgorithmCall and
getterCall = this
}
override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
override string getRawMacAlgorithmName() {
result = this.(Literal).getValue().toString()
or
result = this.(Call).getTarget().getName()
}
override Crypto::MacType getMacType() {
this instanceof KnownOpenSslHMacAlgorithmExpr and result = Crypto::HMAC()
or
this instanceof KnownOpenSslCMacAlgorithmExpr and result = Crypto::CMAC()
}
}
class KnownOpenSslHMacConstantAlgorithmInstance extends Crypto::HmacAlgorithmInstance,
KnownOpenSslMacConstantAlgorithmInstance
{
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
if exists(this.(KnownOpenSslHMacAlgorithmExpr).getExplicitHashAlgorithm())
then
// ASSUMPTION: if there is an explicit hash algorithm, it is already modeled
// and we can simply grab that model's AVC
this.(OpenSslAlgorithmInstance).getAvc() = result
else
// ASSUMPTION: If no explicit algorithm is given, then find
// where the current AVC traces to a HashAlgorithmIO consuming operation step.
// TODO: need to consider getting reset values, tracing down to the first set for now
exists(OperationStep s, AvcContextCreationStep avc |
avc = this.getAvc() and
avc.flowsToOperationStep(s) and
s.getAlgorithmValueConsumerForInput(HashAlgorithmIO()) = result
)
}
}

View File

@@ -1,6 +1,6 @@
private import experimental.quantum.Language private import experimental.quantum.Language
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
abstract class OpenSSLAlgorithmInstance extends Crypto::AlgorithmInstance { abstract class OpenSslAlgorithmInstance extends Crypto::AlgorithmInstance {
abstract OpenSSLAlgorithmValueConsumer getAVC(); abstract OpenSslAlgorithmValueConsumer getAvc();
} }

View File

@@ -4,3 +4,5 @@ import PaddingAlgorithmInstance
import BlockAlgorithmInstance import BlockAlgorithmInstance
import HashAlgorithmInstance import HashAlgorithmInstance
import EllipticCurveAlgorithmInstance import EllipticCurveAlgorithmInstance
import SignatureAlgorithmInstance
import MACAlgorithmInstance

View File

@@ -5,6 +5,7 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
private import AlgToAVCFlow private import AlgToAVCFlow
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
private import codeql.quantum.experimental.Standardization::Types::KeyOpAlg as KeyOpAlg
/** /**
* A class to define padding specific integer values. * A class to define padding specific integer values.
@@ -17,75 +18,75 @@ private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgor
* # define RSA_PKCS1_WITH_TLS_PADDING 7 * # define RSA_PKCS1_WITH_TLS_PADDING 7
* # define RSA_PKCS1_NO_IMPLICIT_REJECT_PADDING 8 * # define RSA_PKCS1_NO_IMPLICIT_REJECT_PADDING 8
*/ */
class OpenSSLPaddingLiteral extends Literal { class OpenSslPaddingLiteral extends Literal {
// TODO: we can be more specific about where the literal is in a larger expression // TODO: we can be more specific about where the literal is in a larger expression
// to avoid literals that are clealy not representing an algorithm, e.g., array indices. // to avoid literals that are clealy not representing an algorithm, e.g., array indices.
OpenSSLPaddingLiteral() { this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8] } OpenSslPaddingLiteral() { this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8] }
} }
/** /**
* Given a `KnownOpenSSLPaddingAlgorithmConstant`, converts this to a padding family type. * Given a `KnownOpenSslPaddingAlgorithmExpr`, converts this to a padding family type.
* Does not bind if there is no mapping (no mapping to 'unknown' or 'other'). * Does not bind if there is no mapping (no mapping to 'unknown' or 'other').
*/ */
predicate knownOpenSSLConstantToPaddingFamilyType( predicate knownOpenSslConstantToPaddingFamilyType(
KnownOpenSSLPaddingAlgorithmConstant e, Crypto::TPaddingType type KnownOpenSslPaddingAlgorithmExpr e, KeyOpAlg::PaddingSchemeType type
) { ) {
exists(string name | exists(string name |
name = e.getNormalizedName() and name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
( (
name.matches("OAEP") and type = Crypto::OAEP() name = "OAEP" and type = KeyOpAlg::OAEP()
or or
name.matches("PSS") and type = Crypto::PSS() name = "PSS" and type = KeyOpAlg::PSS()
or or
name.matches("PKCS7") and type = Crypto::PKCS7() name = "PKCS7" and type = KeyOpAlg::PKCS7()
or or
name.matches("PKCS1V15") and type = Crypto::PKCS1_v1_5() name = "PKCS1V15" and type = KeyOpAlg::PKCS1_V1_5()
) )
) )
} }
//abstract class OpenSSLPaddingAlgorithmInstance extends OpenSSLAlgorithmInstance, Crypto::PaddingAlgorithmInstance{} //abstract class OpenSslPaddingAlgorithmInstance extends OpenSslAlgorithmInstance, Crypto::PaddingAlgorithmInstance{}
// TODO: need to alter this to include known padding constants which don't have the // TODO: need to alter this to include known padding constants which don't have the
// same mechanics as those with known nids // same mechanics as those with known nids
class KnownOpenSSLPaddingConstantAlgorithmInstance extends OpenSSLAlgorithmInstance, class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
Crypto::PaddingAlgorithmInstance instanceof Expr Crypto::PaddingAlgorithmInstance instanceof Expr
{ {
OpenSSLAlgorithmValueConsumer getterCall; OpenSslAlgorithmValueConsumer getterCall;
boolean isPaddingSpecificConsumer; boolean isPaddingSpecificConsumer;
KnownOpenSSLPaddingConstantAlgorithmInstance() { KnownOpenSslPaddingConstantAlgorithmInstance() {
// three possibilities: // three possibilities:
// 1) The source is a 'typical' literal and flows to a getter, then we know we have an instance // 1) The source is a 'typical' literal and flows to a getter, then we know we have an instance
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that // 2) The source is a KnownOpenSslAlgorithm is call, and we know we have an instance immediately from that
// 3) the source is a padding-specific literal flowing to a padding-specific consumer // 3) the source is a padding-specific literal flowing to a padding-specific consumer
// Possibility 1: // Possibility 1:
this instanceof Literal and this instanceof OpenSslAlgorithmLiteral and
this instanceof KnownOpenSSLPaddingAlgorithmConstant and this instanceof KnownOpenSslPaddingAlgorithmExpr and
exists(DataFlow::Node src, DataFlow::Node sink | exists(DataFlow::Node src, DataFlow::Node sink |
// Sink is an argument to a CipherGetterCall // Sink is an argument to a CipherGetterCall
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and sink = getterCall.getInputNode() and
// Source is `this` // Source is `this`
src.asExpr() = this and src.asExpr() = this and
// This traces to a getter // This traces to a getter
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink) and KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink) and
isPaddingSpecificConsumer = false isPaddingSpecificConsumer = false
) )
or or
// Possibility 2: // Possibility 2:
this instanceof DirectAlgorithmValueConsumer and this instanceof OpenSslAlgorithmCall and
getterCall = this and getterCall = this and
this instanceof KnownOpenSSLPaddingAlgorithmConstant and this instanceof KnownOpenSslPaddingAlgorithmExpr and
isPaddingSpecificConsumer = false isPaddingSpecificConsumer = false
or or
// Possibility 3: padding-specific literal // Possibility 3: padding-specific literal
this instanceof OpenSSLPaddingLiteral and this instanceof OpenSslPaddingLiteral and
exists(DataFlow::Node src, DataFlow::Node sink | exists(DataFlow::Node src, DataFlow::Node sink |
// Sink is an argument to a CipherGetterCall // Sink is an argument to a CipherGetterCall
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and sink = getterCall.getInputNode() and
// Source is `this` // Source is `this`
src.asExpr() = this and src.asExpr() = this and
// This traces to a padding-specific consumer // This traces to a padding-specific consumer
RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow::flow(src, sink) RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow::flow(src, sink)
) and ) and
isPaddingSpecificConsumer = true isPaddingSpecificConsumer = true
} }
@@ -96,30 +97,30 @@ class KnownOpenSSLPaddingConstantAlgorithmInstance extends OpenSSLAlgorithmInsta
result = this.(Call).getTarget().getName() result = this.(Call).getTarget().getName()
} }
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall } override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
Crypto::TPaddingType getKnownPaddingType() { KeyOpAlg::PaddingSchemeType getKnownPaddingType() {
this.(Literal).getValue().toInt() in [1, 7, 8] and result = Crypto::PKCS1_v1_5() this.(Literal).getValue().toInt() in [1, 7, 8] and result = KeyOpAlg::PKCS1_V1_5()
or or
this.(Literal).getValue().toInt() = 3 and result = Crypto::NoPadding() this.(Literal).getValue().toInt() = 3 and result = KeyOpAlg::NoPadding()
or or
this.(Literal).getValue().toInt() = 4 and result = Crypto::OAEP() this.(Literal).getValue().toInt() = 4 and result = KeyOpAlg::OAEP()
or or
this.(Literal).getValue().toInt() = 5 and result = Crypto::ANSI_X9_23() this.(Literal).getValue().toInt() = 5 and result = KeyOpAlg::ANSI_X9_23()
or or
this.(Literal).getValue().toInt() = 6 and result = Crypto::PSS() this.(Literal).getValue().toInt() = 6 and result = KeyOpAlg::PSS()
} }
override Crypto::TPaddingType getPaddingType() { override KeyOpAlg::PaddingSchemeType getPaddingType() {
isPaddingSpecificConsumer = true and isPaddingSpecificConsumer = true and
( (
result = this.getKnownPaddingType() result = this.getKnownPaddingType()
or or
not exists(this.getKnownPaddingType()) and result = Crypto::OtherPadding() not exists(this.getKnownPaddingType()) and result = KeyOpAlg::OtherPadding()
) )
or or
isPaddingSpecificConsumer = false and isPaddingSpecificConsumer = false and
knownOpenSSLConstantToPaddingFamilyType(this, result) knownOpenSslConstantToPaddingFamilyType(this, result)
} }
} }
@@ -127,7 +128,7 @@ class KnownOpenSSLPaddingConstantAlgorithmInstance extends OpenSSLAlgorithmInsta
// // not the same as 'typical' constants found in the set of known algorithm constants // // not the same as 'typical' constants found in the set of known algorithm constants
// // they do not have an NID // // they do not have an NID
// // TODO: what about setting the padding directly? // // TODO: what about setting the padding directly?
// class KnownRSAPaddingConstant extends OpenSSLPaddingAlgorithmInstance, Crypto::PaddingAlgorithmInstance instanceof Literal // class KnownRSAPaddingConstant extends OpenSslPaddingAlgorithmInstance, Crypto::PaddingAlgorithmInstance instanceof Literal
// { // {
// KnownRSAPaddingConstant() { // KnownRSAPaddingConstant() {
// // from rsa.h in openssl: // // from rsa.h in openssl:
@@ -143,7 +144,7 @@ class KnownOpenSSLPaddingConstantAlgorithmInstance extends OpenSSLAlgorithmInsta
// this instanceof Literal and // this instanceof Literal and
// this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8] // this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8]
// // TODO: trace to padding-specific consumers // // TODO: trace to padding-specific consumers
// RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow // RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow
// } // }
// override string getRawPaddingAlgorithmName() { result = this.(Literal).getValue().toString() } // override string getRawPaddingAlgorithmName() { result = this.(Literal).getValue().toString() }
// override Crypto::TPaddingType getPaddingType() { // override Crypto::TPaddingType getPaddingType() {
@@ -161,18 +162,18 @@ class KnownOpenSSLPaddingConstantAlgorithmInstance extends OpenSSLAlgorithmInsta
// else result = Crypto::OtherPadding() // else result = Crypto::OtherPadding()
// } // }
// } // }
class OAEPPaddingAlgorithmInstance extends Crypto::OAEPPaddingAlgorithmInstance, class OaepPaddingAlgorithmInstance extends Crypto::OaepPaddingAlgorithmInstance,
KnownOpenSSLPaddingConstantAlgorithmInstance KnownOpenSslPaddingConstantAlgorithmInstance
{ {
OAEPPaddingAlgorithmInstance() { OaepPaddingAlgorithmInstance() {
this.(Crypto::PaddingAlgorithmInstance).getPaddingType() = Crypto::OAEP() this.(Crypto::PaddingAlgorithmInstance).getPaddingType() = KeyOpAlg::OAEP()
} }
override Crypto::HashAlgorithmInstance getOAEPEncodingHashAlgorithm() { override Crypto::HashAlgorithmInstance getOaepEncodingHashAlgorithm() {
none() //TODO none() //TODO
} }
override Crypto::HashAlgorithmInstance getMGF1HashAlgorithm() { override Crypto::HashAlgorithmInstance getMgf1HashAlgorithm() {
none() //TODO none() //TODO
} }
} }

View File

@@ -0,0 +1,102 @@
import cpp
private import experimental.quantum.Language
private import KnownAlgorithmConstants
private import Crypto::KeyOpAlg as KeyOpAlg
private import OpenSSLAlgorithmInstanceBase
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
private import AlgToAVCFlow
/**
* Gets the signature algorithm type based on the normalized algorithm name.
*/
private predicate knownOpenSslConstantToSignatureFamilyType(
KnownOpenSslSignatureAlgorithmExpr e, Crypto::KeyOpAlg::TAlgorithm type
) {
exists(string name |
name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
(
name.matches("RSA%") and type = KeyOpAlg::TAsymmetricCipher(KeyOpAlg::RSA())
or
name.matches("DSA%") and type = KeyOpAlg::TSignature(KeyOpAlg::DSA())
or
name.matches("ECDSA%") and type = KeyOpAlg::TSignature(KeyOpAlg::ECDSA())
or
name.matches("ED25519%") and type = KeyOpAlg::TSignature(KeyOpAlg::EDDSA())
or
name.matches("ED448%") and type = KeyOpAlg::TSignature(KeyOpAlg::EDDSA())
)
)
}
/**
* A signature algorithm instance derived from an OpenSsl constant.
*/
class KnownOpenSslSignatureConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
Crypto::KeyOperationAlgorithmInstance instanceof KnownOpenSslSignatureAlgorithmExpr
{
OpenSslAlgorithmValueConsumer getterCall;
KnownOpenSslSignatureConstantAlgorithmInstance() {
// Two possibilities:
// 1) The source is a literal and flows to a getter, then we know we have an instance
// 2) The source is a KnownOpenSslAlgorithm call, and we know we have an instance immediately from that
// Possibility 1:
this instanceof OpenSslAlgorithmLiteral and
exists(DataFlow::Node src, DataFlow::Node sink |
// Sink is an argument to a signature getter call
sink = getterCall.getInputNode() and
// Source is `this`
src.asExpr() = this and
// This traces to a getter
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
)
or
// Possibility 2:
this instanceof OpenSslAlgorithmCall and
getterCall = this
}
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() { none() }
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() { none() }
override string getRawAlgorithmName() {
result = this.(Literal).getValue().toString()
or
result = this.(Call).getTarget().getName()
}
override int getKeySizeFixed() {
// TODO: use ellipticCurveNameToKeySizeAndFamilyMapping or KnownOpenSslEllipticCurveConstantAlgorithmInstance
// TODO: maybe add getExplicitKeySize to KnownOpenSslSignatureAlgorithmExpr and use it here
none()
}
override KeyOpAlg::AlgorithmType getAlgorithmType() {
knownOpenSslConstantToSignatureFamilyType(this, result)
or
not knownOpenSslConstantToSignatureFamilyType(this, _) and
result = KeyOpAlg::TSignature(KeyOpAlg::OtherSignatureAlgorithmType())
}
override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
// TODO: trace to any key size initializer
// probably PKeyAlgorithmValueConsumer and SignatureAlgorithmValueConsumer
none()
}
/**
* No mode for signatures.
*/
override predicate shouldHaveModeOfOperation() { none() }
/**
* Padding only for RSA.
*/
override predicate shouldHavePaddingScheme() {
this.getAlgorithmType() instanceof KeyOpAlg::TAsymmetricCipher
}
}

View File

@@ -4,14 +4,14 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
private import OpenSSLAlgorithmValueConsumerBase private import OpenSSLAlgorithmValueConsumerBase
abstract class CipherAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { } abstract class CipherAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer { }
// https://www.openssl.org/docs/manmaster/man3/EVP_CIPHER_fetch.html // https://www.openssl.org/docs/manmaster/man3/EVP_CIPHER_fetch.html
class EVPCipherAlgorithmValueConsumer extends CipherAlgorithmValueConsumer { class EvpCipherAlgorithmValueConsumer extends CipherAlgorithmValueConsumer {
DataFlow::Node valueArgNode; DataFlow::Node valueArgNode;
DataFlow::Node resultNode; DataFlow::Node resultNode;
EVPCipherAlgorithmValueConsumer() { EvpCipherAlgorithmValueConsumer() {
resultNode.asExpr() = this and resultNode.asExpr() = this and
( (
this.(Call).getTarget().getName() in [ this.(Call).getTarget().getName() in [
@@ -30,8 +30,8 @@ class EVPCipherAlgorithmValueConsumer extends CipherAlgorithmValueConsumer {
// override DataFlow::Node getInputNode() { result = valueArgNode } // override DataFlow::Node getInputNode() { result = valueArgNode }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() { override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i) exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
//TODO: As a potential alternative, for OpenSSL only, add a generic source node for literals and only create flow (flowsTo) to //TODO: As a potential alternative, for OpenSsl only, add a generic source node for literals and only create flow (flowsTo) to
// OpenSSL AVCs... the unknown literal sources would have to be any literals not in the known set. // OpenSsl AVCs... the unknown literal sources would have to be any literals not in the known set.
} }
} }

View File

@@ -4,29 +4,30 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
/** /**
* Cases like EVP_MD5(), * A call that is considered to inherently 'consume' an algorithm value.
* there is no input, rather it directly gets an algorithm * E.g., cases like EVP_MD5(),
* and returns it. * where there is no input, rather it directly gets an algorithm
* and returns it. Also includes operations directly using an algorithm
* like AES_encrypt().
*/ */
class DirectAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { class DirectAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer instanceof OpenSslAlgorithmCall
DataFlow::Node resultNode; {
Expr resultExpr;
DirectAlgorithmValueConsumer() {
this instanceof KnownOpenSSLAlgorithmConstant and
this instanceof Call and
resultExpr = this and
resultNode.asExpr() = resultExpr
}
/** /**
* These cases take in no explicit value (the value is implicit) * These cases take in no explicit value (the value is implicit)
*/ */
override Crypto::ConsumerInputDataFlowNode getInputNode() { none() } override Crypto::ConsumerInputDataFlowNode getInputNode() { none() }
override DataFlow::Node getResultNode() { result = resultNode } /**
* Gets the DataFlow node represeting the output algorithm entity
* created as a result of this call.
*/
override DataFlow::Node getResultNode() {
this instanceof OpenSslDirectAlgorithmFetchCall and
result.asExpr() = this
// NOTE: if instanceof OpenSslDirectAlgorithmOperationCall then there is no algorithm generated
// the algorithm is directly used
}
// override DataFlow::Node getOutputNode() { result = resultNode }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() { override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
// Note: algorithm source definitions enforces that // Note: algorithm source definitions enforces that
// this class will be a known algorithm source // this class will be a known algorithm source

View File

@@ -4,14 +4,14 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
abstract class EllipticCurveValueConsumer extends OpenSSLAlgorithmValueConsumer { } abstract class EllipticCurveValueConsumer extends OpenSslAlgorithmValueConsumer { }
//https://docs.openssl.org/3.0/man3/EC_KEY_new/#name //https://docs.openssl.org/3.0/man3/EC_KEY_new/#name
class EVPEllipticCurveAlgorithmConsumer extends EllipticCurveValueConsumer { class EvpEllipticCurveAlgorithmConsumer extends EllipticCurveValueConsumer {
DataFlow::Node valueArgNode; DataFlow::Node valueArgNode;
DataFlow::Node resultNode; DataFlow::Node resultNode;
EVPEllipticCurveAlgorithmConsumer() { EvpEllipticCurveAlgorithmConsumer() {
resultNode.asExpr() = this.(Call) and // in all cases the result is the return resultNode.asExpr() = this.(Call) and // in all cases the result is the return
( (
this.(Call).getTarget().getName() in ["EVP_EC_gen", "EC_KEY_new_by_curve_name"] and this.(Call).getTarget().getName() in ["EVP_EC_gen", "EC_KEY_new_by_curve_name"] and
@@ -25,7 +25,7 @@ class EVPEllipticCurveAlgorithmConsumer extends EllipticCurveValueConsumer {
} }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() { override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i) exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
} }
override DataFlow::Node getResultNode() { result = resultNode } override DataFlow::Node getResultNode() { result = resultNode }

View File

@@ -4,20 +4,20 @@ private import semmle.code.cpp.dataflow.new.DataFlow
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
abstract class HashAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { } abstract class HashAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer { }
/** /**
* EVP_Q_Digest directly consumes algorithm constant values * An EVP_Q_Digest directly consumes algorithm constant values
*/ */
class EVP_Q_Digest_Algorithm_Consumer extends HashAlgorithmValueConsumer { class Evp_Q_Digest_Algorithm_Consumer extends HashAlgorithmValueConsumer {
EVP_Q_Digest_Algorithm_Consumer() { this.(Call).getTarget().getName() = "EVP_Q_digest" } Evp_Q_Digest_Algorithm_Consumer() { this.(Call).getTarget().getName() = "EVP_Q_digest" }
override Crypto::ConsumerInputDataFlowNode getInputNode() { override Crypto::ConsumerInputDataFlowNode getInputNode() {
result.asExpr() = this.(Call).getArgument(1) result.asExpr() = this.(Call).getArgument(1)
} }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() { override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i) exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
} }
override DataFlow::Node getResultNode() { override DataFlow::Node getResultNode() {
@@ -27,15 +27,43 @@ class EVP_Q_Digest_Algorithm_Consumer extends HashAlgorithmValueConsumer {
} }
} }
/**
* An instance from https://docs.openssl.org/3.0/man3/EVP_PKEY_CTX_ctrl/
* where the digest is directly consumed by name.
* In these cases, the operation is not yet performed, but there is
* these functions are treated as 'initializers' and track the algorithm through
* `EvpInitializer` mechanics, i.e., the resultNode is considered 'none'
*/
class EvpPkeySetCtxALgorithmConsumer extends HashAlgorithmValueConsumer {
DataFlow::Node valueArgNode;
EvpPkeySetCtxALgorithmConsumer() {
this.(Call).getTarget().getName() in [
"EVP_PKEY_CTX_set_rsa_mgf1_md_name", "EVP_PKEY_CTX_set_rsa_oaep_md_name",
"EVP_PKEY_CTX_set_dsa_paramgen_md_props"
] and
valueArgNode.asExpr() = this.(Call).getArgument(1)
}
override DataFlow::Node getResultNode() { none() }
override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
}
}
/** /**
* The EVP digest algorithm getters * The EVP digest algorithm getters
* https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis * https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
* https://docs.openssl.org/3.0/man3/EVP_DigestSignInit/#name
*/ */
class EVPDigestAlgorithmValueConsumer extends HashAlgorithmValueConsumer { class EvpDigestAlgorithmValueConsumer extends HashAlgorithmValueConsumer {
DataFlow::Node valueArgNode; DataFlow::Node valueArgNode;
DataFlow::Node resultNode; DataFlow::Node resultNode;
EVPDigestAlgorithmValueConsumer() { EvpDigestAlgorithmValueConsumer() {
resultNode.asExpr() = this and resultNode.asExpr() = this and
( (
this.(Call).getTarget().getName() in [ this.(Call).getTarget().getName() in [
@@ -45,6 +73,9 @@ class EVPDigestAlgorithmValueConsumer extends HashAlgorithmValueConsumer {
or or
this.(Call).getTarget().getName() = "EVP_MD_fetch" and this.(Call).getTarget().getName() = "EVP_MD_fetch" and
valueArgNode.asExpr() = this.(Call).getArgument(1) valueArgNode.asExpr() = this.(Call).getArgument(1)
or
this.(Call).getTarget().getName() = "EVP_DigestSignInit_ex" and
valueArgNode.asExpr() = this.(Call).getArgument(2)
) )
} }
@@ -53,6 +84,6 @@ class EVPDigestAlgorithmValueConsumer extends HashAlgorithmValueConsumer {
override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode } override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() { override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i) exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
} }
} }

View File

@@ -4,13 +4,13 @@ private import semmle.code.cpp.dataflow.new.DataFlow
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
abstract class KEMAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { } abstract class KemAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer { }
class EVPKEMAlgorithmValueConsumer extends KEMAlgorithmValueConsumer { class EvpKemAlgorithmValueConsumer extends KemAlgorithmValueConsumer {
DataFlow::Node valueArgNode; DataFlow::Node valueArgNode;
DataFlow::Node resultNode; DataFlow::Node resultNode;
EVPKEMAlgorithmValueConsumer() { EvpKemAlgorithmValueConsumer() {
resultNode.asExpr() = this and resultNode.asExpr() = this and
( (
this.(Call).getTarget().getName() = "EVP_KEM_fetch" and this.(Call).getTarget().getName() = "EVP_KEM_fetch" and
@@ -23,6 +23,6 @@ class EVPKEMAlgorithmValueConsumer extends KEMAlgorithmValueConsumer {
override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode } override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() { override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i) exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
} }
} }

View File

@@ -4,13 +4,13 @@ private import semmle.code.cpp.dataflow.new.DataFlow
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
abstract class KeyExchangeAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { } abstract class KeyExchangeAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer { }
class EVPKeyExchangeAlgorithmValueConsumer extends KeyExchangeAlgorithmValueConsumer { class EvpKeyExchangeAlgorithmValueConsumer extends KeyExchangeAlgorithmValueConsumer {
DataFlow::Node valueArgNode; DataFlow::Node valueArgNode;
DataFlow::Node resultNode; DataFlow::Node resultNode;
EVPKeyExchangeAlgorithmValueConsumer() { EvpKeyExchangeAlgorithmValueConsumer() {
resultNode.asExpr() = this and resultNode.asExpr() = this and
( (
this.(Call).getTarget().getName() = "EVP_KEYEXCH_fetch" and this.(Call).getTarget().getName() = "EVP_KEYEXCH_fetch" and
@@ -23,6 +23,6 @@ class EVPKeyExchangeAlgorithmValueConsumer extends KeyExchangeAlgorithmValueCons
override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode } override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() { override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i) exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
} }
} }

View File

@@ -1,6 +1,6 @@
private import experimental.quantum.Language private import experimental.quantum.Language
abstract class OpenSSLAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer instanceof Call { abstract class OpenSslAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer instanceof Call {
/** /**
* Returns the node representing the resulting algorithm * Returns the node representing the resulting algorithm
*/ */

View File

@@ -5,3 +5,4 @@ import PaddingAlgorithmValueConsumer
import HashAlgorithmValueConsumer import HashAlgorithmValueConsumer
import EllipticCurveAlgorithmValueConsumer import EllipticCurveAlgorithmValueConsumer
import PKeyAlgorithmValueConsumer import PKeyAlgorithmValueConsumer
import SignatureAlgorithmValueConsumer

View File

@@ -4,13 +4,13 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
abstract class PKeyValueConsumer extends OpenSSLAlgorithmValueConsumer { } abstract class PKeyValueConsumer extends OpenSslAlgorithmValueConsumer { }
class EVPPKeyAlgorithmConsumer extends PKeyValueConsumer { class EvpPKeyAlgorithmConsumer extends PKeyValueConsumer {
DataFlow::Node valueArgNode; DataFlow::Node valueArgNode;
DataFlow::Node resultNode; DataFlow::Node resultNode;
EVPPKeyAlgorithmConsumer() { EvpPKeyAlgorithmConsumer() {
resultNode.asExpr() = this.(Call) and // in all cases the result is the return resultNode.asExpr() = this.(Call) and // in all cases the result is the return
( (
// NOTE: some of these consumers are themselves key gen operations, // NOTE: some of these consumers are themselves key gen operations,
@@ -23,7 +23,8 @@ class EVPPKeyAlgorithmConsumer extends PKeyValueConsumer {
or or
this.(Call).getTarget().getName() in [ this.(Call).getTarget().getName() in [
"EVP_PKEY_CTX_new_from_name", "EVP_PKEY_new_raw_private_key_ex", "EVP_PKEY_CTX_new_from_name", "EVP_PKEY_new_raw_private_key_ex",
"EVP_PKEY_new_raw_public_key_ex", "EVP_PKEY_CTX_ctrl", "EVP_PKEY_CTX_set_group_name" "EVP_PKEY_new_raw_public_key_ex", "EVP_PKEY_CTX_ctrl", "EVP_PKEY_CTX_ctrl_uint64",
"EVP_PKEY_CTX_ctrl_str", "EVP_PKEY_CTX_set_group_name"
] and ] and
valueArgNode.asExpr() = this.(Call).getArgument(1) valueArgNode.asExpr() = this.(Call).getArgument(1)
or or
@@ -46,7 +47,7 @@ class EVPPKeyAlgorithmConsumer extends PKeyValueConsumer {
} }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() { override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i) exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
} }
override DataFlow::Node getResultNode() { result = resultNode } override DataFlow::Node getResultNode() { result = resultNode }

View File

@@ -4,16 +4,16 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
private import OpenSSLAlgorithmValueConsumerBase private import OpenSSLAlgorithmValueConsumerBase
abstract class PaddingAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { } abstract class PaddingAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer { }
// https://docs.openssl.org/master/man7/EVP_ASYM_CIPHER-RSA/#rsa-asymmetric-cipher-parameters // https://docs.openssl.org/master/man7/EVP_ASYM_CIPHER-RSA/#rsa-asymmetric-cipher-parameters
// TODO: need to handle setting padding through EVP_PKEY_CTX_set_params, where modes like "OSSL_PKEY_RSA_PAD_MODE_OAEP" // TODO: need to handle setting padding through EVP_PKEY_CTX_set_params, where modes like "OSSL_PKEY_RSA_PAD_MODE_OAEP"
// are set. // are set.
class EVP_PKEY_CTX_set_rsa_padding_AlgorithmValueConsumer extends PaddingAlgorithmValueConsumer { class Evp_PKey_Ctx_set_rsa_padding_AlgorithmValueConsumer extends PaddingAlgorithmValueConsumer {
DataFlow::Node valueArgNode; DataFlow::Node valueArgNode;
DataFlow::Node resultNode; DataFlow::Node resultNode;
EVP_PKEY_CTX_set_rsa_padding_AlgorithmValueConsumer() { Evp_PKey_Ctx_set_rsa_padding_AlgorithmValueConsumer() {
resultNode.asExpr() = this and resultNode.asExpr() = this and
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_rsa_padding" and this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_rsa_padding" and
valueArgNode.asExpr() = this.(Call).getArgument(1) valueArgNode.asExpr() = this.(Call).getArgument(1)
@@ -25,8 +25,8 @@ class EVP_PKEY_CTX_set_rsa_padding_AlgorithmValueConsumer extends PaddingAlgorit
// override DataFlow::Node getInputNode() { result = valueArgNode } // override DataFlow::Node getInputNode() { result = valueArgNode }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() { override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i) exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
//TODO: As a potential alternative, for OpenSSL only, add a generic source node for literals and only create flow (flowsTo) to //TODO: As a potential alternative, for OpenSsl only, add a generic source node for literals and only create flow (flowsTo) to
// OpenSSL AVCs... the unknown literal sources would have to be any literals not in the known set. // OpenSsl AVCs... the unknown literal sources would have to be any literals not in the known set.
} }
} }

View File

@@ -0,0 +1,32 @@
import cpp
private import experimental.quantum.Language
private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
private import OpenSSLAlgorithmValueConsumerBase
private import experimental.quantum.OpenSSL.LibraryDetector
abstract class SignatureAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer { }
class EvpSignatureAlgorithmValueConsumer extends SignatureAlgorithmValueConsumer {
DataFlow::Node valueArgNode;
DataFlow::Node resultNode;
EvpSignatureAlgorithmValueConsumer() {
resultNode.asExpr() = this and
(
// EVP_SIGNATURE
this.(Call).getTarget().getName() = "EVP_SIGNATURE_fetch" and
valueArgNode.asExpr() = this.(Call).getArgument(1)
// EVP_PKEY_get1_DSA, EVP_PKEY_get1_RSA
// DSA_SIG_new, DSA_SIG_get0, RSA_sign ?
)
}
override DataFlow::Node getResultNode() { result = resultNode }
override Crypto::ConsumerInputDataFlowNode getInputNode() { result = valueArgNode }
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
}
}

View File

@@ -0,0 +1,19 @@
import semmle.code.cpp.dataflow.new.DataFlow
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
/**
* Flows from algorithm values to operations, specific to OpenSsl
*/
module AvcToCallArgConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(OpenSslAlgorithmValueConsumer c | c.getResultNode() = source)
}
/**
* Trace to any call accepting the algorithm.
* NOTE: users must restrict this set to the operations they are interested in.
*/
predicate isSink(DataFlow::Node sink) { exists(Call c | c.getAnArgument() = sink.asExpr()) }
}
module AvcToCallArgFlow = DataFlow::Global<AvcToCallArgConfig>;

View File

@@ -1,139 +0,0 @@
//TODO: model as data on open APIs should be able to get common flows, and obviate some of this
// e.g., copy/dup calls, need to ingest those models for openSSL and refactor.
/**
* In OpenSSL, flow between 'context' parameters is often used to
* store state/config of how an operation will eventually be performed.
* Tracing algorithms and configurations to operations therefore
* requires tracing context parameters for many OpenSSL apis.
*
* This library provides a dataflow analysis to track context parameters
* between any two functions accepting openssl context parameters.
* The dataflow takes into consideration flowing through duplication and copy calls
* as well as flow through flow killers (free/reset calls).
*
* TODO: we may need to revisit 'free' as a dataflow killer, depending on how
* we want to model use after frees.
*
* This library also provides classes to represent context Types and relevant
* arguments/expressions.
*/
import semmle.code.cpp.dataflow.new.DataFlow
/**
* An openSSL CTX type, which is type for which the stripped underlying type
* matches the pattern 'evp_%ctx_%st'.
* This includes types like:
* - EVP_CIPHER_CTX
* - EVP_MD_CTX
* - EVP_PKEY_CTX
*/
private class CtxType extends Type {
CtxType() {
// It is possible for users to use the underlying type of the CTX variables
// these have a name matching 'evp_%ctx_%st
this.getUnspecifiedType().stripType().getName().matches("evp_%ctx_%st")
or
// In principal the above check should be sufficient, but in case of build mode none issues
// i.e., if a typedef cannot be resolved,
// or issues with properly stubbing test cases, we also explicitly check for the wrapping type defs
// i.e., patterns matching 'EVP_%_CTX'
exists(Type base | base = this or base = this.(DerivedType).getBaseType() |
base.getName().matches("EVP_%_CTX")
)
}
}
/**
* A pointer to a CtxType
*/
private class CtxPointerExpr extends Expr {
CtxPointerExpr() {
this.getType() instanceof CtxType and
this.getType() instanceof PointerType
}
}
/**
* A call argument of type CtxPointerExpr.
*/
private class CtxPointerArgument extends CtxPointerExpr {
CtxPointerArgument() { exists(Call c | c.getAnArgument() = this) }
Call getCall() { result.getAnArgument() = this }
}
/**
* A call whose target contains 'free' or 'reset' and has an argument of type
* CtxPointerArgument.
*/
private class CtxClearCall extends Call {
CtxClearCall() {
this.getTarget().getName().toLowerCase().matches(["%free%", "%reset%"]) and
this.getAnArgument() instanceof CtxPointerArgument
}
}
/**
* A call whose target contains 'copy' and has an argument of type
* CtxPointerArgument.
*/
private class CtxCopyOutArgCall extends Call {
CtxCopyOutArgCall() {
this.getTarget().getName().toLowerCase().matches("%copy%") and
this.getAnArgument() instanceof CtxPointerArgument
}
}
/**
* A call whose target contains 'dup' and has an argument of type
* CtxPointerArgument.
*/
private class CtxCopyReturnCall extends Call, CtxPointerExpr {
CtxCopyReturnCall() {
this.getTarget().getName().toLowerCase().matches("%dup%") and
this.getAnArgument() instanceof CtxPointerArgument
}
}
/**
* Flow from any CtxPointerArgument to any other CtxPointerArgument
*/
module OpenSSLCtxArgumentFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CtxPointerArgument }
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof CtxPointerArgument }
predicate isBarrier(DataFlow::Node node) {
exists(CtxClearCall c | c.getAnArgument() = node.asExpr())
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(CtxCopyOutArgCall c |
c.getAnArgument() = node1.asExpr() and
c.getAnArgument() = node2.asExpr() and
node1.asExpr() != node2.asExpr() and
node2.asExpr().getType() instanceof CtxType
)
or
exists(CtxCopyReturnCall c |
c.getAnArgument() = node1.asExpr() and
c = node2.asExpr() and
node1.asExpr() != node2.asExpr() and
node2.asExpr().getType() instanceof CtxType
)
}
}
module OpenSSLCtxArgumentFlow = DataFlow::Global<OpenSSLCtxArgumentFlowConfig>;
/**
* Holds if there is a context flow from the source to the sink.
*/
predicate ctxArgFlowsToCtxArg(CtxPointerArgument source, CtxPointerArgument sink) {
exists(DataFlow::Node a, DataFlow::Node b |
OpenSSLCtxArgumentFlow::flow(a, b) and
a.asExpr() = source and
b.asExpr() = sink
)
}

View File

@@ -14,9 +14,9 @@ private class IntLiteral extends Literal {
/** /**
* Holds if a StringLiteral could conceivably be used in some way for cryptography. * Holds if a StringLiteral could conceivably be used in some way for cryptography.
* Note: this predicate should only consider restrictions with respect to strings only. * Note: this predicate should only consider restrictions with respect to strings only.
* General restrictions are in the OpenSSLGenericSourceCandidateLiteral class. * General restrictions are in the OpenSslGenericSourceCandidateLiteral class.
*/ */
private predicate isOpenSSLStringLiteralGenericSourceCandidate(StringLiteral s) { private predicate isOpenSslStringLiteralGenericSourceCandidate(StringLiteral s) {
// 'EC' is a constant that may be used where typical algorithms are specified, // 'EC' is a constant that may be used where typical algorithms are specified,
// but EC specifically means set up a default curve container, that will later be // but EC specifically means set up a default curve container, that will later be
//specified explicitly (or if not a default) curve is used. //specified explicitly (or if not a default) curve is used.
@@ -49,9 +49,9 @@ private predicate isOpenSSLStringLiteralGenericSourceCandidate(StringLiteral s)
/** /**
* Holds if a StringLiteral could conceivably be used in some way for cryptography. * Holds if a StringLiteral could conceivably be used in some way for cryptography.
* Note: this predicate should only consider restrictions with respect to integers only. * Note: this predicate should only consider restrictions with respect to integers only.
* General restrictions are in the OpenSSLGenericSourceCandidateLiteral class. * General restrictions are in the OpenSslGenericSourceCandidateLiteral class.
*/ */
private predicate isOpenSSLIntLiteralGenericSourceCandidate(IntLiteral l) { private predicate isOpenSslIntLiteralGenericSourceCandidate(IntLiteral l) {
// Ignore integer values of 0, commonly referring to NULL only (no known algorithm 0) // Ignore integer values of 0, commonly referring to NULL only (no known algorithm 0)
l.getValue().toInt() != 0 and l.getValue().toInt() != 0 and
// ASSUMPTION, no negative numbers are allowed // ASSUMPTION, no negative numbers are allowed
@@ -102,11 +102,11 @@ private predicate isOpenSSLIntLiteralGenericSourceCandidate(IntLiteral l) {
* "AES" may be a legitimate algorithm literal, but the literal will not be used for an operation directly * "AES" may be a legitimate algorithm literal, but the literal will not be used for an operation directly
* since it is in a equality comparison, hence this case would also be filtered. * since it is in a equality comparison, hence this case would also be filtered.
*/ */
class OpenSSLGenericSourceCandidateLiteral extends Literal { class OpenSslGenericSourceCandidateLiteral extends Literal {
OpenSSLGenericSourceCandidateLiteral() { OpenSslGenericSourceCandidateLiteral() {
( (
isOpenSSLIntLiteralGenericSourceCandidate(this) or isOpenSslIntLiteralGenericSourceCandidate(this) or
isOpenSSLStringLiteralGenericSourceCandidate(this) isOpenSslStringLiteralGenericSourceCandidate(this)
) and ) and
// ********* General filters beyond what is filtered for strings and ints ********* // ********* General filters beyond what is filtered for strings and ints *********
// An algorithm literal in a switch case will not be directly applied to an operation. // An algorithm literal in a switch case will not be directly applied to an operation.

View File

@@ -0,0 +1,27 @@
import semmle.code.cpp.dataflow.new.DataFlow
private import Operations.OpenSSLOperations
private import experimental.quantum.Language
/**
* Flow from key creation to key used in a call
*/
module OpenSslKeyFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
// NOTE/ASSUMPTION: it is assumed the operation is also an OpenSslOperation.
// All operations modeled for openssl should be modeled as OpenSslOperation.
exists(Crypto::KeyCreationOperationInstance keygen | keygen.getOutputKeyArtifact() = source)
}
predicate isSink(DataFlow::Node sink) { exists(Call call | call.getAnArgument() = sink.asExpr()) }
//TODO: consideration for additional flow steps? Can a key be copied for example?
}
module OpenSslKeyFlow = TaintTracking::Global<OpenSslKeyFlowConfig>;
Crypto::KeyCreationOperationInstance getSourceKeyCreationInstanceFromArg(Expr arg) {
exists(DataFlow::Node src, DataFlow::Node sink |
OpenSslKeyFlow::flow(src, sink) and
result.getOutputKeyArtifact() = src and
sink.asExpr() = arg
)
}

View File

@@ -1,7 +1,7 @@
import cpp import cpp
predicate isPossibleOpenSSLFunction(Function f) { predicate isPossibleOpenSslFunction(Function f) {
isPossibleOpenSSLLocation(f.getADeclarationLocation()) isPossibleOpenSslLocation(f.getADeclarationLocation())
} }
predicate isPossibleOpenSSLLocation(Location l) { l.toString().toLowerCase().matches("%openssl%") } predicate isPossibleOpenSslLocation(Location l) { l.toString().toLowerCase().matches("%openssl%") }

View File

@@ -1,4 +1,4 @@
module OpenSSLModel { module OpenSslModel {
import AlgorithmInstances.OpenSSLAlgorithmInstances import AlgorithmInstances.OpenSSLAlgorithmInstances
import AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers import AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
import Operations.OpenSSLOperations import Operations.OpenSSLOperations

View File

@@ -0,0 +1,273 @@
import experimental.quantum.Language
private import OpenSSLOperationBase
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
import EVPPKeyCtxInitializer
/**
* A base class for all EVP cipher operations.
*/
abstract class EvpCipherInitializer extends OperationStep {
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
result.asExpr() = this.getArgument(1) and
type = PrimaryAlgorithmIO() and
// Constants that are not equal to zero or
// non-constants (e.g., variable accesses, which require data-flow to determine the value)
// A zero (null) value typically indicates use of this operation step to initialize
// other out parameters in a multi-step initialization.
(exists(result.asExpr().getValue()) implies result.asExpr().getValue().toInt() != 0)
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override OperationStepType getStepType() { result = InitializerStep() }
}
/**
* A base class for EVP cipher/decrypt/encrypt 'ex' operations.
*/
abstract class EvpEXInitializer extends EvpCipherInitializer {
override DataFlow::Node getInput(IOType type) {
result = super.getInput(type)
or
(
// Constants that are not equal to zero or
// non-constants (e.g., variable accesses, which require data-flow to determine the value)
// A zero (null) value typically indicates use of this operation step to initialize
// other out parameters in a multi-step initialization.
result.asExpr() = this.getArgument(3) and type = KeyIO()
or
result.asExpr() = this.getArgument(4) and type = IVorNonceIO()
) and
(exists(result.asExpr().getValue()) implies result.asExpr().getValue().toInt() != 0)
}
}
/**
* A base class for EVP cipher/decrypt/encrypt 'ex2' operations.
*/
abstract class EvpEX2Initializer extends EvpCipherInitializer {
override DataFlow::Node getInput(IOType type) {
result = super.getInput(type)
or
result.asExpr() = this.getArgument(2) and type = KeyIO()
or
result.asExpr() = this.getArgument(3) and type = IVorNonceIO()
}
}
/**
* A Call to an EVP Cipher/Encrypt/Decrypt initialization operation.
*/
class EvpCipherEXInitCall extends EvpEXInitializer {
EvpCipherEXInitCall() {
this.getTarget().getName() in ["EVP_EncryptInit_ex", "EVP_DecryptInit_ex", "EVP_CipherInit_ex"]
}
override DataFlow::Node getInput(IOType type) {
result = super.getInput(type)
or
// NOTE: for EncryptInit and DecryptInit there is no subtype arg
// the subtype is determined automatically by the initializer based on the operation name
this.getTarget().getName().toLowerCase().matches("%cipherinit%") and
result.asExpr() = this.getArgument(5) and
type = KeyOperationSubtypeIO()
}
}
class Evp_Cipher_EX2_or_Simple_Init_Call extends EvpEX2Initializer {
Evp_Cipher_EX2_or_Simple_Init_Call() {
this.getTarget().getName() in [
"EVP_EncryptInit_ex2", "EVP_DecryptInit_ex2", "EVP_CipherInit_ex2", "EVP_EncryptInit",
"EVP_DecryptInit", "EVP_CipherInit"
]
}
override DataFlow::Node getInput(IOType type) {
result = super.getInput(type)
or
this.getTarget().getName().toLowerCase().matches("%cipherinit%") and
result.asExpr() = this.getArgument(4) and
type = KeyOperationSubtypeIO()
}
}
/**
* A call to EVP_Pkey_encrypt_init, EVP_Pkey_decrypt_init, or their 'ex' variants.
*/
class EvpPkeyEncryptDecryptInit extends OperationStep {
EvpPkeyEncryptDecryptInit() {
this.getTarget().getName() in [
"EVP_PKEY_encrypt_init", "EVP_PKEY_encrypt_init_ex", "EVP_PKEY_decrypt_init",
"EVP_PKEY_decrypt_init_ex"
]
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
result.asExpr() = this.getArgument(1) and type = OsslParamIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override OperationStepType getStepType() { result = InitializerStep() }
}
class EvpCipherInitSKeyCall extends EvpEX2Initializer {
EvpCipherInitSKeyCall() { this.getTarget().getName() = "EVP_CipherInit_SKEY" }
override DataFlow::Node getInput(IOType type) {
result = super.getInput(type)
or
result.asExpr() = this.getArgument(5) and
type = KeyOperationSubtypeIO()
}
}
//EVP_PKEY_encrypt_init
/**
* A Call to EVP_Cipher/Encrypt/DecryptUpdate.
* https://docs.openssl.org/3.2/man3/EVP_CipherUpdate
*/
class EvpCipherUpdateCall extends OperationStep {
EvpCipherUpdateCall() {
this.getTarget().getName() in ["EVP_EncryptUpdate", "EVP_DecryptUpdate", "EVP_CipherUpdate"]
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
or
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override OperationStepType getStepType() { result = UpdateStep() }
}
/**
* A base configuration for all EVP cipher operations.
*/
abstract class EvpCipherOperationFinalStep extends OperationStep {
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override OperationStepType getStepType() { result = FinalStep() }
}
/**
* A Call to EVP_Cipher.
*/
class EvpCipherCall extends EvpCipherOperationFinalStep {
EvpCipherCall() { this.getTarget().getName() = "EVP_Cipher" }
override DataFlow::Node getInput(IOType type) {
super.getInput(type) = result
or
result.asExpr() = this.getArgument(2) and type = PlaintextIO()
}
override DataFlow::Node getOutput(IOType type) {
super.getOutput(type) = result
or
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
}
}
/**
* A Call to an EVP Cipher/Encrypt/Decrypt final operation.
*/
class EvpCipherFinalCall extends EvpCipherOperationFinalStep {
EvpCipherFinalCall() {
this.getTarget().getName() in [
"EVP_EncryptFinal_ex", "EVP_DecryptFinal_ex", "EVP_CipherFinal_ex", "EVP_EncryptFinal",
"EVP_DecryptFinal", "EVP_CipherFinal"
]
}
override DataFlow::Node getOutput(IOType type) {
super.getOutput(type) = result
or
result.asDefiningArgument() = this.getArgument(1) and
type = CiphertextIO()
// TODO: could indicate text lengths here, as well
}
}
/**
* A call to a PKEY_encrypt or PKEY_decrypt operation.
* https://docs.openssl.org/3.2/man3/EVP_PKEY_decrypt/
* https://docs.openssl.org/3.2/man3/EVP_PKEY_encrypt
*/
class EvpPKeyCipherOperation extends EvpCipherOperationFinalStep {
EvpPKeyCipherOperation() {
this.getTarget().getName() in ["EVP_PKEY_encrypt", "EVP_PKEY_decrypt"]
}
override DataFlow::Node getInput(IOType type) {
super.getInput(type) = result
or
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
}
override DataFlow::Node getOutput(IOType type) {
super.getOutput(type) = result
or
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
// TODO: could indicate text lengths here, as well
}
}
/**
* An EVP cipher operation instance.
* Any operation step that is a final operation step for EVP cipher operation steps.
*/
class EvpCipherOperationInstance extends Crypto::KeyOperationInstance instanceof EvpCipherOperationFinalStep
{
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
super.getPrimaryAlgorithmValueConsumer() = result
}
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
result instanceof Crypto::TEncryptMode and
super.getTarget().getName().toLowerCase().matches("%encrypt%")
or
result instanceof Crypto::TDecryptMode and
super.getTarget().getName().toLowerCase().matches("%decrypt%")
or
super.getTarget().getName().toLowerCase().matches("%cipher%") and
resolveKeyOperationSubTypeOperationStep(super
.getDominatingInitializersToStep(KeyOperationSubtypeIO())) = result
}
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
super.getDominatingInitializersToStep(IVorNonceIO()).getInput(IVorNonceIO()) = result
}
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
super.getDominatingInitializersToStep(KeyIO()).getInput(KeyIO()) = result
}
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
super.getOutputStepFlowingToStep(CiphertextIO()).getOutput(CiphertextIO()) = result
}
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
super.getDominatingInitializersToStep(PlaintextIO()).getInput(PlaintextIO()) = result
}
}

View File

@@ -1,34 +0,0 @@
private import experimental.quantum.Language
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
private import OpenSSLOperationBase
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
private import semmle.code.cpp.dataflow.new.DataFlow
class ECKeyGenOperation extends OpenSSLOperation, Crypto::KeyGenerationOperationInstance {
ECKeyGenOperation() { this.(Call).getTarget().getName() = "EC_KEY_generate_key" }
override Expr getAlgorithmArg() { result = this.(Call).getArgument(0) }
override Crypto::KeyArtifactType getOutputKeyType() { result = Crypto::TAsymmetricKeyType() }
override Crypto::ArtifactOutputDataFlowNode getOutputKeyArtifact() {
result.asExpr() = this.(Call).getArgument(0)
}
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
none() // no explicit key size, inferred from algorithm
}
override int getKeySizeFixed() {
none()
// TODO: marked as none as the operation itself has no key size, it
// comes from the algorithm source, but note we could grab the
// algorithm source and get the key size (see below).
// We may need to reconsider what is the best approach here.
// result =
// this.getAnAlgorithmValueConsumer()
// .getAKnownAlgorithmSource()
// .(Crypto::EllipticCurveInstance)
// .getKeySize()
}
}

View File

@@ -1,117 +0,0 @@
/**
* see: https://docs.openssl.org/master/man3/EVP_EncryptInit/
* Models cipher initialization for EVP cipher operations.
*/
private import experimental.quantum.Language
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
private import OpenSSLOperationBase
module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr().getValue().toInt() in [0, 1] }
predicate isSink(DataFlow::Node sink) {
exists(EVP_Cipher_Initializer initCall | sink.asExpr() = initCall.getOperationSubtypeArg())
}
}
module EncValToInitEncArgFlow = DataFlow::Global<EncValToInitEncArgConfig>;
int getEncConfigValue(Expr e) {
exists(EVP_Cipher_Initializer initCall | e = initCall.getOperationSubtypeArg()) and
exists(DataFlow::Node a, DataFlow::Node b |
EncValToInitEncArgFlow::flow(a, b) and b.asExpr() = e and result = a.asExpr().getValue().toInt()
)
}
bindingset[i]
Crypto::KeyOperationSubtype intToCipherOperationSubtype(int i) {
if i = 0
then result instanceof Crypto::TEncryptMode
else
if i = 1
then result instanceof Crypto::TDecryptMode
else result instanceof Crypto::TUnknownKeyOperationMode
}
// TODO: need to add key consumer
abstract class EVP_Cipher_Initializer extends EVPInitialize {
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
abstract Expr getOperationSubtypeArg();
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
if this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%")
then result instanceof Crypto::TEncryptMode
else
if this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
then result instanceof Crypto::TDecryptMode
else
if exists(getEncConfigValue(this.getOperationSubtypeArg()))
then result = intToCipherOperationSubtype(getEncConfigValue(this.getOperationSubtypeArg()))
else result instanceof Crypto::TUnknownKeyOperationMode
}
}
abstract class EVP_EX_Initializer extends EVP_Cipher_Initializer {
override Expr getKeyArg() { result = this.(Call).getArgument(3) }
override Expr getIVArg() { result = this.(Call).getArgument(4) }
}
abstract class EVP_EX2_Initializer extends EVP_Cipher_Initializer {
override Expr getKeyArg() { result = this.(Call).getArgument(2) }
override Expr getIVArg() { result = this.(Call).getArgument(3) }
}
class EVP_Cipher_EX_Init_Call extends EVP_EX_Initializer {
EVP_Cipher_EX_Init_Call() {
this.(Call).getTarget().getName() in [
"EVP_EncryptInit_ex", "EVP_DecryptInit_ex", "EVP_CipherInit_ex"
]
}
override Expr getOperationSubtypeArg() {
this.(Call).getTarget().getName().toLowerCase().matches("%cipherinit%") and
result = this.(Call).getArgument(5)
}
}
class EVP_Cipher_EX2_or_Simple_Init_Call extends EVP_EX2_Initializer {
EVP_Cipher_EX2_or_Simple_Init_Call() {
this.(Call).getTarget().getName() in [
"EVP_EncryptInit_ex2", "EVP_DecryptInit_ex2", "EVP_CipherInit_ex2", "EVP_EncryptInit",
"EVP_DecryptInit", "EVP_CipherInit"
]
}
override Expr getOperationSubtypeArg() {
this.(Call).getTarget().getName().toLowerCase().matches("%cipherinit%") and
result = this.(Call).getArgument(4)
}
}
class EVP_CipherInit_SKEY_Call extends EVP_EX2_Initializer {
EVP_CipherInit_SKEY_Call() { this.(Call).getTarget().getName() in ["EVP_CipherInit_SKEY"] }
override Expr getOperationSubtypeArg() { result = this.(Call).getArgument(5) }
}
class EVPCipherInitializerAlgorithmArgument extends Expr {
EVPCipherInitializerAlgorithmArgument() {
exists(EVP_Cipher_Initializer initCall | this = initCall.getAlgorithmArg())
}
}
class EVPCipherInitializerKeyArgument extends Expr {
EVPCipherInitializerKeyArgument() {
exists(EVP_Cipher_Initializer initCall | this = initCall.getKeyArg())
}
}
class EVPCipherInitializerIVArgument extends Expr {
EVPCipherInitializerIVArgument() {
exists(EVP_Cipher_Initializer initCall | this = initCall.getIVArg())
}
}

View File

@@ -1,77 +0,0 @@
private import experimental.quantum.Language
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
private import EVPCipherInitializer
private import OpenSSLOperationBase
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
class EVP_Cipher_Update_Call extends EVPUpdate {
EVP_Cipher_Update_Call() {
this.(Call).getTarget().getName() in [
"EVP_EncryptUpdate", "EVP_DecryptUpdate", "EVP_CipherUpdate"
]
}
override Expr getInputArg() { result = this.(Call).getArgument(3) }
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
}
/**
* see: https://docs.openssl.org/master/man3/EVP_EncryptInit/#synopsis
* Base configuration for all EVP cipher operations.
*/
abstract class EVP_Cipher_Operation extends EVPOperation, Crypto::KeyOperationInstance {
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
result instanceof Crypto::TEncryptMode and
this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%")
or
result instanceof Crypto::TDecryptMode and
this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
or
result = this.getInitCall().getKeyOperationSubtype() and
this.(Call).getTarget().getName().toLowerCase().matches("%cipher%")
}
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
this.getInitCall().getIVArg() = result.asExpr()
}
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
this.getInitCall().getKeyArg() = result.asExpr()
// todo: or track to the EVP_PKEY_CTX_new
}
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
result = EVPOperation.super.getOutputArtifact()
}
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
result = EVPOperation.super.getInputConsumer()
}
}
class EVP_Cipher_Call extends EVPOperation, EVP_Cipher_Operation {
EVP_Cipher_Call() { this.(Call).getTarget().getName() = "EVP_Cipher" }
override Expr getInputArg() { result = this.(Call).getArgument(2) }
}
class EVP_Cipher_Final_Call extends EVPFinal, EVP_Cipher_Operation {
EVP_Cipher_Final_Call() {
this.(Call).getTarget().getName() in [
"EVP_EncryptFinal_ex", "EVP_DecryptFinal_ex", "EVP_CipherFinal_ex", "EVP_EncryptFinal",
"EVP_DecryptFinal", "EVP_CipherFinal"
]
}
/**
* Output is both from update calls and from the final call.
*/
override Expr getOutputArg() {
result = EVPFinal.super.getOutputArg()
or
result = EVP_Cipher_Operation.super.getOutputArg()
}
}

View File

@@ -1,14 +0,0 @@
import cpp
private import OpenSSLOperationBase
abstract class EVP_Hash_Initializer extends EVPInitialize { }
class EVP_DigestInit_Variant_Calls extends EVP_Hash_Initializer {
EVP_DigestInit_Variant_Calls() {
this.(Call).getTarget().getName() in [
"EVP_DigestInit", "EVP_DigestInit_ex", "EVP_DigestInit_ex2"
]
}
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
}

View File

@@ -1,85 +0,0 @@
/**
* https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
*/
private import experimental.quantum.Language
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
private import OpenSSLOperationBase
private import EVPHashInitializer
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
class EVP_Digest_Update_Call extends EVPUpdate {
EVP_Digest_Update_Call() { this.(Call).getTarget().getName() = "EVP_DigestUpdate" }
override Expr getInputArg() { result = this.(Call).getArgument(1) }
}
//https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
class EVP_Q_Digest_Operation extends EVPOperation, Crypto::HashOperationInstance {
EVP_Q_Digest_Operation() { this.(Call).getTarget().getName() = "EVP_Q_digest" }
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
override EVP_Hash_Initializer getInitCall() {
// This variant of digest does not use an init
// and even if it were used, the init would be ignored/undefined
none()
}
override Expr getInputArg() { result = this.(Call).getArgument(3) }
override Expr getOutputArg() { result = this.(Call).getArgument(5) }
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
result = EVPOperation.super.getOutputArtifact()
}
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
result = EVPOperation.super.getInputConsumer()
}
}
class EVP_Digest_Operation extends EVPOperation, Crypto::HashOperationInstance {
EVP_Digest_Operation() { this.(Call).getTarget().getName() = "EVP_Digest" }
// There is no context argument for this function
override Expr getContextArg() { none() }
override Expr getAlgorithmArg() { result = this.(Call).getArgument(4) }
override EVP_Hash_Initializer getInitCall() {
// This variant of digest does not use an init
// and even if it were used, the init would be ignored/undefined
none()
}
override Expr getInputArg() { result = this.(Call).getArgument(0) }
override Expr getOutputArg() { result = this.(Call).getArgument(2) }
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
result = EVPOperation.super.getOutputArtifact()
}
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
result = EVPOperation.super.getInputConsumer()
}
}
class EVP_Digest_Final_Call extends EVPFinal, Crypto::HashOperationInstance {
EVP_Digest_Final_Call() {
this.(Call).getTarget().getName() in [
"EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"
]
}
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
result = EVPFinal.super.getOutputArtifact()
}
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
result = EVPFinal.super.getInputConsumer()
}
}

View File

@@ -0,0 +1,174 @@
/**
* Initializers for EVP PKey
* including:
* https://docs.openssl.org/3.0/man3/EVP_PKEY_CTX_ctrl/
* https://docs.openssl.org/3.0/man3/EVP_EncryptInit/#synopsis
*/
import cpp
private import OpenSSLOperations
/**
* A call to `EVP_PKEY_CTX_new` or `EVP_PKEY_CTX_new_from_pkey`.
* These calls initialize the context from a prior key.
* The key may be generated previously, or merely had it's
* parameters set (e.g., `EVP_PKEY_paramgen`).
*/
class EvpNewKeyCtx extends OperationStep instanceof Call {
Expr keyArg;
EvpNewKeyCtx() {
this.getTarget().getName() = "EVP_PKEY_CTX_new" and
keyArg = this.getArgument(0)
or
this.getTarget().getName() = "EVP_PKEY_CTX_new_from_pkey" and
keyArg = this.getArgument(1)
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = keyArg and type = KeyIO()
or
this.getTarget().getName() = "EVP_PKEY_CTX_new_from_pkey" and
result.asExpr() = this.getArgument(0) and
type = OsslLibContextIO()
}
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = ContextIO() }
override OperationStepType getStepType() { result = ContextCreationStep() }
}
/**
* A call to "EVP_PKEY_CTX_set_ec_paramgen_curve_nid".
*/
class EvpCtxSetEcParamgenCurveNidInitializer extends OperationStep {
EvpCtxSetEcParamgenCurveNidInitializer() {
this.getTarget().getName() = "EVP_PKEY_CTX_set_ec_paramgen_curve_nid"
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
result.asExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override OperationStepType getStepType() { result = InitializerStep() }
}
/**
* A call to the following:
* - `EVP_PKEY_CTX_set_signature_md`
* - `EVP_PKEY_CTX_set_rsa_mgf1_md_name`
* - `EVP_PKEY_CTX_set_rsa_mgf1_md`
* - `EVP_PKEY_CTX_set_rsa_oaep_md_name`
* - `EVP_PKEY_CTX_set_rsa_oaep_md`
* - `EVP_PKEY_CTX_set_dsa_paramgen_md`
* - `EVP_PKEY_CTX_set_dh_kdf_md`
* - `EVP_PKEY_CTX_set_ecdh_kdf_md`
*/
class EvpCtxSetHashInitializer extends OperationStep {
EvpCtxSetHashInitializer() {
this.getTarget().getName() in [
"EVP_PKEY_CTX_set_signature_md", "EVP_PKEY_CTX_set_rsa_mgf1_md_name",
"EVP_PKEY_CTX_set_rsa_mgf1_md", "EVP_PKEY_CTX_set_rsa_oaep_md_name",
"EVP_PKEY_CTX_set_rsa_oaep_md", "EVP_PKEY_CTX_set_dsa_paramgen_md",
"EVP_PKEY_CTX_set_dh_kdf_md", "EVP_PKEY_CTX_set_ecdh_kdf_md"
]
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
result.asExpr() = this.getArgument(1) and type = HashAlgorithmIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override OperationStepType getStepType() { result = InitializerStep() }
}
/**
* A call to `EVP_PKEY_CTX_set_rsa_keygen_bits`, `EVP_PKEY_CTX_set_dsa_paramgen_bits`,
* or `EVP_CIPHER_CTX_set_key_length`.
*/
class EvpCtxSetKeySizeInitializer extends OperationStep {
EvpCtxSetKeySizeInitializer() {
this.getTarget().getName() in [
"EVP_PKEY_CTX_set_rsa_keygen_bits", "EVP_PKEY_CTX_set_dsa_paramgen_bits",
"EVP_CIPHER_CTX_set_key_length"
]
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
result.asExpr() = this.getArgument(1) and type = KeySizeIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override OperationStepType getStepType() { result = InitializerStep() }
}
class EvpCtxSetMacKeyInitializer extends OperationStep {
EvpCtxSetMacKeyInitializer() { this.getTarget().getName() = "EVP_PKEY_CTX_set_mac_key" }
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
result.asExpr() = this.getArgument(2) and type = KeySizeIO()
or
// the raw key that is configured into the output key
result.asExpr() = this.getArgument(1) and type = KeyIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override OperationStepType getStepType() { result = InitializerStep() }
}
class EvpCtxSetPaddingInitializer extends OperationStep {
EvpCtxSetPaddingInitializer() {
this.getTarget().getName() in ["EVP_PKEY_CTX_set_rsa_padding", "EVP_CIPHER_CTX_set_padding"]
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
result.asExpr() = this.getArgument(1) and type = PaddingAlgorithmIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override OperationStepType getStepType() { result = InitializerStep() }
}
class EvpCtxSetSaltLengthInitializer extends OperationStep {
EvpCtxSetSaltLengthInitializer() {
this.getTarget().getName() = "EVP_PKEY_CTX_set_rsa_pss_saltlen"
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
result.asExpr() = this.getArgument(1) and type = SaltLengthIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override OperationStepType getStepType() { result = InitializerStep() }
}

View File

@@ -0,0 +1,134 @@
/**
* https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
*/
private import experimental.quantum.Language
private import OpenSSLOperationBase
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
/**
* A call to and EVP digest initializer, such as:
* - `EVP_DigestInit`
* - `EVP_DigestInit_ex`
* - `EVP_DigestInit_ex2`
*/
class EvpDigestInitVariantCalls extends OperationStep instanceof Call {
EvpDigestInitVariantCalls() {
this.getTarget().getName() in ["EVP_DigestInit", "EVP_DigestInit_ex", "EVP_DigestInit_ex2"]
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
result.asExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and
type = ContextIO()
}
override OperationStepType getStepType() { result = InitializerStep() }
}
/**
* A call to `EVP_DigestUpdate`.
*/
class EvpDigestUpdateCall extends OperationStep instanceof Call {
EvpDigestUpdateCall() { this.getTarget().getName() = "EVP_DigestUpdate" }
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
result.asExpr() = this.getArgument(1) and type = PlaintextIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and
type = ContextIO()
}
override OperationStepType getStepType() { result = UpdateStep() }
}
/**
* A base class for final digest operations.
*/
abstract class EvpFinalDigestOperationStep extends OperationStep {
override OperationStepType getStepType() { result = FinalStep() }
}
/**
* A call to `EVP_Q_digest`
* https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
*/
class EvpQDigestOperation extends EvpFinalDigestOperationStep instanceof Call {
EvpQDigestOperation() { this.getTarget().getName() = "EVP_Q_digest" }
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(1) and type = PrimaryAlgorithmIO()
or
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and
type = ContextIO()
or
result.asDefiningArgument() = this.getArgument(5) and type = DigestIO()
}
}
class EvpDigestOperation extends EvpFinalDigestOperationStep instanceof Call {
EvpDigestOperation() { this.getTarget().getName() = "EVP_Digest" }
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(4) and type = PrimaryAlgorithmIO()
or
result.asExpr() = this.getArgument(0) and type = PlaintextIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asDefiningArgument() = this.getArgument(2) and type = DigestIO()
}
}
/**
* A call to EVP_DigestFinal variants
*/
class EvpDigestFinalCall extends EvpFinalDigestOperationStep instanceof Call {
EvpDigestFinalCall() {
this.getTarget().getName() in ["EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"]
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and
type = ContextIO()
or
result.asDefiningArgument() = this.getArgument(1) and type = DigestIO()
}
}
/**
* An openssl digest final hash operation instance
*/
class EvpDigestFinalOperationInstance extends Crypto::HashOperationInstance instanceof EvpFinalDigestOperationStep
{
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
super.getPrimaryAlgorithmValueConsumer() = result
}
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
super.getOutputStepFlowingToStep(DigestIO()).getOutput(DigestIO()) = result
}
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
super.getDominatingInitializersToStep(PlaintextIO()).getInput(PlaintextIO()) = result
}
}

View File

@@ -0,0 +1,204 @@
private import experimental.quantum.Language
private import OpenSSLOperationBase
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
/**
* A call to EC_KEY_generate_key, which is used to generate an EC key pair.
* Note: this is an operation, though the input parameter is a "EC_KEY*".
* EC_KEY is really an empty context for a key that hasn't been generated, hence
* we consider this an operation generating a key and not accepting a key input.
*/
class ECKeyGen extends OperationStep instanceof Call {
//, Crypto::KeyGenerationOperationInstance {
ECKeyGen() { this.(Call).getTarget().getName() = "EC_KEY_generate_key" }
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.(Call).getArgument(0) and type = ContextIO()
}
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
override OperationStepType getStepType() { result = ContextCreationStep() }
}
/**
* A call to EVP_PKEY_keygen_init or EVP_PKEY_paramgen_init.
*/
class EvpKeyGenInitialize extends OperationStep {
EvpKeyGenInitialize() {
this.getTarget().getName() in [
"EVP_PKEY_keygen_init",
"EVP_PKEY_paramgen_init"
]
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override OperationStepType getStepType() { result = InitializerStep() }
}
abstract class KeyGenFinalOperationStep extends OperationStep {
override OperationStepType getStepType() { result = FinalStep() }
}
/**
* A call to `EVP_PKEY_Q_keygen`
*/
class EvpPKeyQKeyGen extends KeyGenFinalOperationStep instanceof Call {
EvpPKeyQKeyGen() { this.getTarget().getName() = "EVP_PKEY_Q_keygen" }
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
result.asExpr() = this and type = KeyIO()
}
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
// When arg 3 is a derived type, it is a curve name, otherwise it is a key size for RSA if provided
// and arg 2 is the algorithm type
this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
result.asExpr() = this.getArgument(3) and
type = PrimaryAlgorithmIO()
or
not this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
result.asExpr() = this.getArgument(2) and
type = PrimaryAlgorithmIO()
or
not this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
result.asExpr() = this.getArgument(3) and
type = KeySizeIO()
}
}
/**
* A call to `EVP_RSA_gen`
*/
class EvpRsaGen extends KeyGenFinalOperationStep instanceof Call {
EvpRsaGen() { this.getTarget().getName() = "EVP_RSA_gen" }
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = KeySizeIO()
}
}
/**
* A call to RSA_generate_key
*/
class RsaGenerateKey extends KeyGenFinalOperationStep instanceof Call {
RsaGenerateKey() { this.getTarget().getName() = "RSA_generate_key" }
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = KeySizeIO()
}
}
/**
* A call to RSA_generate_key_ex
*/
class RsaGenerateKeyEx extends KeyGenFinalOperationStep instanceof Call {
RsaGenerateKeyEx() { this.getTarget().getName() = "RSA_generate_key_ex" }
override DataFlow::Node getOutput(IOType type) {
result.asDefiningArgument() = this.getArgument(0) and type = KeyIO()
}
override DataFlow::Node getInput(IOType type) {
// arg 0 comes in as a blank RSA key, which we consider a context,
// on output it is considered a key
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
}
/**
* A call to `EVP_PKEY_generate` or `EVP_PKEY_keygen`.
*/
class EvpPkeyGen extends KeyGenFinalOperationStep instanceof Call {
EvpPkeyGen() { this.getTarget().getName() in ["EVP_PKEY_generate", "EVP_PKEY_keygen"] }
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asDefiningArgument() = this.getArgument(1) and type = KeyIO()
or
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
}
/**
* A call to `EVP_PKEY_new_mac_key` that creates a new generic MAC key.
* - EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e, const unsigned char *key, int keylen);
*/
class EvpNewMacKey extends KeyGenFinalOperationStep {
EvpNewMacKey() { this.getTarget().getName() = "EVP_PKEY_new_mac_key" }
override DataFlow::Node getInput(IOType type) {
result.asExpr() = this.getArgument(0) and type = ContextIO()
or
// the raw key that is configured into the output key
result.asExpr() = this.getArgument(2) and type = KeyIO()
or
result.asExpr() = this.getArgument(3) and type = KeySizeIO()
}
override DataFlow::Node getOutput(IOType type) {
result.asExpr() = this and type = KeyIO()
or
result.asExpr() = this.getArgument(0) and type = ContextIO()
}
}
/// TODO: https://docs.openssl.org/3.0/man3/EVP_PKEY_new/#synopsis
/**
* An `KeyGenerationOperationInstance` for the for all key gen final operation steps.
*/
class KeyGenOperationInstance extends Crypto::KeyGenerationOperationInstance instanceof KeyGenFinalOperationStep
{
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
super.getPrimaryAlgorithmValueConsumer() = result
}
override Crypto::KeyArtifactType getOutputKeyType() { result = Crypto::TAsymmetricKeyType() }
override Crypto::ArtifactOutputDataFlowNode getOutputKeyArtifact() {
super.getOutputStepFlowingToStep(KeyIO()).getOutput(KeyIO()) = result
}
override predicate hasKeyValueConsumer() {
exists(OperationStep s | s.flowsToOperationStep(this) and s.setsValue(KeyIO()))
}
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
super.getDominatingInitializersToStep(KeySizeIO()).getInput(KeySizeIO()) = result
}
override int getKeySizeFixed() {
none()
// TODO: marked as none as the operation itself has no key size, it
// comes from the algorithm source, but note we could grab the
// algorithm source and get the key size (see below).
// We may need to reconsider what is the best approach here.
// result =
// this.getAnAlgorithmValueConsumer()
// .getAKnownAlgorithmSource()
// .(Crypto::EllipticCurveInstance)
// .getKeySize()
}
override Crypto::ConsumerInputDataFlowNode getKeyValueConsumer() {
super.getDominatingInitializersToStep(KeyIO()).getInput(KeyIO()) = result
}
}

View File

@@ -1,162 +1,523 @@
private import experimental.quantum.Language private import experimental.quantum.Language
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
import semmle.code.cpp.dataflow.new.DataFlow
// Importing these intializers here to ensure the are part of any model that is
// using OpenSslOperationBase. This further ensures that initializers are tied to opeartions
// even if only importing the operation by itself.
import EVPPKeyCtxInitializer
/** /**
* A class for all OpenSSL operations. * An openSSL CTX type, which is type for which the stripped underlying type
* matches the pattern 'evp_%ctx_%st'.
* This includes types like:
* - EVP_CIPHER_CTX
* - EVP_MD_CTX
* - EVP_PKEY_CTX
*/ */
abstract class OpenSSLOperation extends Crypto::OperationInstance instanceof Call { class CtxType extends Type {
/** CtxType() {
* Expression that specifies the algorithm for the operation. // It is possible for users to use the underlying type of the CTX variables
* Will be an argument of the operation in the simplest case. // these have a name matching 'evp_%ctx_%st
*/ this.getUnspecifiedType().stripType().getName().matches("evp_%ctx_%st")
abstract Expr getAlgorithmArg(); or
// In principal the above check should be sufficient, but in case of build mode none issues
/** // i.e., if a typedef cannot be resolved,
* Algorithm is specified in initialization call or is implicitly established by the key. // or issues with properly stubbing test cases, we also explicitly check for the wrapping type defs
*/ // i.e., patterns matching 'EVP_%_CTX'
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() { exists(Type base | base = this or base = this.(DerivedType).getBaseType() |
AlgGetterToAlgConsumerFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(), base.getName().matches("EVP_%_CTX")
DataFlow::exprNode(this.getAlgorithmArg())) )
} }
} }
/** /**
* A Call to initialization functions from the EVP API. * A pointer to a CtxType
* These are not operations in the sense of Crypto::OperationInstance,
* but they are used to initialize the context for the operation.
*/ */
abstract class EVPInitialize extends Call { class CtxPointerExpr extends Expr {
/** CtxPointerExpr() {
* Gets the context argument that ties together initialization, updates and/or final calls. this.getType() instanceof CtxType and
*/ this.getType() instanceof PointerType
Expr getContextArg() { result = this.(Call).getArgument(0) } }
/**
* Gets the type of key operation, none if not applicable.
*/
Crypto::KeyOperationSubtype getKeyOperationSubtype() { none() }
/**
* Explicitly specified algorithm or none if implicit (e.g., established by the key).
* None if not applicable.
*/
Expr getAlgorithmArg() { none() }
/**
* Gets the key for the operation, none if not applicable.
*/
Expr getKeyArg() { none() }
/**
* Gets the IV/nonce, none if not applicable.
*/
Expr getIVArg() { none() }
} }
/** /**
* A Call to update functions from the EVP API. * A call argument of type CtxPointerExpr.
* These are not operations in the sense of Crypto::OperationInstance,
* but they are used to update the context for the operation.
*/ */
abstract class EVPUpdate extends Call { class CtxPointerArgument extends CtxPointerExpr {
/** CtxPointerArgument() { exists(Call c | c.getAnArgument() = this) }
* Gets the context argument that ties together initialization, updates and/or final calls.
*/
Expr getContextArg() { result = this.(Call).getArgument(0) }
/** Call getCall() { result.getAnArgument() = this }
* Update calls always have some input data like plaintext or message digest.
*/
abstract Expr getInputArg();
/**
* Update calls sometimes have some output data like a plaintext.
*/
Expr getOutputArg() { none() }
} }
/** /**
* Flows from algorithm values to operations, specific to OpenSSL * The type of inputs and ouputs for an `OperationStep`.
*/ */
private module AlgGetterToAlgConsumerConfig implements DataFlow::ConfigSig { newtype TIOType =
CiphertextIO() or
// Used for typical CTX types, but not for OSSL_PARAM or OSSL_LIB_CTX
// For OSSL_PARAM and OSSL_LIB_CTX use of OsslParamIO and OsslLibContextIO
ContextIO() or
DigestIO() or
HashAlgorithmIO() or
IVorNonceIO() or
KeyIO() or
KeyOperationSubtypeIO() or
KeySizeIO() or
// Used for OSSL_LIB_CTX
OsslLibContextIO() or
// Used for OSSL_PARAM
OsslParamIO() or
MacIO() or
PaddingAlgorithmIO() or
// Plaintext also includes a message for digest, signature, verification, and mac generation
PlaintextIO() or
PrimaryAlgorithmIO() or
RandomSourceIO() or
SaltLengthIO() or
SeedIO() or
SignatureIO()
private string ioTypeToString(TIOType t) {
t = CiphertextIO() and result = "CiphertextIO"
or
t = ContextIO() and result = "ContextIO"
or
t = DigestIO() and result = "DigestIO"
or
t = HashAlgorithmIO() and result = "HashAlgorithmIO"
or
t = IVorNonceIO() and result = "IVorNonceIO"
or
t = KeyIO() and result = "KeyIO"
or
t = KeyOperationSubtypeIO() and result = "KeyOperationSubtypeIO"
or
t = KeySizeIO() and result = "KeySizeIO"
or
t = OsslLibContextIO() and result = "OsslLibContextIO"
or
t = OsslParamIO() and result = "OsslParamIO"
or
t = MacIO() and result = "MacIO"
or
t = PaddingAlgorithmIO() and result = "PaddingAlgorithmIO"
or
t = PlaintextIO() and result = "PlaintextIO"
or
t = PrimaryAlgorithmIO() and result = "PrimaryAlgorithmIO"
or
t = RandomSourceIO() and result = "RandomSourceIO"
or
t = SaltLengthIO() and result = "SaltLengthIO"
or
t = SeedIO() and result = "SeedIO"
or
t = SignatureIO() and result = "SignatureIO"
}
class IOType extends TIOType {
string toString() {
result = ioTypeToString(this)
or
not exists(ioTypeToString(this)) and result = "UnknownIOType"
}
}
//TODO: add more initializers as needed
/**
* The type of step in an `OperationStep`.
* - `ContextCreationStep`: the creation of a context from an algorithm or key.
* for example `EVP_MD_CTX_create(EVP_sha256())` or `EVP_PKEY_CTX_new(pkey, NULL)`
* - `InitializerStep`: the initialization of an operation through some sort of shared/accumulated context
* for example `EVP_DigestInit_ex(ctx, EVP_sha256(), NULL)`
* - `UpdateStep`: any operation that has and update/final paradigm, the update represents an intermediate step in an operation,
* such as `EVP_DigestUpdate(ctx, data, len)`
* - `FinalStep`: an ultimate operation step. This may be an explicit 'final' in an update/final paradigm, but not necessarily.
* Any operation that does nto operate through an update/final paradigm is considered a final step.
*/
newtype OperationStepType =
// Context creation captures cases where a context is created from an algorithm or key
//
ContextCreationStep() or
InitializerStep() or
UpdateStep() or
FinalStep()
/**
* A step in configuring an operation.
* Captures creation of contexts from algorithms or keys,
* initalization of configurations on contexts,
* update operations (intermediate steps in an operation)
* and the operation itself.
*
* NOTE: if an operation is configured through a means other than a call
* e.g., a pattern like ctx->alg = EVP_sha256()
* then this class will need to be modified to account for that paradigm.
* Currently, this is not a known pattern in OpenSSL.
*/
abstract class OperationStep extends Call {
/**
* Gets the output nodes from the given operation step.
* These are the nodes that flow connecting this step
* to any other step in the operation should follow.
*/
abstract DataFlow::Node getOutput(IOType type);
/**
* Gets any output node from the given operation step.
*/
final DataFlow::Node getAnOutput() { result = this.getOutput(_) }
/**
* Gets the input nodes for the given operation step.
*/
abstract DataFlow::Node getInput(IOType type);
/**
* Gets any input node for the given operation step.
*/
final DataFlow::Node getAnInput() { result = this.getInput(_) }
/**
* Gets the type of the step, e.g., ContextCreationStep, InitializerStep, UpdateStep, FinalStep.
*/
abstract OperationStepType getStepType();
/**
* Holds if this operation step flows to the given `OperationStep` `sink`.
* If `sink` is `this`, then this holds true.
*/
predicate flowsToOperationStep(OperationStep sink) {
sink = this or
OperationStepFlow::flow(this.getAnOutput(), sink.getAnInput())
}
/**
* Holds if this operation step flows from the given `OperationStep` (`source`).
* If `source` is `this`, then this holds true.
*/
predicate flowsFromOperationStep(OperationStep source) {
source = this or
OperationStepFlow::flow(source.getAnOutput(), this.getAnInput())
}
/**
* Holds if this operation step sets a value of the given `IOType`.
*/
predicate setsValue(IOType type) { exists(this.getInput(type)) }
/**
* Gets operation steps that flow to `this` and set the given `IOType`.
* This checks for the last initializers that flow to the `this`,
* i.e., if a value is set then re-set, the last set operation step is returned,
* not both.
* Note: Any 'update' that sets a value is not considered to be 'resetting' an input.
* I.e., there is a difference between changing a configuration before use and
* the operation allows for multiple inputs (like plaintext for cipher update calls before final).
*/
OperationStep getDominatingInitializersToStep(IOType type) {
result.flowsToOperationStep(this) and
result.setsValue(type) and
(
// Do not consider a 'reset' to occur on updates
result.getStepType() = UpdateStep()
or
not exists(OperationStep reset |
result != reset and
reset.setsValue(type) and
reset.flowsToOperationStep(this) and
result.flowsToOperationStep(reset)
)
)
}
/**
* Gets all output of `type` that flow to `this`
* if `this` is a final step and the output is not from
* a separate final step.
*/
OperationStep getOutputStepFlowingToStep(IOType type) {
this.getStepType() = FinalStep() and
result.flowsToOperationStep(this) and
exists(result.getOutput(type)) and
(result = this or result.getStepType() != FinalStep())
}
/**
* Gets an AVC for the primary algorithm for this operation.
* A primary algorithm is an AVC that flows to a ctx input directly or
* an AVC that flows to a primary algorithm input directly.
* See `AvcContextCreationStep` for details about resetting scenarios.
* Gets the first OperationStep an AVC flows to. If a context input,
* the AVC is considered primary.
* If a primary algorithm input, then get the last set primary algorithm
* operation step (dominating operation step, see `getDominatingInitializersToStep`).
*/
Crypto::AlgorithmValueConsumer getPrimaryAlgorithmValueConsumer() {
exists(DataFlow::Node src, DataFlow::Node sink, IOType t, OperationStep avcSucc |
(t = PrimaryAlgorithmIO() or t = ContextIO()) and
avcSucc.flowsToOperationStep(this) and
src.asExpr() = result and
sink = avcSucc.getInput(t) and
AvcToOperationStepFlow::flow(src, sink) and
(
// Case 1: the avcSucc step is a dominating initialization step
t = PrimaryAlgorithmIO() and
avcSucc = this.getDominatingInitializersToStep(PrimaryAlgorithmIO())
or
// Case 2: the succ is a context input (any avcSucc is valid)
t = ContextIO()
)
)
}
/**
* Gets the algorithm value consumer for an input to `this` operation step
* of the given `type`.
* TODO: generalize to use this for `getPrimaryAlgorithmValueConsumer`
*/
Crypto::AlgorithmValueConsumer getAlgorithmValueConsumerForInput(IOType type) {
exists(DataFlow::Node src, DataFlow::Node sink |
AvcToOperationStepFlow::flow(src, sink) and
src.asExpr() = result and
sink = this.getInput(type)
)
}
}
/**
* An AVC is considered to output a 'context type', however,
* each AVC has it's own output types in practice.
* Some output algorithm containers (`EVP_get_cipherbyname`)
* some output explicit contexts (`EVP_PKEY_CTX_new_from_name`).
* The output of an AVC cannot be determined to be a primary algorithm (PrimaryAlgorithmIO), that depends
* on the use of the AVC output.
* The use is assumed to be of two forms:
* - The AVC output flows to a known input that accepts an algorithm
* e.g., `EVP_DigestInit(ctx, type)` the `type` parameter is known to be the primary algorithm.
* `EVP_SignInit(ctx, type)` the `type` parameter is known to be a digest algorithm for the signature.
* - The AVC output flows to a context initialization step
* e.g., `pkey_ctx = EVP_PKEY_CTX_new_from_name(libctx, name, propquery)` this is an AVC call, but the
* API says the output is a context. It is consumed typically by something like:
* `ctx = EVP_PKEY_keygen_init(pkey_ctx)`, but note I cannot consider the `pkey_ctx` parameter to always be a primary algorithm,
* a key gen can be inited by a prior key as well, e.g., `ctx = EVP_PKEY_CTX_new(pkey, NULL)`.
* Hence, these initialization steps take in a context that may have come from an AVC or something else,
* and therefore cannot be considered a primary algorithm.
* Assumption: The first operation step an AVC flows to will be of the above two forms.
* Resetting Algorithm Concerns and Assumptions:
* What if a user resets the algorithm through another AVC call?
* How would we detect that and only look at the 'dominating' (last set) AVC?
* From an AVC, always assess the first operation step it flows to.
* If the first step is to a context input, then we assume that reset is not possible in the same path.
* I.e., a user cannot reset the algorithm without starting an entirely new operation step chain.
* See the use patterns for `pkey_ctx = EVP_PKEY_CTX_new_from_name(...)` mentioned above. A user cannot
* reset the algorithm without calling a new `ctx = EVP_PKEY_keygen_init(pkey_ctx)`,
* i.e., subsequent flow follows the `ctx` output.
* If the first step is to any other input, then we use the `getDominatingInitializersToStep`
* to find the last AVC that set the algorithm for the operation step.
* Domination checks must occur at an operation step (e.g., at a final operation).
* This operation step does not find the dominating AVC.
* If a primary algorithm is explicitly set and and AVC is set through a context input,
* we will use both cases as primary inputs.
*/
class AvcContextCreationStep extends OperationStep instanceof OpenSslAlgorithmValueConsumer {
override DataFlow::Node getOutput(IOType type) {
type = ContextIO() and result = super.getResultNode()
}
override DataFlow::Node getInput(IOType type) { none() }
override OperationStepType getStepType() { result = ContextCreationStep() }
}
abstract private class CtxPassThroughCall extends Call {
abstract DataFlow::Node getNode1();
abstract DataFlow::Node getNode2();
}
/**
* A call whose target contains 'free' or 'reset' and has an argument of type
* CtxPointerArgument.
*/
private class CtxClearCall extends Call {
CtxClearCall() {
this.getTarget().getName().toLowerCase().matches(["%free%", "%reset%"]) and
this.getAnArgument() instanceof CtxPointerArgument
}
}
/**
* A call whose target contains 'copy' and has an argument of type
* CtxPointerArgument.
*/
private class CtxCopyOutArgCall extends CtxPassThroughCall {
DataFlow::Node n1;
DataFlow::Node n2;
CtxCopyOutArgCall() {
this.getTarget().getName().toLowerCase().matches("%copy%") and
n1.asExpr() = this.getAnArgument() and
n1.getType() instanceof CtxType and
n2.asDefiningArgument() = this.getAnArgument() and
n2.getType() instanceof CtxType and
n1.asDefiningArgument() != n2.asExpr()
}
override DataFlow::Node getNode1() { result = n1 }
override DataFlow::Node getNode2() { result = n2 }
}
/**
* A call whose target contains 'dup' and has an argument of type
* CtxPointerArgument.
*/
private class CtxCopyReturnCall extends CtxPassThroughCall, CtxPointerExpr {
DataFlow::Node n1;
CtxCopyReturnCall() {
this.getTarget().getName().toLowerCase().matches("%dup%") and
n1.asExpr() = this.getAnArgument() and
n1.getType() instanceof CtxType
}
override DataFlow::Node getNode1() { result = n1 }
override DataFlow::Node getNode2() { result.asExpr() = this }
}
// TODO: is this still needed?
/**
* A call to `EVP_PKEY_paramgen` acts as a kind of pass through.
* It's output pkey is eventually used in a new operation generating
* a fresh context pointer (e.g., `EVP_PKEY_CTX_new`).
* It is easier to model this as a pass through
* than to model the flow from the paramgen to the new key generation.
*/
private class CtxParamGenCall extends CtxPassThroughCall {
DataFlow::Node n1;
DataFlow::Node n2;
CtxParamGenCall() {
this.getTarget().getName() = "EVP_PKEY_paramgen" and
n1.asExpr() = this.getArgument(0) and
(
n2.asExpr() = this.getArgument(1)
or
n2.asDefiningArgument() = this.getArgument(1)
)
}
override DataFlow::Node getNode1() { result = n1 }
override DataFlow::Node getNode2() { result = n2 }
}
//TODO: I am not sure CallArgToCtxRet is needed anymore
/**
* If the current node is an argument to a function
* that returns a pointer type, immediately flow through.
* NOTE: this passthrough is required if we allow
* intermediate steps to go into variables that are not a CTX type.
* See for example `CtxParamGenCall`.
*/
private class CallArgToCtxRet extends CtxPassThroughCall, CtxPointerExpr {
DataFlow::Node n1;
DataFlow::Node n2;
CallArgToCtxRet() {
this.getAnArgument() = n1.asExpr() and
n2.asExpr() = this
}
override DataFlow::Node getNode1() { result = n1 }
override DataFlow::Node getNode2() { result = n2 }
}
/**
* A flow configuration from any non-final `OperationStep` to any other `OperationStep`.
*/
module OperationStepFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { predicate isSource(DataFlow::Node source) {
exists(OpenSSLAlgorithmValueConsumer c | c.getResultNode() = source) exists(OperationStep s |
s.getAnOutput() = source or
s.getAnInput() = source
)
} }
predicate isSink(DataFlow::Node sink) { predicate isSink(DataFlow::Node sink) {
exists(EVPOperation c | c.getAlgorithmArg() = sink.asExpr()) exists(OperationStep s |
s.getAnInput() = sink or
s.getAnOutput() = sink
)
}
predicate isBarrier(DataFlow::Node node) {
exists(CtxClearCall c | c.getAnArgument() = node.asExpr())
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(CtxPassThroughCall c | c.getNode1() = node1 and c.getNode2() = node2)
or
// Flow out through all outputs from an operation step if more than one output
// is defined.
exists(OperationStep s | s.getAnInput() = node1 and s.getAnOutput() = node2)
// TODO: consideration for additional alises defined as follows:
// if an output from an operation step itself flows from the output of another operation step
// then the source of that flow's outputs (all of them) are potential aliases
} }
} }
private module AlgGetterToAlgConsumerFlow = DataFlow::Global<AlgGetterToAlgConsumerConfig>; module OperationStepFlow = DataFlow::Global<OperationStepFlowConfig>;
/** /**
* The base class for all operations of the EVP API. * A flow from AVC to the first `OperationStep` the AVC reaches as an input.
* This captures one-shot APIs (with and without an initilizer call) and final calls.
* Provides some default methods for Crypto::KeyOperationInstance class
*/ */
abstract class EVPOperation extends OpenSSLOperation { module AvcToOperationStepFlowConfig implements DataFlow::ConfigSig {
/** predicate isSource(DataFlow::Node source) {
* Gets the context argument that ties together initialization, updates and/or final calls. exists(AvcContextCreationStep s | s.getAnOutput() = source)
*/
Expr getContextArg() { result = this.(Call).getArgument(0) }
/**
* Some input data like plaintext or message digest.
* Either argument provided direcly in the call or all arguments that were provided in update calls.
*/
abstract Expr getInputArg();
/**
* Some output data like ciphertext or signature.
*/
abstract Expr getOutputArg();
/**
* Overwrite with an explicitly specified algorithm or leave base implementation to find it in the initialization call.
*/
override Expr getAlgorithmArg() { result = this.getInitCall().getAlgorithmArg() }
/**
* Finds the initialization call, may be none.
*/
EVPInitialize getInitCall() {
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
} }
Crypto::ArtifactOutputDataFlowNode getOutputArtifact() { predicate isSink(DataFlow::Node sink) { exists(OperationStep s | s.getAnInput() = sink) }
result = DataFlow::exprNode(this.getOutputArg())
predicate isBarrier(DataFlow::Node node) {
exists(CtxClearCall c | c.getAnArgument() = node.asExpr())
} }
/** /**
* Input consumer is the input argument of the call. * Only get the first operation step encountered.
*/ */
Crypto::ConsumerInputDataFlowNode getInputConsumer() { predicate isBarrierOut(DataFlow::Node node) { isSink(node) }
result = DataFlow::exprNode(this.getInputArg())
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(CtxPassThroughCall c | c.getNode1() = node1 and c.getNode2() = node2)
} }
} }
/** module AvcToOperationStepFlow = DataFlow::Global<AvcToOperationStepFlowConfig>;
* The final calls of the EVP API.
*/ module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
abstract class EVPFinal extends EVPOperation { predicate isSource(DataFlow::Node source) { source.asExpr().getValue().toInt() in [0, 1] }
/**
* All update calls that were executed before this final call. predicate isSink(DataFlow::Node sink) {
*/ exists(OperationStep s | sink = s.getInput(KeyOperationSubtypeIO()))
EVPUpdate getUpdateCalls() {
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
} }
}
/**
* Gets the input data provided to all update calls. module EncValToInitEncArgFlow = DataFlow::Global<EncValToInitEncArgConfig>;
* If more input data was provided in the final call, override the method.
*/ private Crypto::KeyOperationSubtype intToCipherOperationSubtype(int i) {
override Expr getInputArg() { result = this.getUpdateCalls().getInputArg() } i = 0 and
result instanceof Crypto::TEncryptMode
/** or
* Gets the output data provided to all update calls. i = 1 and result instanceof Crypto::TDecryptMode
* If more output data was provided in the final call, override the method. }
*/
override Expr getOutputArg() { result = this.getUpdateCalls().getOutputArg() } Crypto::KeyOperationSubtype resolveKeyOperationSubTypeOperationStep(OperationStep s) {
exists(DataFlow::Node src |
EncValToInitEncArgFlow::flow(src, s.getInput(KeyOperationSubtypeIO())) and
result = intToCipherOperationSubtype(src.asExpr().getValue().toInt())
)
} }

View File

@@ -1,4 +1,5 @@
import OpenSSLOperationBase import OpenSSLOperationBase
import EVPCipherOperation import CipherOperation
import EVPHashOperation import HashOperation
import ECKeyGenOperation import SignatureOperation
import KeyGenOperation

Some files were not shown because too many files have changed in this diff Show More