nubwen-rust-shell 0.1.1__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/__init__.py +1 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/__main__.py +3 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/_build_info.py +3 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/cli.py +116 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/native/bin/rsh-server.exe +0 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/native/bin/rust-shell.exe +0 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/native/cmake/RustShell.cmake +79 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/native/docs/acceptance.md +33 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/native/docs/security.md +61 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/native/lib/rsh_runtime.lib +0 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/native/manifest.json +191 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/native/scripts/extract-llvm.py +42 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/native/scripts/setup-toolchain.ps1 +24 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/native/sdk/c/rust_shell.h +73 -0
- nubwen_rust_shell-0.1.1.data/purelib/rust_shell_tool/payload-manifest.json +62 -0
- nubwen_rust_shell-0.1.1.dist-info/METADATA +60 -0
- nubwen_rust_shell-0.1.1.dist-info/RECORD +22 -0
- nubwen_rust_shell-0.1.1.dist-info/WHEEL +5 -0
- nubwen_rust_shell-0.1.1.dist-info/entry_points.txt +3 -0
- nubwen_rust_shell-0.1.1.dist-info/licenses/LICENSE +5 -0
- nubwen_rust_shell-0.1.1.dist-info/licenses/THIRD_PARTY_NOTICES.txt +37888 -0
- nubwen_rust_shell-0.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Command-line distribution of the native Rust Shell protection tool."""
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
PACKAGE_VERSION = '0.1.1'
|
|
2
|
+
MANIFEST_SHA256 = '26432a3f6f66edeecab31a90a0b6e7d3c96158edd0c0f1d2b331ab5b922fc349'
|
|
3
|
+
PAYLOAD_FILES = ('bin/rust-shell.exe', 'bin/rsh-server.exe', 'lib/rsh_runtime.lib', 'sdk/c/rust_shell.h', 'cmake/RustShell.cmake', 'scripts/setup-toolchain.ps1', 'scripts/extract-llvm.py', 'docs/security.md', 'docs/acceptance.md', 'manifest.json')
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""No runtime dependencies, network downloads or shell command construction."""
|
|
2
|
+
import argparse
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path, PurePosixPath
|
|
7
|
+
import platform
|
|
8
|
+
import shutil
|
|
9
|
+
import struct
|
|
10
|
+
import subprocess
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
from . import _build_info
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _unique_object(pairs):
|
|
17
|
+
result = {}
|
|
18
|
+
for key, value in pairs:
|
|
19
|
+
if key in result:
|
|
20
|
+
raise ValueError("duplicate manifest field")
|
|
21
|
+
result[key] = value
|
|
22
|
+
return result
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _verified_bundle(package, expected_hash, expected_files):
|
|
26
|
+
manifest = package / "payload-manifest.json"
|
|
27
|
+
if manifest.is_symlink() or manifest.stat().st_size > 1024 * 1024:
|
|
28
|
+
raise ValueError("invalid payload manifest")
|
|
29
|
+
content = manifest.read_bytes()
|
|
30
|
+
if hashlib.sha256(content).hexdigest() != expected_hash:
|
|
31
|
+
raise ValueError("payload manifest checksum mismatch")
|
|
32
|
+
data = json.loads(content, object_pairs_hook=_unique_object)
|
|
33
|
+
if data["schema_version"] != 1 or data["target"] != "x86_64-pc-windows-msvc":
|
|
34
|
+
raise ValueError("unsupported payload identity")
|
|
35
|
+
native = (package / "native").resolve(strict=True)
|
|
36
|
+
seen = set()
|
|
37
|
+
for entry in data["files"]:
|
|
38
|
+
name = entry["path"]
|
|
39
|
+
relative = PurePosixPath(name)
|
|
40
|
+
if name not in expected_files or name in seen or relative.is_absolute() or ".." in relative.parts:
|
|
41
|
+
raise ValueError("unexpected payload path")
|
|
42
|
+
seen.add(name)
|
|
43
|
+
path = native.joinpath(*relative.parts)
|
|
44
|
+
if path.is_symlink() or not path.resolve(strict=True).is_relative_to(native) or not path.is_file():
|
|
45
|
+
raise ValueError("linked or missing payload")
|
|
46
|
+
if path.stat().st_size != entry["bytes"]:
|
|
47
|
+
raise ValueError("payload size mismatch: " + name)
|
|
48
|
+
with path.open("rb") as stream:
|
|
49
|
+
digest = hashlib.file_digest(stream, "sha256").hexdigest()
|
|
50
|
+
if digest != entry["sha256"]:
|
|
51
|
+
raise ValueError("payload checksum mismatch: " + name)
|
|
52
|
+
if seen != set(expected_files):
|
|
53
|
+
raise ValueError("incomplete payload inventory")
|
|
54
|
+
return native, data
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _installed_bundle():
|
|
58
|
+
if sys.platform != "win32" or struct.calcsize("P") != 8 or platform.machine().lower() not in ("amd64", "x86_64"):
|
|
59
|
+
raise ValueError("Rust Shell requires Windows x64 and a 64-bit Python interpreter")
|
|
60
|
+
if not _build_info.MANIFEST_SHA256:
|
|
61
|
+
raise ValueError("native payload is not staged; install a built wheel")
|
|
62
|
+
return _verified_bundle(Path(__file__).parent, _build_info.MANIFEST_SHA256, _build_info.PAYLOAD_FILES)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _error(error):
|
|
66
|
+
print("rust-shell package: " + str(error), file=sys.stderr)
|
|
67
|
+
return 2
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def main():
|
|
71
|
+
try:
|
|
72
|
+
native, _ = _installed_bundle()
|
|
73
|
+
return subprocess.run([str(native / "bin/rust-shell.exe"), *sys.argv[1:]], shell=False).returncode
|
|
74
|
+
except (OSError, ValueError, KeyError, TypeError) as error:
|
|
75
|
+
return _error(error)
|
|
76
|
+
except KeyboardInterrupt:
|
|
77
|
+
return 130
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def package_main():
|
|
81
|
+
parser = argparse.ArgumentParser(description="Inspect verified Rust Shell paths or explicitly set up its toolchain.")
|
|
82
|
+
mode = parser.add_mutually_exclusive_group()
|
|
83
|
+
mode.add_argument("--home", action="store_true")
|
|
84
|
+
mode.add_argument("--setup-toolchain", action="store_true")
|
|
85
|
+
parser.add_argument("--install-rust", action="store_true")
|
|
86
|
+
args = parser.parse_args()
|
|
87
|
+
if args.install_rust and not args.setup_toolchain:
|
|
88
|
+
parser.error("--install-rust requires --setup-toolchain")
|
|
89
|
+
try:
|
|
90
|
+
native, data = _installed_bundle()
|
|
91
|
+
if args.setup_toolchain:
|
|
92
|
+
powershell = shutil.which("pwsh.exe")
|
|
93
|
+
if not powershell:
|
|
94
|
+
raise ValueError("PowerShell 7 (pwsh.exe) is required for explicit toolchain setup")
|
|
95
|
+
command = [powershell, "-NoProfile", "-File", str(native / "scripts/setup-toolchain.ps1")]
|
|
96
|
+
if args.install_rust:
|
|
97
|
+
command.append("-InstallRust")
|
|
98
|
+
environment = dict(os.environ)
|
|
99
|
+
environment["PATH"] = str(Path(sys.executable).parent) + os.pathsep + environment.get("PATH", "")
|
|
100
|
+
return subprocess.run(command, shell=False, env=environment).returncode
|
|
101
|
+
if args.home:
|
|
102
|
+
print(native)
|
|
103
|
+
else:
|
|
104
|
+
print(json.dumps({
|
|
105
|
+
"package_version": data["package_version"], "native_version": data["native_version"],
|
|
106
|
+
"native_source_revision": data["native_source_revision"], "home": str(native),
|
|
107
|
+
"cli": str(native / "bin/rust-shell.exe"), "server": str(native / "bin/rsh-server.exe"),
|
|
108
|
+
"runtime_library": str(native / "lib/rsh_runtime.lib"),
|
|
109
|
+
"c_header": str(native / "sdk/c/rust_shell.h"), "cmake": str(native / "cmake/RustShell.cmake"),
|
|
110
|
+
"upstream_manifest": str(native / "manifest.json"), "rust_sdk_bundled": False,
|
|
111
|
+
}, indent=2))
|
|
112
|
+
return 0
|
|
113
|
+
except (OSError, ValueError, KeyError, TypeError) as error:
|
|
114
|
+
return _error(error)
|
|
115
|
+
except KeyboardInterrupt:
|
|
116
|
+
return 130
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
include_guard(GLOBAL)
|
|
2
|
+
include(CMakeParseArguments)
|
|
3
|
+
|
|
4
|
+
# rust_shell_add_protected_library(kernels
|
|
5
|
+
# CONFIG protection.toml CLI /path/to/rust-shell.exe
|
|
6
|
+
# LLVM_BIN /path/to/llvm-22.1.6/bin RUNTIME_LIBRARY /path/to/rsh_runtime.lib
|
|
7
|
+
# SOURCES kernels.c rules.cpp INCLUDE_DIRECTORIES /path/to/headers)
|
|
8
|
+
#
|
|
9
|
+
# All translation units are merged before the one sealing operation. Use one
|
|
10
|
+
# config/build_id and a fresh build directory per protected release build.
|
|
11
|
+
function(rust_shell_add_protected_library target_name)
|
|
12
|
+
cmake_parse_arguments(RSH "" "CONFIG;CLI;LLVM_BIN;RUNTIME_LIBRARY" "SOURCES;INCLUDE_DIRECTORIES" ${ARGN})
|
|
13
|
+
foreach(required CONFIG CLI LLVM_BIN RUNTIME_LIBRARY)
|
|
14
|
+
if(NOT RSH_${required})
|
|
15
|
+
message(FATAL_ERROR "rust_shell_add_protected_library requires ${required}")
|
|
16
|
+
endif()
|
|
17
|
+
endforeach()
|
|
18
|
+
if(NOT WIN32 OR NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
|
19
|
+
message(FATAL_ERROR "rust-shell v1 supports Windows x64 native builds")
|
|
20
|
+
endif()
|
|
21
|
+
if(NOT RSH_SOURCES)
|
|
22
|
+
message(FATAL_ERROR "No protected sources supplied")
|
|
23
|
+
endif()
|
|
24
|
+
get_filename_component(config "${RSH_CONFIG}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
|
25
|
+
get_property(configs GLOBAL PROPERTY RSH_USED_CONFIGS)
|
|
26
|
+
if(config IN_LIST configs)
|
|
27
|
+
message(FATAL_ERROR "Each protection config/build_id can be sealed once; combine sources in one protected library")
|
|
28
|
+
endif()
|
|
29
|
+
set_property(GLOBAL APPEND PROPERTY RSH_USED_CONFIGS "${config}")
|
|
30
|
+
foreach(tool clang-cl.exe llvm-link.exe llc.exe LLVM-C.dll)
|
|
31
|
+
if(NOT EXISTS "${RSH_LLVM_BIN}/${tool}")
|
|
32
|
+
message(FATAL_ERROR "Pinned LLVM tool missing: ${RSH_LLVM_BIN}/${tool}")
|
|
33
|
+
endif()
|
|
34
|
+
endforeach()
|
|
35
|
+
get_filename_component(sdk "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../sdk/c" ABSOLUTE)
|
|
36
|
+
set(includes "/I${sdk}")
|
|
37
|
+
foreach(directory IN LISTS RSH_INCLUDE_DIRECTORIES)
|
|
38
|
+
get_filename_component(directory "${directory}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
|
39
|
+
list(APPEND includes "/I${directory}")
|
|
40
|
+
endforeach()
|
|
41
|
+
set(work "${CMAKE_CURRENT_BINARY_DIR}/${target_name}.rsh")
|
|
42
|
+
file(MAKE_DIRECTORY "${work}")
|
|
43
|
+
set(bitcode_inputs)
|
|
44
|
+
set(index 0)
|
|
45
|
+
foreach(source IN LISTS RSH_SOURCES)
|
|
46
|
+
get_filename_component(source "${source}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
|
47
|
+
set(bitcode "${work}/source-${index}.bc")
|
|
48
|
+
math(EXPR index "${index}+1")
|
|
49
|
+
add_custom_command(OUTPUT "${bitcode}"
|
|
50
|
+
COMMAND "${RSH_LLVM_BIN}/clang-cl.exe" /c /MD /O1 /guard:cf
|
|
51
|
+
/clang:-emit-llvm /clang:-fno-vectorize /clang:-fno-slp-vectorize
|
|
52
|
+
/clang:-ffp-contract=off /clang:-o "/clang:${bitcode}"
|
|
53
|
+
${includes} "${source}"
|
|
54
|
+
DEPENDS "${source}" "${sdk}/rust_shell.h"
|
|
55
|
+
COMMAND_EXPAND_LISTS VERBATIM
|
|
56
|
+
COMMENT "Compile protected source to LLVM bitcode")
|
|
57
|
+
list(APPEND bitcode_inputs "${bitcode}")
|
|
58
|
+
endforeach()
|
|
59
|
+
set(combined "${work}/combined.bc")
|
|
60
|
+
add_custom_command(OUTPUT "${combined}"
|
|
61
|
+
COMMAND "${RSH_LLVM_BIN}/llvm-link.exe" ${bitcode_inputs} -o "${combined}"
|
|
62
|
+
DEPENDS ${bitcode_inputs}
|
|
63
|
+
COMMAND_EXPAND_LISTS VERBATIM
|
|
64
|
+
COMMENT "Merge protected modules before sealing")
|
|
65
|
+
set(protected_object "${work}/protected.obj")
|
|
66
|
+
add_custom_command(OUTPUT "${protected_object}"
|
|
67
|
+
COMMAND "${CMAKE_COMMAND}" -E env
|
|
68
|
+
"RSH_LLVM_BIN=${RSH_LLVM_BIN}" "RSH_LLVM_DLL=${RSH_LLVM_BIN}/LLVM-C.dll"
|
|
69
|
+
"${RSH_CLI}" build --config "${config}" --input "${combined}" --output "${protected_object}"
|
|
70
|
+
DEPENDS "${combined}" "${config}" "${RSH_CLI}"
|
|
71
|
+
VERBATIM COMMENT "Validate and seal protected functions")
|
|
72
|
+
set_source_files_properties("${protected_object}" PROPERTIES GENERATED TRUE EXTERNAL_OBJECT TRUE)
|
|
73
|
+
add_library(${target_name} STATIC "${protected_object}")
|
|
74
|
+
set_target_properties(${target_name} PROPERTIES LINKER_LANGUAGE C)
|
|
75
|
+
target_include_directories(${target_name} INTERFACE "${sdk}")
|
|
76
|
+
target_link_libraries(${target_name} PUBLIC "${RSH_RUNTIME_LIBRARY}"
|
|
77
|
+
bcrypt crypt32 advapi32 userenv ws2_32 ntdll secur32)
|
|
78
|
+
target_link_options(${target_name} INTERFACE /GUARD:CF /DYNAMICBASE /NXCOMPAT)
|
|
79
|
+
endfunction()
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Acceptance and strength claims
|
|
2
|
+
|
|
3
|
+
The implementation is a development build until every required gate has recorded evidence.
|
|
4
|
+
Passing compilation or differential tests is not evidence of VMProtect-equivalent resistance.
|
|
5
|
+
|
|
6
|
+
| Gate | Required evidence |
|
|
7
|
+
|---|---|
|
|
8
|
+
| Toolchain | Pinned Rust 1.97.1, LLVM 22.1.6 C API, clang-cl, llc and lld-link |
|
|
9
|
+
| Correctness | C and Rust corpus, at least 20 functions, unseen inputs, loops, PHI, exceptional floating values, concurrent calls |
|
|
10
|
+
| Coverage | All selected functions transformed; source-owned dependency archive markers included; unsupported required functions fail |
|
|
11
|
+
| Packaging | No original selected function body, source debug metadata or build secrets in distributable files |
|
|
12
|
+
| Licensing | Invalid signatures/key/binding/purpose rejected; expiry, renewal, DPAPI corruption, restart and rollback |
|
|
13
|
+
| Windows | EXE and DLL, load/unload, native exceptions/unwind, ASLR/DEP/CFG and applicable CET, normal and signed artifacts |
|
|
14
|
+
| Fuzzing | Saved campaigns and crash triage for the provided fuzz targets; smoke tests alone do not satisfy this gate |
|
|
15
|
+
| Performance | Record end-to-end latency/throughput, startup, memory and size for real product workloads |
|
|
16
|
+
| Endurance | Long-running product stress, allocation/callback failures, repeated DLL lifecycle |
|
|
17
|
+
| Signing | User-owned production certificate and verified timestamped Authenticode signature |
|
|
18
|
+
| Comparative strength | `benchmarks/protocol.toml`, licensed VMProtect, frozen models/tools/prompts, held-out tests, independent review |
|
|
19
|
+
|
|
20
|
+
The adversary may possess the binaries, a valid license, an administrator account,
|
|
21
|
+
static/dynamic tools and AI assistance. Issuer private keys and original source are
|
|
22
|
+
outside that boundary. License validation and DPAPI are not claims of confidentiality
|
|
23
|
+
against that administrator. Full-machine snapshot restoration defeats a purely local
|
|
24
|
+
clock high-water mark.
|
|
25
|
+
|
|
26
|
+
The native test corpus is public and must not be reused as the secret challenge set
|
|
27
|
+
for competitive reverse-engineering claims. Generate and freeze independent hidden
|
|
28
|
+
inputs and cases before a comparative run. Require a working recovered implementation,
|
|
29
|
+
not just pseudocode. Record failed attempts and censored time limits.
|
|
30
|
+
|
|
31
|
+
`verify` checks the supplied report's hash against the artifact. The report itself
|
|
32
|
+
is not a signature or a trusted assertion. `--require-release` refuses outputs with
|
|
33
|
+
pending commercial gates; a report is never automatically promoted by unit tests.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Security and compatibility boundaries
|
|
2
|
+
|
|
3
|
+
## Trust and key lifecycle
|
|
4
|
+
|
|
5
|
+
The application embeds the issuer public key and expected product/build identity.
|
|
6
|
+
Do not read that trust from the same replaceable file as a license. Activation codes,
|
|
7
|
+
issuer private keys, content keys and build seeds belong outside distribution packages.
|
|
8
|
+
Private files are created with an owner-only DACL before writing on Windows.
|
|
9
|
+
|
|
10
|
+
Every build uses a fresh AES-256 key. Every sealing operation uses a CSPRNG nonce;
|
|
11
|
+
callers cannot select one. Envelopes authenticate format, product, build and purpose.
|
|
12
|
+
Function purpose is a digest of the function identity and source module identity,
|
|
13
|
+
embedded independently by the wrapper. It is checked before decoding bytecode.
|
|
14
|
+
Reproduction records retain the original ciphertext and verify the bytecode hash
|
|
15
|
+
before replay, rather than reusing a nonce for different plaintext.
|
|
16
|
+
|
|
17
|
+
The license signs the content-key digest and installation binding. A 30-day valid
|
|
18
|
+
lease permits offline execution. Renewal can be refused server-side, but an existing
|
|
19
|
+
offline lease remains valid until expiry. The local service is single-instance and
|
|
20
|
+
binds only loopback; use a separately configured HTTPS reverse proxy for remote use.
|
|
21
|
+
Reinitialize the runtime after renewal to adopt the new lease. The persisted clock
|
|
22
|
+
high-water mark advances at cache initialization; calls check an in-memory mark.
|
|
23
|
+
Passive calls never rewrite a cached lease, so they cannot overwrite a newer online
|
|
24
|
+
renewal with an older session's bundle. Clock persistence is not a trusted clock.
|
|
25
|
+
|
|
26
|
+
## Runtime and native ABI
|
|
27
|
+
|
|
28
|
+
The interpreter has register/block/instruction/allocation and configurable fuel limits. Malformed
|
|
29
|
+
or unsupported bytecode returns an error. Floating NaN payload equivalence is not
|
|
30
|
+
promised across native platforms; numerical and ordered/unordered comparison semantics
|
|
31
|
+
are tested. Generated wrappers use the embedded Trust.execution_fuel policy (default
|
|
32
|
+
u64::MAX for native loop compatibility); fuzz and untrusted-input harnesses explicitly
|
|
33
|
+
use small finite budgets. A product choosing a finite execution budget must include
|
|
34
|
+
its longest valid workloads in acceptance. SIMD, atomics, volatile memory, indirect calls, inline assembly and unwinding
|
|
35
|
+
through the VM require explicit rejection until implemented and independently tested.
|
|
36
|
+
|
|
37
|
+
Native memory is an explicit per-thread capability. Register only live, valid ranges;
|
|
38
|
+
do not concurrently mutate aliased writable storage. Clearing a registration revokes
|
|
39
|
+
access for an already-running VM too. Registered external callbacks must implement
|
|
40
|
+
the exact declared ABI and must not unwind. Callback/function registration is a trusted
|
|
41
|
+
host operation, not a user-provided scripting facility.
|
|
42
|
+
|
|
43
|
+
`rsh_vm_execute_bound` returns structured status codes without modifying the result
|
|
44
|
+
on failure. A transparent replacement of an ordinary native function has no spare
|
|
45
|
+
error channel in its original signature; its generated wrapper calls
|
|
46
|
+
`rsh_protection_failure` and aborts on refusal. Hosts should preflight licensing and
|
|
47
|
+
use the status-returning API when recoverable call errors are required. There is no
|
|
48
|
+
unprotected native fallback. No initialization or network request is performed from
|
|
49
|
+
DllMain.
|
|
50
|
+
|
|
51
|
+
The basic layer currently provides limited integer-expression diversity and debug
|
|
52
|
+
metadata removal; it is not a full control-flow flattening implementation. Reports
|
|
53
|
+
distinguish transformed expressions from metadata-only functions. No anti-debugger,
|
|
54
|
+
security-product interference, kernel driver or custom PE loader is required.
|
|
55
|
+
|
|
56
|
+
## Reporting vulnerabilities
|
|
57
|
+
|
|
58
|
+
Keep reproduction inputs, private keys and protected product code out of public
|
|
59
|
+
issue trackers. Capture toolchain versions, the bounded failing input, and a minimal
|
|
60
|
+
non-sensitive reproducer. Rotate affected build keys and issuer keys according to the
|
|
61
|
+
incident's actual exposure; rotating a server key does not remotely erase offline copies.
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"name": "rust-shell",
|
|
4
|
+
"version": "0.1.1",
|
|
5
|
+
"release_tag": "v0.1.1",
|
|
6
|
+
"target": "x86_64-pc-windows-msvc",
|
|
7
|
+
"source_revision": "da11d588a1b484c8fc5d5af54764f8388d9407b6",
|
|
8
|
+
"source_tree_state": "clean",
|
|
9
|
+
"source_date_epoch": 315532800,
|
|
10
|
+
"toolchain": {
|
|
11
|
+
"rust": "1.97.1",
|
|
12
|
+
"llvm": "22.1.6",
|
|
13
|
+
"source": "repository_pins_not_binary_attestation",
|
|
14
|
+
"packager": "PowerShell 7.4.21 / .NET 8.0.32"
|
|
15
|
+
},
|
|
16
|
+
"package_signing": "unsigned",
|
|
17
|
+
"binary_signing": {
|
|
18
|
+
"bin/rust-shell.exe": {
|
|
19
|
+
"state": "unsigned",
|
|
20
|
+
"authenticode_status": "NotSigned"
|
|
21
|
+
},
|
|
22
|
+
"bin/rsh-server.exe": {
|
|
23
|
+
"state": "unsigned",
|
|
24
|
+
"authenticode_status": "NotSigned"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"validation_evidence": {
|
|
28
|
+
"status": "provided_passed",
|
|
29
|
+
"sha256": "61e170bace44207fc9b2c3be59e851f471ff4fb791fa71df045b45ae7e28bec6"
|
|
30
|
+
},
|
|
31
|
+
"commercial_acceptance": "pending",
|
|
32
|
+
"vmprotect_comparison": "not_run",
|
|
33
|
+
"ai_resistance": "unproven",
|
|
34
|
+
"files": [
|
|
35
|
+
{
|
|
36
|
+
"path": "README.md",
|
|
37
|
+
"bytes": 1453,
|
|
38
|
+
"sha256": "09050ae3137a2487abc13ec4288564a0f6e2298a2f7bbe4e90ce523cbb525f3e"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"path": "bin/rsh-server.exe",
|
|
42
|
+
"bytes": 2063360,
|
|
43
|
+
"sha256": "e5682ee6945af3fe32e0bea365a57f0ce2d5676410891425839fac704fc2bd1f"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"path": "bin/rust-shell.exe",
|
|
47
|
+
"bytes": 5137408,
|
|
48
|
+
"sha256": "9d9aff85fda3d77a93902de375050fc82809e627a77b3740cbed591b330da815"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"path": "cmake/RustShell.cmake",
|
|
52
|
+
"bytes": 4000,
|
|
53
|
+
"sha256": "b482febb2bd96976e0dc5a0c81d45816a6ac52c4c4940fb63d28cbc49c155731"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"path": "docs/acceptance.md",
|
|
57
|
+
"bytes": 2472,
|
|
58
|
+
"sha256": "5952f8fc61e9d4093532f3b243195a039e68528c916773edda609b99f29af41a"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"path": "docs/ci-cd.md",
|
|
62
|
+
"bytes": 3413,
|
|
63
|
+
"sha256": "00cf17755581d902253d7a9e9ed444d4d595acdab5efd195a1dfb813fb1423ad"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"path": "docs/security.md",
|
|
67
|
+
"bytes": 3903,
|
|
68
|
+
"sha256": "71d1f3e75951af4316c251c837f1d48f31cd10efec6087883ff09e063deeaaef"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"path": "lib/rsh_runtime.lib",
|
|
72
|
+
"bytes": 17575002,
|
|
73
|
+
"sha256": "70b253bd192876377cefdcdda70006e9d2bcc17cdfb73bd71ec2e90d2815a2a9"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"path": "scripts/extract-llvm.py",
|
|
77
|
+
"bytes": 1885,
|
|
78
|
+
"sha256": "b35268e5eca9bc92e490622574e85bb867d93c4108a717f17f6307bef6844856"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"path": "scripts/setup-toolchain.ps1",
|
|
82
|
+
"bytes": 1540,
|
|
83
|
+
"sha256": "8e44e65980febd52fd324f216c60c2ca8572bd85b90af94db1d66fba4c36d106"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"path": "sdk/c/README.md",
|
|
87
|
+
"bytes": 2863,
|
|
88
|
+
"sha256": "0749c7b1f141262ad26108fec1126ba4bbe885502aead3e97520de071b5043cd"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"path": "sdk/c/rust_shell.h",
|
|
92
|
+
"bytes": 3038,
|
|
93
|
+
"sha256": "f4f4d6eff30e41356b6a0282da841b4ae0c6fbfa521af595c5de0caf71c14b08"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"path": "sdk/rust/Cargo.toml",
|
|
97
|
+
"bytes": 522,
|
|
98
|
+
"sha256": "c610821bc39d29005d7364e79d2744115b780e4167f894224d99be20ea970f24"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"path": "sdk/rust/crates/rsh-license/Cargo.toml",
|
|
102
|
+
"bytes": 652,
|
|
103
|
+
"sha256": "f4d340588ba179b83f0547ec7f6d2d9c0b7653b28da32a9907b25a8e29ccf2ca"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"path": "sdk/rust/crates/rsh-license/src/cache.rs",
|
|
107
|
+
"bytes": 6361,
|
|
108
|
+
"sha256": "36b05a6755ff928f5febfe40c52e9d6c4afa26f3e09914dff24f3a85b676d6e3"
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"path": "sdk/rust/crates/rsh-license/src/lib.rs",
|
|
112
|
+
"bytes": 24725,
|
|
113
|
+
"sha256": "5f22bd8c68ce2c587af335b04dd5b5a17f17282ac325a96a0feab6feb8a72c5b"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"path": "sdk/rust/crates/rsh-license/src/private_file.rs",
|
|
117
|
+
"bytes": 9144,
|
|
118
|
+
"sha256": "be82af2ba49fc380bba23a1958e8523851ab4f47bc5012284a5f71b5ccda28a4"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"path": "sdk/rust/crates/rsh-macros/Cargo.toml",
|
|
122
|
+
"bytes": 212,
|
|
123
|
+
"sha256": "91a8e3291b4a1ad0b985b4a2606f58c20878e5fcdf29996330248377190e8e58"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"path": "sdk/rust/crates/rsh-macros/src/lib.rs",
|
|
127
|
+
"bytes": 1417,
|
|
128
|
+
"sha256": "b21f0e55515519a4cab6b66f829c8e2427a167823d3b9bc9d994c36de8c7ab81"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"path": "sdk/rust/crates/rsh-runtime/Cargo.toml",
|
|
132
|
+
"bytes": 354,
|
|
133
|
+
"sha256": "4e3efd8f9b3e326ad1148a63bd547114521b63841887b06ebc5ee881f4b8fd58"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"path": "sdk/rust/crates/rsh-runtime/src/lib.rs",
|
|
137
|
+
"bytes": 25729,
|
|
138
|
+
"sha256": "7a122d2fdc55f97f78b1169dd62a5e105ff7cb51fb9edb087c51b5e62008aada"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"path": "sdk/rust/crates/rsh-sdk/Cargo.toml",
|
|
142
|
+
"bytes": 191,
|
|
143
|
+
"sha256": "be7cb38eee67263225f289a7dc523dd3000d6c46108ee09fe5d281af2ce4b1ad"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"path": "sdk/rust/crates/rsh-sdk/src/lib.rs",
|
|
147
|
+
"bytes": 278,
|
|
148
|
+
"sha256": "69d2a798df6caa80518693822fbae2e16bf62e93642c8bd2cdf841b44f954d3d"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"path": "sdk/rust/crates/rsh-vm/Cargo.toml",
|
|
152
|
+
"bytes": 179,
|
|
153
|
+
"sha256": "f5dfcd5811a60a5257a1ab9d7e5371bc0a4c4a5ed6762772228cb9ca52dc63c3"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"path": "sdk/rust/crates/rsh-vm/README.md",
|
|
157
|
+
"bytes": 2984,
|
|
158
|
+
"sha256": "826ea14f728421db1108e36847f3e2eb3edc90765c01d41a37bb476b742b7550"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"path": "sdk/rust/crates/rsh-vm/src/codec.rs",
|
|
162
|
+
"bytes": 21917,
|
|
163
|
+
"sha256": "cccf1f8e21f5d3cb58bc751f0841e394b3cec834301cbac73b40e911fe86b9d2"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"path": "sdk/rust/crates/rsh-vm/src/diversify.rs",
|
|
167
|
+
"bytes": 12522,
|
|
168
|
+
"sha256": "d26b65cec178dc3e3f6a4820b60aa005ed755753cef62ab7e46e9ecdf690dd87"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"path": "sdk/rust/crates/rsh-vm/src/execute.rs",
|
|
172
|
+
"bytes": 18984,
|
|
173
|
+
"sha256": "0ad145a0b35bcbc149a7f48bb1fd821306d375173115c509a04b478c00b90754"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"path": "sdk/rust/crates/rsh-vm/src/lib.rs",
|
|
177
|
+
"bytes": 8120,
|
|
178
|
+
"sha256": "ed06f56872a527cb906bef6589bb08069cdde66848fc36c57592312a24559d30"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"path": "sdk/rust/crates/rsh-vm/src/validate.rs",
|
|
182
|
+
"bytes": 16701,
|
|
183
|
+
"sha256": "277dbdbc916702ad5ee4e00fc2c68fdc72b31952948c70d0a43230ad94ad1e02"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"path": "sdk/rust/rust-toolchain.toml",
|
|
187
|
+
"bytes": 145,
|
|
188
|
+
"sha256": "7dbe0e914284b765040c4f8094bca38dafab815b44494e654c303cb0b7ec0c2d"
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Extract the verified LLVM archive without relying on Windows tar's XZ support."""
|
|
2
|
+
import pathlib
|
|
3
|
+
import sys
|
|
4
|
+
import tarfile
|
|
5
|
+
|
|
6
|
+
ARCHIVE_ROOT = "clang+llvm-22.1.6-x86_64-pc-windows-msvc"
|
|
7
|
+
TOOLS = {
|
|
8
|
+
"clang-cl.exe", "llc.exe", "lld-link.exe", "LLVM-C.dll", "llvm-as.exe",
|
|
9
|
+
"llvm-ar.exe", "llvm-lib.exe", "llvm-link.exe", "llvm-dis.exe",
|
|
10
|
+
"llvm-nm.exe", "llvm-readobj.exe", "llvm-objdump.exe", "opt.exe",
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def extract(archive, destination):
|
|
15
|
+
destination = pathlib.Path(destination).resolve()
|
|
16
|
+
destination.mkdir(parents=True, exist_ok=True)
|
|
17
|
+
with tarfile.open(archive, "r|xz") as source:
|
|
18
|
+
for member in source:
|
|
19
|
+
parts = pathlib.PurePosixPath(member.name).parts
|
|
20
|
+
if not parts or parts[0] != ARCHIVE_ROOT or ".." in parts:
|
|
21
|
+
raise ValueError("Unexpected archive path")
|
|
22
|
+
if len(parts) == 1:
|
|
23
|
+
continue
|
|
24
|
+
if not (member.isfile() or member.isdir()):
|
|
25
|
+
raise ValueError("LLVM archive links and special files are not supported")
|
|
26
|
+
member.name = str(pathlib.PurePosixPath(*parts[1:]))
|
|
27
|
+
target = (destination / member.name).resolve()
|
|
28
|
+
if not target.is_relative_to(destination):
|
|
29
|
+
raise ValueError("Archive member escapes destination")
|
|
30
|
+
# Keep only this project's tools and Clang's builtin headers/runtime.
|
|
31
|
+
if not ((len(parts) == 3 and parts[1] == "bin" and parts[2] in TOOLS)
|
|
32
|
+
or member.name.startswith("lib/clang/")):
|
|
33
|
+
continue
|
|
34
|
+
source.extract(member, destination, filter="data")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
if __name__ == "__main__":
|
|
38
|
+
extract(*sys.argv[1:])
|
|
39
|
+
destination = pathlib.Path(sys.argv[2])
|
|
40
|
+
missing = sorted(name for name in TOOLS if not (destination / "bin" / name).is_file())
|
|
41
|
+
if missing:
|
|
42
|
+
raise ValueError("Incomplete LLVM tool installation: " + ", ".join(missing))
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
param([switch]$InstallRust)
|
|
2
|
+
$ErrorActionPreference = 'Stop'
|
|
3
|
+
$root = Split-Path -Parent $PSScriptRoot
|
|
4
|
+
$tools = Join-Path $root '.tools'
|
|
5
|
+
$archive = Join-Path $tools 'clang+llvm-22.1.6-x86_64-pc-windows-msvc.tar.xz'
|
|
6
|
+
$destination = Join-Path $tools 'llvm-22.1.6'
|
|
7
|
+
$expected = '657343edf361ca463bd642e39c74b251c6338b96cdbd55ff277555298b027696'
|
|
8
|
+
$url = 'https://github.com/llvm/llvm-project/releases/download/llvmorg-22.1.6/clang%2Bllvm-22.1.6-x86_64-pc-windows-msvc.tar.xz'
|
|
9
|
+
New-Item -ItemType Directory -Force -Path $tools | Out-Null
|
|
10
|
+
if (-not (Test-Path -LiteralPath $archive)) { Invoke-WebRequest -Uri $url -OutFile $archive }
|
|
11
|
+
if ((Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash.ToLowerInvariant() -ne $expected) {
|
|
12
|
+
throw 'LLVM archive hash mismatch. Nothing will be extracted.'
|
|
13
|
+
}
|
|
14
|
+
$python = (Get-Command python.exe -ErrorAction Stop).Source
|
|
15
|
+
& $python -c 'import lzma, tarfile; assert hasattr(tarfile, "data_filter")'
|
|
16
|
+
if ($LASTEXITCODE -ne 0) { throw 'Python 3.11.9+ with lzma and tarfile.data_filter is required' }
|
|
17
|
+
& $python (Join-Path $PSScriptRoot 'extract-llvm.py') $archive $destination
|
|
18
|
+
if ($LASTEXITCODE -ne 0) { throw 'LLVM extraction failed' }
|
|
19
|
+
if ($InstallRust) {
|
|
20
|
+
& rustup toolchain install 1.97.1 --profile minimal --component rustfmt,clippy,llvm-tools-preview --target x86_64-pc-windows-msvc
|
|
21
|
+
if ($LASTEXITCODE -ne 0) { throw 'Rust toolchain setup failed' }
|
|
22
|
+
}
|
|
23
|
+
Write-Output "Verified LLVM 22.1.6 is available at $destination"
|
|
24
|
+
Write-Output 'Use an x64 Visual Studio developer environment with Windows SDK installed.'
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#ifndef RUST_SHELL_H
|
|
2
|
+
#define RUST_SHELL_H
|
|
3
|
+
|
|
4
|
+
#include <stdint.h>
|
|
5
|
+
#include <stdbool.h>
|
|
6
|
+
|
|
7
|
+
/* Compile protected translation units with the pinned clang-cl toolchain.
|
|
8
|
+
* Whole functions are selected; optimized IR unsupported by the backend makes
|
|
9
|
+
* the protection build fail. This marker is not protection by itself. */
|
|
10
|
+
#if defined(__clang__)
|
|
11
|
+
#define RSH_PROTECT __attribute__((section("rsh.protect"), noinline))
|
|
12
|
+
#elif defined(_MSC_VER)
|
|
13
|
+
#define RSH_PROTECT __declspec(code_seg("rsh.protect")) __declspec(noinline)
|
|
14
|
+
#else
|
|
15
|
+
#error "rust-shell v1 requires the Windows x64 LLVM toolchain"
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
#if defined(__cplusplus)
|
|
19
|
+
#define RSH_NORETURN [[noreturn]]
|
|
20
|
+
extern "C" {
|
|
21
|
+
#else
|
|
22
|
+
#define RSH_NORETURN _Noreturn
|
|
23
|
+
#endif
|
|
24
|
+
|
|
25
|
+
enum rsh_status {
|
|
26
|
+
RSH_OK = 0,
|
|
27
|
+
RSH_INVALID_INPUT = 1,
|
|
28
|
+
RSH_LICENSE_ERROR = 2,
|
|
29
|
+
RSH_EXECUTION_ERROR = 3,
|
|
30
|
+
RSH_NOT_INITIALIZED = 4,
|
|
31
|
+
RSH_INTERNAL_ERROR = 5
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/* Trust JSON is application-owned. Do not obtain the trusted issuer public key
|
|
35
|
+
* from an unverified activation response. Buffers need not be NUL terminated. */
|
|
36
|
+
int32_t rsh_initialize(const uint8_t *trust_json, uint64_t trust_len,
|
|
37
|
+
const uint8_t *activation_json, uint64_t activation_len);
|
|
38
|
+
int32_t rsh_initialize_cached(const uint8_t *trust_json, uint64_t trust_len,
|
|
39
|
+
const uint8_t *utf8_path, uint64_t path_len);
|
|
40
|
+
int32_t rsh_license_status(void);
|
|
41
|
+
/* Call after joining all callers, before unloading a DLL containing the runtime. */
|
|
42
|
+
int32_t rsh_shutdown(void);
|
|
43
|
+
uint64_t rsh_last_error(uint8_t *buffer, uint64_t capacity);
|
|
44
|
+
|
|
45
|
+
/* Regions are thread-local and must remain live until cleared. Writable
|
|
46
|
+
* regions require exclusive access during protected calls. */
|
|
47
|
+
int32_t rsh_register_memory(uint8_t *pointer, uint64_t length, bool writable);
|
|
48
|
+
void rsh_clear_memory_regions(void);
|
|
49
|
+
|
|
50
|
+
/* A null output with zero capacity queries the decrypted size. The host owns
|
|
51
|
+
* clearing copied plaintext. The resource name is trusted application policy. */
|
|
52
|
+
int32_t rsh_decrypt_resource(const uint8_t *payload, uint64_t payload_len,
|
|
53
|
+
const uint8_t *name, uint64_t name_len,
|
|
54
|
+
uint8_t *output, uint64_t capacity, uint64_t *written);
|
|
55
|
+
|
|
56
|
+
typedef int32_t (*rsh_host_callback)(const uint64_t *arguments, uint64_t count,
|
|
57
|
+
uint64_t *result);
|
|
58
|
+
int32_t rsh_register_host(const uint8_t *signature_json, uint64_t signature_len,
|
|
59
|
+
rsh_host_callback callback);
|
|
60
|
+
|
|
61
|
+
/* Generated wrappers use the bound entrypoint. Payloads must come from the
|
|
62
|
+
* authenticated build pipeline. A failed protected call terminates instead of
|
|
63
|
+
* fabricating an algorithm result. */
|
|
64
|
+
int32_t rsh_vm_execute_bound(const uint8_t *payload, uint64_t payload_len,
|
|
65
|
+
const uint8_t *purpose, uint64_t purpose_len,
|
|
66
|
+
const uint64_t *arguments, uint64_t argument_count,
|
|
67
|
+
uint64_t *result);
|
|
68
|
+
RSH_NORETURN void rsh_protection_failure(int32_t status);
|
|
69
|
+
|
|
70
|
+
#if defined(__cplusplus)
|
|
71
|
+
}
|
|
72
|
+
#endif
|
|
73
|
+
#endif
|