mirror of
https://github.com/github/codeql.git
synced 2025-12-16 08:43:11 +01:00
Merge branch 'main' into redsun82/go-internal-tests
This commit is contained in:
4
.github/copilot-instructions.md
vendored
Normal file
4
.github/copilot-instructions.md
vendored
Normal 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.
|
||||
1
.github/workflows/check-change-note.yml
vendored
1
.github/workflows/check-change-note.yml
vendored
@@ -16,7 +16,6 @@ on:
|
||||
- "shared/**/*.qll"
|
||||
- "!**/experimental/**"
|
||||
- "!ql/**"
|
||||
- "!rust/**"
|
||||
- ".github/workflows/check-change-note.yml"
|
||||
|
||||
jobs:
|
||||
|
||||
23
.github/workflows/check-overlay-annotations.yml
vendored
Normal file
23
.github/workflows/check-overlay-annotations.yml
vendored
Normal 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
|
||||
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
- name: Create database
|
||||
run: |
|
||||
"${CODEQL}" database create \
|
||||
--search-path "${{ github.workspace }}"
|
||||
--search-path "${{ github.workspace }}" \
|
||||
--threads 4 \
|
||||
--language ql --source-root "${{ github.workspace }}/repo" \
|
||||
"${{ runner.temp }}/database"
|
||||
|
||||
@@ -9,7 +9,7 @@ repos:
|
||||
- id: trailing-whitespace
|
||||
exclude: /test/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$
|
||||
- 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
|
||||
rev: v17.0.6
|
||||
@@ -20,7 +20,7 @@ repos:
|
||||
rev: 25.1.0
|
||||
hooks:
|
||||
- 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
|
||||
hooks:
|
||||
|
||||
920
Cargo.lock
generated
920
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -11,8 +11,3 @@ members = [
|
||||
"rust/autobuild",
|
||||
]
|
||||
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" }
|
||||
|
||||
54
MODULE.bazel
54
MODULE.bazel
@@ -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.
|
||||
RUST_EDITION = "2024"
|
||||
|
||||
RUST_VERSION = "1.85.0"
|
||||
RUST_VERSION = "1.86.0"
|
||||
|
||||
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
|
||||
rust.toolchain(
|
||||
@@ -71,11 +71,11 @@ use_repo(
|
||||
tree_sitter_extractors_deps = use_extension("//misc/bazel/3rdparty:tree_sitter_extractors_extension.bzl", "r")
|
||||
use_repo(
|
||||
tree_sitter_extractors_deps,
|
||||
"vendor_ts__anyhow-1.0.97",
|
||||
"vendor_ts__anyhow-1.0.98",
|
||||
"vendor_ts__argfile-0.2.1",
|
||||
"vendor_ts__chalk-ir-0.100.0",
|
||||
"vendor_ts__chrono-0.4.40",
|
||||
"vendor_ts__clap-4.5.35",
|
||||
"vendor_ts__chalk-ir-0.103.0",
|
||||
"vendor_ts__chrono-0.4.41",
|
||||
"vendor_ts__clap-4.5.40",
|
||||
"vendor_ts__dunce-1.0.5",
|
||||
"vendor_ts__either-1.15.0",
|
||||
"vendor_ts__encoding-0.2.33",
|
||||
@@ -87,33 +87,33 @@ use_repo(
|
||||
"vendor_ts__lazy_static-1.5.0",
|
||||
"vendor_ts__mustache-0.9.0",
|
||||
"vendor_ts__num-traits-0.2.19",
|
||||
"vendor_ts__num_cpus-1.16.0",
|
||||
"vendor_ts__proc-macro2-1.0.94",
|
||||
"vendor_ts__num_cpus-1.17.0",
|
||||
"vendor_ts__proc-macro2-1.0.95",
|
||||
"vendor_ts__quote-1.0.40",
|
||||
"vendor_ts__ra_ap_base_db-0.0.273",
|
||||
"vendor_ts__ra_ap_cfg-0.0.273",
|
||||
"vendor_ts__ra_ap_hir-0.0.273",
|
||||
"vendor_ts__ra_ap_hir_def-0.0.273",
|
||||
"vendor_ts__ra_ap_hir_expand-0.0.273",
|
||||
"vendor_ts__ra_ap_hir_ty-0.0.273",
|
||||
"vendor_ts__ra_ap_ide_db-0.0.273",
|
||||
"vendor_ts__ra_ap_intern-0.0.273",
|
||||
"vendor_ts__ra_ap_load-cargo-0.0.273",
|
||||
"vendor_ts__ra_ap_parser-0.0.273",
|
||||
"vendor_ts__ra_ap_paths-0.0.273",
|
||||
"vendor_ts__ra_ap_project_model-0.0.273",
|
||||
"vendor_ts__ra_ap_span-0.0.273",
|
||||
"vendor_ts__ra_ap_stdx-0.0.273",
|
||||
"vendor_ts__ra_ap_syntax-0.0.273",
|
||||
"vendor_ts__ra_ap_vfs-0.0.273",
|
||||
"vendor_ts__rand-0.9.0",
|
||||
"vendor_ts__ra_ap_base_db-0.0.288",
|
||||
"vendor_ts__ra_ap_cfg-0.0.288",
|
||||
"vendor_ts__ra_ap_hir-0.0.288",
|
||||
"vendor_ts__ra_ap_hir_def-0.0.288",
|
||||
"vendor_ts__ra_ap_hir_expand-0.0.288",
|
||||
"vendor_ts__ra_ap_hir_ty-0.0.288",
|
||||
"vendor_ts__ra_ap_ide_db-0.0.288",
|
||||
"vendor_ts__ra_ap_intern-0.0.288",
|
||||
"vendor_ts__ra_ap_load-cargo-0.0.288",
|
||||
"vendor_ts__ra_ap_parser-0.0.288",
|
||||
"vendor_ts__ra_ap_paths-0.0.288",
|
||||
"vendor_ts__ra_ap_project_model-0.0.288",
|
||||
"vendor_ts__ra_ap_span-0.0.288",
|
||||
"vendor_ts__ra_ap_stdx-0.0.288",
|
||||
"vendor_ts__ra_ap_syntax-0.0.288",
|
||||
"vendor_ts__ra_ap_vfs-0.0.288",
|
||||
"vendor_ts__rand-0.9.1",
|
||||
"vendor_ts__rayon-1.10.0",
|
||||
"vendor_ts__regex-1.11.1",
|
||||
"vendor_ts__serde-1.0.219",
|
||||
"vendor_ts__serde_json-1.0.140",
|
||||
"vendor_ts__serde_with-3.12.0",
|
||||
"vendor_ts__syn-2.0.100",
|
||||
"vendor_ts__toml-0.8.20",
|
||||
"vendor_ts__serde_with-3.13.0",
|
||||
"vendor_ts__syn-2.0.103",
|
||||
"vendor_ts__toml-0.8.23",
|
||||
"vendor_ts__tracing-0.1.41",
|
||||
"vendor_ts__tracing-flame-0.2.0",
|
||||
"vendor_ts__tracing-subscriber-0.3.19",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -2,7 +2,7 @@ import runs_on
|
||||
import pytest
|
||||
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
|
||||
@pytest.mark.parametrize("query_suite", well_known_query_suites)
|
||||
|
||||
@@ -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
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -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.
|
||||
7
actions/ql/lib/change-notes/released/0.4.12.md
Normal file
7
actions/ql/lib/change-notes/released/0.4.12.md
Normal 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.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.11
|
||||
lastReleaseVersion: 0.4.12
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -16,6 +16,10 @@ private module RequestForgeryConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
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. */
|
||||
|
||||
@@ -15,6 +15,10 @@ private module SecretExfiltrationConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
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. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-all
|
||||
version: 0.4.12-dev
|
||||
version: 0.4.13-dev
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.6.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -24,6 +24,10 @@ private module MyConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof CodeInjectionSink and not madSink(sink, "code-injection")
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
@@ -34,6 +34,10 @@ private module MyConfig implements DataFlow::ConfigSig {
|
||||
isSink(node) and
|
||||
set instanceof DataFlow::FieldContent
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
@@ -25,6 +25,10 @@ private module MyConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(CompositeAction c | c.getAnOutputExpr() = sink.asExpr())
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
@@ -24,6 +24,10 @@ private module MyConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof CodeInjectionSink and not madSink(sink, "code-injection")
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
@@ -34,6 +34,10 @@ private module MyConfig implements DataFlow::ConfigSig {
|
||||
isSink(node) and
|
||||
set instanceof DataFlow::FieldContent
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
@@ -25,6 +25,10 @@ private module MyConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(ReusableWorkflow w | w.getAnOutputExpr() = sink.asExpr())
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module MyFlow = TaintTracking::Global<MyConfig>;
|
||||
|
||||
3
actions/ql/src/change-notes/released/0.6.4.md
Normal file
3
actions/ql/src/change-notes/released/0.6.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.4
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.3
|
||||
lastReleaseVersion: 0.6.4
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
- queries: .
|
||||
- apply: code-quality-extended-selectors.yml
|
||||
from: codeql/suite-helpers
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-queries
|
||||
version: 0.6.4-dev
|
||||
version: 0.6.5-dev
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
274
config/add-overlay-annotations.py
Normal file
274
config/add-overlay-annotations.py
Normal 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)
|
||||
@@ -11,6 +11,7 @@
|
||||
"/*- Diagnostic messages -*/",
|
||||
"/*- Diagnostic messages: severity -*/",
|
||||
"/*- Source location prefix -*/",
|
||||
"/*- Database metadata -*/",
|
||||
"/*- Lines of code -*/",
|
||||
"/*- Configuration files with key value pairs -*/",
|
||||
"/*- YAML -*/",
|
||||
@@ -31,4 +32,4 @@
|
||||
"/*- Python dbscheme -*/",
|
||||
"/*- Empty location -*/"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
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 '*'
|
||||
instruction_class_re = re.compile(r'^class (?P<name>[A-aa-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_class_re = re.compile(r'^ class (?P<name>[A-aa-z0-9]+)\s') # Declaration of an `Opcode` 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-Za-z0-9]+)Opcode\s') # Declaration of an `Opcode` base 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__))
|
||||
instruction_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll'))
|
||||
|
||||
@@ -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
|
||||
2509
cpp/downgrades/7bc12b02a4363149f0727a4bce07952dbb9d98aa/old.dbscheme
Normal file
2509
cpp/downgrades/7bc12b02a4363149f0727a4bce07952dbb9d98aa/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Introduce new complex 16-bit floating-point types
|
||||
compatibility: backwards
|
||||
builtintypes.rel: run builtintypes.qlo
|
||||
2499
cpp/downgrades/9baef67d1ffc1551429dbe1c1130815693e28218/old.dbscheme
Normal file
2499
cpp/downgrades/9baef67d1ffc1551429dbe1c1130815693e28218/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Add a predicate `getAnAttribute` to `Namespace`
|
||||
compatibility: full
|
||||
namespaceattributes.rel: delete
|
||||
@@ -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
|
||||
@@ -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
|
||||
2506
cpp/downgrades/e38346051783182ea75822e4adf8d4c6a949bc37/old.dbscheme
Normal file
2506
cpp/downgrades/e38346051783182ea75822e4adf8d4c6a949bc37/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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))
|
||||
)
|
||||
}
|
||||
2475
cpp/downgrades/e70d0b653187b93d9688f21c9db46bb1cd46ab78/old.dbscheme
Normal file
2475
cpp/downgrades/e70d0b653187b93d9688f21c9db46bb1cd46ab78/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -2,7 +2,7 @@ import runs_on
|
||||
import pytest
|
||||
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
|
||||
@pytest.mark.parametrize("query_suite", well_known_query_suites)
|
||||
|
||||
@@ -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
|
||||
|
||||
### New Features
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The `ThrowingFunction` class (`semmle.code.cpp.models.interfaces.Throwing`) has been deprecated. Please use the `AlwaysSehThrowingFunction` class instead.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added a predicate `hasParameterList` to `LambdaExpression` to capture whether a lambda has an explicitly specified parameter list.
|
||||
@@ -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.
|
||||
4
cpp/ql/lib/change-notes/2025-06-20-oracle-oci-models.md
Normal file
4
cpp/ql/lib/change-notes/2025-06-20-oracle-oci-models.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added `sql-injection` sink models for the Oracle Call Interface (OCI) database library functions `OCIStmtPrepare` and `OCIStmtPrepare2`.
|
||||
4
cpp/ql/lib/change-notes/2025-06-24-float16.md
Normal file
4
cpp/ql/lib/change-notes/2025-06-24-float16.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added support for `__fp16 _Complex` and `__bf16 _Complex` types
|
||||
4
cpp/ql/lib/change-notes/2025-06-27-locations.md
Normal file
4
cpp/ql/lib/change-notes/2025-06-27-locations.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The `UnknownDefaultLocation`, `UnknownExprLocation`, and `UnknownStmtLocation` classes have been deprecated. Use `UnknownLocation` instead.
|
||||
16
cpp/ql/lib/change-notes/released/5.2.0.md
Normal file
16
cpp/ql/lib/change-notes/released/5.2.0.md
Normal 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.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 5.1.0
|
||||
lastReleaseVersion: 5.2.0
|
||||
|
||||
@@ -8,12 +8,14 @@ module CryptoInput implements InputSig<Language::Location> {
|
||||
|
||||
class LocatableElement = Language::Locatable;
|
||||
|
||||
class UnknownLocation = Language::UnknownDefaultLocation;
|
||||
class UnknownLocation = Language::UnknownLocation;
|
||||
|
||||
LocatableElement dfn_to_element(DataFlow::Node node) {
|
||||
result = node.asExpr() or
|
||||
result = node.asParameter() or
|
||||
result = node.asVariable()
|
||||
result = node.asVariable() or
|
||||
result = node.asDefiningArgument()
|
||||
// TODO: do we need asIndirectExpr()?
|
||||
}
|
||||
|
||||
string locationToFileBaseNameAndLineNumberString(Location location) {
|
||||
@@ -54,7 +56,7 @@ module ArtifactFlowConfig implements DataFlow::ConfigSig {
|
||||
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 DataFlow::Node getOutput();
|
||||
@@ -89,9 +91,8 @@ module GenericDataSourceFlowConfig implements DataFlow::ConfigSig {
|
||||
|
||||
module GenericDataSourceFlow = TaintTracking::Global<GenericDataSourceFlowConfig>;
|
||||
|
||||
private class ConstantDataSource extends Crypto::GenericConstantSourceInstance instanceof Literal {
|
||||
ConstantDataSource() { this instanceof OpenSSLGenericSourceCandidateLiteral }
|
||||
|
||||
private class ConstantDataSource extends Crypto::GenericConstantSourceInstance instanceof OpenSslGenericSourceCandidateLiteral
|
||||
{
|
||||
override DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
|
||||
override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
|
||||
@@ -12,13 +12,15 @@ private import PaddingAlgorithmInstance
|
||||
* overlap with the known algorithm constants.
|
||||
* 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) {
|
||||
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) {
|
||||
exists(OpenSSLAlgorithmValueConsumer c |
|
||||
exists(OpenSslAlgorithmValueConsumer c |
|
||||
c.getInputNode() = sink and
|
||||
// exclude padding algorithm consumers, since
|
||||
// these consumers take in different constant values
|
||||
@@ -43,11 +45,11 @@ module KnownOpenSSLAlgorithmToAlgorithmValueConsumerConfig implements DataFlow::
|
||||
}
|
||||
}
|
||||
|
||||
module KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow =
|
||||
DataFlow::Global<KnownOpenSSLAlgorithmToAlgorithmValueConsumerConfig>;
|
||||
module KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow =
|
||||
DataFlow::Global<KnownOpenSslAlgorithmToAlgorithmValueConsumerConfig>;
|
||||
|
||||
module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof OpenSSLPaddingLiteral }
|
||||
module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof OpenSslPaddingLiteral }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(PaddingAlgorithmValueConsumer c | c.getInputNode() = sink)
|
||||
@@ -58,11 +60,11 @@ module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataF
|
||||
}
|
||||
}
|
||||
|
||||
module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow =
|
||||
DataFlow::Global<RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>;
|
||||
module RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow =
|
||||
DataFlow::Global<RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>;
|
||||
|
||||
class OpenSSLAlgorithmAdditionalFlowStep extends AdditionalFlowInputStep {
|
||||
OpenSSLAlgorithmAdditionalFlowStep() { exists(AlgorithmPassthroughCall c | c.getInNode() = this) }
|
||||
class OpenSslAlgorithmAdditionalFlowStep extends AdditionalFlowInputStep {
|
||||
OpenSslAlgorithmAdditionalFlowStep() { exists(AlgorithmPassthroughCall c | c.getInNode() = this) }
|
||||
|
||||
override DataFlow::Node getOutput() {
|
||||
exists(AlgorithmPassthroughCall c | c.getInNode() = this and c.getOutNode() = result)
|
||||
@@ -112,11 +114,11 @@ class CopyAndDupAlgorithmPassthroughCall extends AlgorithmPassthroughCall {
|
||||
override DataFlow::Node getOutNode() { result = outNode }
|
||||
}
|
||||
|
||||
class NIDToPointerPassthroughCall extends AlgorithmPassthroughCall {
|
||||
class NidToPointerPassthroughCall extends AlgorithmPassthroughCall {
|
||||
DataFlow::Node inNode;
|
||||
DataFlow::Node outNode;
|
||||
|
||||
NIDToPointerPassthroughCall() {
|
||||
NidToPointerPassthroughCall() {
|
||||
this.getTarget().getName() in ["OBJ_nid2obj", "OBJ_nid2ln", "OBJ_nid2sn"] and
|
||||
inNode.asExpr() = this.getArgument(0) and
|
||||
outNode.asExpr() = this
|
||||
@@ -148,11 +150,11 @@ class PointerToPointerPassthroughCall extends AlgorithmPassthroughCall {
|
||||
override DataFlow::Node getOutNode() { result = outNode }
|
||||
}
|
||||
|
||||
class PointerToNIDPassthroughCall extends AlgorithmPassthroughCall {
|
||||
class PointerToNidPassthroughCall extends AlgorithmPassthroughCall {
|
||||
DataFlow::Node inNode;
|
||||
DataFlow::Node outNode;
|
||||
|
||||
PointerToNIDPassthroughCall() {
|
||||
PointerToNidPassthroughCall() {
|
||||
this.getTarget().getName() in ["OBJ_obj2nid", "OBJ_ln2nid", "OBJ_sn2nid", "OBJ_txt2nid"] and
|
||||
(
|
||||
inNode.asIndirectExpr() = this.getArgument(0)
|
||||
|
||||
@@ -5,68 +5,68 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
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').
|
||||
*/
|
||||
predicate knownOpenSSLConstantToBlockModeFamilyType(
|
||||
KnownOpenSSLBlockModeAlgorithmConstant e, Crypto::TBlockCipherModeOfOperationType type
|
||||
predicate knownOpenSslConstantToBlockModeFamilyType(
|
||||
KnownOpenSslBlockModeAlgorithmExpr e, KeyOpAlg::ModeOfOperationType type
|
||||
) {
|
||||
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
|
||||
name.matches("CFB%") and type instanceof Crypto::CFB
|
||||
name = "CFB%" and type instanceof KeyOpAlg::CFB
|
||||
or
|
||||
name.matches("CTR") and type instanceof Crypto::CTR
|
||||
name = "CTR" and type instanceof KeyOpAlg::CTR
|
||||
or
|
||||
name.matches("GCM") and type instanceof Crypto::GCM
|
||||
name = "GCM" and type instanceof KeyOpAlg::GCM
|
||||
or
|
||||
name.matches("OFB") and type instanceof Crypto::OFB
|
||||
name = "OFB" and type instanceof KeyOpAlg::OFB
|
||||
or
|
||||
name.matches("XTS") and type instanceof Crypto::XTS
|
||||
name = "XTS" and type instanceof KeyOpAlg::XTS
|
||||
or
|
||||
name.matches("CCM") and type instanceof Crypto::CCM
|
||||
name = "CCM" and type instanceof KeyOpAlg::CCM
|
||||
or
|
||||
name.matches("GCM") and type instanceof Crypto::GCM
|
||||
name = "CCM" and type instanceof KeyOpAlg::CCM
|
||||
or
|
||||
name.matches("CCM") and type instanceof Crypto::CCM
|
||||
or
|
||||
name.matches("ECB") and type instanceof Crypto::ECB
|
||||
name = "ECB" and type instanceof KeyOpAlg::ECB
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class KnownOpenSSLBlockModeConstantAlgorithmInstance extends OpenSSLAlgorithmInstance,
|
||||
Crypto::ModeOfOperationAlgorithmInstance instanceof KnownOpenSSLBlockModeAlgorithmConstant
|
||||
class KnownOpenSslBlockModeConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
Crypto::ModeOfOperationAlgorithmInstance instanceof KnownOpenSslBlockModeAlgorithmExpr
|
||||
{
|
||||
OpenSSLAlgorithmValueConsumer getterCall;
|
||||
OpenSslAlgorithmValueConsumer getterCall;
|
||||
|
||||
KnownOpenSSLBlockModeConstantAlgorithmInstance() {
|
||||
KnownOpenSslBlockModeConstantAlgorithmInstance() {
|
||||
// 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
|
||||
// 2) The source is a KnownOpenSslAlgorithm is call, and we know we have an instance immediately from that
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
this instanceof OpenSslAlgorithmLiteral and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
or
|
||||
// Possibility 2:
|
||||
this instanceof DirectAlgorithmValueConsumer and getterCall = this
|
||||
this instanceof OpenSslAlgorithmCall and
|
||||
getterCall = this
|
||||
}
|
||||
|
||||
override Crypto::TBlockCipherModeOfOperationType getModeType() {
|
||||
knownOpenSSLConstantToBlockModeFamilyType(this, result)
|
||||
override KeyOpAlg::ModeOfOperationType getModeType() {
|
||||
knownOpenSslConstantToBlockModeFamilyType(this, result)
|
||||
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
|
||||
@@ -77,5 +77,5 @@ class KnownOpenSSLBlockModeConstantAlgorithmInstance extends OpenSSLAlgorithmIns
|
||||
result = this.(Call).getTarget().getName()
|
||||
}
|
||||
|
||||
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall }
|
||||
override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
|
||||
}
|
||||
|
||||
@@ -10,14 +10,14 @@ private import AlgToAVCFlow
|
||||
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').
|
||||
*/
|
||||
predicate knownOpenSSLConstantToCipherFamilyType(
|
||||
KnownOpenSSLCipherAlgorithmConstant e, Crypto::KeyOpAlg::TAlgorithm type
|
||||
predicate knownOpenSslConstantToCipherFamilyType(
|
||||
KnownOpenSslCipherAlgorithmExpr e, Crypto::KeyOpAlg::TAlgorithm type
|
||||
) {
|
||||
exists(string name |
|
||||
name = e.getNormalizedName() and
|
||||
name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
|
||||
(
|
||||
name.matches("AES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::AES())
|
||||
or
|
||||
@@ -33,9 +33,9 @@ predicate knownOpenSSLConstantToCipherFamilyType(
|
||||
or
|
||||
name.matches("CAST5%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::CAST5())
|
||||
or
|
||||
name.matches("2DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DoubleDES())
|
||||
name.matches("2DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DOUBLE_DES())
|
||||
or
|
||||
name.matches("3DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::TripleDES())
|
||||
name.matches("3DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::TRIPLE_DES())
|
||||
or
|
||||
name.matches("DES%") and type = KeyOpAlg::TSymmetricCipher(KeyOpAlg::DES())
|
||||
or
|
||||
@@ -64,28 +64,29 @@ predicate knownOpenSSLConstantToCipherFamilyType(
|
||||
)
|
||||
}
|
||||
|
||||
class KnownOpenSSLCipherConstantAlgorithmInstance extends OpenSSLAlgorithmInstance,
|
||||
Crypto::KeyOperationAlgorithmInstance instanceof KnownOpenSSLCipherAlgorithmConstant
|
||||
class KnownOpenSslCipherConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
Crypto::KeyOperationAlgorithmInstance instanceof KnownOpenSslCipherAlgorithmExpr
|
||||
{
|
||||
OpenSSLAlgorithmValueConsumer getterCall;
|
||||
OpenSslAlgorithmValueConsumer getterCall;
|
||||
|
||||
KnownOpenSSLCipherConstantAlgorithmInstance() {
|
||||
KnownOpenSslCipherConstantAlgorithmInstance() {
|
||||
// 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
|
||||
// 2) The source is a KnownOpenSslAlgorithm is call, and we know we have an instance immediately from that
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
this instanceof OpenSslAlgorithmLiteral and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
or
|
||||
// Possibility 2:
|
||||
this instanceof DirectAlgorithmValueConsumer and getterCall = this
|
||||
this instanceof OpenSslAlgorithmCall and
|
||||
getterCall = this
|
||||
}
|
||||
|
||||
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() {
|
||||
@@ -109,17 +110,17 @@ class KnownOpenSSLCipherConstantAlgorithmInstance extends OpenSSLAlgorithmInstan
|
||||
}
|
||||
|
||||
override int getKeySizeFixed() {
|
||||
this.(KnownOpenSSLCipherAlgorithmConstant).getExplicitKeySize() = result
|
||||
this.(KnownOpenSslCipherAlgorithmExpr).getExplicitKeySize() = result
|
||||
}
|
||||
|
||||
override Crypto::KeyOpAlg::Algorithm getAlgorithmType() {
|
||||
knownOpenSSLConstantToCipherFamilyType(this, result)
|
||||
override KeyOpAlg::AlgorithmType getAlgorithmType() {
|
||||
knownOpenSslConstantToCipherFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSSLConstantToCipherFamilyType(this, _) and
|
||||
not knownOpenSslConstantToCipherFamilyType(this, _) and
|
||||
result = Crypto::KeyOpAlg::TUnknownKeyOperationAlgorithmType()
|
||||
}
|
||||
|
||||
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall }
|
||||
override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
|
||||
// TODO: trace to any key size initializer, symmetric and asymmetric
|
||||
|
||||
@@ -6,31 +6,32 @@ private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgor
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
private import AlgToAVCFlow
|
||||
|
||||
class KnownOpenSSLEllipticCurveConstantAlgorithmInstance extends OpenSSLAlgorithmInstance,
|
||||
Crypto::EllipticCurveInstance instanceof KnownOpenSSLEllipticCurveAlgorithmConstant
|
||||
class KnownOpenSslEllipticCurveConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
Crypto::EllipticCurveInstance instanceof KnownOpenSslEllipticCurveAlgorithmExpr
|
||||
{
|
||||
OpenSSLAlgorithmValueConsumer getterCall;
|
||||
OpenSslAlgorithmValueConsumer getterCall;
|
||||
|
||||
KnownOpenSSLEllipticCurveConstantAlgorithmInstance() {
|
||||
KnownOpenSslEllipticCurveConstantAlgorithmInstance() {
|
||||
// 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
|
||||
// 2) The source is a KnownOpenSslAlgorithm is call, and we know we have an instance immediately from that
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
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)
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
or
|
||||
// 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() {
|
||||
result = this.(Literal).getValue().toString()
|
||||
@@ -38,16 +39,22 @@ class KnownOpenSSLEllipticCurveConstantAlgorithmInstance extends OpenSSLAlgorith
|
||||
result = this.(Call).getTarget().getName()
|
||||
}
|
||||
|
||||
override Crypto::TEllipticCurveType getEllipticCurveType() {
|
||||
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _, result)
|
||||
override Crypto::EllipticCurveFamilyType getEllipticCurveFamilyType() {
|
||||
if
|
||||
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _,
|
||||
_)
|
||||
then
|
||||
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.getParsedEllipticCurveName(), _,
|
||||
result)
|
||||
else result = Crypto::OtherEllipticCurveType()
|
||||
}
|
||||
|
||||
override string getParsedEllipticCurveName() {
|
||||
result = this.(KnownOpenSSLEllipticCurveAlgorithmConstant).getNormalizedName()
|
||||
result = this.(KnownOpenSslAlgorithmExpr).getNormalizedName()
|
||||
}
|
||||
|
||||
override int getKeySize() {
|
||||
Crypto::ellipticCurveNameToKeySizeAndFamilyMapping(this.(KnownOpenSSLEllipticCurveAlgorithmConstant)
|
||||
Crypto::ellipticCurveNameToKnownKeySizeAndFamilyMapping(this.(KnownOpenSslAlgorithmExpr)
|
||||
.getNormalizedName(), result, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,75 +5,76 @@ private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgor
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
|
||||
private import AlgToAVCFlow
|
||||
|
||||
predicate knownOpenSSLConstantToHashFamilyType(
|
||||
KnownOpenSSLHashAlgorithmConstant e, Crypto::THashType type
|
||||
predicate knownOpenSslConstantToHashFamilyType(
|
||||
KnownOpenSslHashAlgorithmExpr e, Crypto::THashType type
|
||||
) {
|
||||
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
|
||||
name.matches("BLAKE2S") and type instanceof Crypto::BLAKE2S
|
||||
name = "BLAKE2S" and type instanceof Crypto::BLAKE2S
|
||||
or
|
||||
name.matches("GOST%") and type instanceof Crypto::GOSTHash
|
||||
name.matches("GOST%") and type instanceof Crypto::GOST_HASH
|
||||
or
|
||||
name.matches("MD2") and type instanceof Crypto::MD2
|
||||
name = "MD2" and type instanceof Crypto::MD2
|
||||
or
|
||||
name.matches("MD4") and type instanceof Crypto::MD4
|
||||
name = "MD4" and type instanceof Crypto::MD4
|
||||
or
|
||||
name.matches("MD5") and type instanceof Crypto::MD5
|
||||
name = "MD5" and type instanceof Crypto::MD5
|
||||
or
|
||||
name.matches("MDC2") and type instanceof Crypto::MDC2
|
||||
name = "MDC2" and type instanceof Crypto::MDC2
|
||||
or
|
||||
name.matches("POLY1305") and type instanceof Crypto::POLY1305
|
||||
name = "POLY1305" and type instanceof Crypto::POLY1305
|
||||
or
|
||||
name.matches(["SHA", "SHA1"]) and type instanceof Crypto::SHA1
|
||||
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
|
||||
name.matches("SHA3-%") and type instanceof Crypto::SHA3
|
||||
or
|
||||
name.matches(["SHAKE"]) and type instanceof Crypto::SHAKE
|
||||
name = "SHAKE" and type instanceof Crypto::SHAKE
|
||||
or
|
||||
name.matches("SM3") and type instanceof Crypto::SM3
|
||||
name = "SM3" and type instanceof Crypto::SM3
|
||||
or
|
||||
name.matches("RIPEMD160") and type instanceof Crypto::RIPEMD160
|
||||
name = "RIPEMD160" and type instanceof Crypto::RIPEMD160
|
||||
or
|
||||
name.matches("WHIRLPOOL") and type instanceof Crypto::WHIRLPOOL
|
||||
name = "WHIRLPOOL" and type instanceof Crypto::WHIRLPOOL
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class KnownOpenSSLHashConstantAlgorithmInstance extends OpenSSLAlgorithmInstance,
|
||||
Crypto::HashAlgorithmInstance instanceof KnownOpenSSLHashAlgorithmConstant
|
||||
class KnownOpenSslHashConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
Crypto::HashAlgorithmInstance instanceof KnownOpenSslHashAlgorithmExpr
|
||||
{
|
||||
OpenSSLAlgorithmValueConsumer getterCall;
|
||||
OpenSslAlgorithmValueConsumer getterCall;
|
||||
|
||||
KnownOpenSSLHashConstantAlgorithmInstance() {
|
||||
KnownOpenSslHashConstantAlgorithmInstance() {
|
||||
// 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
|
||||
// 2) The source is a KnownOpenSslAlgorithm is call, and we know we have an instance immediately from that
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
this instanceof OpenSslAlgorithmLiteral and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
or
|
||||
// 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() {
|
||||
knownOpenSSLConstantToHashFamilyType(this, result)
|
||||
knownOpenSslConstantToHashFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSSLConstantToHashFamilyType(this, _) and result = Crypto::OtherHashType()
|
||||
not knownOpenSslConstantToHashFamilyType(this, _) and result = Crypto::OtherHashType()
|
||||
}
|
||||
|
||||
override string getRawHashAlgorithmName() {
|
||||
@@ -83,6 +84,6 @@ class KnownOpenSSLHashConstantAlgorithmInstance extends OpenSSLAlgorithmInstance
|
||||
}
|
||||
|
||||
override int getFixedDigestLength() {
|
||||
this.(KnownOpenSSLHashAlgorithmConstant).getExplicitDigestLength() = result
|
||||
this.(KnownOpenSslHashAlgorithmExpr).getExplicitDigestLength() = result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgor
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
|
||||
private import AlgToAVCFlow
|
||||
|
||||
predicate knownOpenSSLConstantToKeyAgreementFamilyType(
|
||||
KnownOpenSSLKeyAgreementAlgorithmConstant e, Crypto::TKeyAgreementType type
|
||||
predicate knownOpenSslConstantToKeyAgreementFamilyType(
|
||||
KnownOpenSslKeyAgreementAlgorithmExpr e, Crypto::TKeyAgreementType type
|
||||
) {
|
||||
exists(string name |
|
||||
name = e.getNormalizedName() and
|
||||
name = e.(KnownOpenSslAlgorithmExpr).getNormalizedName() and
|
||||
(
|
||||
name = "ECDH" and type = Crypto::ECDH()
|
||||
or
|
||||
@@ -22,36 +22,37 @@ predicate knownOpenSSLConstantToKeyAgreementFamilyType(
|
||||
)
|
||||
}
|
||||
|
||||
class KnownOpenSSLHashConstantAlgorithmInstance extends OpenSSLAlgorithmInstance,
|
||||
Crypto::KeyAgreementAlgorithmInstance instanceof KnownOpenSSLKeyAgreementAlgorithmConstant
|
||||
class KnownOpenSslKeyAgreementConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
Crypto::KeyAgreementAlgorithmInstance instanceof KnownOpenSslKeyAgreementAlgorithmExpr
|
||||
{
|
||||
OpenSSLAlgorithmValueConsumer getterCall;
|
||||
OpenSslAlgorithmValueConsumer getterCall;
|
||||
|
||||
KnownOpenSSLHashConstantAlgorithmInstance() {
|
||||
KnownOpenSslKeyAgreementConstantAlgorithmInstance() {
|
||||
// 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
|
||||
// 2) The source is a KnownOpenSslAlgorithm is call, and we know we have an instance immediately from that
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
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)
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
)
|
||||
or
|
||||
// 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() {
|
||||
knownOpenSSLConstantToKeyAgreementFamilyType(this, result)
|
||||
knownOpenSslConstantToKeyAgreementFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSSLConstantToKeyAgreementFamilyType(this, _) and
|
||||
not knownOpenSslConstantToKeyAgreementFamilyType(this, _) and
|
||||
result = Crypto::OtherKeyAgreementType()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,79 +1,44 @@
|
||||
import cpp
|
||||
import experimental.quantum.OpenSSL.GenericSourceCandidateLiteral
|
||||
|
||||
predicate resolveAlgorithmFromExpr(Expr e, string normalizedName, string algType) {
|
||||
resolveAlgorithmFromCall(e, normalizedName, algType)
|
||||
or
|
||||
resolveAlgorithmFromLiteral(e, normalizedName, algType)
|
||||
}
|
||||
|
||||
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") }
|
||||
predicate resolveAlgorithmFromExpr(
|
||||
KnownOpenSslAlgorithmExpr e, string normalizedName, string algType
|
||||
) {
|
||||
normalizedName = e.getNormalizedName() and
|
||||
algType = e.getAlgType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a call to a 'direct algorithm getter', e.g., EVP_MD5()
|
||||
* This approach to fetching algorithms was used in OpenSSL 1.0.2.
|
||||
* An expression that resolves to a known OpenSsl algorithm constant.
|
||||
* 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
|
||||
* and resolve the name as though it were a known literal.
|
||||
* 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
|
||||
* alias = "dss" and target = "dsa"
|
||||
* or
|
||||
* alias = "dss1" and target = "dsaWithSHA1"
|
||||
* alias = "dss1" and target = "dsaWithSHA1"
|
||||
*/
|
||||
predicate resolveAlgorithmFromCall(Call c, string normalized, string algType) {
|
||||
exists(string name, string parsedTargetName |
|
||||
parsedTargetName =
|
||||
c.getTarget().getName().replaceAll("EVP_", "").toLowerCase().replaceAll("_", "-") and
|
||||
name = resolveAlgorithmAlias(parsedTargetName) and
|
||||
knownOpenSSLAlgorithmLiteral(name, _, normalized, algType)
|
||||
)
|
||||
class OpenSslDirectAlgorithmFetchCall extends OpenSslAlgorithmCall {
|
||||
string normalizedName;
|
||||
string algType;
|
||||
|
||||
OpenSslDirectAlgorithmFetchCall() {
|
||||
//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.
|
||||
*/
|
||||
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
|
||||
exists(string name |
|
||||
name = resolveAlgorithmAlias(e.getValue()) and
|
||||
knownOpenSSLAlgorithmLiteral(name, _, normalized, algType)
|
||||
knownOpenSslAlgorithmLiteral(name, _, normalized, algType)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -115,7 +199,7 @@ string resolveAlgorithmAlias(string name) {
|
||||
result = getAlgorithmAlias(lower)
|
||||
or
|
||||
// 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.
|
||||
*/
|
||||
@@ -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
|
||||
* OpenSSL code base directly.
|
||||
* OpenSsl code base directly.
|
||||
*
|
||||
* 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")
|
||||
* `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"
|
||||
or
|
||||
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
|
||||
name = "id-alg-dh-sig-hmac-sha1" and nid = 325 and normalized = "DH" and algType = "KEY_AGREEMENT"
|
||||
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"
|
||||
or
|
||||
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
|
||||
name = "hmac-md5" and nid = 780 and normalized = "MD5" and algType = "HASH"
|
||||
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"
|
||||
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"
|
||||
or
|
||||
name = "gost94" and nid = 812 and normalized = "GOST94" and algType = "HASH"
|
||||
@@ -1140,10 +1231,14 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
or
|
||||
name = "rc4-hmac-md5" and nid = 915 and normalized = "MD5" and algType = "HASH"
|
||||
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"
|
||||
or
|
||||
name = "aes-128-cbc-hmac-sha1" and nid = 916 and normalized = "SHA1" and algType = "HASH"
|
||||
or
|
||||
name = "aes-128-cbc-hmac-sha1" and nid = 916 and normalized = "HMAC" and algType = "MAC"
|
||||
or
|
||||
name = "aes-128-cbc-hmac-sha1" and
|
||||
nid = 916 and
|
||||
normalized = "AES-128" and
|
||||
@@ -1153,6 +1248,8 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
or
|
||||
name = "aes-192-cbc-hmac-sha1" and nid = 917 and normalized = "SHA1" and algType = "HASH"
|
||||
or
|
||||
name = "aes-192-cbc-hmac-sha1" and nid = 917 and normalized = "HMAC" and algType = "MAC"
|
||||
or
|
||||
name = "aes-192-cbc-hmac-sha1" and
|
||||
nid = 917 and
|
||||
normalized = "AES-192" and
|
||||
@@ -1167,6 +1264,8 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
or
|
||||
name = "aes-256-cbc-hmac-sha1" and nid = 918 and normalized = "CBC" and algType = "BLOCK_MODE"
|
||||
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"
|
||||
or
|
||||
name = "aes-128-cbc-hmac-sha256" and
|
||||
@@ -1178,6 +1277,8 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
or
|
||||
name = "aes-192-cbc-hmac-sha256" and nid = 949 and normalized = "SHA-256" and algType = "HASH"
|
||||
or
|
||||
name = "aes-192-cbc-hmac-sha256" and nid = 949 and normalized = "HMAC" and algType = "MAC"
|
||||
or
|
||||
name = "aes-192-cbc-hmac-sha256" and
|
||||
nid = 949 and
|
||||
normalized = "AES-192" and
|
||||
@@ -1187,6 +1288,8 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
or
|
||||
name = "aes-256-cbc-hmac-sha256" and nid = 950 and normalized = "SHA-256" and algType = "HASH"
|
||||
or
|
||||
name = "aes-256-cbc-hmac-sha256" and nid = 950 and normalized = "HMAC" and algType = "MAC"
|
||||
or
|
||||
name = "aes-256-cbc-hmac-sha256" and
|
||||
nid = 950 and
|
||||
normalized = "AES-256" and
|
||||
@@ -1226,6 +1329,11 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
normalized = "CAMELLIA-128" and
|
||||
algType = "SYMMETRIC_ENCRYPTION"
|
||||
or
|
||||
name = "camellia-128-cmac" and
|
||||
nid = 964 and
|
||||
normalized = "CMAC" and
|
||||
algType = "MAC"
|
||||
or
|
||||
name = "camellia-192-gcm" and
|
||||
nid = 965 and
|
||||
normalized = "CAMELLIA-192" and
|
||||
@@ -1278,6 +1386,11 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
normalized = "CAMELLIA-256" and
|
||||
algType = "SYMMETRIC_ENCRYPTION"
|
||||
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"
|
||||
or
|
||||
name = "gost89-cnt-12" and
|
||||
@@ -1291,11 +1404,13 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
or
|
||||
name = "md_gost12_512" and nid = 983 and normalized = "GOST" and algType = "HASH"
|
||||
or
|
||||
// TODO: re-evaluate: this is a signing algorithm using hashing and curves
|
||||
name = "id-tc26-signwithdigest-gost3410-2012-256" and
|
||||
nid = 985 and
|
||||
normalized = "GOST34102012" and
|
||||
algType = "SYMMETRIC_ENCRYPTION"
|
||||
or
|
||||
// TODO: re-evaluate: this is a signing algorithm using hashing and curves
|
||||
name = "id-tc26-signwithdigest-gost3410-2012-512" and
|
||||
nid = 986 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
|
||||
nid = 988 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
|
||||
name = "id-tc26-hmac-gost-3411-2012-512" and
|
||||
nid = 989 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
|
||||
name = "id-tc26-agreement-gost-3410-2012-256" and
|
||||
nid = 992 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
|
||||
name = "id-tc26-agreement-gost-3410-2012-512" and
|
||||
nid = 993 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
|
||||
name = "id-tc26-gost-3410-2012-512-constants" and
|
||||
nid = 996 and
|
||||
@@ -1407,12 +1542,20 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
or
|
||||
name = "hmac-sha3-224" and nid = 1102 and normalized = "SHA3-224" and algType = "HASH"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
or
|
||||
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
|
||||
algType = "SYMMETRIC_ENCRYPTION"
|
||||
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
|
||||
nid = 989 and
|
||||
normalized = "GOST" and
|
||||
algType = "SYMMETRIC_ENCRYPTION"
|
||||
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
|
||||
nid = 810 and
|
||||
normalized = "GOST" and
|
||||
algType = "SYMMETRIC_ENCRYPTION"
|
||||
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"
|
||||
or
|
||||
name = "hmacwithmd5" and nid = 797 and normalized = "HMAC" and algType = "MAC"
|
||||
or
|
||||
name = "hmacwithsha1" and nid = 163 and normalized = "SHA1" and algType = "HASH"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
or
|
||||
name = "hmacwithsm3" and nid = 1281 and normalized = "HMAC" and algType = "MAC"
|
||||
or
|
||||
name = "id-aes128-ccm" and
|
||||
nid = 896 and
|
||||
normalized = "AES-128" and
|
||||
@@ -2457,12 +2633,20 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
or
|
||||
name = "id-hmacwithsha3-224" and nid = 1102 and normalized = "SHA3-224" and algType = "HASH"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
or
|
||||
name = "id-smime-alg-3deswrap" and
|
||||
@@ -2818,93 +3002,93 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
name = "ripemd160withrsa" and
|
||||
nid = 119 and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
algType = "SIGNATURE"
|
||||
or
|
||||
name = "ripemd160withrsa" and nid = 119 and normalized = "RIPEMD160" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-md2" and nid = 7 and normalized = "MD2" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-md4" and nid = 396 and normalized = "MD4" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-md5" and nid = 8 and normalized = "MD5" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-mdc2" and nid = 96 and normalized = "MDC2" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-np-md5" and nid = 104 and normalized = "MD5" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-ripemd160" and nid = 119 and normalized = "RIPEMD160" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-sha" and nid = 42 and normalized = "SHA" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-sha1" and nid = 65 and normalized = "SHA1" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-sha1-2" and nid = 115 and normalized = "SHA1" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-sha224" and nid = 671 and normalized = "SHA-224" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-sha256" and nid = 668 and normalized = "SHA-256" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-sha3-224" and nid = 1116 and normalized = "SHA3-224" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-sha3-256" and nid = 1117 and normalized = "SHA3-256" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-sha3-384" and nid = 1118 and normalized = "SHA3-384" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-sha3-512" and nid = 1119 and normalized = "SHA3-512" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-sha384" and nid = 669 and normalized = "SHA-384" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-sha512" and nid = 670 and normalized = "SHA-512" and algType = "HASH"
|
||||
or
|
||||
name = "rsa-sha512/224" and
|
||||
nid = 1145 and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
algType = "SIGNATURE"
|
||||
or
|
||||
name = "rsa-sha512/224" and nid = 1145 and normalized = "SHA-512-224" and algType = "HASH"
|
||||
or
|
||||
name = "rsa-sha512/256" and
|
||||
nid = 1146 and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
algType = "SIGNATURE"
|
||||
or
|
||||
name = "rsa-sha512/256" and nid = 1146 and normalized = "SHA-512-256" and algType = "HASH"
|
||||
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
|
||||
name = "rsa-sm3" and nid = 1144 and normalized = "SM3" and algType = "HASH"
|
||||
or
|
||||
@@ -2928,52 +3112,52 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
normalized = "OAEP" and
|
||||
algType = "ASYMMETRIC_PADDING"
|
||||
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
|
||||
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
|
||||
name = "rsassa-pss" and nid = 912 and normalized = "PSS" and algType = "ASYMMETRIC_PADDING"
|
||||
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
|
||||
name = "rsassapss" and nid = 912 and normalized = "PSS" and algType = "ASYMMETRIC_PADDING"
|
||||
name = "rsassapss" and nid = 912 and normalized = "PSS" and algType = "SIGNATURE"
|
||||
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
|
||||
name = "sha1withrsa" and nid = 115 and normalized = "SHA1" and algType = "HASH"
|
||||
or
|
||||
name = "sha1withrsaencryption" and
|
||||
nid = 65 and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
algType = "SIGNATURE"
|
||||
or
|
||||
name = "sha1withrsaencryption" and nid = 65 and normalized = "SHA1" and algType = "HASH"
|
||||
or
|
||||
name = "sha224withrsaencryption" and
|
||||
nid = 671 and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
algType = "SIGNATURE"
|
||||
or
|
||||
name = "sha224withrsaencryption" and nid = 671 and normalized = "SHA-224" and algType = "HASH"
|
||||
or
|
||||
name = "sha256withrsaencryption" and
|
||||
nid = 668 and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
algType = "SIGNATURE"
|
||||
or
|
||||
name = "sha256withrsaencryption" and nid = 668 and normalized = "SHA-256" and algType = "HASH"
|
||||
or
|
||||
name = "sha384withrsaencryption" and
|
||||
nid = 669 and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
algType = "SIGNATURE"
|
||||
or
|
||||
name = "sha384withrsaencryption" and nid = 669 and normalized = "SHA-384" and algType = "HASH"
|
||||
or
|
||||
name = "sha512-224withrsaencryption" and
|
||||
nid = 1145 and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
algType = "SIGNATURE"
|
||||
or
|
||||
name = "sha512-224withrsaencryption" and
|
||||
nid = 1145 and
|
||||
@@ -2983,7 +3167,7 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
name = "sha512-256withrsaencryption" and
|
||||
nid = 1146 and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
algType = "SIGNATURE"
|
||||
or
|
||||
name = "sha512-256withrsaencryption" and
|
||||
nid = 1146 and
|
||||
@@ -2993,14 +3177,14 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
name = "sha512withrsaencryption" and
|
||||
nid = 670 and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
algType = "SIGNATURE"
|
||||
or
|
||||
name = "sha512withrsaencryption" and nid = 670 and normalized = "SHA-512" and algType = "HASH"
|
||||
or
|
||||
name = "shawithrsaencryption" and
|
||||
nid = 42 and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
algType = "SIGNATURE"
|
||||
or
|
||||
name = "shawithrsaencryption" and nid = 42 and normalized = "SHA" and algType = "HASH"
|
||||
or
|
||||
@@ -3017,7 +3201,11 @@ predicate knownOpenSSLAlgorithmLiteral(string name, int nid, string normalized,
|
||||
name = "sm3withrsaencryption" and
|
||||
nid = 1144 and
|
||||
normalized = "RSA" and
|
||||
algType = "ASYMMETRIC_ENCRYPTION"
|
||||
algType = "SIGNATURE"
|
||||
or
|
||||
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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
|
||||
abstract class OpenSSLAlgorithmInstance extends Crypto::AlgorithmInstance {
|
||||
abstract OpenSSLAlgorithmValueConsumer getAVC();
|
||||
abstract class OpenSslAlgorithmInstance extends Crypto::AlgorithmInstance {
|
||||
abstract OpenSslAlgorithmValueConsumer getAvc();
|
||||
}
|
||||
|
||||
@@ -4,3 +4,5 @@ import PaddingAlgorithmInstance
|
||||
import BlockAlgorithmInstance
|
||||
import HashAlgorithmInstance
|
||||
import EllipticCurveAlgorithmInstance
|
||||
import SignatureAlgorithmInstance
|
||||
import MACAlgorithmInstance
|
||||
|
||||
@@ -5,6 +5,7 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
|
||||
private import AlgToAVCFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.DirectAlgorithmValueConsumer
|
||||
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.
|
||||
@@ -17,75 +18,75 @@ private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgor
|
||||
* # define RSA_PKCS1_WITH_TLS_PADDING 7
|
||||
* # 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
|
||||
// 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').
|
||||
*/
|
||||
predicate knownOpenSSLConstantToPaddingFamilyType(
|
||||
KnownOpenSSLPaddingAlgorithmConstant e, Crypto::TPaddingType type
|
||||
predicate knownOpenSslConstantToPaddingFamilyType(
|
||||
KnownOpenSslPaddingAlgorithmExpr e, KeyOpAlg::PaddingSchemeType type
|
||||
) {
|
||||
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
|
||||
name.matches("PSS") and type = Crypto::PSS()
|
||||
name = "PSS" and type = KeyOpAlg::PSS()
|
||||
or
|
||||
name.matches("PKCS7") and type = Crypto::PKCS7()
|
||||
name = "PKCS7" and type = KeyOpAlg::PKCS7()
|
||||
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
|
||||
// same mechanics as those with known nids
|
||||
class KnownOpenSSLPaddingConstantAlgorithmInstance extends OpenSSLAlgorithmInstance,
|
||||
class KnownOpenSslPaddingConstantAlgorithmInstance extends OpenSslAlgorithmInstance,
|
||||
Crypto::PaddingAlgorithmInstance instanceof Expr
|
||||
{
|
||||
OpenSSLAlgorithmValueConsumer getterCall;
|
||||
OpenSslAlgorithmValueConsumer getterCall;
|
||||
boolean isPaddingSpecificConsumer;
|
||||
|
||||
KnownOpenSSLPaddingConstantAlgorithmInstance() {
|
||||
KnownOpenSslPaddingConstantAlgorithmInstance() {
|
||||
// three possibilities:
|
||||
// 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
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
this instanceof KnownOpenSSLPaddingAlgorithmConstant and
|
||||
this instanceof OpenSslAlgorithmLiteral and
|
||||
this instanceof KnownOpenSslPaddingAlgorithmExpr and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink) and
|
||||
KnownOpenSslAlgorithmToAlgorithmValueConsumerFlow::flow(src, sink) and
|
||||
isPaddingSpecificConsumer = false
|
||||
)
|
||||
or
|
||||
// Possibility 2:
|
||||
this instanceof DirectAlgorithmValueConsumer and
|
||||
this instanceof OpenSslAlgorithmCall and
|
||||
getterCall = this and
|
||||
this instanceof KnownOpenSSLPaddingAlgorithmConstant and
|
||||
this instanceof KnownOpenSslPaddingAlgorithmExpr and
|
||||
isPaddingSpecificConsumer = false
|
||||
or
|
||||
// Possibility 3: padding-specific literal
|
||||
this instanceof OpenSSLPaddingLiteral and
|
||||
this instanceof OpenSslPaddingLiteral and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.(OpenSSLAlgorithmValueConsumer).getInputNode() and
|
||||
sink = getterCall.getInputNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a padding-specific consumer
|
||||
RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow::flow(src, sink)
|
||||
) and
|
||||
isPaddingSpecificConsumer = true
|
||||
}
|
||||
@@ -96,30 +97,30 @@ class KnownOpenSSLPaddingConstantAlgorithmInstance extends OpenSSLAlgorithmInsta
|
||||
result = this.(Call).getTarget().getName()
|
||||
}
|
||||
|
||||
override OpenSSLAlgorithmValueConsumer getAVC() { result = getterCall }
|
||||
override OpenSslAlgorithmValueConsumer getAvc() { result = getterCall }
|
||||
|
||||
Crypto::TPaddingType getKnownPaddingType() {
|
||||
this.(Literal).getValue().toInt() in [1, 7, 8] and result = Crypto::PKCS1_v1_5()
|
||||
KeyOpAlg::PaddingSchemeType getKnownPaddingType() {
|
||||
this.(Literal).getValue().toInt() in [1, 7, 8] and result = KeyOpAlg::PKCS1_V1_5()
|
||||
or
|
||||
this.(Literal).getValue().toInt() = 3 and result = Crypto::NoPadding()
|
||||
this.(Literal).getValue().toInt() = 3 and result = KeyOpAlg::NoPadding()
|
||||
or
|
||||
this.(Literal).getValue().toInt() = 4 and result = Crypto::OAEP()
|
||||
this.(Literal).getValue().toInt() = 4 and result = KeyOpAlg::OAEP()
|
||||
or
|
||||
this.(Literal).getValue().toInt() = 5 and result = Crypto::ANSI_X9_23()
|
||||
this.(Literal).getValue().toInt() = 5 and result = KeyOpAlg::ANSI_X9_23()
|
||||
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
|
||||
(
|
||||
result = this.getKnownPaddingType()
|
||||
or
|
||||
not exists(this.getKnownPaddingType()) and result = Crypto::OtherPadding()
|
||||
not exists(this.getKnownPaddingType()) and result = KeyOpAlg::OtherPadding()
|
||||
)
|
||||
or
|
||||
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
|
||||
// // they do not have an NID
|
||||
// // TODO: what about setting the padding directly?
|
||||
// class KnownRSAPaddingConstant extends OpenSSLPaddingAlgorithmInstance, Crypto::PaddingAlgorithmInstance instanceof Literal
|
||||
// class KnownRSAPaddingConstant extends OpenSslPaddingAlgorithmInstance, Crypto::PaddingAlgorithmInstance instanceof Literal
|
||||
// {
|
||||
// KnownRSAPaddingConstant() {
|
||||
// // from rsa.h in openssl:
|
||||
@@ -143,7 +144,7 @@ class KnownOpenSSLPaddingConstantAlgorithmInstance extends OpenSSLAlgorithmInsta
|
||||
// this instanceof Literal and
|
||||
// this.getValue().toInt() in [0, 1, 3, 4, 5, 6, 7, 8]
|
||||
// // TODO: trace to padding-specific consumers
|
||||
// RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow
|
||||
// RsaPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow
|
||||
// }
|
||||
// override string getRawPaddingAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
// override Crypto::TPaddingType getPaddingType() {
|
||||
@@ -161,18 +162,18 @@ class KnownOpenSSLPaddingConstantAlgorithmInstance extends OpenSSLAlgorithmInsta
|
||||
// else result = Crypto::OtherPadding()
|
||||
// }
|
||||
// }
|
||||
class OAEPPaddingAlgorithmInstance extends Crypto::OAEPPaddingAlgorithmInstance,
|
||||
KnownOpenSSLPaddingConstantAlgorithmInstance
|
||||
class OaepPaddingAlgorithmInstance extends Crypto::OaepPaddingAlgorithmInstance,
|
||||
KnownOpenSslPaddingConstantAlgorithmInstance
|
||||
{
|
||||
OAEPPaddingAlgorithmInstance() {
|
||||
this.(Crypto::PaddingAlgorithmInstance).getPaddingType() = Crypto::OAEP()
|
||||
OaepPaddingAlgorithmInstance() {
|
||||
this.(Crypto::PaddingAlgorithmInstance).getPaddingType() = KeyOpAlg::OAEP()
|
||||
}
|
||||
|
||||
override Crypto::HashAlgorithmInstance getOAEPEncodingHashAlgorithm() {
|
||||
override Crypto::HashAlgorithmInstance getOaepEncodingHashAlgorithm() {
|
||||
none() //TODO
|
||||
}
|
||||
|
||||
override Crypto::HashAlgorithmInstance getMGF1HashAlgorithm() {
|
||||
override Crypto::HashAlgorithmInstance getMgf1HashAlgorithm() {
|
||||
none() //TODO
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,14 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
|
||||
private import OpenSSLAlgorithmValueConsumerBase
|
||||
|
||||
abstract class CipherAlgorithmValueConsumer extends OpenSSLAlgorithmValueConsumer { }
|
||||
abstract class CipherAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer { }
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_CIPHER_fetch.html
|
||||
class EVPCipherAlgorithmValueConsumer extends CipherAlgorithmValueConsumer {
|
||||
class EvpCipherAlgorithmValueConsumer extends CipherAlgorithmValueConsumer {
|
||||
DataFlow::Node valueArgNode;
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EVPCipherAlgorithmValueConsumer() {
|
||||
EvpCipherAlgorithmValueConsumer() {
|
||||
resultNode.asExpr() = this and
|
||||
(
|
||||
this.(Call).getTarget().getName() in [
|
||||
@@ -30,8 +30,8 @@ class EVPCipherAlgorithmValueConsumer extends CipherAlgorithmValueConsumer {
|
||||
|
||||
// override DataFlow::Node getInputNode() { result = valueArgNode }
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
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
|
||||
// OpenSSL AVCs... the unknown literal sources would have to be any literals not in the known set.
|
||||
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
|
||||
// OpenSsl AVCs... the unknown literal sources would have to be any literals not in the known set.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,29 +4,30 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
|
||||
/**
|
||||
* Cases like EVP_MD5(),
|
||||
* there is no input, rather it directly gets an algorithm
|
||||
* and returns it.
|
||||
* A call that is considered to inherently 'consume' an algorithm value.
|
||||
* E.g., cases like EVP_MD5(),
|
||||
* 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 {
|
||||
DataFlow::Node resultNode;
|
||||
Expr resultExpr;
|
||||
|
||||
DirectAlgorithmValueConsumer() {
|
||||
this instanceof KnownOpenSSLAlgorithmConstant and
|
||||
this instanceof Call and
|
||||
resultExpr = this and
|
||||
resultNode.asExpr() = resultExpr
|
||||
}
|
||||
|
||||
class DirectAlgorithmValueConsumer extends OpenSslAlgorithmValueConsumer instanceof OpenSslAlgorithmCall
|
||||
{
|
||||
/**
|
||||
* These cases take in no explicit value (the value is implicit)
|
||||
*/
|
||||
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() {
|
||||
// Note: algorithm source definitions enforces that
|
||||
// this class will be a known algorithm source
|
||||
|
||||
@@ -4,14 +4,14 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
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
|
||||
class EVPEllipticCurveAlgorithmConsumer extends EllipticCurveValueConsumer {
|
||||
class EvpEllipticCurveAlgorithmConsumer extends EllipticCurveValueConsumer {
|
||||
DataFlow::Node valueArgNode;
|
||||
DataFlow::Node resultNode;
|
||||
|
||||
EVPEllipticCurveAlgorithmConsumer() {
|
||||
EvpEllipticCurveAlgorithmConsumer() {
|
||||
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
|
||||
@@ -25,7 +25,7 @@ class EVPEllipticCurveAlgorithmConsumer extends EllipticCurveValueConsumer {
|
||||
}
|
||||
|
||||
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 }
|
||||
|
||||
@@ -4,20 +4,20 @@ private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
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 {
|
||||
EVP_Q_Digest_Algorithm_Consumer() { this.(Call).getTarget().getName() = "EVP_Q_digest" }
|
||||
class Evp_Q_Digest_Algorithm_Consumer extends HashAlgorithmValueConsumer {
|
||||
Evp_Q_Digest_Algorithm_Consumer() { this.(Call).getTarget().getName() = "EVP_Q_digest" }
|
||||
|
||||
override Crypto::ConsumerInputDataFlowNode getInputNode() {
|
||||
result.asExpr() = this.(Call).getArgument(1)
|
||||
}
|
||||
|
||||
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() {
|
||||
@@ -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
|
||||
* 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 resultNode;
|
||||
|
||||
EVPDigestAlgorithmValueConsumer() {
|
||||
EvpDigestAlgorithmValueConsumer() {
|
||||
resultNode.asExpr() = this and
|
||||
(
|
||||
this.(Call).getTarget().getName() in [
|
||||
@@ -45,6 +73,9 @@ class EVPDigestAlgorithmValueConsumer extends HashAlgorithmValueConsumer {
|
||||
or
|
||||
this.(Call).getTarget().getName() = "EVP_MD_fetch" and
|
||||
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::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i)
|
||||
exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
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 resultNode;
|
||||
|
||||
EVPKEMAlgorithmValueConsumer() {
|
||||
EvpKemAlgorithmValueConsumer() {
|
||||
resultNode.asExpr() = this 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::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i)
|
||||
exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
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 resultNode;
|
||||
|
||||
EVPKeyExchangeAlgorithmValueConsumer() {
|
||||
EvpKeyExchangeAlgorithmValueConsumer() {
|
||||
resultNode.asExpr() = this 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::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
exists(OpenSSLAlgorithmInstance i | i.getAVC() = this and result = i)
|
||||
exists(OpenSslAlgorithmInstance i | i.getAvc() = this and result = i)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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
|
||||
*/
|
||||
|
||||
@@ -5,3 +5,4 @@ import PaddingAlgorithmValueConsumer
|
||||
import HashAlgorithmValueConsumer
|
||||
import EllipticCurveAlgorithmValueConsumer
|
||||
import PKeyAlgorithmValueConsumer
|
||||
import SignatureAlgorithmValueConsumer
|
||||
|
||||
@@ -4,13 +4,13 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
|
||||
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 resultNode;
|
||||
|
||||
EVPPKeyAlgorithmConsumer() {
|
||||
EvpPKeyAlgorithmConsumer() {
|
||||
resultNode.asExpr() = this.(Call) and // in all cases the result is the return
|
||||
(
|
||||
// NOTE: some of these consumers are themselves key gen operations,
|
||||
@@ -23,7 +23,8 @@ class EVPPKeyAlgorithmConsumer extends PKeyValueConsumer {
|
||||
or
|
||||
this.(Call).getTarget().getName() in [
|
||||
"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
|
||||
valueArgNode.asExpr() = this.(Call).getArgument(1)
|
||||
or
|
||||
@@ -46,7 +47,7 @@ class EVPPKeyAlgorithmConsumer extends PKeyValueConsumer {
|
||||
}
|
||||
|
||||
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 }
|
||||
|
||||
@@ -4,16 +4,16 @@ private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmCon
|
||||
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstanceBase
|
||||
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
|
||||
// TODO: need to handle setting padding through EVP_PKEY_CTX_set_params, where modes like "OSSL_PKEY_RSA_PAD_MODE_OAEP"
|
||||
// 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 resultNode;
|
||||
|
||||
EVP_PKEY_CTX_set_rsa_padding_AlgorithmValueConsumer() {
|
||||
Evp_PKey_Ctx_set_rsa_padding_AlgorithmValueConsumer() {
|
||||
resultNode.asExpr() = this and
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_rsa_padding" and
|
||||
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 Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
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
|
||||
// OpenSSL AVCs... the unknown literal sources would have to be any literals not in the known set.
|
||||
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
|
||||
// OpenSsl AVCs... the unknown literal sources would have to be any literals not in the known set.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
19
cpp/ql/lib/experimental/quantum/OpenSSL/AvcFlow.qll
Normal file
19
cpp/ql/lib/experimental/quantum/OpenSSL/AvcFlow.qll
Normal 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>;
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
@@ -14,9 +14,9 @@ private class IntLiteral extends Literal {
|
||||
/**
|
||||
* 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.
|
||||
* 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,
|
||||
// but EC specifically means set up a default curve container, that will later be
|
||||
//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.
|
||||
* 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)
|
||||
l.getValue().toInt() != 0 and
|
||||
// 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
|
||||
* since it is in a equality comparison, hence this case would also be filtered.
|
||||
*/
|
||||
class OpenSSLGenericSourceCandidateLiteral extends Literal {
|
||||
OpenSSLGenericSourceCandidateLiteral() {
|
||||
class OpenSslGenericSourceCandidateLiteral extends Literal {
|
||||
OpenSslGenericSourceCandidateLiteral() {
|
||||
(
|
||||
isOpenSSLIntLiteralGenericSourceCandidate(this) or
|
||||
isOpenSSLStringLiteralGenericSourceCandidate(this)
|
||||
isOpenSslIntLiteralGenericSourceCandidate(this) or
|
||||
isOpenSslStringLiteralGenericSourceCandidate(this)
|
||||
) and
|
||||
// ********* 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.
|
||||
|
||||
27
cpp/ql/lib/experimental/quantum/OpenSSL/KeyFlow.qll
Normal file
27
cpp/ql/lib/experimental/quantum/OpenSSL/KeyFlow.qll
Normal 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
|
||||
)
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import cpp
|
||||
|
||||
predicate isPossibleOpenSSLFunction(Function f) {
|
||||
isPossibleOpenSSLLocation(f.getADeclarationLocation())
|
||||
predicate isPossibleOpenSslFunction(Function f) {
|
||||
isPossibleOpenSslLocation(f.getADeclarationLocation())
|
||||
}
|
||||
|
||||
predicate isPossibleOpenSSLLocation(Location l) { l.toString().toLowerCase().matches("%openssl%") }
|
||||
predicate isPossibleOpenSslLocation(Location l) { l.toString().toLowerCase().matches("%openssl%") }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module OpenSSLModel {
|
||||
module OpenSslModel {
|
||||
import AlgorithmInstances.OpenSSLAlgorithmInstances
|
||||
import AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
import Operations.OpenSSLOperations
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -1,162 +1,523 @@
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
|
||||
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 {
|
||||
/**
|
||||
* Expression that specifies the algorithm for the operation.
|
||||
* Will be an argument of the operation in the simplest case.
|
||||
*/
|
||||
abstract Expr getAlgorithmArg();
|
||||
|
||||
/**
|
||||
* Algorithm is specified in initialization call or is implicitly established by the key.
|
||||
*/
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
AlgGetterToAlgConsumerFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
|
||||
DataFlow::exprNode(this.getAlgorithmArg()))
|
||||
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 Call to initialization functions from the EVP API.
|
||||
* These are not operations in the sense of Crypto::OperationInstance,
|
||||
* but they are used to initialize the context for the operation.
|
||||
* A pointer to a CtxType
|
||||
*/
|
||||
abstract class EVPInitialize extends Call {
|
||||
/**
|
||||
* Gets the context argument that ties together initialization, updates and/or final calls.
|
||||
*/
|
||||
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() }
|
||||
class CtxPointerExpr extends Expr {
|
||||
CtxPointerExpr() {
|
||||
this.getType() instanceof CtxType and
|
||||
this.getType() instanceof PointerType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Call to update functions from the EVP API.
|
||||
* These are not operations in the sense of Crypto::OperationInstance,
|
||||
* but they are used to update the context for the operation.
|
||||
* A call argument of type CtxPointerExpr.
|
||||
*/
|
||||
abstract class EVPUpdate extends Call {
|
||||
/**
|
||||
* Gets the context argument that ties together initialization, updates and/or final calls.
|
||||
*/
|
||||
Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
class CtxPointerArgument extends CtxPointerExpr {
|
||||
CtxPointerArgument() { exists(Call c | c.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() }
|
||||
Call getCall() { result.getAnArgument() = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
exists(OpenSSLAlgorithmValueConsumer c | c.getResultNode() = source)
|
||||
exists(OperationStep s |
|
||||
s.getAnOutput() = source or
|
||||
s.getAnInput() = source
|
||||
)
|
||||
}
|
||||
|
||||
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.
|
||||
* This captures one-shot APIs (with and without an initilizer call) and final calls.
|
||||
* Provides some default methods for Crypto::KeyOperationInstance class
|
||||
* A flow from AVC to the first `OperationStep` the AVC reaches as an input.
|
||||
*/
|
||||
abstract class EVPOperation extends OpenSSLOperation {
|
||||
/**
|
||||
* Gets the context argument that ties together initialization, updates and/or final calls.
|
||||
*/
|
||||
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())
|
||||
module AvcToOperationStepFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(AvcContextCreationStep s | s.getAnOutput() = source)
|
||||
}
|
||||
|
||||
Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||
result = DataFlow::exprNode(this.getOutputArg())
|
||||
predicate isSink(DataFlow::Node sink) { exists(OperationStep s | s.getAnInput() = sink) }
|
||||
|
||||
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() {
|
||||
result = DataFlow::exprNode(this.getInputArg())
|
||||
predicate isBarrierOut(DataFlow::Node node) { isSink(node) }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(CtxPassThroughCall c | c.getNode1() = node1 and c.getNode2() = node2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The final calls of the EVP API.
|
||||
*/
|
||||
abstract class EVPFinal extends EVPOperation {
|
||||
/**
|
||||
* All update calls that were executed before this final call.
|
||||
*/
|
||||
EVPUpdate getUpdateCalls() {
|
||||
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
|
||||
module AvcToOperationStepFlow = DataFlow::Global<AvcToOperationStepFlowConfig>;
|
||||
|
||||
module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr().getValue().toInt() in [0, 1] }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(OperationStep s | sink = s.getInput(KeyOperationSubtypeIO()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the input data provided to all update calls.
|
||||
* If more input data was provided in the final call, override the method.
|
||||
*/
|
||||
override Expr getInputArg() { result = this.getUpdateCalls().getInputArg() }
|
||||
|
||||
/**
|
||||
* Gets the output data provided to all update calls.
|
||||
* If more output data was provided in the final call, override the method.
|
||||
*/
|
||||
override Expr getOutputArg() { result = this.getUpdateCalls().getOutputArg() }
|
||||
}
|
||||
|
||||
module EncValToInitEncArgFlow = DataFlow::Global<EncValToInitEncArgConfig>;
|
||||
|
||||
private Crypto::KeyOperationSubtype intToCipherOperationSubtype(int i) {
|
||||
i = 0 and
|
||||
result instanceof Crypto::TEncryptMode
|
||||
or
|
||||
i = 1 and result instanceof Crypto::TDecryptMode
|
||||
}
|
||||
|
||||
Crypto::KeyOperationSubtype resolveKeyOperationSubTypeOperationStep(OperationStep s) {
|
||||
exists(DataFlow::Node src |
|
||||
EncValToInitEncArgFlow::flow(src, s.getInput(KeyOperationSubtypeIO())) and
|
||||
result = intToCipherOperationSubtype(src.asExpr().getValue().toInt())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import OpenSSLOperationBase
|
||||
import EVPCipherOperation
|
||||
import EVPHashOperation
|
||||
import ECKeyGenOperation
|
||||
import CipherOperation
|
||||
import HashOperation
|
||||
import SignatureOperation
|
||||
import KeyGenOperation
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user