libmongocrypt-1.11.0/000077500000000000000000000000001465326363200144745ustar00rootroot00000000000000libmongocrypt-1.11.0/.clang-format000066400000000000000000000017351465326363200170550ustar00rootroot00000000000000--- Language: Cpp # (Options are sorted alphabetically) AlignAfterOpenBracket: Align AlignEscapedNewlines: Right AlignOperands: AlignAfterOperator AllowAllArgumentsOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: Empty AllowShortCaseLabelsOnASingleLine: true AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: Never AllowShortLoopsOnASingleLine: false BinPackArguments: false BinPackParameters: false BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Attach ColumnLimit: 120 ContinuationIndentWidth: 4 IndentCaseLabels: false IndentWidth: 4 InsertBraces: true KeepEmptyLinesAtTheStartOfBlocks: false PointerAlignment: Right QualifierAlignment: Custom QualifierOrder: ["static", "inline", "const", "volatile", "type", "restrict"] SeparateDefinitionBlocks: Always SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpacesInLineCommentPrefix: Minimum: 1 Maximum: -1 UseTab: Never libmongocrypt-1.11.0/.clang-tidy000066400000000000000000000005161465326363200165320ustar00rootroot00000000000000# Older clang-tidy gives a warning for an uninitialized va_args, # even on the test case that they assert should not produce that warning: # https://github.com/llvm-mirror/clang/blob/59207d134acb8a1c6cb9974c32c1c04bd31f8f7b/test/Analysis/valist-uninitialized.c#L30 Checks: "-clang-analyzer-valist.Uninitialized" WarningsAsErrors: "*" libmongocrypt-1.11.0/.earthlyignore000066400000000000000000000000461465326363200173510ustar00rootroot00000000000000cmake-build/ cmake-build-deb/ _build/ libmongocrypt-1.11.0/.evergreen/000077500000000000000000000000001465326363200165345ustar00rootroot00000000000000libmongocrypt-1.11.0/.evergreen/benchmark-java.sh000077500000000000000000000015441465326363200217500ustar00rootroot00000000000000#!/usr/bin/env bash . "$(dirname "${BASH_SOURCE[0]}")/init.sh" if test "$OS_NAME" != "linux"; then log "Warning: Script is expected only to run on distro: rhel90-dbx-perf-large" log "More changes may be needed to run on other distros."; fi MONGOCRYPT_INSTALL_PREFIX=$LIBMONGOCRYPT_DIR/.install # Install libmongocrypt. build_dir="$LIBMONGOCRYPT_DIR/cmake-build" run_cmake \ -DCMAKE_INSTALL_PREFIX="$MONGOCRYPT_INSTALL_PREFIX" \ -DCMAKE_BUILD_TYPE="RelWithDebInfo" \ -B"$build_dir" run_cmake --build "$build_dir" --target install # Run Java benchmarks. Do not use JDK 8 to avoid hang in gradle observed in MONGOCRYPT-590. export JAVA_HOME=/opt/java/jdk17 # Include path to installed libmongocrypt.so export LD_LIBRARY_PATH="$MONGOCRYPT_INSTALL_PREFIX/lib64" cd bindings/java/mongocrypt ./gradlew --version ./gradlew clean benchmarks:run --info libmongocrypt-1.11.0/.evergreen/benchmark-python.sh000077500000000000000000000016531465326363200223510ustar00rootroot00000000000000#!/usr/bin/env bash . "$(dirname "${BASH_SOURCE[0]}")/init.sh" if test "$OS_NAME" != "linux"; then log "Warning: Script is expected only to run on distro: rhel90-dbx-perf-large" log "More changes may be needed to run on other distros."; fi MONGOCRYPT_INSTALL_PREFIX=$LIBMONGOCRYPT_DIR/.install # Install libmongocrypt. build_dir="$LIBMONGOCRYPT_DIR/cmake-build" run_cmake \ -DCMAKE_INSTALL_PREFIX="$MONGOCRYPT_INSTALL_PREFIX" \ -DCMAKE_BUILD_TYPE="RelWithDebInfo" \ -B"$build_dir" run_cmake --build "$build_dir" --target install # Run Python benchmarks. # Include path to installed libmongocrypt.so export LD_LIBRARY_PATH="$MONGOCRYPT_INSTALL_PREFIX/lib64" cd bindings/python/ /opt/mongodbtoolchain/v4/bin/python3 -m venv venv . ./venv/bin/activate python -m pip install --prefer-binary -r requirements-test.txt python -m pip install -e . export OUTPUT_FILE=results.json python test/performance/perf_test.py -v libmongocrypt-1.11.0/.evergreen/build_all.sh000077500000000000000000000104571465326363200210310ustar00rootroot00000000000000#!/bin/bash # Compiles libmongocrypt dependencies and targets. # # Set extra cflags for libmongocrypt variables by setting LIBMONGOCRYPT_EXTRA_CFLAGS. # echo "Begin compile process" . "$(dirname "${BASH_SOURCE[0]}")/setup-env.sh" # We may need some more C++ flags _cxxflags="" : "${CONFIGURE_ONLY:=}" : "${LIBMONGOCRYPT_BUILD_TYPE:=RelWithDebInfo}" if [ "$OS_NAME" = "windows" ]; then # Enable exception handling for MSVC _cxxflags="-EHsc" if is_false WINDOWS_32BIT && is_false USE_NINJA; then # These options are only needed for VS CMake generators to force it to # generate a 64-bit build. Default is 32-bit. Ninja inherits settings # from the build environment variables. ADDITIONAL_CMAKE_FLAGS="-Thost=x64 -A x64" fi fi # Have CTest print test failure info to stderr export CTEST_OUTPUT_ON_FAILURE=1 if [ "$PPA_BUILD_ONLY" ]; then # Clean-up from previous build iteration rm -rf -- "$LIBMONGOCRYPT_DIR"/cmake-build* "$MONGOCRYPT_INSTALL_PREFIX" ADDITIONAL_CMAKE_FLAGS="$ADDITIONAL_CMAKE_FLAGS -DENABLE_BUILD_FOR_PPA=ON" fi if [ "$MACOS_UNIVERSAL" = "ON" ]; then ADDITIONAL_CMAKE_FLAGS="$ADDITIONAL_CMAKE_FLAGS -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64'" fi for suffix in "dll" "dylib" "so"; do cand="$(abspath "$LIBMONGOCRYPT_DIR/../mongocrypt_v1.$suffix")" if test -f "$cand"; then ADDITIONAL_CMAKE_FLAGS="$ADDITIONAL_CMAKE_FLAGS -DMONGOCRYPT_TESTING_CRYPT_SHARED_FILE=$cand" fi done ADDITIONAL_CMAKE_FLAGS="$ADDITIONAL_CMAKE_FLAGS -DENABLE_MORE_WARNINGS_AS_ERRORS=ON" build_dir="$LIBMONGOCRYPT_DIR/cmake-build" common_cmake_args=( $ADDITIONAL_CMAKE_FLAGS $LIBMONGOCRYPT_EXTRA_CMAKE_FLAGS -DCMAKE_C_FLAGS="$LIBMONGOCRYPT_EXTRA_CFLAGS" -DCMAKE_CXX_FLAGS="$LIBMONGOCRYPT_EXTRA_CFLAGS $_cxxflags" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE="$LIBMONGOCRYPT_BUILD_TYPE" -H"$LIBMONGOCRYPT_DIR" -B"$build_dir" ) if is_true USE_NINJA; then export NINJA_EXE : "${NINJA_EXE:="$build_dir/ninja$EXE_SUFFIX"}" common_cmake_args+=( -GNinja -DCMAKE_MAKE_PROGRAM="$NINJA_EXE" ) bash "$EVG_DIR/ensure-ninja.sh" fi # Build and install libmongocrypt. run_cmake \ -DCMAKE_INSTALL_PREFIX="$MONGOCRYPT_INSTALL_PREFIX" \ "${common_cmake_args[@]}" if [ "$CONFIGURE_ONLY" ]; then echo "Only running cmake"; exit 0; fi echo "Installing libmongocrypt" run_cmake --build "$build_dir" --target install --config "$LIBMONGOCRYPT_BUILD_TYPE" run_cmake --build "$build_dir" --target test-mongocrypt --config "$LIBMONGOCRYPT_BUILD_TYPE" run_cmake --build "$build_dir" --target test_kms_request --config "$LIBMONGOCRYPT_BUILD_TYPE" run_chdir "$build_dir" run_ctest -C "$LIBMONGOCRYPT_BUILD_TYPE" # MONGOCRYPT-372, ensure macOS universal builds contain both x86_64 and arm64 architectures. if [ "$MACOS_UNIVERSAL" = "ON" ]; then echo "Checking if libmongocrypt.dylib contains both x86_64 and arm64 architectures..." ARCHS=$(lipo -archs $MONGOCRYPT_INSTALL_PREFIX/lib/libmongocrypt.dylib) if [[ "$ARCHS" == *"x86_64"* && "$ARCHS" == *"arm64"* ]]; then echo "Checking if libmongocrypt.dylib contains both x86_64 and arm64 architectures... OK" else echo "Checking if libmongocrypt.dylib contains both x86_64 and arm64 architectures... ERROR. Got: $ARCHS" exit 1 fi fi if [ "$PPA_BUILD_ONLY" ]; then echo "Only building/installing for PPA"; exit 0; fi if "${DEFAULT_BUILD_ONLY:-false}"; then echo "Skipping nocrypto+sharedbson builds" exit 0 fi # Build and install libmongocrypt with no native crypto. run_cmake \ -DDISABLE_NATIVE_CRYPTO=ON \ -DCMAKE_INSTALL_PREFIX="$MONGOCRYPT_INSTALL_PREFIX/nocrypto" \ "${common_cmake_args[@]}" run_cmake --build "$build_dir" --target install --config "$LIBMONGOCRYPT_BUILD_TYPE" run_cmake --build "$build_dir" --target test-mongocrypt --config "$LIBMONGOCRYPT_BUILD_TYPE" run_chdir "$build_dir" run_ctest -C "$LIBMONGOCRYPT_BUILD_TYPE" # Build and install libmongocrypt without statically linking libbson run_cmake \ -UDISABLE_NATIVE_CRYPTO \ -DUSE_SHARED_LIBBSON=ON \ -DCMAKE_INSTALL_PREFIX="$MONGOCRYPT_INSTALL_PREFIX/sharedbson" \ "${common_cmake_args[@]}" run_cmake --build "$build_dir" --target install --config "$LIBMONGOCRYPT_BUILD_TYPE" run_chdir "$build_dir" run_ctest -C "$LIBMONGOCRYPT_BUILD_TYPE" libmongocrypt-1.11.0/.evergreen/clang-tidy.sh000077500000000000000000000006001465326363200211220ustar00rootroot00000000000000#!/bin/bash # Run after running "CONFIGURE_ONLY=ON compile.sh" to run the clang-tidy # static analyzer. # . "$(dirname "${BASH_SOURCE[0]}")/setup-env.sh" CLANG_TIDY=/opt/mongodbtoolchain/v3/bin/clang-tidy $CLANG_TIDY --version python "$LIBMONGOCRYPT_DIR/etc/list-compile-files.py" \ "$LIBMONGOCRYPT_DIR/cmake-build/" \ | xargs $CLANG_TIDY -p "$LIBMONGOCRYPT_DIR/cmake-build/" libmongocrypt-1.11.0/.evergreen/cmake.sh000066400000000000000000000002121465326363200201430ustar00rootroot00000000000000#!/usr/bin/env bash . "$(dirname "${BASH_SOURCE[0]}")/init.sh" . "$EVG_DIR/ensure-cmake.sh" # Execute CMake: command "$CMAKE_EXE" "$@" libmongocrypt-1.11.0/.evergreen/compile.sh000077500000000000000000000005341465326363200205250ustar00rootroot00000000000000#!/bin/bash # Downloads and prepares the C driver source, then compiles libmongocrypt's # dependencies and targets. # # NOTE: This script is not meant to be invoked for Evergreen builds. It is a # convenience script for users of libmongocrypt . "$(dirname "${BASH_SOURCE[0]}")/init.sh" bash "$EVG_DIR/setup-env.sh" bash "$EVG_DIR/build_all.sh" libmongocrypt-1.11.0/.evergreen/compile_cs.sh000066400000000000000000000017151465326363200212110ustar00rootroot00000000000000#!/bin/bash # Compiles libmongocrypt dependencies and targets. # # Set extra cflags for libmongocrypt variables by setting LIBMONGOCRYPT_EXTRA_CFLAGS. # . "$(dirname "${BASH_SOURCE[0]}")/setup-env.sh" echo "Begin compile process" evergreen_root="$(pwd)" if [ "$OS_NAME" = "windows" ]; then # Make sure libbson.dll is in the path on Windows export PATH="${MONGOCRYPT_INSTALL_PREFIX}/mongo-c-driver/bin:$PATH" for var in TMP TEMP NUGET_PACKAGES NUGET_HTTP_CACHE_PATH APPDATA; do export $var=z:\\data\\tmp; done # Make dotnet happy over ssh export DOTNET_CLI_HOME=$(cygpath -w "${evergreen_root}/dotnet_home") else export PATH=$PATH:/usr/share/dotnet fi dotnet_tool=$(which dotnet) "$dotnet_tool" build -c Release "$LIBMONGOCRYPT_DIR/cmake-build/bindings/cs/cs.sln" "$dotnet_tool" test -c Release "$LIBMONGOCRYPT_DIR/cmake-build/bindings/cs/MongoDB.Libmongocrypt.Test/MongoDB.Libmongocrypt.Test.csproj" -- RunConfiguration.TargetPlatform=x64 libmongocrypt-1.11.0/.evergreen/config.yml000077500000000000000000001440471465326363200205410ustar00rootroot00000000000000# Welcome. Evergreen configuration can be time consuming to modify and test. # So each script has a header comment describing how to run it locally. # # Some environment variables are hidden in the evergreen project config. # View this in Evergreen => Projects => libmongocrypt. # functions: "cleanup environment": - command: shell.exec params: script: | set -o verbose rm -rf ~/.aws ~/.notary_env.sh exit 0 "fetch source": - command: git.get_project params: {directory: libmongocrypt} - command: shell.exec params: shell: bash script: |- set -o errexit . libmongocrypt/.evergreen/init.sh bash "$EVG_DIR/print-env-info.sh" # determine if we have a release tag present on HEAD head_tag=$(run_chdir libmongocrypt/ git tag -l --points-at HEAD '[0-9].*' || true) use_tag="" if test "${is_patch}" != "true"; then echo "Setting tag_upload_location to '$head_tag'" use_tag="$head_tag" fi echo "tag_upload_location: '$use_tag'" > tag_expansion.yml - command: expansions.update params: ignore_missing_file: true file: tag_expansion.yml "tar and upload libmongocrypt libraries": - command: archive.targz_pack params: target: libmongocrypt.tar.gz source_dir: install/libmongocrypt include: [./**] - command: s3.put params: aws_key: '${aws_key}' aws_secret: '${aws_secret}' remote_file: '${project}/${build_variant}/${branch_name}/${libmongocrypt_s3_suffix}/libmongocrypt.tar.gz' bucket: mciuploads permissions: public-read local_file: 'libmongocrypt.tar.gz' content_type: '${content_type|application/x-gzip}' - command: s3.put params: aws_key: '${aws_key}' aws_secret: '${aws_secret}' remote_file: '${project}/${build_variant}/${branch_name}/${libmongocrypt_s3_suffix_copy}/libmongocrypt.tar.gz' bucket: mciuploads permissions: public-read local_file: 'libmongocrypt.tar.gz' content_type: '${content_type|application/x-gzip}' "build and test": - command: "shell.exec" params: shell: bash script: |- . libmongocrypt/.evergreen/init.sh export LSAN_OPTIONS="suppressions=$LIBMONGOCRYPT_DIR/.lsan-suppressions" export VS_VERSION=${vs_version|} export VS_TARGET_ARCH=${vs_target_arch|amd64} export USE_NINJA=ON env ${compile_env|} \ bash "$EVG_DIR/env-run.sh" \ bash "$EVG_DIR/build_all.sh" env ${compile_env|} \ bash "$EVG_DIR/env-run.sh" \ bash "$EVG_DIR/linker-tests.sh" env ${compile_env|} \ bash "$EVG_DIR/env-run.sh" \ bash "$EVG_DIR/pkgconfig-tests.sh" "create packages and repos": - command: "shell.exec" params: shell: bash script: | env "WORKDIR=${workdir}" \ "PYTHON=${python|}" \ "HAS_PACKAGES=${has_packages|false}" \ "PACKAGER_DISTRO=${packager_distro}" \ "PACKAGER_ARCH=${packager_arch}" \ ${compile_env|} \ bash libmongocrypt/.evergreen/create-packages-and-repos.sh "upload packages and repos": - command: archive.targz_pack params: target: libmongocrypt-distro-packages.tar.gz source_dir: libmongocrypt/repo include: [./**] - command: s3.put params: aws_key: '${aws_key}' aws_secret: '${aws_secret}' remote_file: '${project}/${build_variant}/${branch_name}/${libmongocrypt_s3_suffix}/libmongocrypt-distro-packages.tar.gz' bucket: mciuploads permissions: public-read local_file: 'libmongocrypt-distro-packages.tar.gz' content_type: '${content_type|application/x-gzip}' optional: true "run clang-tidy": - command: "shell.exec" params: script: |- if test "$OS_NAME" != "windows"; then export USE_NINJA=ON; fi env ${compile_env|} CONFIGURE_ONLY=ON ${clang_env|CC=clang CXX=clang++} \ bash libmongocrypt/.evergreen/build_all.sh ./libmongocrypt/.evergreen/clang-tidy.sh "test java": - command: "shell.exec" params: script: |- export GIT_REVISION="${revision}" cd ./libmongocrypt/bindings/java/mongocrypt && ${test_env|} ./.evergreen/test.sh "test python": - command: "shell.exec" params: script: |- export MONGOCRYPT_DIR="$(pwd)/all/${variant_name}" cd ./libmongocrypt/bindings/python && ${test_env|} ./.evergreen/test.sh "test python integ": - command: subprocess.exec params: binary: bash include_expansions_in_env: - project_directory - variant_name args: - ./libmongocrypt/bindings/python/.evergreen/integ-setup.sh - command: expansions.update params: file: expansion.yml - command: subprocess.exec params: binary: bash background: true args: - ${DRIVERS_TOOLS}/.evergreen/csfle/start-servers.sh - command: subprocess.exec params: binary: bash args: - ${DRIVERS_TOOLS}/.evergreen/csfle/await-servers.sh - command: subprocess.exec params: binary: bash env: TOPOLOGY: replica_set args: - ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh - command: "subprocess.exec" params: binary: bash include_expansions_in_env: - DRIVERS_TOOLS - PYMONGO_DIR - MONGOCRYPT_DIR args: - ./libmongocrypt/bindings/python/.evergreen/integ-test.sh - command: subprocess.exec params: binary: bash include_expansions_in_env: - DRIVERS_TOOLS args: - ./libmongocrypt/bindings/python/.evergreen/integ-teardown.sh - command: attach.xunit_results params: file: ${PYMONGO_DIR}/xunit-results/TEST-*.xml "publish java": - command: git.get_project params: {directory: libmongocrypt} - command: shell.exec params: script: |- set -o errexit chmod u+x libmongocrypt/.evergreen/*.sh ./libmongocrypt/.evergreen/print-env-info.sh - command: shell.exec params: include_expansions_in_env: - nexus_username - nexus_password - signing_password - signing_keyId - ring_file_gpg_base64 script: |- if [ "${is_patch}" = "true" ]; then echo "Patch build detected, skipping" exit 0 fi export PROJECT_DIRECTORY=${project_directory} cd ./libmongocrypt/bindings/java/mongocrypt && ${test_env|} ./.evergreen/publish.sh "download tarball": - command: s3.get params: aws_key: '${aws_key}' aws_secret: '${aws_secret}' remote_file: '${project}/${variant_name}/${branch_name}/${libmongocrypt_s3_suffix}/libmongocrypt.tar.gz' bucket: mciuploads extract_to: all/${variant_name} "setup packaging credentials": - command: shell.exec params: silent: true shell: bash script: | set -o errexit if [ "${is_patch}" = "true" ]; then exit 0 fi # set AWS credentials rm -rf ~/.aws mkdir -p ~/.aws cat <> ~/.aws/config [default] region = us-east-1 EOF cat <> ~/.aws/credentials [default] aws_access_key_id = ${repo_aws_key} aws_secret_access_key = ${repo_aws_secret} EOF # set notary credentials rm -f ~/.notary_env.sh cat < ~/.notary_env.sh export NOTARY_TOKEN=${repo_notary_secret} export NOTARY_KEY_NAME=${repo_notary_name} export BARQUE_USERNAME=${barque_username} export BARQUE_API_KEY=${barque_api_key} EOF "publish packages": - command: shell.exec params: working_dir: libmongocrypt shell: bash script: |- [ -f ~/.notary_env.sh ] && . ~/.notary_env.sh set -o xtrace set -o errexit set -o verbose if [ "${is_patch}" = "true" ]; then echo "patch build, skipping packaging publication" exit 0 fi if [ "${has_packages|}" != "true" ] ; then echo "'has_packages' is not 'true', skipping package publication" exit 0 fi # Some venv-activate scripts are not nounset-clean set +u # Need requests and poster for notary-client.py python -m virtualenv venv cd venv . bin/activate ./bin/pip install requests ./bin/pip install poster ./bin/pip install pycrypto cd .. # Get the current version of libmongocrypt. pkg_version="$(python etc/calc_release_version.py)" CURATOR_RELEASE=${curator_release|"e0b5f66fc89ec0acddcd40ea5f447a8300ded2b9"} curl -L -O http://boxes.10gen.com/build/curator/curator-dist-rhel70-$CURATOR_RELEASE.tar.gz tar -zxvf curator-dist-rhel70-$CURATOR_RELEASE.tar.gz ./curator version ./curator repo submit --config etc/repo_config.yaml --distro ${packager_distro} --edition org --version $pkg_version --arch ${packager_arch} --service https://barque.corp.mongodb.com/ --packages https://mciuploads.s3.amazonaws.com/${project}/${build_variant}/${branch_name}/${libmongocrypt_s3_suffix}/libmongocrypt-distro-packages.tar.gz "build csharp and test": - command: "shell.exec" params: shell: bash script: |- . libmongocrypt/.evergreen/init.sh if test "$OS_NAME" != "windows"; then export USE_NINJA=ON; fi env ${compile_env|} DEFAULT_BUILD_ONLY=true \ bash ./libmongocrypt/.evergreen/build_all.sh env ${compile_env|} bash ./libmongocrypt/.evergreen/compile_cs.sh "build python release": - command: shell.exec params: shell: bash script: | set -ex cd ./libmongocrypt/bindings/python PYTHON=${PYTHON} ./release.sh "upload python release": - command: archive.targz_pack params: target: "release-files.tgz" source_dir: "libmongocrypt/bindings/python/dist" include: - "*" - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: release-files.tgz remote_file: '${project}/python-release/${branch_name}/${libmongocrypt_s3_suffix}/${task_id}-${execution}-release-files.tar.gz' bucket: mciuploads permissions: public-read content_type: ${content_type|application/gzip} display_name: Release Python files "download and merge python releases": - command: shell.exec params: silent: true shell: "bash" script: | # set AWS credentials rm -rf ~/.aws mkdir -p ~/.aws cat <> ~/.aws/config [default] region = us-east-1 EOF cat <> ~/.aws/credentials [default] aws_access_key_id = ${aws_key} aws_secret_access_key = ${aws_secret} EOF - command: shell.exec params: shell: "bash" script: | set -o xtrace # Download all the release files. aws s3 cp --recursive s3://mciuploads/${project}/python-release/${branch_name}/${libmongocrypt_s3_suffix}/ release/ # Combine releases into one directory. ls -la release/ mkdir releases for REL in release/*; do tar zxvf $REL -C releases/ done - command: archive.targz_pack params: target: "release-files-all.tgz" source_dir: "releases/" include: - "*" - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: release-files-all.tgz remote_file: '${project}/python-release/${branch_name}/${libmongocrypt_s3_suffix}/${task_id}-${execution}-release-files-all.tar.gz' bucket: mciuploads permissions: public-read content_type: ${content_type|application/gzip} display_name: Release Python files all earthly: - command: shell.exec params: shell: bash working_dir: ${working_dir|libmongocrypt} script: bash ${workdir}/libmongocrypt/.evergreen/earthly.sh ${args} tasks: - name: build-and-test-and-upload commands: - func: "fetch source" - func: "build and test" - func: "tar and upload libmongocrypt libraries" - func: "create packages and repos" - func: "upload packages and repos" - name: build-with-earthly commands: - func: "fetch source" - func: "earthly" vars: args: --artifact +build/libmongocrypt-install --env=${earthly_env} ${workdir}/install - func: "tar and upload libmongocrypt libraries" - name: build-deb-packages-with-earthly commands: - func: "fetch source" - func: "earthly" vars: args: +create-deb-packages-and-repos --env=${earthly_env} --packager_distro=${packager_distro} --packager_arch=${packager_arch} - func: "upload packages and repos" - name: publish-deb-packages-with-earthly depends_on: build-deb-packages-with-earthly commands: - func: "fetch source" - func: "setup packaging credentials" - func: "publish packages" - name: clang-tidy commands: - func: "fetch source" - func: "run clang-tidy" - name: build-and-test-shared-bson commands: - func: "fetch source" - func: "build and test" vars: compile_env: ${compile_env|} LIBMONGOCRYPT_EXTRA_CMAKE_FLAGS="-DUSE_SHARED_LIBBSON=ON" - name: build-and-test-asan commands: - func: "fetch source" - func: "build and test" vars: compile_env: >- ${compile_env|} LIBMONGOCRYPT_EXTRA_CFLAGS="-fsanitize=address -pthread" # Add detect_odr_violation=0 to ASAN_OPTIONS to ignore odr-violation in IntelDFP symbol: __dpml_bid_globals_table ASAN_OPTIONS="detect_leaks=1 detect_odr_violation=0" - name: build-and-test-asan-mac commands: - func: "fetch source" - func: "build and test" vars: compile_env: ${compile_env|} LIBMONGOCRYPT_EXTRA_CFLAGS="-fsanitize=address" - name: build-and-test-asan-s390x commands: - func: "fetch source" - func: "build and test" vars: compile_env: ${compile_env|} LIBMONGOCRYPT_EXTRA_CFLAGS="-fsanitize=address" - name: test-java depends_on: - variant: ubuntu2004-64 name: upload-java commands: - func: "fetch source" - func: "test java" vars: { variant_name: "${build_variant}" } - name: test-python depends_on: - build-and-test-and-upload commands: - func: "fetch source" - func: "download tarball" vars: { variant_name: "${build_variant}" } - func: "test python" vars: { variant_name: "${build_variant}" } - name: test-python-windows depends_on: # Depends on the windows-64-vs2017-test upload. - variant: windows-test name: build-and-test-and-upload commands: - func: "fetch source" - func: "download tarball" vars: { variant_name: windows-test } - func: "test python" vars: { variant_name: windows-test } - name: test-python-integ depends_on: - build-and-test-and-upload commands: - func: "fetch source" - func: "download tarball" vars: { variant_name: "${build_variant}" } - func: "test python integ" vars: { variant_name: "${build_variant}" } - name: "release-python-macos-1100" tags: ["release_python_tag"] run_on: macos-1100 commands: - func: "fetch source" - func: "build python release" vars: { PYTHON: /Library/Frameworks/Python.framework/Versions/3.10/bin/python3 } - func: "upload python release" - name: "release-python-linux" tags: ["release_python_tag"] run_on: ubuntu2004-large exec_timeout_secs: 216000 # 60 minutes (manylinux task is slow). commands: - func: "fetch source" - func: "build python release" vars: { PYTHON: /opt/python/3.8/bin/python3 } - func: "upload python release" - name: "release-python-windows" tags: ["release_python_tag"] run_on: windows-64-vsMulti-small commands: - func: "fetch source" - func: "build python release" vars: { PYTHON: C:/python/Python38/python.exe } - func: "upload python release" - name: "release-python-combine" tags: ["release_python_tag"] run_on: rhel84-small depends_on: - name: "*" variant: ".release_python_tag" patch_optional: true commands: - func: "download and merge python releases" - name: build-and-test-csharp commands: - func: "fetch source" - func: "build csharp and test" vars: test_env: PROJECT_DIRECTORY=${project_directory} - name: publish-java depends_on: - variant: ubuntu2004-64 name: upload-java commands: - func: "publish java" - name: upload-java depends_on: - variant: rhel-62-64-bit name: build-and-test-and-upload - variant: rhel72-zseries-test name: build-and-test-and-upload - variant: rhel-71-ppc64el name: build-and-test-and-upload - variant: ubuntu1604-arm64 name: build-and-test-and-upload - variant: windows-test name: build-and-test-and-upload - variant: macos_x86_64 name: build-and-test-and-upload - variant: macos name: build-and-test-and-upload commands: - command: shell.exec params: script: mkdir all - func: "download tarball" vars: { variant_name: "rhel-62-64-bit" } - func: "download tarball" vars: { variant_name: "rhel72-zseries-test" } - func: "download tarball" vars: { variant_name: "rhel-71-ppc64el" } - func: "download tarball" vars: { variant_name: "ubuntu1604-arm64" } - func: "download tarball" vars: { variant_name: "windows-test" } - func: "download tarball" vars: { variant_name: "macos_x86_64" } - func: "download tarball" vars: { variant_name: "macos" } - command: archive.targz_pack params: target: libmongocrypt-java.tar.gz source_dir: all include: [./**] - command: shell.exec params: script: |- set -o errexit if [ -n "${tag_upload_location}" ]; then # the "fetch source" step detected a release tag on HEAD, so we # prepare a local file for upload to a location based on the tag cp -a libmongocrypt-java.tar.gz libmongocrypt-java-${tag_upload_location}.tar.gz fi - command: s3.put params: aws_key: '${aws_key}' aws_secret: '${aws_secret}' remote_file: 'libmongocrypt/java/${revision}/libmongocrypt-java.tar.gz' bucket: mciuploads permissions: public-read local_file: 'libmongocrypt-java.tar.gz' content_type: '${content_type|application/x-gzip}' - command: s3.put params: aws_key: '${aws_key}' aws_secret: '${aws_secret}' remote_file: 'libmongocrypt/java/${tag_upload_location}/libmongocrypt-java.tar.gz' bucket: mciuploads permissions: public-read optional: true display_name: 'libmongocrypt-java-${tag_upload_location}.tar.gz' local_file: 'libmongocrypt-java-${tag_upload_location}.tar.gz' content_type: '${content_type|application/x-gzip}' - name: upload-all depends_on: - variant: ubuntu1604 name: build-and-test-and-upload - variant: macos_x86_64 name: build-and-test-and-upload - variant: rhel72-zseries-test name: build-and-test-and-upload - variant: windows-test name: build-and-test-and-upload - variant: linux-64-amazon-ami name: build-and-test-and-upload - variant: amazon2 name: build-and-test-and-upload - variant: amazon2-arm64 name: build-and-test-and-upload - variant: amazon2023 name: build-and-test-and-upload - variant: amazon2023-arm64 name: build-and-test-and-upload - variant: debian12 name: build-and-test-and-upload - variant: debian11 name: build-and-test-and-upload - variant: debian10 name: build-and-test-and-upload - variant: debian92 name: build-and-test-and-upload - variant: rhel-62-64-bit name: build-and-test-and-upload - variant: rhel-70-64-bit name: build-and-test-and-upload - variant: rhel-71-ppc64el name: build-and-test-and-upload - variant: rhel-80-64-bit name: build-and-test-and-upload - variant: rhel-81-ppc64el name: build-and-test-and-upload - variant: rhel-82-arm64 name: build-and-test-and-upload - variant: rhel-83-zseries name: build-and-test-and-upload - variant: rhel-91-64-bit name: build-and-test-and-upload - variant: rhel-91-arm64 name: build-and-test-and-upload - variant: suse12-64 name: build-and-test-and-upload - variant: suse15-64 name: build-and-test-and-upload - variant: ubuntu1604-arm64 name: build-and-test-and-upload - variant: ubuntu1804-64 name: build-and-test-and-upload - variant: ubuntu1804-arm64 name: build-and-test-and-upload - variant: ubuntu2004-64 name: build-and-test-and-upload - variant: ubuntu2004-arm64 name: build-and-test-and-upload - variant: ubuntu2204-64 name: build-and-test-and-upload - variant: ubuntu2204-arm64 name: build-and-test-and-upload - variant: macos name: build-and-test-and-upload - variant: alpine-amd64-earthly name: build-with-earthly - variant: alpine-arm64-earthly name: build-with-earthly commands: - func: "fetch source" - command: shell.exec params: script: mkdir all - func: "download tarball" vars: { variant_name: ubuntu1604 } - func: "download tarball" vars: { variant_name: "macos" } - func: "download tarball" vars: { variant_name: "rhel72-zseries-test" } - func: "download tarball" vars: { variant_name: "windows-test" } - func: "download tarball" vars: { variant_name: "linux-64-amazon-ami" } - func: "download tarball" vars: { variant_name: "amazon2" } - func: "download tarball" vars: { variant_name: "amazon2-arm64" } - func: "download tarball" vars: { variant_name: "amazon2023" } - func: "download tarball" vars: { variant_name: "amazon2023-arm64" } - func: "download tarball" vars: { variant_name: "debian12" } - func: "download tarball" vars: { variant_name: "debian11" } - func: "download tarball" vars: { variant_name: "debian10" } - func: "download tarball" vars: { variant_name: "debian92" } - func: "download tarball" vars: { variant_name: "rhel-62-64-bit" } - func: "download tarball" vars: { variant_name: "rhel-70-64-bit" } - func: "download tarball" vars: { variant_name: "rhel-71-ppc64el" } - func: "download tarball" vars: { variant_name: "rhel-80-64-bit" } - func: "download tarball" vars: { variant_name: "rhel-81-ppc64el" } - func: "download tarball" vars: { variant_name: "rhel-82-arm64" } - func: "download tarball" vars: { variant_name: "rhel-83-zseries" } - func: "download tarball" vars: { variant_name: "rhel-91-64-bit" } - func: "download tarball" vars: { variant_name: "rhel-91-arm64" } - func: "download tarball" vars: { variant_name: "suse12-64" } - func: "download tarball" vars: { variant_name: "suse15-64" } - func: "download tarball" vars: { variant_name: "ubuntu1604-arm64" } - func: "download tarball" vars: { variant_name: "ubuntu1804-64" } - func: "download tarball" vars: { variant_name: "ubuntu1804-arm64" } - func: "download tarball" vars: { variant_name: "ubuntu2004-64" } - func: "download tarball" vars: { variant_name: "ubuntu2004-arm64" } - func: "download tarball" vars: { variant_name: "ubuntu2204-64" } - func: "download tarball" vars: { variant_name: "ubuntu2204-arm64" } - func: "download tarball" vars: { variant_name: "macos" } - func: "download tarball" vars: { variant_name: "alpine-amd64-earthly" } - func: "download tarball" vars: { variant_name: "alpine-arm64-earthly" } - command: archive.targz_pack params: target: libmongocrypt-all.tar.gz source_dir: all include: [./**] - command: shell.exec params: script: |- set -o errexit if [ -n "${tag_upload_location}" ]; then # the "fetch source" step detected a release tag on HEAD, so we # prepare a local file for upload to a location based on the tag cp -a libmongocrypt-all.tar.gz libmongocrypt-all-${tag_upload_location}.tar.gz fi - command: s3.put params: aws_key: '${aws_key}' aws_secret: '${aws_secret}' remote_file: 'libmongocrypt/all/${branch_name}/${libmongocrypt_s3_suffix}/libmongocrypt-all.tar.gz' bucket: mciuploads permissions: public-read local_file: 'libmongocrypt-all.tar.gz' content_type: '${content_type|application/x-gzip}' - command: s3.put params: aws_key: '${aws_key}' aws_secret: '${aws_secret}' remote_file: 'libmongocrypt/all/${branch_name}/${libmongocrypt_s3_suffix_copy}/libmongocrypt-all.tar.gz' bucket: mciuploads permissions: public-read local_file: 'libmongocrypt-all.tar.gz' content_type: '${content_type|application/x-gzip}' - command: s3.put params: aws_key: '${aws_key}' aws_secret: '${aws_secret}' remote_file: 'libmongocrypt/all/${tag_upload_location}/libmongocrypt-all.tar.gz' bucket: mciuploads permissions: public-read optional: true display_name: 'libmongocrypt-all-${tag_upload_location}.tar.gz' local_file: 'libmongocrypt-all-${tag_upload_location}.tar.gz' content_type: '${content_type|application/x-gzip}' - name: publish-packages depends_on: build-and-test-and-upload commands: - func: "fetch source" - func: "setup packaging credentials" - func: "publish packages" - name: windows-upload-release depends_on: - variant: windows-test name: build-and-test-and-upload commands: - func: "fetch source" - command: shell.exec params: shell: bash working_dir: libmongocrypt script: |- set -o xtrace set -o errexit . .evergreen/init.sh libmongocrypt_release_version=$(run_python ./etc/calc_release_version.py) case "$libmongocrypt_release_version" in *+*) # Not a tagged release. Use full release version suffix. upload_suffix="$libmongocrypt_release_version" ;; *-*) # Unstable release, like 1.1.0-beta1 or 1.0.1-rc0. Overwrite the latest unstable URL. upload_suffix='_unstable' ;; *) # Tagged release. Overwrite the latest stable URL. upload_suffix='' ;; esac # Add expansions used in later commands: echo "libmongocrypt_release_version: '$libmongocrypt_release_version'" > expansions.yml echo "upload_suffix: '$upload_suffix'" >> expansions.yml - command: expansions.update params: file: libmongocrypt/expansions.yml - command: s3.get # Download Windows build. params: aws_key: '${aws_key}' aws_secret: '${aws_secret}' remote_file: '${project}/windows-test/${branch_name}/${libmongocrypt_s3_suffix}/libmongocrypt.tar.gz' bucket: mciuploads extract_to: libmongocrypt_download - command: shell.exec params: script: |- set -o xtrace set -o errexit # Move just the mongocrypt files needed into the final upload mkdir libmongocrypt_upload mkdir libmongocrypt_upload/bin mkdir libmongocrypt_upload/include mv libmongocrypt_download/bin/mongocrypt.dll libmongocrypt_upload/bin/mongocrypt.dll mv libmongocrypt_download/include/mongocrypt libmongocrypt_upload/include - command: archive.targz_pack params: target: libmongocrypt_upload.tar.gz source_dir: libmongocrypt_upload include: [./**] - command: s3.put # Windows tarballs were previously documented as available from these fixed URLs: # (stable) : https://s3.amazonaws.com/mciuploads/libmongocrypt/windows/latest_release/libmongocrypt.tar.gz # (unstable): https://s3.amazonaws.com/mciuploads/libmongocrypt/windows/latest_release/libmongocrypt_unstable.tar.gz # Documentation now refers to the GitHub release page, which includes the per-release tarball. # The fixed URL upload is kept to avoid possibly breaking expectations. Consider removing in the future. params: aws_key: '${aws_key}' aws_secret: '${aws_secret}' remote_file: 'libmongocrypt/windows/latest_release/libmongocrypt${upload_suffix}.tar.gz' display_name: (Deprecated) libmongocrypt${upload_suffix}.tar.gz bucket: mciuploads permissions: public-read local_file: 'libmongocrypt_upload.tar.gz' content_type: 'application/x-gzip' - command: s3.put # Upload tarball for GitHub Release. params: aws_key: '${aws_key}' aws_secret: '${aws_secret}' remote_file: '${project}/${build_variant}/${branch_name}/${revision}/${version_id}/libmongocrypt-windows-x86_64-${libmongocrypt_release_version}.tar.gz' display_name: libmongocrypt-windows-x86_64-${libmongocrypt_release_version}.tar.gz bucket: mciuploads permissions: public-read local_file: 'libmongocrypt_upload.tar.gz' content_type: 'application/x-gzip' - command: shell.exec params: shell: bash script: |- set -o errexit # Authenticate to artifactory for signing image. echo "${artifactory_password}" | docker login --password-stdin --username "${artifactory_username}" artifactory.corp.mongodb.com # Copy file to sign into `libmongocrypt` directory to be used by Earthly. cp libmongocrypt_upload.tar.gz libmongocrypt - func: "earthly" # Sign tarball. vars: args: --secret garasign_username=${garasign_username} --secret garasign_password=${garasign_password} +sign --file_to_sign=libmongocrypt_upload.tar.gz --output_file=libmongocrypt_upload.asc - command: s3.put # Upload signature for GitHub Release. params: aws_key: '${aws_key}' aws_secret: '${aws_secret}' remote_file: '${project}/${build_variant}/${branch_name}/${revision}/${version_id}/libmongocrypt-windows-x86_64-${libmongocrypt_release_version}.asc' display_name: libmongocrypt-windows-x86_64-${libmongocrypt_release_version}.asc bucket: mciuploads permissions: public-read local_file: 'libmongocrypt/libmongocrypt_upload.asc' content_type: 'application/pgp-signature' - name: debian-package-build run_on: &deb-package-build-run_on - ubuntu2004 - ubuntu2004-small tags: [packaging] commands: - func: "fetch source" - command: shell.exec type: test params: working_dir: "libmongocrypt" shell: bash script: |- set -o errexit set -o xtrace bash .evergreen/debian_package_build.sh --is-patch=${is_patch} - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: deb.tar.gz remote_file: libmongocrypt/${branch_name}/${revision}/${version_id}/${build_id}/${execution}/debian-packages.tar.gz bucket: mciuploads permissions: public-read content_type: ${content_type|application/x-gzip} display_name: "deb.tar.gz" - name: debian-package-build-i386 run_on: *deb-package-build-run_on tags: [packaging] commands: - func: "fetch source" - command: shell.exec type: test params: working_dir: "libmongocrypt" shell: bash script: |- set -o errexit set -o xtrace bash .evergreen/debian_package_build.sh --arch=i386 --is-patch=${is_patch} - command: s3.put params: aws_key: ${aws_key} aws_secret: ${aws_secret} local_file: deb.tar.gz remote_file: libmongocrypt/${branch_name}/${revision}/${version_id}/${build_id}/${execution}/debian-packages-i386.tar.gz bucket: mciuploads permissions: public-read content_type: ${content_type|application/x-gzip} display_name: "deb.tar.gz" - name: rpm-package-build tags: [packaging] run_on: &docker-distros # * The RHEL76-docker distro runs an old and unsupported version of Docker. # * (We requires the --mount parameter) - ubuntu2004-small - ubuntu2004 - ubuntu1804 - ubuntu1804-medium - debian10 - debian11 - amazon2 commands: - func: fetch source - func: earthly vars: args: +rpm-runtime-test - name: check-format tags: [misc] run_on: *docker-distros commands: - func: fetch source - func: earthly vars: args: +check-format - name: benchmark-java commands: - func: "fetch source" - command: "subprocess.exec" params: binary: bash working_dir: "./libmongocrypt" args: - "./.evergreen/benchmark-java.sh" - command: "perf.send" params: file: libmongocrypt/bindings/java/mongocrypt/benchmarks/results.json - name: benchmark-python commands: - func: "fetch source" - command: "subprocess.exec" params: binary: bash working_dir: "./libmongocrypt" args: - "./.evergreen/benchmark-python.sh" - command: "perf.send" params: file: libmongocrypt/bindings/python/results.json pre: # Update the evergreen expansion to dynamically set the ${libmongocrypt_s3_suffix} and ${libmongocrypt_s3_suffix_copy} expansions. - command: "shell.exec" params: # Uploads are prefixed with ${project}/${build_variant}/${branch_name|all} script: |- if [ "${is_patch}" = "true" ]; then # patch build. REMOTE_SUFFIX="${revision}/${version_id}" REMOTE_SUFFIX_COPY="latest/${version_id}" elif [ "${branch_name}" = "master" ]; then # waterfall build. REMOTE_SUFFIX="${revision}" REMOTE_SUFFIX_COPY="latest" else # waterfall build, not on master branch. REMOTE_SUFFIX="${revision}" REMOTE_SUFFIX_COPY="latest-${branch_name}" fi PROJECT_DIRECTORY="$(pwd)" echo "libmongocrypt_s3_suffix: $REMOTE_SUFFIX" echo "libmongocrypt_s3_suffix_copy: $REMOTE_SUFFIX_COPY" echo "project_directory: $PROJECT_DIRECTORY" cat < expansion.yml libmongocrypt_s3_suffix: "$REMOTE_SUFFIX" libmongocrypt_s3_suffix_copy: "$REMOTE_SUFFIX_COPY" project_directory: "$PROJECT_DIRECTORY" EOT - command: expansions.update params: file: expansion.yml - func: "cleanup environment" post: - func: "cleanup environment" # NOTE: When adding a new variant, update the "upload-all" task. buildvariants: - name: ubuntu1604 display_name: "Ubuntu 16.04 64-bit" run_on: ubuntu1604-test expansions: has_packages: true packager_distro: ubuntu1604 packager_arch: x86_64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan - test-java - name: publish-packages distros: - ubuntu2004-small - name: macos_x86_64 display_name: "macOS (x86_64) 10.14" run_on: macos-1014 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan-mac # - build-and-test-csharp // temporary removed to make strong named release. - test-java - name: rhel72-zseries-test display_name: "RHEL 7.2 on zSeries" run_on: rhel72-zseries-test expansions: has_packages: true packager_distro: rhel72 packager_arch: s390x tasks: - build-and-test-and-upload - build-and-test-shared-bson - test-java - name: publish-packages distros: - rhel70-small - name: rhel83-zseries # rhel83-zseries has a new enough g++ to build the C++ tests. # rhel72-zseries-test does not build the C++ tests. display_name: "RHEL 8.3 on zSeries" run_on: rhel83-zseries-small tasks: - build-and-test-and-upload - name: windows-vs2015-compile display_name: "Windows VS 2015 compile" run_on: windows-64-vs2015-test expansions: vs_version: "14" vs_target_arch: amd64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - name: windows-test display_name: "Windows 2016" run_on: windows-64-vs2017-test expansions: vs_version: "15" vs_target_arch: amd64 tasks: - build-and-test-and-upload - build-and-test-shared-bson # - build-and-test-csharp // temporary removed to make strong named release. - test-java - name: windows-test-python display_name: "Windows Python" run_on: windows-64-vsMulti-small tasks: - test-python-windows - name: python-release display_name: Python Release batchtime: 20160 # 14 days tags: ["release_python_tag"] tasks: - ".release_python_tag" - name: linux-64-amazon-ami display_name: "Amazon Linux" run_on: amazon1-2018-test expansions: has_packages: true packager_distro: amazon packager_arch: x86_64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - test-java - name: publish-packages distros: - rhel70-small - name: amazon2 display_name: "Amazon Linux 2" run_on: amazon2-test expansions: has_packages: true packager_distro: amazon2 packager_arch: x86_64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan - test-java - name: publish-packages distros: - rhel70-small - name: amazon2-arm64 display_name: "Amazon Linux 2 (arm64)" run_on: amazon2-arm64 expansions: has_packages: true packager_distro: amazon2 packager_arch: aarch64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan - name: publish-packages distros: - rhel70-small - name: amazon2023 display_name: "Amazon Linux 2023" run_on: amazon2023.0-small expansions: has_packages: true packager_distro: amazon2023 packager_arch: x86_64 tasks: - build-and-test-and-upload - name: publish-packages distros: - rhel70-small - name: amazon2023-arm64 display_name: "Amazon Linux 2023 (arm64)" run_on: amazon2023-arm64-small expansions: has_packages: true packager_distro: amazon2023 packager_arch: aarch64 tasks: - build-and-test-and-upload - name: publish-packages distros: - rhel70-small - name: debian11 display_name: "Debian 11" run_on: debian11-large expansions: has_packages: true packager_distro: debian11 packager_arch: x86_64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan - test-java - name: publish-packages distros: - ubuntu2004-small - name: debian12 display_name: "Debian 12" run_on: debian12-large expansions: has_packages: true packager_distro: debian12 packager_arch: x86_64 python: python3 tasks: - build-and-test-and-upload - name: publish-packages distros: - ubuntu2004-small - name: debian10 display_name: "Debian 10" run_on: debian10-test expansions: has_packages: true packager_distro: debian10 packager_arch: x86_64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan - test-java - name: publish-packages distros: - ubuntu2004-small - name: debian92 display_name: "Debian 9.2" run_on: debian92-test expansions: has_packages: true packager_distro: debian92 packager_arch: x86_64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan - test-java - name: publish-packages distros: - ubuntu2004-small - name: rhel-62-64-bit display_name: "RHEL 6.2 64-bit" run_on: rhel62-small expansions: has_packages: true packager_distro: rhel62 packager_arch: x86_64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - test-java - name: publish-packages distros: - rhel70-small - name: rhel-70-64-bit display_name: "RHEL 7.0 64-bit" run_on: rhel70-small expansions: has_packages: true packager_distro: rhel70 packager_arch: x86_64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - test-java - name: publish-packages distros: - rhel70-small - name: rhel-71-ppc64el display_name: "RHEL 7.1 ppc64el" run_on: rhel71-power8-test expansions: has_packages: true packager_distro: rhel71 packager_arch: ppc64le tasks: - build-and-test-and-upload - build-and-test-shared-bson - test-java - name: publish-packages distros: - rhel70-small - name: rhel-80-64-bit display_name: "RHEL 8.0 64-bit" run_on: rhel80-test expansions: has_packages: true packager_distro: rhel80 packager_arch: x86_64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - test-java - test-python - test-python-integ - name: publish-packages distros: - rhel70-small - name: rhel-82-arm64 display_name: "RHEL 8.2 arm64" run_on: rhel82-arm64-small expansions: has_packages: true packager_distro: rhel82 packager_arch: aarch64 tasks: - build-and-test-and-upload - test-python - test-python-integ - name: publish-packages distros: - rhel70-small - name: rhel-81-ppc64el display_name: "RHEL 8.1 ppc64el" run_on: rhel81-power8-small expansions: has_packages: true packager_distro: rhel81 packager_arch: ppc64le tasks: - build-and-test-and-upload - name: publish-packages distros: - rhel70-small - name: rhel-83-zseries display_name: "RHEL 8.3 zSeries" run_on: rhel83-zseries-small expansions: has_packages: true packager_distro: rhel83 packager_arch: s390x tasks: - build-and-test-and-upload - name: publish-packages distros: - rhel70-small - name: rhel-91-64-bit display_name: "RHEL 9.1 64-bit" run_on: rhel91-small expansions: has_packages: true packager_distro: rhel91 packager_arch: x86_64 tasks: - build-and-test-and-upload - name: publish-packages distros: - rhel70-small - name: rhel-91-arm64 display_name: "RHEL 9.1 arm64" run_on: rhel91-arm64-small expansions: has_packages: true packager_distro: rhel91 packager_arch: aarch64 tasks: - build-and-test-and-upload - name: publish-packages distros: - rhel70-small - name: suse12-64 display_name: "SLES 12 64-bit" run_on: suse12-sp5-small expansions: has_packages: true packager_distro: suse12 packager_arch: x86_64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan - name: publish-packages distros: - rhel70-small - name: suse15-64 display_name: "SLES 15 64-bit" run_on: suse15-test expansions: has_packages: true packager_distro: suse15 packager_arch: x86_64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan - test-java - name: publish-packages distros: - rhel70-small - name: ubuntu1604-arm64 display_name: "Ubuntu 16.04 arm64" run_on: ubuntu1604-arm64-large expansions: has_packages: true packager_distro: ubuntu1604 packager_arch: arm64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan - test-java - name: publish-packages distros: - ubuntu2004-small - name: ubuntu1804-64 display_name: "Ubuntu 18.04 64-bit" run_on: ubuntu1804-test expansions: has_packages: true packager_distro: ubuntu1804 packager_arch: x86_64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan # - build-and-test-csharp // temporary removed to make strong named release. - test-java - name: publish-packages distros: - ubuntu2004-small - name: ubuntu1804-64-clang7 # ubuntu1804-64-clang7 is used to test Ubuntu 18.04 with Clang 7.0.1. # This is a supported configuration built by the MongoDB Server. # The MongoDB Server vendors libmongocrypt. Refer: MONGOCRYPT-501. display_name: "Ubuntu 18.04 64-bit clang7" run_on: ubuntu1804-test expansions: compile_env: LIBMONGOCRYPT_EXTRA_CMAKE_FLAGS="-DCMAKE_C_COMPILER=/opt/mongodbtoolchain/v3/bin/clang -DCMAKE_CXX_COMPILER=/opt/mongodbtoolchain/v3/bin/clang++" tasks: - build-and-test-and-upload - name: ubuntu1804-arm64 display_name: "Ubuntu 18.04 arm64" run_on: ubuntu1804-arm64-build expansions: has_packages: true packager_distro: ubuntu1804 packager_arch: arm64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan - test-java - name: publish-packages distros: - ubuntu2004-small - name: ubuntu2004-64 display_name: "Ubuntu 20.04 64-bit" run_on: ubuntu2004-small expansions: has_packages: true packager_distro: ubuntu2004 packager_arch: x86_64 tasks: - clang-tidy - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan # - build-and-test-csharp // temporary removed to make strong named release. - test-java - upload-java - publish-packages - name: ubuntu2004-arm64 display_name: "Ubuntu 20.04 arm64" run_on: ubuntu2004-arm64-small expansions: has_packages: true packager_distro: ubuntu2004 packager_arch: arm64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan - name: publish-packages distros: - ubuntu2004-small - name: ubuntu2204-64 display_name: "Ubuntu 22.04 64-bit" run_on: ubuntu2204-small expansions: has_packages: true packager_distro: ubuntu2204 packager_arch: x86_64 clang_env: CC=clang-12 CXX=clang++-12 tasks: - clang-tidy - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan # see https://jira.mongodb.org/browse/MONGOCRYPT-515 #- build-and-test-csharp - test-java - upload-java - name: publish-packages distros: - ubuntu2004-small - windows-upload-release - name: ubuntu2204-arm64 display_name: "Ubuntu 22.04 arm64" run_on: ubuntu2204-arm64-small expansions: has_packages: true packager_distro: ubuntu2204 packager_arch: arm64 tasks: - build-and-test-and-upload - build-and-test-shared-bson - build-and-test-asan - name: publish-packages distros: - ubuntu2004-small - name: publish display_name: "Publish" run_on: ubuntu1804-test tasks: - name: "upload-java" - name: "upload-all" - name: java-release display_name: Java Release run_on: ubuntu2004-small tasks: - "publish-java" - name: packaging display_name: "Linux Distro Packaging" tasks: [.packaging] - name: misc display_name: Miscellaneous tasks: [.misc] - name: macos display_name: macOS m1 (Apple LLVM) run_on: macos-1100-arm64 expansions: compile_env: MACOS_UNIVERSAL=ON CMAKE=/opt/homebrew/bin/cmake tasks: - build-and-test-and-upload - test-python - test-java - name: windows-vs2017-32bit # Test Windows 32 bit builds for PHPC. PHPC builds libmongocrypt from source. See MONGOCRYPT-391. display_name: "Windows VS 2017 32-bit compile" run_on: windows-64-vs2017-small expansions: compile_env: WINDOWS_32BIT=ON vs_version: "15" vs_target_arch: x86 tasks: - build-and-test-and-upload - name: benchmark display_name: "Benchmark" # rhel90-dbx-perf-large is the dedicated performance distro referenced in DRIVERS-2666. run_on: rhel90-dbx-perf-large tasks: - benchmark-java - benchmark-python - name: alpine-amd64-earthly display_name: "Alpine Linux 3.18 amd64 (via Earthly)" expansions: earthly_env: alpine tasks: - name: build-with-earthly run_on: ubuntu2204-small - name: alpine-arm64-earthly display_name: "Alpine Linux 3.18 arm64 (via Earthly)" expansions: earthly_env: alpine tasks: - name: build-with-earthly run_on: ubuntu2204-arm64-small - name: debian11-arm64-earthly display_name: "Debian 11 arm64 (via Earthly)" expansions: has_packages: true packager_distro: debian11 packager_arch: arm64 earthly_env: deb11 tasks: - name: build-deb-packages-with-earthly # Use an arm64 distro to match the intended target architecture of .deb packages. run_on: ubuntu2204-arm64-small - name: publish-deb-packages-with-earthly # Use a distro suitable for running curator to publish .deb packages. run_on: ubuntu2004-small - name: debian12-arm64-earthly display_name: "Debian 12 arm64 (via Earthly)" expansions: has_packages: true packager_distro: debian12 packager_arch: arm64 earthly_env: deb12 tasks: - name: build-deb-packages-with-earthly # Use an arm64 distro to match the intended target architecture of .deb packages. run_on: ubuntu2204-arm64-small - name: publish-deb-packages-with-earthly # Use a distro suitable for running curator to publish .deb packages. run_on: ubuntu2004-small - name: debian10-arm64-earthly display_name: "Debian 10 arm64 (via Earthly)" expansions: has_packages: true packager_distro: debian10 packager_arch: arm64 earthly_env: deb10 tasks: - name: build-deb-packages-with-earthly # Use an arm64 distro to match the intended target architecture of .deb packages. run_on: ubuntu2204-arm64-small - name: publish-deb-packages-with-earthly # Use a distro suitable for running curator to publish .deb packages. run_on: ubuntu2004-small - name: debian9-arm64-earthly display_name: "Debian 9 arm64 (via Earthly)" expansions: has_packages: true packager_distro: debian92 packager_arch: arm64 earthly_env: deb9 tasks: - name: build-deb-packages-with-earthly # Use an arm64 distro to match the intended target architecture of .deb packages. run_on: ubuntu2204-arm64-small - name: publish-deb-packages-with-earthly # Use a distro suitable for running curator to publish .deb packages. run_on: ubuntu2004-small libmongocrypt-1.11.0/.evergreen/create-packages-and-repos.sh000066400000000000000000000041141465326363200237750ustar00rootroot00000000000000#!/bin/bash . "$(dirname "${BASH_SOURCE[0]}")/setup-env.sh" # Generate an error if these are unset: : "$PACKAGER_DISTRO" "$PACKAGER_ARCH" if ! "${HAS_PACKAGES:-false}"; then echo "'HAS_PACKAGES' is not 'true': Skipping package build" exit 0 fi if test -d "$WORKDIR/venv"; then if test "$OS" = "Windows_NT"; then # Need to quote the path on Windows to preserve the separator. . "$WORKDIR/venv/Scripts/activate" 2> /tmp/activate_error.log else . "$WORKDIR/venv/bin/activate" 2> /tmp/activate_error.log fi if test $? -ne 0; then echo "Failed to activate virtualenv: $(cat /tmp/activate_error.log)" fi python=python else python="${PYTHON:-/opt/mongodbtoolchain/v3/bin/python3}" fi export PYTHONPATH : "${PYTHONPATH:=}" if test "$OS" = "Windows_NT"; then PYTHONPATH="$PYTHONPATH;$(cygpath -w "$WORKDIR/src")" else PYTHONPATH="$PYTHONPATH:$WORKDIR/src" fi # Get current version of libmongocrypt. pushd "$LIBMONGOCRYPT_DIR" mongocrypt_version="$("$python" etc/calc_release_version.py)" popd PPA_BUILD_ONLY=1 "$LIBMONGOCRYPT_DIR/.evergreen/build_all.sh" pkg_version=$mongocrypt_version tar -zcv -C install \ --transform="s|^libmongocrypt/|libmongocrypt-$pkg_version/|" \ --exclude=nocrypto \ --exclude=sharedbson \ -f "libmongocrypt-$pkg_version.tar.gz" \ libmongocrypt pushd "$LIBMONGOCRYPT_DIR/" (git remote | grep -q upstream) || git remote add upstream https://github.com/mongodb/libmongocrypt git fetch upstream git checkout $(git rev-parse upstream/debian/unstable) -- debian popd pushd "$LIBMONGOCRYPT_DIR/etc/" # The files from libmongocrypt/debian/ are the official maintainer scripts, # but libmongocrypt/etc/debian/ contains a few custom scripts that are # meant to support the packager.py workflow. This step "fills in" around # those custom scripts. cp -nr ../debian/* debian/ command "$python" ./packager.py \ --prefix "$LIBMONGOCRYPT_DIR" \ --distros "$PACKAGER_DISTRO" \ --tarball "$LIBMONGOCRYPT_DIR-$pkg_version.tar.gz" \ --library-version "$pkg_version" \ --metadata-gitspec HEAD \ --arches "$PACKAGER_ARCH" popd libmongocrypt-1.11.0/.evergreen/ctest.sh000066400000000000000000000002121465326363200202050ustar00rootroot00000000000000#!/usr/bin/env bash . "$(dirname "${BASH_SOURCE[0]}")/init.sh" . "$EVG_DIR/ensure-cmake.sh" # Execute CTest: command "$CTEST_EXE" "$@" libmongocrypt-1.11.0/.evergreen/debian_package_build.sh000066400000000000000000000061261465326363200231510ustar00rootroot00000000000000#!/bin/env bash # # Test libmongocrypt's Debian packaging scripts. # # Supported options: # --is-patch={true,false} # If "true", this is an Evergreen patch build. (Default 'false') # --arch= # If specified, sets the "--arch" option for debootstrap. set -euxo pipefail IS_PATCH=false _dbs_args=() for arg in "$@"; do case $arg in --arch=*) a="${arg#*=}" _dbs_args+=(--arch "$a") ;; --is-patch=*) IS_PATCH="${arg#*=}" ;; *) echo "Unknown argument '$arg'" exit 1 ;; esac done on_exit () { if [ -e ./unstable-chroot/debootstrap/debootstrap.log ]; then echo "Dumping debootstrap.log" cat ./unstable-chroot/debootstrap/debootstrap.log fi } trap on_exit EXIT if [ "${IS_PATCH}" = "true" ]; then git diff HEAD > ../upstream.patch git clean -fdx git reset --hard HEAD (git remote | grep -q upstream) || git remote add upstream https://github.com/mongodb/libmongocrypt git fetch upstream git checkout $(git rev-parse upstream/debian/unstable) -- debian if [ -s ../upstream.patch ]; then [ -d debian/patches ] || mkdir debian/patches mv ../upstream.patch debian/patches/ echo upstream.patch >> debian/patches/series git add debian/patches/* git commit -m 'Evergreen patch build - upstream changes' git log -n1 -p fi fi export CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)" cd .. _dbs_args+=(unstable) git clone https://salsa.debian.org/installer-team/debootstrap.git debootstrap.git export DEBOOTSTRAP_DIR=`pwd`/debootstrap.git sudo -E ./debootstrap.git/debootstrap "${_dbs_args[@]}" ./unstable-chroot/ http://cdn-aws.deb.debian.org/debian cp -a libmongocrypt ./unstable-chroot/tmp/ sudo chroot ./unstable-chroot /bin/bash -c '(set -o xtrace && \ apt-get install -y build-essential git-buildpackage fakeroot debhelper cmake curl ca-certificates libssl-dev pkg-config libbson-dev libintelrdfpmath-dev && \ chown -R root:root /tmp/libmongocrypt && \ cd /tmp/libmongocrypt && \ git clean -fdx && \ git reset --hard HEAD && \ python3 etc/calc_release_version.py > VERSION_CURRENT && \ git add --force VERSION_CURRENT && \ git commit VERSION_CURRENT -m "Set current version" && \ (git remote | grep -q upstream) || git remote add upstream https://github.com/mongodb/libmongocrypt git fetch upstream git checkout $(git rev-parse upstream/debian/unstable) -- debian LANG=C /bin/bash ./debian/build_snapshot.sh && \ debc ../*.changes && \ dpkg -i ../*.deb && \ /usr/bin/gcc -I/usr/include/mongocrypt -I/usr/include/libbson-1.0 -o example-state-machine test/example-state-machine.c -lmongocrypt -lbson-1.0 )' [ -e ./unstable-chroot/tmp/libmongocrypt/example-state-machine ] || (echo "Example 'example-state-machine' was not built!" ; exit 1) (cd ./unstable-chroot/tmp/ ; tar zcvf ../../deb.tar.gz *.dsc *.orig.tar.gz *.debian.tar.xz *.build *.deb) # Build a second time, to ensure a "double build" works sudo chroot ./unstable-chroot /bin/bash -c "(\ cd /tmp/libmongocrypt && \ rm -f example-state-machine && \ git status --ignored && \ dpkg-buildpackage -b && dpkg-buildpackage -S )" libmongocrypt-1.11.0/.evergreen/earthly.sh000077500000000000000000000025341465326363200205470ustar00rootroot00000000000000#!/usr/bin/env bash . "$(dirname "${BASH_SOURCE[0]}")/setup-env.sh" set -euo pipefail : "${EARTHLY_VERSION:=0.7.8}" # Bring in the debian/ directory from the debian/unstable branch pushd "$(dirname "${BASH_SOURCE[0]}")/../" (git remote | grep -q upstream) || git remote add upstream https://github.com/mongodb/libmongocrypt git fetch upstream git checkout $(git rev-parse upstream/debian/unstable) -- debian popd # Calc the arch of the executable we want arch="$(uname -m)" case "$arch" in x86_64) arch=amd64 ;; aarch64|arm64) arch=arm64 ;; *) echo "Unknown architecture: $arch" 1>&1 exit 99 ;; esac # The location where the Earthly executable will live cache_dir="$USER_CACHES_DIR/earthly-sh/$EARTHLY_VERSION" mkdir -p "$cache_dir" exe_filename="earthly-$OS_NAME-$arch$EXE_SUFFIX" if [[ "$OS_NAME" == "macos" ]]; then # Earthly downloads use `darwin`. exe_filename="earthly-darwin-$arch$EXE_SUFFIX" fi exe_path="$cache_dir/$exe_filename" # Download if it isn't already present if ! test -f "$exe_path"; then echo "Downloading $exe_filename $EARTHLY_VERSION" url="https://github.com/earthly/earthly/releases/download/v$EARTHLY_VERSION/$exe_filename" curl --retry 5 -LsS --max-time 120 --fail "$url" --output "$exe_path" fi chmod a+x "$exe_path" "$exe_path" "$@" libmongocrypt-1.11.0/.evergreen/ensure-cmake.sh000066400000000000000000000135351465326363200214560ustar00rootroot00000000000000#!/usr/bin/env bash ## This script ensures the presence of a CMake executable matching a specific ## version. After sourcing this script, a variable "$CMAKE_EXE" will refer to ## the CMake executable to be used. ## ## The following environment variables are defined by this script, and can also ## be defined by a caller to control this script. All variables are optional ## and have defaults for this file: ## ## - CMAKE_VERSION: The CMake version to obtain ## - CMAKE_CACHES_ROOT: The directory where all obtained CMake versions will be cached ## - CMAKE_CACHE_DIR: The directory where we will expect/write the CMake that we obtain. ## - CMAKE_EXE: A CMake executable to use. If set, no obtaining logic will execute. ## - CTEST_EXE: The CTest executable for the CMAKE_EXE. . "$(dirname "${BASH_SOURCE[0]}")/setup-env.sh" # The version that we will attempt to obtain: : "${CMAKE_VERSION:=3.25.1}" # Root of all cached versions : "${CMAKE_CACHES_ROOT:="$BUILD_CACHE_DIR/cmake"}" # Cache directory for this particular version: : "${CMAKE_CACHE_DIR:="$CMAKE_CACHES_ROOT/$CMAKE_VERSION"}" # The executable that we want to use (can be overriden by an invoker) _prev_cmake_exe=${CMAKE_EXE-} : "${CMAKE_EXE:="$CMAKE_CACHE_DIR/bin/cmake$EXE_SUFFIX"}" : "${CTEST_EXE:="${CMAKE_EXE%cmake*}ctest"}" # Downloads a prebuilt CMake binary: _download_cmake() { # Directory where we will extract to (temporary) declare extract_dir="$CMAKE_CACHE_DIR.tmp" debug "Temporary extraction dir: [$extract_dir]" test -d "$extract_dir" && rm -r -- "$extract_dir" mkdir -p "$extract_dir" # The path for the downloaded archive (may be zip or tgz) declare archive="$CMAKE_CACHE_DIR.archive" debug "Temporary archive file: [$archive]" # The --strip-components for tar (different on macos) declare strip_components=1 # By default we will use tar. (Windows uses unzip) declare use=tar # Common prefix: declare url_base="https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION" # Select the URL and options: case "$OS_NAME" in linux) declare arch arch="$(uname -m)" url="$url_base/cmake-$CMAKE_VERSION-Linux-$arch.tar.gz" ;; macos) url="$url_base/cmake-$CMAKE_VERSION-macos10.10-universal.tar.gz" # We're pulling out the app bundle contents, so we need to skip more intermediate directories strip_components=3 ;; windows) url="$url_base/cmake-$CMAKE_VERSION-windows-x86_64.zip" # On windows we use 'unzip' use=unzip ;; *) fail "Unrecognized platform $(uname -a)" ;; esac # Download the file: log "Downloading [$url] ..." curl --retry 5 -LsS --max-time 120 --fail --output "$archive" "$url" # Extract the downloaded archive: log "Extracting to [$CMAKE_CACHE_DIR] ..." case $use in tar) debug "Expand with 'tar' into [$extract_dir]" tar -x -f "$archive" -C "$extract_dir" --strip-components=$strip_components ;; unzip) # Unzip has no --strip-components, so we need to move the files ourself debug "Expand with 'unzip' into [$extract_dir.1]" unzip -o -qq "$archive" -d "$extract_dir.1" mv -- "$extract_dir.1"/cmake-$CMAKE_VERSION-*/* "$extract_dir" ;; esac # Check that we got the file: declare test_file="$extract_dir/bin/cmake$EXE_SUFFIX" debug "Checking for file [$test_file]" test -f "$test_file" || fail "Download+extract did not produce the expected file [$test_file]??" # Put the temporary extracted dir into its final location: test -d "$CMAKE_CACHE_DIR" && rm -r -- "$CMAKE_CACHE_DIR" mv -- "$extract_dir" "$CMAKE_CACHE_DIR" } # Download and build CMake from source: _build_cmake() { declare src_dir="$CMAKE_CACHE_DIR.src" debug "Building in directory [$src_dir]" test -d "$src_dir" && rm -r -- "$src_dir" mkdir -p "$src_dir" declare src_tgz="$CMAKE_CACHE_DIR.tgz" declare url="https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION.tar.gz" log "Downloading source archive [$url] ..." curl --retry 5 -LsS --max-time 120 --fail --output "$src_tgz" "$url" log "Extracting [$src_tgz] into [$src_dir] ..." tar -x -f "$src_tgz" -C "$src_dir" --strip-components 1 log "Bootstrapping CMake build ..." run_chdir "$src_dir" bash "./bootstrap" --prefix="$CMAKE_CACHE_DIR" --parallel=10 log "Building CMake" make -C "$src_dir" log "Installing result ..." make -C "$src_dir" install test -f "$CMAKE_EXE" || fail "CMake build did not produce the expected file [$CMAKE_EXE]??" log "Successfully built CMake $CMAKE_VERSION into [$CMAKE_CACHE_DIR]" } # Ensures that we have a CMake executable matching our cache settings: _ensure_cmake() { # If we already have the executable, we don't need to get one debug "Expecting CMake executable [$CMAKE_EXE]" debug "Expecting CTest executable [$CTEST_EXE]" if test -f "$CMAKE_EXE"; then debug "CMake executable [$CMAKE_EXE] is already present. Nothing to to." return 0 fi declare arch arch="$(uname -m)" if test -f /etc/alpine-release; then arch="$arch-musl" fi # Otherwise we need to obtain it log "Obtaining CMake $CMAKE_VERSION for $OS_NAME-$arch" case "$OS_NAME-$arch" in linux-x86_64|linux-aarch64|windows-*|macos-*) # Download a pre-built _download_cmake ;; linux-*) # Build our own _build_cmake ;; *) fail "We don't know how to automatically obtain CMake $CMAKE_VERSION for this platform" ;; esac } if test -z "$_prev_cmake_exe"; then _ensure_cmake elif ! test -f "$_prev_cmake_exe"; then log "ensure-cmake.sh: CMAKE_EXE is set and refers to a non-existent file [$_prev_cmake_exe]" else debug "Using existing CMAKE_EXE [$_prev_cmake_exe]" fi libmongocrypt-1.11.0/.evergreen/ensure-ninja.sh000066400000000000000000000061231465326363200214700ustar00rootroot00000000000000#!/usr/bin/env bash . "$(dirname "${BASH_SOURCE[0]}")/setup-env.sh" test -n "${NINJA_EXE-}" || fail "Set \$NINJA_EXE to point to a filepath where we will write the Ninja executable" # 1.8.2 is chosen as the last pre-built version that supports RHEL 6 : "${NINJA_VERSION:=1.8.2}" _ninja_cache_dir="${BUILD_CACHE_DIR}/ninja-${NINJA_VERSION}" _download_ninja() { declare extract_dir="$_ninja_cache_dir/ninja.d" declare expect_exe="$extract_dir/ninja$EXE_SUFFIX" if test -f "$expect_exe"; then debug "Using downloaded Ninja executable [$expect_exe]" mkdir -p -- "$(dirname "$NINJA_EXE")" cp -- "$expect_exe" "$NINJA_EXE" return 0 fi declare url_base="https://github.com/ninja-build/ninja/releases/download/v$NINJA_VERSION" declare fname case "$OS_NAME" in linux) fname="ninja-linux.zip" ;; macos) fname="ninja-mac.zip" ;; windows) fname="ninja-win.zip" ;; esac declare url="$url_base/$fname" log "Downloading Ninja Zip [$url]" mkdir -p "$BUILD_CACHE_DIR" declare archive=$_ninja_cache_dir/ninja.bin mkdir -p -- "$_ninja_cache_dir" curl --retry 5 -LsS --max-time 120 --fail --output "$archive" "$url" unzip -qq -o "$archive" "ninja$EXE_SUFFIX" -d "$extract_dir" test -f "$expect_exe" || fail "Unzip did not generate expected executable [$expect_exe]" # Recurisve invocation will find the extracted executable and copy it _download_ninja } _build_ninja() { declare build_out_dir="$_ninja_cache_dir/built" mkdir -p "$build_out_dir" declare expect_exe="$build_out_dir/ninja$EXE_SUFFIX" if test -f "$expect_exe"; then debug "Using built Ninja executable [$expect_exe]" mkdir -p -- "$(dirname "$NINJA_EXE")" cp -- "$expect_exe" "$NINJA_EXE" return 0 fi declare extract_dir="$_ninja_cache_dir/ninja-src" declare src_tgz="$_ninja_cache_dir/ninja-src.tgz" declare url="https://github.com/ninja-build/ninja/archive/refs/tags/v$NINJA_VERSION.tar.gz" if test -d "$extract_dir"; then rm -r -- "$extract_dir"; fi mkdir -p -- "$extract_dir" log "Downloading Ninja source [$url]" mkdir -p -- "$_ninja_cache_dir" curl --retry 5 -LsS --max-time 120 --fail --output "$src_tgz" "$url" tar -x -f "$src_tgz" -C "$extract_dir" --strip-components=1 log "Building Ninja from source" run_chdir "$build_out_dir" run_python "$extract_dir/configure.py" --bootstrap test -f "$expect_exe" || fail "Bootstrap did not generate the expected executable [$expect_exe]" # Recursive invocation will find our build and copy it _build_ninja } _ensure_ninja() { declare arch arch="$(uname -m)" if test -f /etc/alpine-release; then arch="$arch-musl" fi case "$OS_NAME-$arch" in linux-x86_64|windows-x86_64|macos-*) # Download a pre-built version _download_ninja ;; linux-*|windows-*) _build_ninja ;; *) fail "We don't know how to automatically obtain a Ninja executable for this platform" ;; esac } _ensure_ninja libmongocrypt-1.11.0/.evergreen/env-run.sh000066400000000000000000000013051465326363200204610ustar00rootroot00000000000000#!/usr/bin/env bash # Executes a subcommand using a VS environment if one is requested, otherwise # just executes the command with no modified environment set -eu if test -n "${VS_VERSION-}"; then here="$(dirname "${BASH_SOURCE[0]}")" # Set CC and CXX to force CMake to use cl.exe even if GCC/Clang is visible on PATH env _run_argv="$*" \ CC=cl \ CXX=cl \ powershell -NoLogo -NonInteractive -NoProfile -ExecutionPolicy Unrestricted \ -Command "$here/vs-env-run.ps1" \ -Version "$VS_VERSION*" \ -TargetArch "${VS_TARGET_ARCH-amd64}" \ -Command "{ & Invoke-Expression \$env:_run_argv }" else command "$@" fi libmongocrypt-1.11.0/.evergreen/init.sh000066400000000000000000000165721465326363200200460ustar00rootroot00000000000000#!/bin/bash # Initial variables and helper functions for the libmongocrypt build ## Variables set by this file: # EVG_DIR = The path to the directory containing this script file # LIBMONGOCRYPT_DIR = The path to the libmongocrypt source directory # OS_NAME = One of 'windows', 'linux', 'macos', or 'unknown' ## (All of the above directory paths are native absolute paths) ## This script defines the following commands: # * abspath # Convert a given path into an absolute path. Relative paths are # resolved relative to the working directory. # # * have_command # Return zero if is the name of a command that can be executed, # returns non-zero otherwise. # # * run_chdir [args ...] # Run the given command with a working directory given by # # * log # Print to stderr # # * fail # Print to stderr and return non-zero # # * native_path # On MinGW/Cygwin/MSYS, convert the given Cygwin path to a Windows-native # path. NOTE: the MinGW runtime will almost always automatically convert # filepaths automatically when passed to non-MinGW programs, so this # utility is not usually needed. set -o errexit set -o pipefail set -o nounset # Inhibit msys path conversion export MSYS2_ARG_CONV_EXCL="*" if test "${TRACE:-0}" != "0"; then set -o xtrace fi # Write a message to stderr function log() { echo "${@}" 1>&2 return 0 } function debug() { if test "${DEBUG:-0}" != "0"; then log "${@}" fi } # Print a message and return non-zero function fail() { log "${@}" return 1 } # Determine whether we can execute the given name as a command function have_command() { test "$#" -eq 1 || fail "have_command expects a single argument" if type "${1}" > /dev/null 2>&1; then return 0 fi return 1 } # Run a command in a different directory: # * run_chdir [command ...] function run_chdir() { test "$#" -gt 1 || fail "run_chdir expects at least two arguments" local _dir="$1" shift pushd "$_dir" > /dev/null debug "Run in directory [$_dir]:" "$@" "$@" local _rc=$? popd > /dev/null return $_rc } # Given a path string, convert it to an absolute path with no redundant components or directory separators function abspath() { test "$#" -eq 1 || fail "abspath expects a single argument" local ret local arg="$1" debug "Resolve path [$arg]" # The parent path: local _parent _parent="$(dirname "$arg")" # The filename part: local _fname _fname="$(basename "$arg")" # There are four cases to consider from dirname: if test "$_parent" = "."; then # The parent is '.' as in './foo' # Replace the leading '.' with the working directory _parent="$PWD" elif test "$_parent" = ".."; then # The parent is '..' as in '../foo' # Replace a leading '..' with the parent of the working directory _parent="$(dirname "$PWD")" elif test "$arg" = "$_parent"; then # The parent is itself, as in '/' # A root directory is its own parent according to 'dirname' printf %s "$arg" return 0 else # The parent is some other path, like 'foo' in 'foo/bar' # Resolve the parent path _parent="$(set +x; DEBUG=0 abspath "$_parent")" fi # At this point $_parent is an absolute path if test "$_fname" = ".."; then # Strip one component ret="$(dirname "$_parent")" elif test "$_fname" = "."; then # Drop a '.' at the end of a path ret="$_parent" else # Join the result ret="$_parent/$_fname" fi # Remove duplicate dir separators while [[ "$ret" =~ "//" ]]; do ret="${ret//\/\///}" done debug "Resolved to: [$arg] -> [$ret]" printf %s "$ret" } # Get the platform name: One of 'windows', 'macos', 'linux', or 'unknown' function os_name() { have_command uname || fail "No 'uname' executable found" debug "Uname is [$(uname -a)]" local _uname _uname="$(uname -a | tr '[:upper:]' '[:lower:]')" local _os_name="unknown" if [[ "$_uname" =~ .*cygwin|windows|mingw|msys.* ]] || (have_command cmd.exe && ! [[ $_uname =~ .*wsl.* ]]); then # We are running on Windows, and not within a WSL environment _os_name="windows" elif [[ $_uname =~ darwin.* ]]; then _os_name='macos' elif [[ $_uname =~ linux.* ]]; then _os_name='linux' fi printf %s "$_os_name" } # Ensure the given path is in a native format (converts cygwin paths to Windows-local paths) function native_path() { test "$#" -eq 1 || fail "native_path expects one argument" if test "$OS_NAME" = "windows"; then have_command cygpath || fail "No 'cygpath' command is available, but we require it to normalize file paths." debug "Convert path [$1]" local r r="$(cygpath -w "$1")" debug "Convert to [$r]" printf %s "$r" else printf %s "$1" fi } # Join the given arguments with the given joiner string. Writes to stdout # Usage: join_str [argv [...]] function join_str() { local joiner first joiner="$1" first="${2-}" if shift 2; then # Print each element. Do a string-replace of the beginning of each # subsequent string with the joiner. printf "%s" "$first" "${@/#/$joiner}" fi } OS_NAME="$(os_name)" _init_sh_this_file="$(abspath "${BASH_SOURCE[0]}")" _init_sh_evg_dir="$(dirname "${_init_sh_this_file}")" # Get the EVG dir as a native absolute path. All other path vars are derived from # this one, and will therefore remain as native paths EVG_DIR="$(native_path "${_init_sh_evg_dir}")" LIBMONGOCRYPT_DIR="$(dirname "${EVG_DIR}")" is_true() { declare var="$1" declare val="${!var-}" # Default is '' empty case "$val" in 1|true|TRUE|True|yes|YES|Yes|on|ON|On) return 0;; 0|false|FALSE|False|no|NO|No|off|OFF|Off|"") return 1;; *) log "Unknown 'boolean' value for \$$var: '$val'" return 2;; esac } is_false() { ! is_true "$@" } # Executes CMake via the cache-managing script run_cmake() { command bash "$EVG_DIR/cmake.sh" "$@" } # Executes CTest via the cache-managing script run_ctest() { command bash "$EVG_DIR/ctest.sh" "$@" } run_python() { pys=( py python3.14 python3.13 python3.12 python3.11 python3.10 python3.9 python3.8 python3 python ) for cand in "${pys[@]}"; do if have_command "$cand" && "$cand" -c ""; then "$cand" "$@" return $? fi done } EXE_SUFFIX="" if test "$OS_NAME" = "windows"; then EXE_SUFFIX=".exe" fi if test "${USER_CACHES_DIR:=${XDG_CACHE_HOME:-}}" = ""; then case "$OS_NAME" in linux) USER_CACHES_DIR=$HOME/.cache ;; macos) USER_CACHES_DIR=$HOME/Library/Caches ;; windows) USER_CACHES_DIR=${LOCALAPPDATA:-$USERPROFILE/.cache} ;; *) log "Using ~/.cache as fallback user caching directory" USER_CACHES_DIR="$(abspath ~/.cache)" esac fi # Ensure we are dealing with a complete path USER_CACHES_DIR="$(abspath "$USER_CACHES_DIR")" : "${BUILD_CACHE_BUST:=1}" : "${BUILD_CACHE_DIR:="$USER_CACHES_DIR/libmongocrypt/build.$BUILD_CACHE_BUST"}" # Silence shellcheck: : "$LIBMONGOCRYPT_DIR,$EXE_SUFFIX" libmongocrypt-1.11.0/.evergreen/init.test.sh000066400000000000000000000020761465326363200210160ustar00rootroot00000000000000#!/bin/bash # Test shell utilities. . "$(dirname "${BASH_SOURCE[0]}")/init.sh" function assert_eq() { if [ "$1" != "$2" ]; then echo "${BASH_SOURCE[0]}:${BASH_LINENO[0]} assertion failed: '$1' != '$2'" return 1 fi } function test_abspath() { mkdir -p /tmp/a/b/c cd /tmp/a/b/c got=$(abspath .) expect=/tmp/a/b/c assert_eq "$got" "$expect" got=$(abspath ..) expect=/tmp/a/b assert_eq "$got" "$expect" got=$(abspath .././foo.txt) expect=/tmp/a/b/foo.txt assert_eq "$got" "$expect" got=$(abspath /foo.txt) expect=/foo.txt assert_eq "$got" "$expect" got=$(abspath /tmp/a/../a/foo.txt) expect=/tmp/a/foo.txt assert_eq "$got" "$expect" got=$(abspath /tmp//a//b//c//foo.txt) expect=/tmp/a/b/c/foo.txt assert_eq "$got" "$expect" pushd /tmp > /dev/null got=$(abspath ./a/b/c/foo.txt) expect=/tmp/a/b/c/foo.txt assert_eq "$got" "$expect" popd > /dev/null got=$(abspath /a/b/c/foo.txt) expect=/a/b/c/foo.txt assert_eq "$got" "$expect" } test_abspath libmongocrypt-1.11.0/.evergreen/linker-tests.sh000077500000000000000000000075241465326363200215270ustar00rootroot00000000000000#!/bin/bash # Directory layout # .evergreen # -linker_tests_deps # --app # --bson_patches # # linker_tests (created by this script) # -libmongocrypt-cmake-build (for artifacts built from libmongocrypt source) # -app-cmake-build # -mongo-c-driver # --cmake-build # -install # --bson1 # --bson2 # --libmongocrypt # . "$(dirname "${BASH_SOURCE[0]}")/setup-env.sh" linker_tests_root="$LIBMONGOCRYPT_DIR/linker_tests" linker_tests_deps_root="$EVG_DIR/linker_tests_deps" rm -rf -- "$linker_tests_root" mkdir -p "$linker_tests_root"/{install,libmongocrypt-cmake-build,app-cmake-build} # Make libbson1 run_chdir "$linker_tests_root" bash "$EVG_DIR/prep_c_driver_source.sh" MONGOC_DIR="$linker_tests_root/mongo-c-driver" if test "$OS_NAME" = "windows" && is_false WINDOWS_32BIT && is_false USE_NINJA; then # These options are only needed for VS CMake generators to force it to # generate a 64-bit build. Default is 32-bit. Ninja inherits settings # from the build environment variables. ADDITIONAL_CMAKE_FLAGS="-Thost=x64 -A x64" fi if [ "${MACOS_UNIVERSAL-}" = "ON" ]; then ADDITIONAL_CMAKE_FLAGS="$ADDITIONAL_CMAKE_FLAGS -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64'" fi common_cmake_args=( $ADDITIONAL_CMAKE_FLAGS -DCMAKE_BUILD_TYPE=RelWithDebInfo ) if is_true USE_NINJA; then export NINJA_EXE : "${NINJA_EXE:="$linker_tests_root/ninja$EXE_SUFFIX"}" common_cmake_args+=( -GNinja -DCMAKE_MAKE_PROGRAM="$NINJA_EXE" ) bash "$EVG_DIR/ensure-ninja.sh" fi run_chdir "$MONGOC_DIR" git apply --ignore-whitespace "$linker_tests_deps_root/bson_patches/libbson1.patch" # Apply patch to fix compile on RHEL 6.2. TODO: try to remove once RHEL 6.2 is dropped (MONGOCRYPT-688). run_chdir "$MONGOC_DIR" git apply "$LIBMONGOCRYPT_DIR/etc/libbson-remove-GCC-diagnostic-pragma.patch" BUILD_PATH="$MONGOC_DIR/cmake-build" BSON1_INSTALL_PATH="$linker_tests_root/install/bson1" SRC_PATH="$MONGOC_DIR" run_cmake \ -DENABLE_MONGOC=OFF \ "${common_cmake_args[@]}" \ -DCMAKE_INSTALL_PREFIX="$BSON1_INSTALL_PATH" \ "-H$SRC_PATH" \ "-B$BUILD_PATH" run_cmake --build "$BUILD_PATH" --target install --config RelWithDebInfo # Prepare libbson2 run_chdir "$MONGOC_DIR" git reset --hard run_chdir "$MONGOC_DIR" git apply --ignore-whitespace "$linker_tests_deps_root/bson_patches/libbson2.patch" # Apply patch to fix compile on RHEL 6.2. TODO: try to remove once RHEL 6.2 is dropped (MONGOCRYPT-688). run_chdir "$MONGOC_DIR" git apply "$LIBMONGOCRYPT_DIR/etc/libbson-remove-GCC-diagnostic-pragma.patch" LIBBSON2_SRC_DIR="$MONGOC_DIR" # Build libmongocrypt, static linking against libbson2 BUILD_DIR="$linker_tests_root/libmongocrypt-cmake-build" LMC_INSTALL_PATH="$linker_tests_root/install/libmongocrypt" SRC_PATH="$LIBMONGOCRYPT_DIR" run_cmake \ "-DMONGOCRYPT_MONGOC_DIR=$LIBBSON2_SRC_DIR" \ "${common_cmake_args[@]}" \ -DCMAKE_INSTALL_PREFIX="$LMC_INSTALL_PATH" \ "-H$SRC_PATH" \ "-B$BUILD_DIR" run_cmake --build "$BUILD_DIR" --target install --config RelWithDebInfo echo "Test case: Modelling libmongoc's use" # app links against libbson1.so # app links against libmongocrypt.so BUILD_DIR="$linker_tests_root/app-cmake-build" PREFIX_PATH="$LMC_INSTALL_PATH;$BSON1_INSTALL_PATH" SRC_PATH="$linker_tests_deps_root/app" run_cmake \ "${common_cmake_args[@]}" \ -DCMAKE_PREFIX_PATH="$PREFIX_PATH" \ "-H$SRC_PATH" \ "-B$BUILD_DIR" run_cmake --build "$BUILD_DIR" --target app --config RelWithDebInfo export PATH="$PATH:$BSON1_INSTALL_PATH/bin:$LMC_INSTALL_PATH/bin" if is_true IS_MULTICONF; then APP_CMD="$BUILD_DIR/RelWithDebInfo/app.exe" else APP_CMD="$BUILD_DIR/app" fi check_output () { output="$($APP_CMD)" if [[ "$output" != *"$1"* ]]; then printf " Got: %s\nExpected: %s\n" "$output" "$1" exit 1; fi echo "ok" } check_output ".calling bson_malloc0..from libbson1..calling mongocrypt_binary_new..from libbson2." exit 0 libmongocrypt-1.11.0/.evergreen/linker_tests_deps/000077500000000000000000000000001465326363200222555ustar00rootroot00000000000000libmongocrypt-1.11.0/.evergreen/linker_tests_deps/app/000077500000000000000000000000001465326363200230355ustar00rootroot00000000000000libmongocrypt-1.11.0/.evergreen/linker_tests_deps/app/CMakeLists.txt000066400000000000000000000005051465326363200255750ustar00rootroot00000000000000cmake_minimum_required (VERSION 3.5) project (app C) add_executable (app app.c) find_package (bson-1.0 1.11 REQUIRED) message ("-- libbson found version \"${bson-1.0_VERSION}\"") target_link_libraries (app PRIVATE mongo::bson_static) find_package (mongocrypt REQUIRED) target_link_libraries (app PRIVATE mongo::mongocrypt)libmongocrypt-1.11.0/.evergreen/linker_tests_deps/app/app.c000066400000000000000000000005111465326363200237560ustar00rootroot00000000000000#include #include int main () { char *a; mongocrypt_binary_t *b; printf(".calling bson_malloc0."); a = bson_malloc0 (1); printf(".calling mongocrypt_binary_new."); b = mongocrypt_binary_new (); bson_free (a); mongocrypt_binary_destroy (b); return 0; }libmongocrypt-1.11.0/.evergreen/linker_tests_deps/bson_patches/000077500000000000000000000000001465326363200247255ustar00rootroot00000000000000libmongocrypt-1.11.0/.evergreen/linker_tests_deps/bson_patches/libbson1.patch000066400000000000000000000012661465326363200274640ustar00rootroot00000000000000Adds a printf to bson_malloc0 to test linking scenarios with two forms of libbson. See linker-tests.sh. If this patch fails to apply, regenerate from libbson's source. diff --git a/src/libbson/src/bson/bson-memory.c b/src/libbson/src/bson/bson-memory.c index 0e1523331..aa7112305 100644 --- a/src/libbson/src/bson/bson-memory.c +++ b/src/libbson/src/bson/bson-memory.c @@ -104,6 +104,7 @@ bson_malloc0 (size_t num_bytes) /* IN */ { void *mem = NULL; + printf (".from libbson1."); if (BSON_LIKELY (num_bytes)) { if (BSON_UNLIKELY (!(mem = gMemVtable.calloc (1, num_bytes)))) { fprintf (stderr, "Failure to allocate memory in bson_malloc0(). errno: %d.\n", errno); libmongocrypt-1.11.0/.evergreen/linker_tests_deps/bson_patches/libbson2.patch000066400000000000000000000012701465326363200274600ustar00rootroot00000000000000Adds a printf to bson_malloc0 to test linking scenarios with two forms of libbson. See linker-tests.sh. If this patch fails to apply, regenerate from libbson's source. diff --git a/src/libbson/src/bson/bson-memory.c b/src/libbson/src/bson/bson-memory.c index 0e1523331..aa7112305 100644 --- a/src/libbson/src/bson/bson-memory.c +++ b/src/libbson/src/bson/bson-memory.c @@ -104,6 +104,7 @@ bson_malloc0 (size_t num_bytes) /* IN */ { void *mem = NULL; + printf (".from libbson2.\n"); if (BSON_LIKELY (num_bytes)) { if (BSON_UNLIKELY (!(mem = gMemVtable.calloc (1, num_bytes)))) { fprintf (stderr, "Failure to allocate memory in bson_malloc0(). errno: %d.\n", errno); libmongocrypt-1.11.0/.evergreen/pkgconfig-tests.sh000077500000000000000000000142671465326363200222140ustar00rootroot00000000000000#!/bin/bash . "$(dirname "${BASH_SOURCE[0]}")/setup-env.sh" if ! have_command pkg-config; then echo "pkg-config not present on this platform; skipping test ..." exit 0 fi pkgconfig_tests_root=$LIBMONGOCRYPT_DIR/_build/pkgconfig_tests rm -rf "$pkgconfig_tests_root" mongoc_src_dir="$pkgconfig_tests_root/mongo-c-driver" mkdir -p "$mongoc_src_dir" run_chdir "$pkgconfig_tests_root" "$EVG_DIR/prep_c_driver_source.sh" if test "$OS_NAME" = "windows" && is_false WINDOWS_32BIT && is_false USE_NINJA; then # These options are only needed for VS CMake generators to force it to # generate a 64-bit build. Default is 32-bit. Ninja inherits settings # from the build environment variables. ADDITIONAL_CMAKE_FLAGS="-Thost=x64 -A x64" fi if [ "$MACOS_UNIVERSAL" = "ON" ]; then ADDITIONAL_CMAKE_FLAGS="$ADDITIONAL_CMAKE_FLAGS -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64'" fi common_cmake_args=( -DCMAKE_BUILD_TYPE=RelWithDebInfo $ADDITIONAL_CMAKE_FLAGS ) if is_true USE_NINJA; then export NINJA_EXE : "${NINJA_EXE:="$pkgconfig_tests_root/ninja$EXE_SUFFIX"}" common_cmake_args+=( -GNinja -DCMAKE_MAKE_PROGRAM="$NINJA_EXE" ) bash "$EVG_DIR/ensure-ninja.sh" fi libbson_install_dir="$pkgconfig_tests_root/install/libbson" build_dir="$mongoc_src_dir/_build" run_cmake -DENABLE_MONGOC=OFF \ "${common_cmake_args[@]}" \ -DCMAKE_INSTALL_PREFIX="$libbson_install_dir" \ -H"$mongoc_src_dir" \ -B"$build_dir" run_cmake --build "$build_dir" --target install --config RelWithDebInfo libbson_pkg_config_path="$(native_path "$(dirname "$(find "$libbson_install_dir" -name libbson-1.0.pc)")")" # Build libmongocrypt, static linking against libbson and configured for the PPA mongocrypt_install_dir="$pkgconfig_tests_root/install/libmongocrypt" build_dir=$pkgconfig_tests_root/mongocrypt-build run_cmake -DUSE_SHARED_LIBBSON=OFF \ -DENABLE_BUILD_FOR_PPA=ON \ "${common_cmake_args[@]}" \ -DCMAKE_INSTALL_PREFIX="$mongocrypt_install_dir" \ -H"$LIBMONGOCRYPT_DIR" \ -B"$build_dir" run_cmake --build "$build_dir" --target install --config RelWithDebInfo # To validate the pkg-config scripts, we don't want the libbson script to be visible mongocrypt_pkg_config_path="$(native_path "$(dirname "$(find "$mongocrypt_install_dir" -name libmongocrypt.pc)")")" export PKG_CONFIG_PATH PKG_CONFIG_PATH="$mongocrypt_pkg_config_path:$libbson_pkg_config_path" echo "Validating pkg-config scripts" pkg-config --debug --print-errors --exists libmongocrypt-static pkg-config --debug --print-errors --exists libmongocrypt # Build example-state-machine, static linking against libmongocrypt gcc $(pkg-config --cflags libmongocrypt-static libbson-static-1.0) \ -o "$pkgconfig_tests_root/example-state-machine" \ "$LIBMONGOCRYPT_DIR/test/example-state-machine.c" \ $(pkg-config --libs libmongocrypt-static) run_chdir "$LIBMONGOCRYPT_DIR" "$pkgconfig_tests_root/example-state-machine" # Build example-no-bson, static linking against libmongocrypt gcc $(pkg-config --cflags libmongocrypt-static) \ -o "$pkgconfig_tests_root/example-no-bson" \ "$LIBMONGOCRYPT_DIR/test/example-no-bson.c" \ $(pkg-config --libs libmongocrypt-static) command "$pkgconfig_tests_root/example-no-bson" # Build example-state-machine, dynamic linking against libmongocrypt gcc $(pkg-config --cflags libmongocrypt libbson-static-1.0) \ -o "$pkgconfig_tests_root/example-state-machine" \ "$LIBMONGOCRYPT_DIR/test/example-state-machine.c" \ $(pkg-config --libs libmongocrypt) run_chdir "$LIBMONGOCRYPT_DIR" \ env LD_LIBRARY_PATH="$mongocrypt_install_dir/lib:$mongocrypt_install_dir/lib64" \ "$pkgconfig_tests_root/example-state-machine" # Build example-no-bson, dynamic linking against libmongocrypt gcc $(pkg-config --cflags libmongocrypt) \ -o "$pkgconfig_tests_root/example-no-bson" \ "$LIBMONGOCRYPT_DIR/test/example-no-bson.c" \ $(pkg-config --libs libmongocrypt) env LD_LIBRARY_PATH="$mongocrypt_install_dir/lib:$mongocrypt_install_dir/lib64" \ "$pkgconfig_tests_root/example-no-bson" # Clean up prior to next execution rm -r "$mongocrypt_install_dir" # Build libmongocrypt, dynamic linking against libbson run_cmake -DUSE_SHARED_LIBBSON=ON \ -DENABLE_BUILD_FOR_PPA=OFF \ "${common_cmake_args[@]}" \ -DCMAKE_INSTALL_PREFIX="$mongocrypt_install_dir" \ -H"$LIBMONGOCRYPT_DIR" \ -B"$build_dir" run_cmake --build "$build_dir" --target install --config RelWithDebInfo # Build example-state-machine, static linking against libmongocrypt gcc $(pkg-config --cflags libmongocrypt-static libbson-static-1.0) \ -o "$pkgconfig_tests_root/example-state-machine" \ "$LIBMONGOCRYPT_DIR/test/example-state-machine.c" \ $(pkg-config --libs libmongocrypt-static) run_chdir "$LIBMONGOCRYPT_DIR" \ env LD_LIBRARY_PATH="$libbson_install_dir/lib:/$libbson_install_dir/lib64" \ "$pkgconfig_tests_root/example-state-machine" # Build example-no-bson, static linking against libmongocrypt gcc $(pkg-config --cflags libmongocrypt-static) \ -o "$pkgconfig_tests_root/example-no-bson" \ "$LIBMONGOCRYPT_DIR/test/example-no-bson.c" \ $(pkg-config --libs libmongocrypt-static) env LD_LIBRARY_PATH="$libbson_install_dir/lib:/$libbson_install_dir/lib64" \ "$pkgconfig_tests_root/example-no-bson" # Build example-state-machine, dynamic linking against libmongocrypt gcc $(pkg-config --cflags libmongocrypt libbson-static-1.0) \ -o "$pkgconfig_tests_root/example-state-machine" \ "$LIBMONGOCRYPT_DIR/test/example-state-machine.c" \ $(pkg-config --libs libmongocrypt) run_chdir "$LIBMONGOCRYPT_DIR" \ env LD_LIBRARY_PATH="$mongocrypt_install_dir/lib:$mongocrypt_install_dir/lib64:$libbson_install_dir/lib:$libbson_install_dir/lib64" \ "$pkgconfig_tests_root/example-state-machine" # Build example-no-bson, dynamic linking against libmongocrypt gcc $(pkg-config --cflags libmongocrypt) \ -o "$pkgconfig_tests_root/example-no-bson" \ "$LIBMONGOCRYPT_DIR/test/example-no-bson.c" \ $(pkg-config --libs libmongocrypt) env LD_LIBRARY_PATH="$mongocrypt_install_dir/lib:$mongocrypt_install_dir/lib64:$libbson_install_dir/lib:$libbson_install_dir/lib64" \ "$pkgconfig_tests_root/example-no-bson" echo "pkg-config tests PASS" libmongocrypt-1.11.0/.evergreen/prep_c_driver_source.sh000077500000000000000000000005341465326363200233000ustar00rootroot00000000000000#!/bin/bash set -euxo pipefail # Clone mongo-c-driver and check out to a tagged version. MONGO_C_DRIVER_VERSION=1.27.1 # Force checkout with lf endings since .sh must have lf, not crlf on Windows git clone https://github.com/mongodb/mongo-c-driver.git --config core.eol=lf --config core.autocrlf=false --depth=1 --branch $MONGO_C_DRIVER_VERSION libmongocrypt-1.11.0/.evergreen/print-env-info.sh000077500000000000000000000003441465326363200217470ustar00rootroot00000000000000#!/bin/bash # Print information about the environment. # set -o xtrace evergreen_root=$(pwd) git --version openssl version python --version if which gcc; then gcc --version fi if which clang; then clang --version filibmongocrypt-1.11.0/.evergreen/requirements.txt000077500000000000000000000000121465326363200220140ustar00rootroot00000000000000virtualenvlibmongocrypt-1.11.0/.evergreen/setup-env.sh000066400000000000000000000021061465326363200210150ustar00rootroot00000000000000#!/bin/bash . "$(dirname "${BASH_SOURCE[0]}")/init.sh" : "${ADDITIONAL_CMAKE_FLAGS:=}" : "${LIBMONGOCRYPT_EXTRA_CMAKE_FLAGS:=}" : "${LIBMONGOCRYPT_EXTRA_CFLAGS:=}" : "${PPA_BUILD_ONLY:=}" : "${MACOS_UNIVERSAL:=}" : "${WINDOWS_32BIT:=}" : "${OS:=unspecified}" IS_MULTICONF=OFF if test "$OS_NAME" = "windows" && is_false USE_NINJA; then IS_MULTICONF=ON fi : "$IS_MULTICONF" # Silence shellcheck evergreen_root="$(dirname "$LIBMONGOCRYPT_DIR")" : "${MONGOCRYPT_INSTALL_PREFIX:="$evergreen_root/install/libmongocrypt"}" MONGOCRYPT_INSTALL_PREFIX="$(native_path "$MONGOCRYPT_INSTALL_PREFIX")" mkdir -p "$MONGOCRYPT_INSTALL_PREFIX" if test -f /proc/cpuinfo; then # Count the number of lines beginning with "processor" in the cpuinfo jobs="$(grep -c '^processor' /proc/cpuinfo)" if have_command bc; then # Add two (hueristic to compensate for I/O latency) jobs="$(echo "$jobs+2" | bc)" fi export MAKEFLAGS="-j$jobs ${MAKEFLAGS-}" else # Cannot tell the best number of jobs. Provide a reasonable default. export MAKEFLAGS="-j8 ${MAKEFLAGS-}" fi libmongocrypt-1.11.0/.evergreen/vs-env-run.ps1000066400000000000000000000221061465326363200212020ustar00rootroot00000000000000<# .SYNOPSIS Execute a command with a Visual Studio environment loaded .DESCRIPTION This script will load the specified Visual Studio environment with the specified options set, and then execute the given program This script makes use of vswhere.exe, which is installed with Visual Studio 2017 or later, but supports all Visual Studio versions. Only the -Version and -TargetArch parameters are required. The command should be given as a script block or executable string. .EXAMPLE PS C:\> vs-env-run.ps1 -Version 14.* -TargetArch amd64 { build_all.ps1 } This will load the Visual Studio 14 environment targetting amd64 processors and then run 'build_all.ps1' #> [CmdletBinding(PositionalBinding = $false)] param ( # Select a version of Visual Studio to activate. Accepts wildcards. # # Major versions by year release: # # - 14.* => VS 2015 # - 15.* => VS 2017 # - 16.* => VS 2019 # - 17.* => VS 2022 # # Use of a wildcard pattern in scripts is recommended for portability. # # Supports tab-completion if vswhere.exe is present. [Parameter(Mandatory)] # xxx: This requires PowerShell 5+, which some build hosts don't have: # [ArgumentCompleter({ # param($commandName, $paramName, $wordToComplete, $commandAst, $fakeBoundParameters) # $vswhere_found = @(Get-ChildItem -Filter vswhere.exe ` # -Path 'C:\Program Files*\Microsoft Visual Studio\Installer\' ` # -Recurse)[0] # if ($null -eq $vswhere_found) { # Write-Host "No vswhere found" # return $null # } # return & $vswhere_found -utf8 -nologo -format json -all -legacy -prerelease -products * ` # | ConvertFrom-Json ` # | ForEach-Object { $_.installationVersion } ` # | Where-Object { $_ -like "$wordToComplete*" } # })] [string] $Version, # The target architecture for the build [Parameter(Mandatory)] [ValidateSet("x86", "amd64", "arm", "arm64", IgnoreCase = $false)] [string] $TargetArch, # Select a specific Windows SDK version. [string] # xxx: This requires PowerShell 5+, which some build hosts don't have: # [ArgumentCompleter({ # param($commandName, $paramName, $wordToComplete, $commandAst, $fakeBoundParameters) # $found = @() # if (Test-Path "${env:ProgramFiles(x86)}\Windows Kits\10\Include") { # $found += $( # Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\10\Include"` # | Where-Object { Test-Path "$($_.FullName)\um\Windows.h" }` # | ForEach-Object { Split-Path -Leaf $_.FullName } # ) # } # if (Test-Path "${env:ProgramFiles(x86)}\Windows Kits\8.1\Include") { # $found += $( # Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\8.1\Include"` # | Where-Object { Test-Path "$($_.FullName)\um\Windows.h" }` # | ForEach-Object { Split-Path -Leaf $_.FullName } # ) # } # return $found | Where-Object { $_ -like "$wordToComplete*" } # })] $WinSDKVersion, # The host architecture to use. Not usually needed. Defaults to x86. [ValidateSet("x86", "amd64", IgnoreCase = $false)] [string] $HostArch = "x86", # The Visual C++ toolset to load [string] $VCToolsetVersion, # Prefer Visual C++ libraries with Spectre mitigations [switch] $UseSpectreMitigationLibraries, # The app platform to load. Default is "Desktop" [ValidateSet("Desktop", "UWP", IgnoreCase = $false)] [string] $AppPlatform = "Desktop", # The directory to store ephemeral files [string] $ScratchDir, # The command to execute within the VS environment. May be any invocable object. [Parameter(Mandatory, Position = 1)] $Command ) $ErrorActionPreference = 'Stop' $this_dir = $PSScriptRoot if ([string]::IsNullOrEmpty($ScratchDir)) { $ScratchDir = Join-Path (Split-Path -Parent $this_dir) "_build" } New-Item $ScratchDir -ItemType Directory -ErrorAction Ignore $vswhere = Join-Path $ScratchDir "vswhere.exe" if (!(Test-Path $vswhere)) { $ProgressPreference = "SilentlyContinue" [Net.ServicePointManager]::SecurityProtocol = 'tls12, tls11' Invoke-WebRequest ` -UseBasicParsing ` -Uri "https://github.com/microsoft/vswhere/releases/download/3.0.3/vswhere.exe" ` -OutFile $vswhere } # Ask vswhere for all the installed products: $vswhere_json = & $vswhere -utf8 -nologo -format json -all -legacy -prerelease -products * | Out-String $vs_versions = $vswhere_json | ConvertFrom-Json Write-Debug "Detected VS versions: $vs_versions" # Pick the product that matches the pattern $selected = @($vs_versions | Where-Object { $_.installationVersion -like $Version }) if ($selected.Length -eq 0) { throw "No Visual Studio was found with a version matching '$Version'" } $selected = $selected[0] Write-Host "Selected Visual Studio version $($selected.installationVersion) [$($selected.installationPath)]" # Find Windows SDK version if (-not [String]::IsNullOrEmpty($WinSDKVersion)) { $sdk_avail = @() if (Test-Path "${env:ProgramFiles(x86)}\Windows Kits\10\Include") { $sdk_avail += $( Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\10\Include" ` | Where-Object { Test-Path "$($_.FullName)\um\Windows.h" } ` | ForEach-Object { Split-Path -Leaf $_.FullName } ) } if (Test-Path "${env:ProgramFiles(x86)}\Windows Kits\8.1\Include") { $sdk_avail += $( Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\8.1\Include" ` | Where-Object { Test-Path "$($_.FullName)\um\Windows.h" } ` | ForEach-Object { Split-Path -Leaf $_.FullName } ) } Write-Debug "Detected Windows SDK versions: $sdk_avail" $sdk_selected = @($sdk_avail | Where-Object { $_ -like $WinSDKVersion })[0] if ($null -eq $sdk_selected) { throw "No Windows SDK version was found matching '$WinSDKVersion' (Of $sdk_avail)" } $WinSDKVersion = $sdk_selected } # Find the environment-activation script for the chosen VS $vsdevcmd_bat = @(Get-ChildItem ` -Path $selected.installationPath ` -Filter "VsDevCmd.bat" -Recurse)[0] $env_script_content = "" # Use batch and the 'set' command to get the required environment variables out. if ($null -eq $vsdevcmd_bat) { Write-Warning "No VsDevCmd.bat found for the requested VS version. Falling back to vcvarsall.bat" Write-Warning "Additional platform selection functionality will be limited" $vcvarsall_bat = @(Get-ChildItem -Path $selected.installationPath -Filter "vcvarsall.bat" -Recurse)[0] if ($null -eq $vcvarsall_bat) { throw "No VsDevCmd.bat nor vcvarsall.bat file found for requested Visual Studio version '$($selected.installationVersion)'" } Write-Debug "Using vcvarsall: [$($vcvarsall_bat.FullName)]" $env_script_content = @" @echo off call "$($vcvarsall_bat.FullName)" $TargetArch $WinSDKVersion set _rc=%ERRORLEVEL% set exit /b %_rc% "@ } else { # Build up the argument string to load the appropriate environment $argstr = "-no_logo -arch=$TargetArch -host_arch=$HostArch -app_platform=$AppPlatform" if ($UseSpectreMitigationLibraries) { $argstr += " -vcvars_spectre_libs=spectre" } if ($WinSDKVersion) { $argstr += " -winsdk=$WinSDKVersion" } if ($VCToolsetVersion) { $argstr += " -vcvars_ver=$VCToolsetVersion" } Write-Debug "Using VsDevCmd: [${vsdevcmd_bat.FullName}]" $env_script_content = @" @echo off call "$($vsdevcmd_bat.FullName)" $argstr set _rc=%ERRORLEVEL% set exit /b %_rc% "@ } # Write the script and then execute it, capturing its output Set-Content "$ScratchDir/.env.bat" $env_script_content Write-Host "Loading VS environment..." $output = & cmd.exe /c "$ScratchDir/.env.bat" if ($LASTEXITCODE -ne 0) { throw "Loading the environment failed [$LASTEXITCODE]:`n$output" } # The plain 'set' command emits VAR=VALUE lines for each loaded environment # variable. Parse those out and set them in our own environment. $prior_env = @{} foreach ($line in $output.Split("`r`n")) { if ($line -match "(\w+)=(.+)") { $varname = $Matches[1] $value = $Matches[2] # Set the environment value (may be null): $prior_env[$varname] = [System.Environment]::GetEnvironmentVariable($varname) [System.Environment]::SetEnvironmentVariable($varname, $value) } } Write-Debug "Running command: $(ConvertTo-Json $Command)" try { # Now invoke the external command. & $Command if ($LASTEXITCODE -ne 0) { # If it was a process that returned non-zero, throw an error. throw "Subcommand failed [$LASTEXITCODE]" } } finally { # Restore the prior environment foreach ($key in $prior_env.Keys) { [System.Environment]::SetEnvironmentVariable($key, $prior_env[$key]) } } libmongocrypt-1.11.0/.git-blame-ignore-revs000066400000000000000000000002021465326363200205660ustar00rootroot00000000000000# Mass reformat: d60041a1a863c27bb08c43fe56c2e9588f56d920 # Python pre-commit formatting c03df9ecc60b9d26aa67b72378f0945c1b577b72libmongocrypt-1.11.0/.gitattributes000066400000000000000000000000771465326363200173730ustar00rootroot00000000000000# Shell scripts require lf endings *.sh text eol=lf libmongocrypt-1.11.0/.github/000077500000000000000000000000001465326363200160345ustar00rootroot00000000000000libmongocrypt-1.11.0/.github/dependabot.yml000066400000000000000000000006201465326363200206620ustar00rootroot00000000000000version: 2 updates: # GitHub Actions - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" groups: actions: patterns: - "*" assignees: - "@mongodb/dbx-python" # Python - package-ecosystem: "pip" directory: "/bindings/python" schedule: interval: "weekly" assignees: - "@mongodb/dbx-python"libmongocrypt-1.11.0/.github/workflows/000077500000000000000000000000001465326363200200715ustar00rootroot00000000000000libmongocrypt-1.11.0/.github/workflows/codeql.yml000066400000000000000000000032451465326363200220670ustar00rootroot00000000000000name: "CodeQL" on: push: branches: [ "master"] tags: ['*'] pull_request: paths: - bindings/python/* - bindings/python/**/*.py - .github/workflows/*python.yml schedule: - cron: '17 10 * * 2' workflow_call: inputs: ref: required: true type: string jobs: analyze-python: name: Analyze Python runs-on: "macos-latest" timeout-minutes: 360 permissions: # required for all workflows security-events: write # required to fetch internal or private CodeQL packs packages: read steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ inputs.ref }} - uses: actions/setup-python@v5 with: python-version: 3.x # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: python build-mode: none # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs queries: security-extended config: | paths: - bindings/python/pymongocrypt - name: Install package run: | cd bindings/python export LIBMONGOCRYPT_VERSION=$(cat ./libmongocrypt-version.txt) git fetch origin $LIBMONGOCRYPT_VERSION bash release.sh pip install dist/*.whl - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: category: "/language:python" libmongocrypt-1.11.0/.github/workflows/dist-python.yml000066400000000000000000000041631465326363200231020ustar00rootroot00000000000000name: Python Dist on: push: tags: - "pymongocrypt-[0-9]+.[0-9]+.[0-9]+" - "pymongocrypt-[0-9]+.[0-9]+.[0-9]+.post[0-9]+" - "pymongocrypt-[0-9]+.[0-9]+.[0-9]+[a-b][0-9]+" - "pymongocrypt-[0-9]+.[0-9]+.[0-9]+rc[0-9]+" pull_request: paths: - bindings/python/* - bindings/python/**/*.py - .github/workflows/*python.yml workflow_dispatch: workflow_call: inputs: force: required: true type: boolean ref: required: true type: string concurrency: group: python-dist-${{ github.ref }} cancel-in-progress: true defaults: run: working-directory: ./bindings/python shell: bash -eux {0} jobs: build_dist: if: github.repository_owner == 'mongodb' || inputs.force == true runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] fail-fast: false steps: - name: Checkout libmongocrypt uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ inputs.ref }} - uses: actions/setup-python@v5 with: python-version: 3.8 cache: 'pip' cache-dependency-path: 'bindings/python/pyproject.toml' allow-prereleases: true - name: Build and test dist files run: | export LIBMONGOCRYPT_VERSION=$(cat ./libmongocrypt-version.txt) git fetch origin $LIBMONGOCRYPT_VERSION bash ./release.sh - uses: actions/upload-artifact@v4 with: name: dist-${{ matrix.os }} path: ./bindings/python/dist/*.* if-no-files-found: error collect_dist: runs-on: ubuntu-latest needs: [build_dist] name: Collect dist files steps: - name: Download all workflow run artifacts uses: actions/download-artifact@v4 - name: Flatten directory working-directory: . run: | find . -mindepth 2 -type f -exec mv {} . \; find . -type d -empty -delete - uses: actions/upload-artifact@v4 with: name: all-dist-${{ github.run_id }} path: "./*" libmongocrypt-1.11.0/.github/workflows/release-python.yml000066400000000000000000000060371465326363200235610ustar00rootroot00000000000000name: Python Release on: workflow_dispatch: inputs: version: description: "The new version to set" required: true following_version: description: "The post (dev) version to set" required: true dry_run: description: "Dry Run?" default: false type: boolean env: # Changes per repo PRODUCT_NAME: PyMongoCrypt # Changes per branch SILK_ASSET_GROUP: pymongocrypt EVERGREEN_PROJECT: libmongocrypt defaults: run: shell: bash -eux {0} jobs: pre-publish: environment: release-python runs-on: ubuntu-latest permissions: id-token: write contents: write outputs: version: ${{ steps.pre-publish.outputs.version }} steps: - uses: mongodb-labs/drivers-github-tools/secure-checkout@v2 with: app_id: ${{ vars.APP_ID }} private_key: ${{ secrets.APP_PRIVATE_KEY }} - uses: mongodb-labs/drivers-github-tools/setup@v2 with: aws_role_arn: ${{ secrets.AWS_ROLE_ARN }} aws_region_name: ${{ vars.AWS_REGION_NAME }} aws_secret_id: ${{ secrets.AWS_SECRET_ID }} artifactory_username: ${{ vars.ARTIFACTORY_USERNAME }} - uses: mongodb-labs/drivers-github-tools/python/pre-publish@v2 id: pre-publish with: version: ${{ inputs.version }} working_directory: ./bindings/python dry_run: ${{ inputs.dry_run }} tag_template: "pymongocrypt-${VERSION}" tag_message_template: "Release PyMongoCrypt ${VERSION}" build-dist: needs: [pre-publish] uses: ./.github/workflows/dist-python.yml with: force: true ref: ${{ needs.pre-publish.outputs.version }} static-scan: needs: [pre-publish] uses: ./.github/workflows/codeql.yml with: ref: ${{ needs.pre-publish.outputs.version }} publish: needs: [build-dist, static-scan] runs-on: ubuntu-latest environment: release-python permissions: id-token: write contents: write attestations: write security-events: write steps: - uses: mongodb-labs/drivers-github-tools/secure-checkout@v2 with: app_id: ${{ vars.APP_ID }} private_key: ${{ secrets.APP_PRIVATE_KEY }} - uses: mongodb-labs/drivers-github-tools/setup@v2 with: aws_role_arn: ${{ secrets.AWS_ROLE_ARN }} aws_region_name: ${{ vars.AWS_REGION_NAME }} aws_secret_id: ${{ secrets.AWS_SECRET_ID }} artifactory_username: ${{ vars.ARTIFACTORY_USERNAME }} - uses: mongodb-labs/drivers-github-tools/python/publish@v2 with: version: ${{ inputs.version }} following_version: ${{ inputs.following_version }} working_directory: ./bindings/python product_name: ${{ env.PRODUCT_NAME }} silk_asset_group: ${{ env.SILK_ASSET_GROUP }} evergreen_project: ${{ env.EVERGREEN_PROJECT }} tag_template: "pymongocrypt-${VERSION}" token: ${{ github.token }} dry_run: ${{ inputs.dry_run }}libmongocrypt-1.11.0/.github/workflows/test-python.yml000066400000000000000000000030051465326363200231100ustar00rootroot00000000000000name: Python Tests on: push: pull_request: paths: - bindings/python/* - bindings/python/**/*.py - .github/workflows/*python.yml concurrency: group: python-test-${{ github.ref }} cancel-in-progress: true defaults: run: working-directory: ./bindings/python shell: bash -eux {0} jobs: static: if: github.repository_owner == 'mongodb' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 - name: "Run pre-commit" working-directory: . run: | pip install -U -q pre-commit pre-commit run --all-files --hook-stage manual - run: | pip install check-manifest check-manifest -v build: if: github.repository_owner == 'mongodb' runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] python-version: ["3.8", "3.13"] steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: allow-prereleases: true python-version: ${{ matrix.python-version }} - name: Build and test dist files run: | if [ "${{ matrix.python-version }}" == "3.13" ]; then export PIP_PRE=1 fi export LIBMONGOCRYPT_VERSION=$(cat ./libmongocrypt-version.txt) git fetch origin $LIBMONGOCRYPT_VERSION bash ./release.sh libmongocrypt-1.11.0/.gitignore000066400000000000000000000010741465326363200164660ustar00rootroot00000000000000doc/html doc/latex test/schema.json .vscode # Default build directories cmake-build cmake-build-nocrypto _build/ # CMake generated files *.sln *.vcxproj *.vcxproj.filters *.xcodeproj CMakeCache.txt CTestTestFile.cmake CMakeFiles CMakeScripts Debug/* Makefile Win32/* cmake_install.cmake x64/* Testing/ CPackConfig.cmake CPackSourceConfig.cmake dist_manifest.txt *.sdf .vs install_manifest.txt # Build artifacts. *.a *.dylib *.gcda *.gcno *.gz *.lo *.o *.pc *.so *.so.* # Generated header src/mongocrypt-export.h # IDEs .idea/ VERSION_CURRENT .csfle *.pyc .DS_Store libmongocrypt-1.11.0/.lsan-suppressions000066400000000000000000000002221465326363200202010ustar00rootroot00000000000000leak:ccrng_cryptographic_init_once leak:ccrng_cryptographic_generate leak:CRYPTO_zalloc # Ignore leak reported in dlopen error. leak:_dlerror_run libmongocrypt-1.11.0/.pre-commit-config.yaml000066400000000000000000000027411465326363200207610ustar00rootroot00000000000000files: '^bindings/python' repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: - id: check-added-large-files - id: check-case-conflict - id: check-toml - id: check-yaml - id: check-json exclude: '.evergreen/atlas_data_lake/test.driverdata.json' - id: debug-statements - id: end-of-file-fixer exclude: '.*\.txt' - id: forbid-new-submodules - id: trailing-whitespace - id: check-executables-have-shebangs # We use the Python version instead of the original version which seems to require Docker # https://github.com/koalaman/shellcheck-precommit - repo: https://github.com/shellcheck-py/shellcheck-py rev: v0.9.0.6 hooks: - id: shellcheck name: shellcheck args: ["--severity=error"] - repo: https://github.com/sirosen/check-jsonschema rev: 0.29.0 hooks: - id: check-github-workflows - id: check-github-actions - id: check-dependabot - repo: https://github.com/codespell-project/codespell rev: "v2.2.6" hooks: - id: codespell exclude: | (?x)( .evergreen/github_app/package-lock.json| .evergreen/csfle/bottle.py| .pem$ ) args: ["-L", "fle"] - repo: local hooks: - id: executable-shell name: executable-shell entry: chmod +x language: system types: [shell] - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. rev: v0.1.3 hooks: - id: ruff args: [ "--fix", "--show-fixes" ] - id: ruff-format libmongocrypt-1.11.0/CHANGELOG.md000066400000000000000000000160461465326363200163140ustar00rootroot00000000000000# ChangeLog ## 1.11.0 ### New features - Support `range` algorithm as stable. ### Deprecated - The Windows download URLs for [stable](https://s3.amazonaws.com/mciuploads/libmongocrypt/windows/latest_release/libmongocrypt.tar.gz) and [unstable](https://s3.amazonaws.com/mciuploads/libmongocrypt/windows/latest_release/libmongocrypt_unstable.tar.gz) are now deprecated. See the GitHub Release page for Windows downloads. ## 1.10.1 ## Fixed - Document `range` algorithm as unstable. ## 1.10.0 ### New features - Support KMIP `delegated` option. - Support processing `bulkWrite` command. - Support `range` algorithm. ## 1.9.1 ### New features - Add Debian 12 packages ## 1.9.0 ### New features - Support named KMS providers. - Add `arm64` Debian packages ## Fixed - Fix `arm64` Alpine build. ## 1.8.4 ### Fixed - Fix `aarch64` packages for RHEL 8, RHEL 9, Amazon 2023, and Amazon 2 ## 1.8.3 ### Improvements - Include packages for RHEL 8, RHEL 9, and Amazon 2023 ## 1.8.2 ### Fixed - Fix possible leaks in Queryable Encryption in errors on malformed data. ## 1.8.1 - Bypass search index management commands in automatic encryption ## 1.8.0 This release adds stable support of the Queryable Encryption (QE) feature for the "Indexed" and "Unindexed" algorithms. ## 1.8.0-alpha1 This release makes backwards breaking changes to Queryable Encryption (QE) behavior added in the 1.8.0-alpha0 release: - Do not apply default to min/max values for int/long/date. - Enable the QEv2 protocol by default. Remove function to enable QEv2. ## 1.8.0-alpha0 ### Improvements - Support Queryable Encryption v2 protocol. ## 1.7.2 ### Improvements - Add toggle for Decimal128 Range Support. ### Fixed - Fix i686 (32-bit) build. - Fix 32-bit ARM build. ## 1.7.1 ### Improvements - Vendor Intel DFP library and allow using system DFP. ### Fixed - Fix possible abort on base64 decode error of KMS messages. - Fix ILP32-target builds. - Fix LTO build. - Fix IntelDFP to not require Git. ## 1.7.0 ### New Features - Add encryptExpression helper - Support for range index. NOTE: The Range algorithm is experimental only. It is not intended for public use. ## 1.7.0-alpha2 ### New Features - Support range index for decimal128. NOTE: The Range algorithm is experimental only. It is not intended for public use. ## 1.7.0-alpha1 ### New Features - Add encryptExpression helper ## 1.7.0-alpha0 ### New Features - Support range index for int32, int64, double, and date. NOTE: The Range algorithm is experimental only. It is not intended for public use. ## 1.6.2 ## Fixed - Fix build on FreeBSD. - Set context error state during KMS provider validation. ## 1.6.1 ## Fixed - Fix libbson dependency in pkg-config for PPA. ## 1.6.0 ## New Features - Support accessToken to authenticate with Azure. ## Fixed - Use correct schema when `collMod` command includes `validator.$jsonSchema`. ## 1.6.0-alpha0 ### New Features - Support accessToken to authenticate with GCP. ### Improvements - Use CRLF, not LF, for HTTP request newlines. - Include full body of HTTP errors in `mongocrypt_status_t`. ## 1.5.2 ### Fixed - Fix datakey decryption requiring multiple rounds of KMS requests. ## 1.5.1 ## Warnings - This release has a severe bug in the context returned by `mongocrypt_ctx_rewrap_many_datakey_init` that may result in data corruption. Please upgrade to 1.5.2 before using `mongocrypt_ctx_rewrap_many_datakey_init`. ### New Features - Update Java bindings to support remaining 1.5.0 API. ## 1.5.0 ## Warnings - This release has a severe bug in the context returned by `mongocrypt_ctx_rewrap_many_datakey_init` that may result in data corruption. Please upgrade to 1.5.2 before using `mongocrypt_ctx_rewrap_many_datakey_init`. ## Fixed - Update to use new payload for FLE 2.0 find. - Require contention factor. ## 1.5.0-rc2 ### Fixed - Fix handling of create command with $jsonSchema. - Fix leak on encrypt or decrypt error. ## Improved - Accept string values for QueryType and IndexType. ## 1.4.1 ### Fixed - Add missing MONGOCRYPT_EXPORT to mongocrypt_ctx_provide_kms_providers ## 1.5.0-rc1 ## Fixed - Revert new payload for FLE 2.0 find. - Do not send "create" and "createIndexes" to mongocryptd when bypassing query analysis. ## 1.5.0-rc0 ## Fixed - Account for shared library rename. - Update to use new payload for FLE 2.0 find. ## 1.5.0-alpha2 ## New Features - Fix explain when using csfle shared library. - Do not bypass "create" or "createIndexes" commands. Support "collMod". - Bypass "hello", "buildInfo", "getCmdLineOpts", and "getLog" commands. ## Fixed - Preserve $db in output command. - Add missing MONGOCRYPT_EXPORT to mongocrypt_ctx_provide_kms_providers ## 1.5.0-alpha1 ### Fixed - Pick a random contention factor on FLE 2.0 insert. ## 1.5.0-alpha0 ### New Features - Support FLE 2.0. - Support FLE 1.0 Shared Library. - Support Key Management API. ## 1.4.0 ### New Features - Support on-demand credentials with `MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS` state and `mongocrypt_ctx_provide_kms_providers`. ## 1.4.0-alpha0 ### New Features - Support on-demand AWS credentials with `MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS` state and `mongocrypt_ctx_provide_kms_providers`. ### Fixed - Resolve 32 bit Windows compile errors. ## 1.3.1 ### New Features - Support custom key material through `mongocrypt_ctx_setopt_key_material`. ### Fixed - Fix deprecation warnings with OpenSSL 3.0. - Resolve possible symbol conflicts with OpenSSL. ## 1.3.0 - Support "kmip" KMS provider. - Add mongocrypt_kms_ctx_get_kms_provider. - Apply default port to endpoints returned in mongocrypt_kms_ctx_endpoint ## 1.2.2 - Fix pkg-config and PPA build dependency on libbson. - Fix JSON schema caching behavior when server reports no JSON schema. ## 1.2.1 ### Fixed - Fix possible crash when oauth credentials expire. ## 1.2.0 ### Added - Support AWS temporary credentials via session token. ### Fixed - Add "=" padding to base64url encoding. ## 1.1.0 ### Added - Add ENABLE_PIC cmake option, set to ON by default, so static libraries build with -fPIC by default on relevant systems. ### Fixed - Errors produced in all crypto callbacks are propagated to user. ## 1.1.0-beta1 ### Deprecated - mongocrypt_setopt_kms_provider_aws and mongocrypt_setopt_kms_provider_local are deprecated in favor of the more flexible mongocrypt_setopt_kms_providers, which supports configuration of all KMS providers. - mongocrypt_ctx_setopt_masterkey_aws, mongocrypt_ctx_setopt_masterkey_aws_endpoint, and mongocrypt_ctx_setopt_masterkey_local are deprecated in favor of the more flexible mongocrypt_ctx_setopt_key_encryption_key, which supports configuration for all KMS providers. ### Added - Introduces a new crypto hook for signing the JSON Web Token (JWT) for Google Cloud Platform (GCP) requests: - mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5 - Introduces a CLI utility `csfle` to test the context state machine against live KMS, mongocryptd, and mongod. See ./test/util/README.md. - Introduces two new functions to the libmongocrypt API. - mongocrypt_setopt_kms_providers To set the KMS providers. - mongocrypt_ctx_setopt_key_encryption_key To set the key encryption key. - Adds support for Azure and GCP KMS providers. libmongocrypt-1.11.0/CMakeLists.txt000066400000000000000000000634131465326363200172430ustar00rootroot00000000000000cmake_minimum_required (VERSION 3.12) # Preempt the MSVC_RUNTIME_LIBRARY properties if (POLICY CMP0091) cmake_policy (SET CMP0091 NEW) elseif (DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) message (WARNING "The CMAKE_MSVC_RUNTIME_LIBRARY variable is set, but CMake is too old to understand it") endif () if (POLICY CMP0135) cmake_policy (SET CMP0135 NEW) endif () project (mongocrypt C) # Used for the csfle-markup util: enable_language (CXX OPTIONAL) set (CMAKE_C_STANDARD 99) option (ENABLE_STATIC "Install static libraries" ON) option (ENABLE_PIC "Enables building of position independent code for static library components." ON ) option (ENABLE_BUILD_FOR_PPA "Maintainer-only option for preparing PPA build" OFF) option (ENABLE_ONLINE_TESTS "Enable online tests and the csfle utility. Requires libmongoc." ON) if (ENABLE_WINDOWS_STATIC_RUNTIME) if (POLICY CMP0091) # CMake 3.15 makes this trivial: set (CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") else () # Fix it up the old-fashioned way string (REPLACE "/MDd" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") string (REPLACE "/MD" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") string (REPLACE "/MDd" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string (REPLACE "/MD" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") string (APPEND CMAKE_C_FLAGS_DEBUG " /MTd") string (APPEND CMAKE_CXX_FLAGS_DEBUG " /MTd") string (APPEND CMAKE_C_FLAGS_RELEASE " /MT") string (APPEND CMAKE_CXX_FLAGS_RELEASE " /MT") endif () endif () list (APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) include (GNUInstallDirs) include (LTO) include (ImportBSON) option (MONGOCRYPT_ENABLE_DECIMAL128 "Enable extended support for Decimal128" ON) mark_as_advanced (MONGOCRYPT_ENABLE_DECIMAL128) set (maybe_dfp_library) if (MONGOCRYPT_ENABLE_DECIMAL128) include (ImportDFP) set (maybe_dfp_library mongocrypt::intel_dfp) endif () if (USE_SHARED_LIBBSON AND ENABLE_BUILD_FOR_PPA) message (FATAL_ERROR "PPA build requires static linking to libbson") endif () if (DEFINED MONGOCRYPT_DFP_DIR AND ENABLE_BUILD_FOR_PPA) message (FATAL_ERROR "PPA build requires building with vendored Intel DFP") endif () # Enable a higher warning level and warnings-as-errors include (MongoC-Warnings) option (ENABLE_MORE_WARNINGS_AS_ERRORS "Enable extra warnings-as-errors in the build." OFF) if (ENABLE_MORE_WARNINGS_AS_ERRORS) mongoc_add_platform_compile_options ( msvc:/W3 msvc:/WX msvc:/wd4996 msvc:/wd4359 gnu-like:-Wall gnu-like:-Werror gnu-like:-Wswitch-enum gnu-like:-Wswitch-default gnu-like:-Wsign-compare ) add_link_options ( # Enable link-time warnings. VS 2015 sees LNK4099 spuriously, but it is a # non-fatal issue. LNK4217 and LNK4049 appear when using dllimport on # locally-defined symbols in kms-message. "$,/WX;/ignore:4217;/ignore:4049;/ignore:4099,-Werror>" ) endif () add_subdirectory (bindings/cs) include (GenerateExportHeader) include (CTest) include (Platform) set (MONGOCRYPT_PUBLIC_HEADERS src/mongocrypt-compat.h src/mongocrypt.h ) set (MONGOCRYPT_SOURCES src/crypto/cng.c src/crypto/commoncrypto.c src/crypto/libcrypto.c src/crypto/none.c src/mc-array.c src/mc-efc.c src/mc-fle2-find-range-payload.c src/mc-fle2-find-range-payload-v2.c src/mc-fle2-insert-update-payload.c src/mc-fle2-insert-update-payload-v2.c src/mc-fle2-encryption-placeholder.c src/mc-fle2-find-equality-payload.c src/mc-fle2-find-equality-payload-v2.c src/mc-fle2-payload-iev.c src/mc-fle2-payload-iev-v2.c src/mc-fle2-payload-uev.c src/mc-fle2-payload-uev-common.c src/mc-fle2-payload-uev-v2.c src/mc-fle2-rfds.c src/mc-range-edge-generation.c src/mc-range-mincover.c src/mc-range-encoding.c src/mc-rangeopts.c src/mc-reader.c src/mc-tokens.c src/mc-writer.c src/mongocrypt-binary.c src/mongocrypt-buffer.c src/mongocrypt-cache.c src/mongocrypt-cache-collinfo.c src/mongocrypt-cache-key.c src/mongocrypt-cache-oauth.c src/mongocrypt-ciphertext.c src/mongocrypt-crypto.c src/mongocrypt-ctx-datakey.c src/mongocrypt-ctx-decrypt.c src/mongocrypt-ctx-encrypt.c src/mongocrypt-ctx-rewrap-many-datakey.c src/mongocrypt-ctx.c src/mongocrypt-endpoint.c src/mongocrypt-kek.c src/mongocrypt-key.c src/mongocrypt-key-broker.c src/mongocrypt-kms-ctx.c src/mongocrypt-log.c src/mongocrypt-marking.c src/mongocrypt-opts.c src/mongocrypt-status.c src/mongocrypt-traverse-util.c src/mongocrypt-util.c src/mongocrypt.c src/os_win/os_mutex.c src/os_posix/os_mutex.c src/os_win/os_dll.c src/os_posix/os_dll.c ) # If MONGOCRYPT_CRYPTO is not set, choose a system default. if (NOT MONGOCRYPT_CRYPTO) set (MONGOCRYPT_CRYPTO OpenSSL) if (APPLE) set (MONGOCRYPT_CRYPTO CommonCrypto) elseif (WIN32) set (MONGOCRYPT_CRYPTO CNG) endif () endif () # Otherwise, override with crypto hooks. if (DISABLE_NATIVE_CRYPTO) set (MONGOCRYPT_CRYPTO none) endif () set (MONGOCRYPT_ENABLE_CRYPTO 0) set (MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO 0) set (MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO 0) set (MONGOCRYPT_ENABLE_CRYPTO_CNG 0) if (MONGOCRYPT_CRYPTO STREQUAL CommonCrypto) message ("Building with common crypto") set (MONGOCRYPT_ENABLE_CRYPTO 1) set (MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO 1) elseif (MONGOCRYPT_CRYPTO STREQUAL CNG) message ("Building with CNG") set (MONGOCRYPT_ENABLE_CRYPTO 1) set (MONGOCRYPT_ENABLE_CRYPTO_CNG 1) elseif (MONGOCRYPT_CRYPTO STREQUAL OpenSSL) message ("Building with OpenSSL") include (FindOpenSSL) message ("Found OpenSSL version ${OPENSSL_VERSION}") set (MONGOCRYPT_ENABLE_CRYPTO 1) set (MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO 1) elseif (MONGOCRYPT_CRYPTO STREQUAL none) message ("Building with no native crypto, hooks MUST be supplied with mongocrypt_setopt_crypto_hooks") else () message (FATAL_ERROR "Unknown crypto provider ${MONGOCRYPT_CRYPTO}") endif () set (MONGOCRYPT_ENABLE_TRACE 0) if (ENABLE_TRACE) message (WARNING "Building with trace logging. This is highly insecure. Do not use in a production environment") set (MONGOCRYPT_ENABLE_TRACE 1) endif () set (BUILD_VERSION "0.0.0" CACHE STRING "Library version") if (BUILD_VERSION STREQUAL "0.0.0") if (EXISTS ${CMAKE_BINARY_DIR}/VERSION_CURRENT) file (STRINGS ${CMAKE_BINARY_DIR}/VERSION_CURRENT BUILD_VERSION) elseif (EXISTS ${PROJECT_SOURCE_DIR}/VERSION_CURRENT) file (STRINGS ${PROJECT_SOURCE_DIR}/VERSION_CURRENT BUILD_VERSION) message (STATUS "File VERSION_CURRENT contained BUILD_VERSION ${BUILD_VERSION}") else () find_package (PythonInterp) if (PYTHONINTERP_FOUND) execute_process ( COMMAND ${PYTHON_EXECUTABLE} etc/calc_release_version.py WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} OUTPUT_VARIABLE CALC_RELEASE_VERSION RESULT_VARIABLE CALC_RELEASE_VERSION_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE ) if (NOT CALC_RELEASE_VERSION_RESULT STREQUAL 0) # If python failed above, stderr would tell the user about it message (FATAL_ERROR "BUILD_VERSION not specified and could not be calculated\ (script invocation failed); specify in CMake command, -DBUILD_VERSION=" ) else () set (BUILD_VERSION ${CALC_RELEASE_VERSION}) message ("calculated BUILD_VERSION ${BUILD_VERSION}") file (WRITE ${CMAKE_BINARY_DIR}/VERSION_CURRENT ${CALC_RELEASE_VERSION}) endif () else () message (FATAL_ERROR "BUILD_VERSION not specified and could not be calculated\ (Python was not found on the system); specify in CMake command, -DBUILD_VERSION=" ) endif () message (STATUS "Storing BUILD_VERSION ${BUILD_VERSION} in file VERSION_CURRENT for later use") file (WRITE ${PROJECT_SOURCE_DIR}/VERSION_CURRENT ${BUILD_VERSION}) endif () else () message (STATUS "Storing BUILD_VERSION ${BUILD_VERSION} in file VERSION_CURRENT for later use") file (WRITE ${PROJECT_SOURCE_DIR}/VERSION_CURRENT ${BUILD_VERSION}) endif () set (MONGOCRYPT_BUILD_VERSION ${BUILD_VERSION}) configure_file ( "${PROJECT_SOURCE_DIR}/src/mongocrypt-config.h.in" "${PROJECT_BINARY_DIR}/src/mongocrypt-config.h" ) # Define the mlib target, which is private and header-only. It is not exported # nor are its headers installed. add_library (_mongo-mlib INTERFACE) add_library (mongo::mlib ALIAS _mongo-mlib) list (APPEND MLIB_DEFINITIONS MLIB_USER) CHECK_INCLUDE_FILE (strings.h HAVE_STRINGS_H) if (HAVE_STRINGS_H) list (APPEND MLIB_DEFINITIONS MLIB_HAVE_STRINGS_H) endif () set_property( TARGET _mongo-mlib APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS ${MLIB_DEFINITIONS} ) set_property( TARGET _mongo-mlib APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$" ) # kms-message add_subdirectory (kms-message) # Define mongocrypt library add_library (mongocrypt SHARED ${MONGOCRYPT_SOURCES}) target_include_directories ( mongocrypt PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/kms-message/src" "${CMAKE_CURRENT_SOURCE_DIR}/src" PUBLIC "$" ) target_link_libraries ( mongocrypt PRIVATE _mongocrypt::libbson_for_shared kms_message_static $ PUBLIC mongocrypt::platform ${maybe_dfp_library} ) if (NOT USE_SHARED_LIBBSON) if (APPLE) message ("compiling with unexported symbols list to hide bson symbols") set_target_properties (mongocrypt PROPERTIES LINK_FLAGS "-Wl,-unexported_symbols_list,\"${CMAKE_CURRENT_SOURCE_DIR}/cmake/libmongocrypt-hidden-symbols.txt\"") elseif (UNIX) message ("compiling with version map to version and hide bson symbols") set_target_properties (mongocrypt PROPERTIES LINK_FLAGS "-Wl,--version-script=\"${CMAKE_CURRENT_SOURCE_DIR}/cmake/libmongocrypt-hidden-symbols.map\"") endif () endif () if (NOT WIN32 AND CMAKE_VERSION VERSION_GREATER 3.25) # Do not enable conversion warnings with older cmake. Older cmake does not support # including headers as system headers when the headers are added to the project via # the add_subdirectory() CMake command. libbson produces conversion warnings and is # included in ImportBSON.cmake. target_compile_options (mongocrypt PRIVATE -Wconversion -Wsign-conversion) target_compile_options (kms_message_static PRIVATE -Wconversion -Wsign-conversion) endif () generate_export_header (mongocrypt EXPORT_FILE_NAME src/mongocrypt-export.h BASE_NAME mongocrypt ) add_library (mongocrypt_static STATIC ${MONGOCRYPT_SOURCES}) # Checking CMAKE_C_FLAGS for -fPIC is not a foolproof way of checking whether # -fPIC was set as a compiler flag. However, users were instructed before to # pass -fPIC through CMAKE_C_FLAGS. This will prevent redundant output in # the common case that users are setting -DCMAKE_C_FLAGS='-fPIC' string (FIND "${CMAKE_C_FLAGS}" "-fPIC" FPIC_LOCATION) if (NOT WIN32 AND ENABLE_PIC AND "${FPIC_LOCATION}" EQUAL "-1") target_compile_options (mongocrypt_static PUBLIC -fPIC) message ("Adding -fPIC to compilation of mongocrypt_static components") endif () target_include_directories ( mongocrypt_static PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/kms-message/src" "${CMAKE_CURRENT_SOURCE_DIR}/src" PUBLIC "$" ) target_compile_definitions ( mongocrypt_static PUBLIC MONGOCRYPT_STATIC_DEFINE KMS_MSG_STATIC ) target_link_libraries ( mongocrypt_static PRIVATE _mongocrypt::libbson_for_static kms_message_static $ PUBLIC mongocrypt::platform ${maybe_dfp_library} ) set (PKG_CONFIG_STATIC_LIBS "\${prefix}/${CMAKE_INSTALL_LIBDIR}/libmongocrypt-static.a") set (PKG_CONFIG_STATIC_LIBS "${PKG_CONFIG_STATIC_LIBS} ${CMAKE_THREAD_LIBS_INIT}") if (CMAKE_DL_LIBS) string (APPEND PKG_CONFIG_STATIC_LIBS " -l${CMAKE_DL_LIBS}") endif () set (PKG_CONFIG_STATIC_LIBS "${PKG_CONFIG_STATIC_LIBS} \${prefix}/${CMAKE_INSTALL_LIBDIR}/libkms_message-static.a") if (ENABLE_BUILD_FOR_PPA) set (PKG_CONFIG_STATIC_LIBS "${PKG_CONFIG_STATIC_LIBS} \${prefix}/${CMAKE_INSTALL_LIBDIR}/libbson-static-for-libmongocrypt.a") #librt needed for libbson on linux for clock_gettime find_library (RT_LIBRARY rt) if (RT_LIBRARY) set (PKG_CONFIG_STATIC_LIBS "${PKG_CONFIG_STATIC_LIBS} ${RT_LIBRARY}") endif () set (PKG_CONFIG_STATIC_LIBS "${PKG_CONFIG_STATIC_LIBS} -pthread") endif () if (MONGOCRYPT_DFP_DIR STREQUAL "USE-SYSTEM" AND MONGOCRYPT_ENABLE_DECIMAL128) get_property (SYSTEM_DFP_LOC TARGET intel_dfp PROPERTY IMPORTED_LOCATION) set (PKG_CONFIG_STATIC_LIBS "${PKG_CONFIG_STATIC_LIBS} ${SYSTEM_DFP_LOC}") endif () if (MONGOCRYPT_CRYPTO STREQUAL CommonCrypto) target_link_libraries (mongocrypt PRIVATE "-framework CoreFoundation -framework Security") target_link_libraries (mongocrypt_static PRIVATE "-framework CoreFoundation -framework Security") set (PKG_CONFIG_STATIC_LIBS "${PKG_CONFIG_STATIC_LIBS} -framework CoreFoundation -framework Security") elseif (MONGOCRYPT_CRYPTO STREQUAL CNG) target_link_libraries (mongocrypt PRIVATE "bcrypt") target_link_libraries (mongocrypt_static PRIVATE "bcrypt") set (PKG_CONFIG_STATIC_LIBS "${PKG_CONFIG_STATIC_LIBS} -lbcrypt") elseif (MONGOCRYPT_CRYPTO STREQUAL OpenSSL) target_link_libraries (mongocrypt PRIVATE OpenSSL::SSL OpenSSL::Crypto) target_link_libraries (mongocrypt_static PRIVATE OpenSSL::SSL OpenSSL::Crypto) set (PKG_CONFIG_STATIC_LIBS "${PKG_CONFIG_STATIC_LIBS} -lssl -lcrypto") endif () # Link to libm for math functions (pow, log, etc.) # Do not link on Apple. On macOS Big Sur, libm resolves to the SDK's tbd file, like: # /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib/libm.tbd # Not all consumers can easily link to a tbd file (notably golang will reject a tbd suffix by default) # macOS includes libm as part of libSystem (along with libc). # It does not need to be explicitly linked. if (NOT APPLE) find_library (M_LIBRARY m) if (M_LIBRARY) set (PKG_CONFIG_STATIC_LIBS "${PKG_CONFIG_STATIC_LIBS} -lm") endif () endif () set_target_properties (mongocrypt PROPERTIES SOVERSION 0 VERSION "0.0.0" OUTPUT_NAME "mongocrypt" ) set_target_properties (mongocrypt_static PROPERTIES SOVERSION 0 VERSION "0.0.0" OUTPUT_NAME "mongocrypt-static" ) if (BUILD_TESTING) # Use C++ in the testing DLL to ensure we can load a library with the C++ runtime enable_language (CXX) add_library (test-dll MODULE test/test-dll.cpp) set_target_properties (test-dll PROPERTIES SUFFIX ".dll" PREFIX "" ) # Create two stubbed crypt_shared libraries add_library (stubbed-crypt_shared SHARED test/crypt_shared-stub.cpp) add_library (stubbed-crypt_shared-2 SHARED test/crypt_shared-stub.cpp) set_target_properties(stubbed-crypt_shared stubbed-crypt_shared-2 PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/src" LINK_LIBRARIES _mongocrypt::libbson_for_static COMPILE_FEATURES cxx_std_11 # Define `__STDC_LIMIT_MACROS` in libbson to define integer macros (e.g. SIZE_MAX) when including in C++ code. # C99 standard notes: "C++ implementations should define these macros only when __STDC_LIMIT_MACROS is defined before is included." COMPILE_DEFINITIONS __STDC_LIMIT_MACROS PREFIX "" ) set_target_properties(stubbed-crypt_shared-2 PROPERTIES SUFFIX ".dll") if (MONGOCRYPT_TESTING_CRYPT_SHARED_FILE) # Generate a target that copies the CSFLE library into the binary directory of test-mongocrypt set (stamp "${CMAKE_CURRENT_BINARY_DIR}/mongo_crypt_v1.copied.$.stamp") add_custom_command ( OUTPUT "${stamp}" COMMAND "${CMAKE_COMMAND}" -E copy "${MONGOCRYPT_TESTING_CRYPT_SHARED_FILE}" "$/mongo_crypt_v1${CMAKE_SHARED_LIBRARY_SUFFIX}" COMMAND "${CMAKE_COMMAND}" -E touch "${stamp}" DEPENDS "${MONGOCRYPT_TESTING_CRYPT_SHARED_FILE}" COMMENT "Getting mongo_crypt library" ) add_custom_target (copy-crypt_shared ALL DEPENDS "${stamp}") else () # The first stubbed crypt_shared library will take the place of the actual crypt_shared for testing message (STATUS "Generating a stubbed crypt_shared dynamic library for use in testing.") message (STATUS "Provide a MONGOCRYPT_TESTING_CRYPT_SHARED_FILE= to provide a crypt_shared for use in testing") set_target_properties (stubbed-crypt_shared PROPERTIES # Normalize the output name expected by libmongocrypt OUTPUT_NAME "mongo_crypt_v1" ) endif () endif () set (TEST_MONGOCRYPT_SOURCES test/test-gcp-auth.c test/test-mc-efc.c test/test-mc-fle2-find-equality-payload-v2.c test/test-mc-fle2-find-range-payload-v2.c test/test-mc-fle2-payload-iev.c test/test-mc-fle2-payload-iev-v2.c test/test-mc-fle2-payload-iup.c test/test-mc-fle2-payload-iup-v2.c test/test-mc-fle2-payload-uev.c test/test-mc-fle2-payload-uev-v2.c test/test-mc-fle2-rfds.c test/test-mc-range-edge-generation.c test/test-mc-range-mincover.c test/test-mc-rangeopts.c test/test-mc-reader.c test/test-mc-tokens.c test/test-mc-range-encoding.c test/test-mc-writer.c test/test-mongocrypt-assert-match-bson.c test/test-mongocrypt-buffer.c test/test-mongocrypt-cache.c test/test-mongocrypt-cache-oauth.c test/test-mongocrypt-ciphertext.c test/test-mongocrypt-cleanup.c test/test-mongocrypt-compact.c test/test-mongocrypt-crypto.c test/test-mongocrypt-crypto-hooks.c test/test-mongocrypt-crypto-std-hooks.c test/test-mongocrypt-csfle-lib.c test/test-mongocrypt-ctx-decrypt.c test/test-mongocrypt-ctx-encrypt.c test/test-mongocrypt-ctx-rewrap-many-datakey.c test/test-mongocrypt-ctx-setopt.c test/test-mongocrypt-datakey.c test/test-mongocrypt-dll.c test/test-mongocrypt-endpoint.c test/test-mongocrypt-kek.c test/test-mongocrypt-key.c test/test-mongocrypt-key-broker.c test/test-mongocrypt-key-cache.c test/test-mongocrypt-kms-ctx.c test/test-mongocrypt-kms-responses.c test/test-mongocrypt-local-kms.c test/test-mongocrypt-log.c test/test-mongocrypt-marking.c test/test-mongocrypt-opts.c test/test-mongocrypt-status.c test/test-mongocrypt-traverse-util.c test/test-mongocrypt-util.c test/test-mongocrypt.c test/test-named-kms-providers.c ) # Define test-mongocrypt add_executable (test-mongocrypt ${TEST_MONGOCRYPT_SOURCES}) # Use the static version since it allows the test binary to use private symbols target_include_directories (test-mongocrypt PRIVATE ./src "${CMAKE_CURRENT_SOURCE_DIR}/kms-message/src") target_link_libraries (test-mongocrypt PRIVATE _mongocrypt::libbson_for_static mongocrypt_static mongo::mlib) target_include_directories (test-mongocrypt PRIVATE "${CMAKE_CURRENT_LIST_DIR}/test") target_compile_definitions (test-mongocrypt PRIVATE # Set a definition so that testcases can know where test-mongocrypt.exe was written to "TEST_MONGOCRYPT_OUTPUT_PATH=\"$\"" # Tell test-mongocrypt whether we have a real csfle library for testing TEST_MONGOCRYPT_HAVE_REAL_CRYPT_SHARED_LIB=$ ) add_test ( NAME mongocrypt COMMAND test-mongocrypt WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) foreach (test IN ITEMS path str) add_executable (mlib.${test}.test src/mlib/${test}.test.c) add_test (mlib.${test} mlib.${test}.test) target_link_libraries (mlib.${test}.test PRIVATE mongo::mlib) endforeach () if ("cxx_relaxed_constexpr" IN_LIST CMAKE_CXX_COMPILE_FEATURES) file (GLOB_RECURSE test_files CONFIGURE_DEPENDS src/*.test.cpp) foreach (file IN LISTS test_files) # Compute a nice test name file (RELATIVE_PATH relpath "${CMAKE_CURRENT_LIST_DIR}/src" "${file}") file (TO_CMAKE_PATH "${relpath}" relpath) string (REPLACE "src/" "" relpath "${relpath}") string (REPLACE "/" "." test_name "${relpath}") string (REGEX REPLACE "\\.test\\.cpp$" "" test_name "${test_name}") # Generate a test executable: set (exe_name "${test_name}.test") add_executable ("${exe_name}" "${file}") target_compile_features ("${exe_name}" PRIVATE cxx_relaxed_constexpr) target_link_libraries ("${exe_name}" PRIVATE mongocrypt mongo::mlib ${maybe_dfp_library} _mongocrypt::libbson_for_static ) add_test ("${test_name}" "${exe_name}") endforeach () endif () if ("cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES) add_executable (csfle-markup src/csfle-markup.cpp) target_link_libraries (csfle-markup PRIVATE mongocrypt_static _mongocrypt::libbson_for_static mongo::mlib) target_compile_features (csfle-markup PRIVATE cxx_std_20) endif () # Exclude example-state-machine since it requires native crypto. if (NOT MONGOCRYPT_CRYPTO STREQUAL none) # Define example-state-machine add_executable (example-state-machine test/example-state-machine.c) target_link_libraries (example-state-machine PRIVATE mongocrypt _mongocrypt::libbson_for_shared) target_include_directories (example-state-machine PRIVATE ./src "${CMAKE_CURRENT_SOURCE_DIR}/kms-message/src") add_test ( NAME example-state-machine COMMAND example-state-machine WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" ) # Define example-state-machine-static add_executable (example-state-machine-static test/example-state-machine.c) target_link_libraries (example-state-machine-static PRIVATE mongocrypt_static _mongocrypt::libbson_for_static) target_include_directories (example-state-machine-static PRIVATE ./src) add_test ( NAME example-state-machine-static COMMAND example-state-machine-static WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" ) if (ENABLE_ONLINE_TESTS) message ("compiling utilities") add_executable (csfle test/util/csfle.c test/util/util.c) target_link_libraries (csfle PRIVATE mongocrypt_static) target_include_directories (csfle PRIVATE ${CMAKE_BINARY_DIR}/src) target_include_directories (csfle PRIVATE ./src) target_include_directories (csfle PRIVATE ./kms-message/src) target_link_libraries (csfle PRIVATE _mongocrypt::mongoc) endif () endif () if (ENABLE_STATIC) set (TARGETS_TO_INSTALL mongocrypt mongocrypt_static) else () set (TARGETS_TO_INSTALL mongocrypt) endif () install ( TARGETS ${TARGETS_TO_INSTALL} EXPORT mongocrypt_targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) # This export set is not installed, and is only to allow export() of the mlib-using targets install (TARGETS _mongo-mlib EXPORT _exports_for_export) export (EXPORT _exports_for_export) install ( FILES ${MONGOCRYPT_PUBLIC_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/src/mongocrypt-config.h ${CMAKE_CURRENT_BINARY_DIR}/src/mongocrypt-export.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mongocrypt COMPONENT Devel ) set (PROJECT_VERSION "${BUILD_VERSION}") set (PROJECT_DESCRIPTION "The libmongocrypt client-side field level encryption library.") if (NOT ENABLE_BUILD_FOR_PPA) set (PKG_CONFIG_STATIC_REQUIRES "libbson-static-1.0") endif () if (USE_SHARED_LIBBSON) set (PKG_CONFIG_REQUIRES "libbson-1.0") set (PKG_CONFIG_STATIC_REQUIRES "libbson-1.0") endif () set (PKG_CONFIG_LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}") set (PKG_CONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}/mongocrypt") set (PKG_CONFIG_LIBS "-L\${libdir} -lmongocrypt") if (ENABLE_BUILD_FOR_PPA) set (PKG_CONFIG_LIBS "${PKG_CONFIG_LIBS} \${prefix}/${CMAKE_INSTALL_LIBDIR}/libbson-static-for-libmongocrypt.a") #librt needed for libbson on linux for clock_gettime find_library (RT_LIBRARY rt) if (RT_LIBRARY) set (PKG_CONFIG_LIBS "${PKG_CONFIG_LIBS} ${RT_LIBRARY}") endif () set (PKG_CONFIG_LIBS "${PKG_CONFIG_LIBS} -pthread") endif () if (MONGOCRYPT_DFP_DIR STREQUAL "USE-SYSTEM" AND MONGOCRYPT_ENABLE_DECIMAL128) get_property (SYSTEM_DFP_LOC TARGET intel_dfp PROPERTY IMPORTED_LOCATION) set (PKG_CONFIG_LIBS "${PKG_CONFIG_LIBS} ${SYSTEM_DFP_LOC}") endif () set (PKG_CONFIG_CFLAGS "-I\${includedir}") set (PKG_CONFIG_STATIC_CFLAGS "${PKG_CONFIG_CFLAGS} -DMONGOCRYPT_STATIC_DEFINE -DKMS_MSG_STATIC") configure_file ( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/libmongocrypt.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libmongocrypt.pc" ) configure_file ( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/libmongocrypt-static.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libmongocrypt-static.pc" ) install ( FILES "${CMAKE_BINARY_DIR}/libmongocrypt.pc" DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) if (ENABLE_STATIC) install ( FILES "${CMAKE_BINARY_DIR}/libmongocrypt-static.pc" DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) endif () include (CMakePackageConfigHelpers) set (INCLUDE_INSTALL_DIRS "${CMAKE_INSTALL_INCLUDEDIR}/mongocrypt") set (LIBRARY_INSTALL_DIRS ${CMAKE_INSTALL_LIBDIR}) write_basic_package_version_file ( "${CMAKE_CURRENT_BINARY_DIR}/mongocrypt/mongocrypt-config-version.cmake" COMPATIBILITY AnyNewerVersion ) configure_file (cmake/mongocrypt-config.cmake "${CMAKE_CURRENT_BINARY_DIR}/mongocrypt/mongocrypt-config.cmake" @ONLY ) install (EXPORT mongocrypt_targets NAMESPACE mongo:: FILE mongocrypt_targets.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/mongocrypt ) install ( FILES "${CMAKE_CURRENT_BINARY_DIR}/mongocrypt/mongocrypt-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/mongocrypt/mongocrypt-config-version.cmake" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/mongocrypt COMPONENT Devel ) libmongocrypt-1.11.0/CODEOWNERS000066400000000000000000000003221465326363200160640ustar00rootroot00000000000000# Code Owners will automatically be added as reviewers on PRs # Python Bindings bindings/python @mongodb/dbx-python # Java Bindings bindings/java @jyemin @rozza # CSharp Bindings bindings/cs @DmitryLukyanov libmongocrypt-1.11.0/Earthfile000066400000000000000000000457001465326363200163300ustar00rootroot00000000000000# Earthly Intro: https://docs.earthly.dev/ # Earthfile Reference: https://docs.earthly.dev/docs/earthfile # Quick notes: # • The shell script at ".evergreen/earthly.sh" can be used to automatically # download and use a fixed version of Earthly that is compatible with # this file version. Execute the shell script as if it were the Earthly # executable itself. # • In this file, the convention is to copy the source tree into /s/libmongocrypt # • Earthly copies the "build context" (working directory) into the local buildkit # daemon before each build execution. (Similar to the Docker build context). # If you have a large amount of data in the working directory, this could be # slow. The ".earthlyignore" file specifies patterns of files and directories # to exclude from the context upload. Modify it to suite your needs, if necessary. # • Only a subset of the source tree is COPY'd into the build environment. Files # outside of this set will not be available in the build. See the COPY_SOURCE # command for the list. # • Modification at any layer will invalidate caching on all subsequent build # layers. This is important and by-design in Earthly. Push infrequently-modified # operations to earlier in the process the pipeline to make better use of # the cache. # # This file has a few major sections: # - Setup COMMANDs # - Utility COMMANDs # - Environment targets # - Build/test/CI targets # # All environment targets begin with "env.". All build targets (should) accept an "env" # parameter that specifies the name of the environment to use for the task. The name # of an environment is specified following the "env." prefix. For example, the # Ubuntu 22.04 environment is named "u22", so its environment target is "env.u22", # and can be used i.e. "earthly +build --env=u22" # # The following environment are defined in this file: # • u22 - Ubuntu 22.04 # • u20 - Ubuntu 20.04 # • u18 - Ubuntu 18.04 # • u16 - Ubuntu 16.04 # • u14 - Ubuntu 14.04 # • rl8 - RockyLinux 8 - Stand-in for RHEL 8 # • c7 - CentOS 7 - Stand-in for RHEL 7 # • c6 - CentOS 6 - Stand-in for RHEL 6 # • amzn1 - AmazonLinux (2018.03) # • amzn2 - AmazonLinux 2 # • deb9 - Debian 9.2 # • deb10 - Debian 10.0 # • deb11 - Debian 11.0 # • deb12 - Debian 12.0 # • sles15 - OpenSUSE Leap 15.0 # • alpine - Alpine Linux 3.18 # # When adding new environments, always pull from a fully-qualified image ID: # • DO NOT: "ubuntu" # • DO NOT: "ubuntu:latest" # • DO NOT: "ubuntu:22.10" # • DO: "docker.io/library/ubuntu:22.10" # ### VERSION --use-cache-command 0.6 FROM docker.io/library/alpine:3.16 WORKDIR /s init: # Special initializing target that sets up the base image and adds the "__install" # script. This scripts abstracts around the underlying package manager interface # to "do the right thing" when you want to install packages. Package names will # still need to be spelled correctly for the respective system. # # Invoke +init with a "--base" parameter that specifies the base image to pull ARG --required base FROM $base COPY etc/install-package.sh /usr/local/bin/__install RUN chmod +x /usr/local/bin/__install ENV USER_CACHES_DIR=/Cache # Environment setup commands below. Each provides the basic environment for a # libmongocrypt build. Additional packages and setup may be required for # individual tasks. DEBIAN_SETUP: # Setup for a debian-like build environment. Used for both Debian and Ubuntu COMMAND RUN __install build-essential g++ libssl-dev curl unzip python3 pkg-config \ git ccache findutils ca-certificates REDHAT_SETUP: # Setup for a redhat-like build environment. Used for CentOS and RockyLinux. COMMAND RUN __install epel-release && \ __install gcc-c++ make openssl-devel curl unzip git ccache findutils \ patch CENTOS6_SETUP: # Special setup for CentOS6: The packages have been moved to the vault, so # we need to enable the vault repos before we perform any __installs COMMAND RUN rm /etc/yum.repos.d/*.repo COPY etc/c6-vault.repo /etc/yum.repos.d/CentOS-Base.repo DO +REDHAT_SETUP AMZ_SETUP: # Setup for Amazon Linux. COMMAND # amzn1 has "python38", but amzn2 has "python3." Try both RUN __install python3 || __install python38 RUN __install gcc-c++ make openssl-devel curl unzip tar gzip \ openssh-clients patch git SLES_SETUP: # Setup for a SLES/SUSE build environment COMMAND RUN __install gcc-c++ make libopenssl-devel curl unzip tar gzip python3 \ patch git xz which ALPINE_SETUP: # Setup for an Alpine Linux build environment COMMAND RUN __install make bash gcc g++ unzip curl tar gzip git musl-dev \ linux-headers openssl-dev python3 # Environment targets are defined below. These do not have build outputs, but # are rather themselves the "outputs" to be used as the environment for subsequent # tasks env.c6: # A CentOS 6 environment. FROM +init --base=docker.io/library/centos:6 DO +CENTOS6_SETUP env.c7: # A CentOS 7 environment. FROM +init --base=docker.io/library/centos:7 DO +REDHAT_SETUP env.rl8: # CentOS 8 is cancelled. Use RockyLinux 8 for our RHEL 8 environment. FROM +init --base=docker.io/library/rockylinux:8 DO +REDHAT_SETUP # Utility command for Ubuntu environments ENV_UBUNTU: COMMAND ARG --required version FROM +init --base=docker.io/library/ubuntu:$version DO +DEBIAN_SETUP env.u14: # An Ubuntu 14.04 environment DO +ENV_UBUNTU --version 14.04 env.u16: # An Ubuntu 16.04 environment DO +ENV_UBUNTU --version 16.04 env.u18: # An Ubuntu 18.04 environment DO +ENV_UBUNTU --version 18.04 env.u20: # An Ubuntu 20.04 environment DO +ENV_UBUNTU --version 20.04 env.u22: # An Ubuntu 22.04 environment DO +ENV_UBUNTU --version 22.04 env.amzn1: # An Amazon "1" environment. (AmazonLinux 2018) FROM +init --base=docker.io/library/amazonlinux:2018.03 DO +AMZ_SETUP env.amzn2: # An AmazonLinux 2 environment FROM +init --base=docker.io/library/amazonlinux:2 DO +AMZ_SETUP # Utility command for Debian setup ENV_DEBIAN: COMMAND ARG --required version FROM +init --base=docker.io/library/debian:$version IF [ $version = "9.2" ] # Update source list for archived Debian stretch packages. # Refer: https://unix.stackexchange.com/a/743865/260858 RUN echo "deb http://archive.debian.org/debian stretch main" > /etc/apt/sources.list END DO +DEBIAN_SETUP env.deb9: # A Debian 9.2 environment DO +ENV_DEBIAN --version 9.2 env.deb10: # A Debian 10.0 environment DO +ENV_DEBIAN --version 10.0 env.deb-unstable: DO +ENV_DEBIAN --version=unstable env.deb11: # A Debian 11.0 environment DO +ENV_DEBIAN --version 11.0 env.deb12: # A Debian 12.0 environment DO +ENV_DEBIAN --version 12.0 env.sles15: # An OpenSUSE Leap 15.0 environment. FROM +init --base=docker.io/opensuse/leap:15.0 DO +SLES_SETUP env.alpine: FROM +init --base=docker.io/library/alpine:3.18 DO +ALPINE_SETUP # Utility: Warm-up obtaining CMake and Ninja for the build. This is usually # very quick, but on some platforms we need to compile them from source. CACHE_WARMUP: COMMAND # Copy only the scripts that are strictly necessary for the operation, to # avoid cache invalidation later on. COPY .evergreen/setup-env.sh \ .evergreen/init.sh \ .evergreen/ensure-cmake.sh \ .evergreen/ensure-ninja.sh \ /T/ RUN bash /T/ensure-cmake.sh RUN env NINJA_EXE=/usr/local/bin/ninja \ bash /T/ensure-ninja.sh COPY_SOURCE: COMMAND COPY --dir \ .git/ \ cmake/ \ kms-message/ \ test/ \ debian/ \ src/ \ doc/ \ etc/ \ LICENSE \ .evergreen/ \ third-party/ \ CMakeLists.txt \ "/s/libmongocrypt" COPY --dir bindings/cs/ "/s/libmongocrypt/bindings/" BUILD_EXAMPLE_STATE_MACHINE: COMMAND COPY test/example-state-machine.c /s/ RUN pkg-config --exists libmongocrypt --print-errors && \ gcc /s/example-state-machine.c \ -o /s/example-state-machine \ $(pkg-config --cflags --libs libmongocrypt) COPY --dir test/example /s/test/example RUN cd /s && /s/example-state-machine rpm-build: FROM +init --base fedora:38 GIT CLONE https://src.fedoraproject.org/rpms/libmongocrypt.git /R # Install the packages listed by "BuildRequires" and rpm-build: RUN __install $(awk '/^BuildRequires:/ { print $2 }' /R/libmongocrypt.spec) \ rpm-build DO +COPY_SOURCE RUN cp -r /s/libmongocrypt/. /R RUN awk -f /R/etc/rpm/tweak.awk < /R/libmongocrypt.spec > /R/libmongocrypt.2.spec RUN rpmbuild -ba /R/libmongocrypt.2.spec \ -D "_topdir /X" \ -D "_sourcedir /R" SAVE ARTIFACT /X/RPMS / SAVE ARTIFACT /X/SRPMS / rpm-install-runtime: # Install the runtime RPM FROM +init --base fedora:38 COPY +rpm-build/RPMS /tmp/libmongocrypt-rpm/ RUN dnf makecache RUN __install $(find /tmp/libmongocrypt-rpm/ -name 'libmongocrypt-1.*.rpm') rpm-install-dev: # Install the development RPM FROM +rpm-install-runtime COPY +rpm-build/RPMS /tmp/libmongocrypt-rpm/ RUN dnf makecache RUN __install $(find /tmp/libmongocrypt-rpm/ -name 'libmongocrypt-devel-*.rpm') rpm-devel-test: # Attempt to build a small app using pkg-config and the dev RPM FROM +rpm-install-dev RUN __install gcc DO +BUILD_EXAMPLE_STATE_MACHINE SAVE ARTIFACT /s/example-state-machine / rpm-runtime-test: # Attempt to run a libmongocrypt-using app with the runtime RPM installed FROM +rpm-install-runtime COPY +rpm-devel-test/example-state-machine /s/ COPY --dir test/example /s/test/example RUN cd /s/ && /s/example-state-machine # A target to build the debian package. Options: # • --env=[...] (default: deb-unstable) # · Set the environment for the build. Affects which packages are available # for build dependencies. # NOTE: Uncommited local changes will be ignored and not affect the result! deb-build: ARG env=deb-unstable FROM +env.$env RUN __install git-buildpackage fakeroot debhelper cmake libbson-dev \ libintelrdfpmath-dev DO +COPY_SOURCE WORKDIR /s/libmongocrypt RUN git clean -fdx && git reset --hard RUN python3 etc/calc_release_version.py > VERSION_CURRENT RUN git add -f VERSION_CURRENT && \ git -c user.name=anon -c user.email=anon@localhost \ commit VERSION_CURRENT -m 'Set version' && \ env LANG=C bash debian/build_snapshot.sh && \ debc ../*.changes && \ dpkg -i ../*.deb SAVE ARTIFACT /s/*.deb /debs/ deb-install-runtime: # Install the runtime deb package FROM +init --base=docker.io/library/debian:unstable COPY +deb-build/debs/libmongocrypt0*.deb /tmp/lmc.deb RUN __install /tmp/lmc.deb deb-install-dev: # Install the development deb package FROM +deb-install-runtime COPY +deb-build/debs/libmongocrypt-dev*.deb /tmp/lmc-dev.deb RUN __install /tmp/lmc-dev.deb deb-dev-test: # Attempt to build a small app using pkg-config and the dev deb package FROM +deb-install-dev RUN __install pkg-config gcc DO +BUILD_EXAMPLE_STATE_MACHINE SAVE ARTIFACT /s/example-state-machine / deb-runtime-test: # Attempt to run a libmongocrypt-using app with the runtime DEB installed FROM +deb-install-runtime COPY +deb-dev-test/example-state-machine /s/ COPY --dir test/example /s/test/example RUN cd /s/ && /s/example-state-machine packaging-full-test: BUILD +deb-runtime-test BUILD +rpm-runtime-test check-format: FROM python:3.11.2-slim-buster RUN pip install pipx COPY etc/format* /X/etc/ COPY .evergreen/init.sh /X/.evergreen/ RUN /X/etc/format.sh # Does nothing, but warms the cache COPY --dir .clang-format src test /X/ RUN /X/etc/format-all.sh --dry-run -Werror --verbose # The main "build" target. Options: # • --env=[...] (default "u22") # · Set the environment for the build. Any name of and "env." targets # can be used. # • --persist_build={true,false} (default "true") # · Persist the build directory between executions. Enables incremental # compilation and reusing of configuration between builds. The build # directory is NOT shared between different "--env" environments, only # within a single environment. build: ARG env=u22 FROM +env.$env DO +CACHE_WARMUP DO +COPY_SOURCE WORKDIR /s ARG persist_build=true IF $persist_build CACHE /s/libmongocrypt/cmake-build END RUN env USE_NINJA=1 bash libmongocrypt/.evergreen/build_all.sh SAVE ARTIFACT /s/install /libmongocrypt-install # `create-deb-packages-and-repos` creates the .deb packages and repo directories intended for the PPA on debian-like distros. Options: # • --env=[...] # · Set the environment for the build. Only debian-like environments are supported. # • --packager_distro=[...] is passed to `create-packages-and-repos.sh` # • --packager_arch=[...] is passed to `create-packages-and-repos.sh` create-deb-packages-and-repos: ARG env FROM +env.$env DO +CACHE_WARMUP DO +COPY_SOURCE WORKDIR /s RUN __install dh-make dpkg-dev apt-utils ARG packager_distro ARG packager_arch RUN env \ WORKDIR=/s \ PYTHON=python3 \ HAS_PACKAGES=true \ PACKAGER_DISTRO=$packager_distro \ PACKAGER_ARCH=$packager_arch \ bash libmongocrypt/.evergreen/create-packages-and-repos.sh SAVE ARTIFACT libmongocrypt/repo AS LOCAL repo # `test-deb-packages-from-ppa` tests Debian and Ubuntu packages installed on the PPA. # • --env=[...] (default "deb11") # · Set the environment for the build. Only debian-like environments are supported. # • --distro=[...] (default "debian bullseye") # · Has the form: "(debian|ubuntu) (name)". Must match distro set for `--env`. # • --version=[...] (default "development"). The libmongocrypt package version. # · May refer to a release branch (e.g. "1.8"). Release branch packages are updated on a tagged release. # · "development" packages are updated by the `publish-packages` tasks every commit. test-deb-packages-from-ppa: ARG env="deb11" ARG distro="debian bullseye" ARG version="development" FROM +env.$env WORKDIR /s RUN __install apt-transport-https # Install libmongocrypt following install steps described in README.md: RUN curl -s --location https://pgp.mongodb.com/libmongocrypt.asc | gpg --dearmor >/etc/apt/trusted.gpg.d/libmongocrypt.gpg RUN echo "deb https://libmongocrypt.s3.amazonaws.com/apt/$distro/libmongocrypt/$version main" | tee /etc/apt/sources.list.d/libmongocrypt.list # Test using libmongocrypt: RUN __install libmongocrypt-dev gcc RUN echo " #include #include int main(void) { const char *ver = mongocrypt_version(NULL); printf (\"Using libmongocrypt %s\", ver); }" > test.c RUN gcc -o test.out test.c $(pkg-config --libs --cflags libmongocrypt) RUN ./test.out # `sign` uses Garasign to sign a file with the libmongocrypt key. # Requires prior authentication with Artifactory. # See: https://docs.devprod.prod.corp.mongodb.com/release-tools-container-images/garasign/garasign_signing/. sign: ARG --required file_to_sign ARG --required output_file FROM artifactory.corp.mongodb.com/release-tools-container-registry-local/garasign-gpg WORKDIR /s COPY ${file_to_sign} /s/file RUN --secret garasign_username --secret garasign_password \ GRS_CONFIG_USER1_USERNAME=${garasign_username} \ GRS_CONFIG_USER1_PASSWORD=${garasign_password} \ /bin/bash -c "gpgloader && gpg --yes -v --armor -o /s/file.asc --detach-sign /s/file" # Verify the signature RUN touch /keyring RUN curl -sS https://pgp.mongodb.com/libmongocrypt.pub | gpg -q --no-default-keyring --keyring "/keyring" --import - RUN gpgv --keyring "/keyring" "/s/file.asc" "/s/file" SAVE ARTIFACT /s/file.asc AS LOCAL ${output_file} # silkbomb: # An environment with the `silkbomb` command. # # See https://docs.devprod.prod.corp.mongodb.com/mms/python/src/sbom/silkbomb/ for documentation of silkbomb. silkbomb: FROM artifactory.corp.mongodb.com/release-tools-container-registry-public-local/silkbomb:1.0 # Alias the silkbom executable to a simpler name: RUN ln -s /python/src/sbom/silkbomb/bin /usr/local/bin/silkbomb # sbom-generate: # Generate/update the etc/cyclonedx.sbom.json file from the etc/purls.txt file. # # This target will update the existing etc/cyclonedx.sbom.json file in-place based # on the content of etc/purls.txt. # sbom-generate: FROM +silkbomb # Copy in the relevant files: WORKDIR /s COPY etc/purls.txt etc/cyclonedx.sbom.json /s/ # Update the SBOM file: RUN silkbomb update \ --purls purls.txt \ --sbom-in cyclonedx.sbom.json \ --sbom-out cyclonedx.sbom.json # Save the result back to the host: SAVE ARTIFACT /s/cyclonedx.sbom.json AS LOCAL etc/cyclonedx.sbom.json # sbom-download: # Download the Augmented SBOM file from Silk. # # See https://wiki.corp.mongodb.com/display/DRIVERS/Using+AWS+Secrets+Manager+to+Store+Testing+Secrets for instructions to get secrets from AWS Secrets Manager. Secrets are available under `drivers/libmongocrypt`. # sbom-download: ARG --required out ARG --required branch FROM +silkbomb WORKDIR /s # Download the Augmented SBOM file: RUN --no-cache --secret silk_client_id --secret silk_client_secret \ SILK_CLIENT_ID=${silk_client_id} \ SILK_CLIENT_SECRET=${silk_client_secret} \ silkbomb download \ --sbom-out cyclonedx.augmented.sbom.json \ --silk-asset-group libmongocrypt-${branch} # Save the result back to the host: SAVE ARTIFACT /s/cyclonedx.augmented.sbom.json AS LOCAL ${out} RUN echo "Augmented SBOM saved to ${out}" # silk-create-asset-group: # Create an asset group for Silk. # # See https://wiki.corp.mongodb.com/display/DRIVERS/Using+AWS+Secrets+Manager+to+Store+Testing+Secrets for instructions to get secrets from AWS Secrets Manager. Secrets are available under `drivers/libmongocrypt`. # silk-create-asset-group: ARG --required branch FROM +env.alpine RUN __install curl jq COPY etc/silk-create-asset-group.sh /s/silk-create-asset-group.sh RUN --no-cache --secret silk_client_id --secret silk_client_secret \ silk_client_id=${silk_client_id} \ silk_client_secret=${silk_client_secret} \ branch=${branch} \ /s/silk-create-asset-group.sh libmongocrypt-1.11.0/LICENSE000066400000000000000000000261341465326363200155070ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.libmongocrypt-1.11.0/README.md000066400000000000000000000177101465326363200157610ustar00rootroot00000000000000# libmongocrypt # The companion C library for client side encryption in drivers. # Bugs / Feature Requests # If you have encountered a bug, or would like to see a new feature in libmongocrypt, please open a case in our issue management tool, JIRA: - [Create an account and login](https://jira.mongodb.org). - Navigate to [the MONGOCRYPT project](https://jira.mongodb.org/projects/MONGOCRYPT). - Click **Create Issue** - Please provide as much information as possible about the issue type and how to reproduce it. ## Documentation ## See [The Integration Guide](integrating.md) to integrate with your driver. See [mongocrypt.h](src/mongocrypt.h) for the public API reference. The documentation can be rendered into HTML with doxygen. Run `doxygen ./doc/Doxygen`, then open `./doc/html/index.html`. ## Building libmongocrypt ## On Windows and macOS, libmongocrypt can use the platform's default encryption APIs as its encryption backend. On other systems, one will want to install the OpenSSL development libraries, which libmongocrypt will use as the default encryption backend. Then build libmongocrypt: ``` git clone https://github.com/mongodb/libmongocrypt cd libmongocrypt mkdir cmake-build && cd cmake-build cmake ../ make ``` This builds libmongocrypt.dylib and test-libmongocrypt, in the cmake-build directory. ## Installing libmongocrypt on macOS ## Install the latest release of libmongocrypt with the following. ``` brew install mongodb/brew/libmongocrypt ``` To install the latest unstable development version of libmongocrypt, use `brew install mongodb/brew/libmongocrypt --HEAD`. Do not use the unstable version of libmongocrypt in a production environment. ## Building libmongocrypt from source on macOS ## First install [Homebrew according to its own instructions](https://brew.sh/). Install the XCode Command Line Tools: ``` xcode-select --install ``` Then clone and build libmongocrypt: ``` git clone https://github.com/mongodb/libmongocrypt.git cd libmongocrypt cmake . cmake --build . --target install ``` Then, libmongocrypt can be used with pkg-config: ``` pkg-config libmongocrypt --libs --cflags ``` Or use cmake's `find_package`: ``` find_package (mongocrypt) # Then link against mongo::mongocrypt ``` ## Installing libmongocrypt on Windows ## A Windows DLL for x86_64 is available on the Github Releases page. See the [latest release](https://github.com/mongodb/libmongocrypt/releases/latest). Use `gpg` to verify the signature. The public key for `libmongocrypt` is available on https://pgp.mongodb.com/. ### Testing ### `test-mongocrypt` mocks all I/O with files stored in the `test/data` and `test/example` directories. Run `test-mongocrypt` from the source directory: ``` cd libmongocrypt ./cmake-build/test-mongocrypt ``` libmongocrypt is continuously built and published on evergreen. Submit patch builds to this evergreen project when making changes to test on supported platforms. The latest tarball containing libmongocrypt built on all supported variants is [published here](https://s3.amazonaws.com/mciuploads/libmongocrypt/all/master/latest/libmongocrypt-all.tar.gz). ### Troubleshooting ### If OpenSSL is installed in a non-default directory, pass `-DOPENSSL_ROOT_DIR=/path/to/openssl` to the cmake command for libmongocrypt. If there are errors with cmake configuration, send the set of steps you performed to the maintainers of this project. If there are compilation or linker errors, run `make` again, setting `VERBOSE=1` in the environment or on the command line (which shows exact compile and link commands), and send the output to the maintainers of this project. ### Design Principles ### The design of libmongocrypt adheres to these principles. #### Easy to integrate #### The main reason behind creating a C library is to make it easier for drivers to support FLE. Some consequences of this principle: the API is minimal, structs are opaque, and global initialization is lazy. #### Lightweight #### We decided against the "have libmongocrypt do everything" approach because it complicated integration, especially with async drivers. Because of this we decided no I/O occurs in libmongocrypt. ### Releasing ### See [releasing](./doc/releasing.md). ## Installing libmongocrypt From Distribution Packages ## Distribution packages (i.e., .deb/.rpm) are built and published for several Linux distributions. The installation of these packages for supported platforms is documented here. ### Unstable Development Distribution Packages ### To install the latest unstable development package, change `1.11` to `development` in the package URLs listed in the subsequent instructions. For example, `https://libmongocrypt.s3.amazonaws.com/apt/ubuntu /libmongocrypt/1.11` in the instructions would become `https://libmongocrypt.s3.amazonaws.com/apt/ubuntu /libmongocrypt/development`. Do not use the unstable version of libmongocrypt in a production environment. ### .deb Packages (Debian and Ubuntu) ### First, import the public key used to sign the package repositories: ``` sudo sh -c 'curl -s --location https://pgp.mongodb.com/libmongocrypt.asc | gpg --dearmor >/etc/apt/trusted.gpg.d/libmongocrypt.gpg' ``` Second, create a list entry for the repository. For Ubuntu systems (be sure to change `` to `xenial`, `bionic`, `focal`, or `jammy`, as appropriate to your system): ``` echo "deb https://libmongocrypt.s3.amazonaws.com/apt/ubuntu /libmongocrypt/1.11 universe" | sudo tee /etc/apt/sources.list.d/libmongocrypt.list ``` For Debian systems (be sure to change `` to `stretch`, `buster`, `bullseye`, or `bookworm` as appropriate to your system): ``` echo "deb https://libmongocrypt.s3.amazonaws.com/apt/debian /libmongocrypt/1.11 main" | sudo tee /etc/apt/sources.list.d/libmongocrypt.list ``` Third, update the package cache: ``` sudo apt-get update ``` Finally, install the libmongocrypt packages: ``` sudo apt-get install -y libmongocrypt-dev ``` ### .rpm Packages (RedHat, Suse, and Amazon) ### #### RedHat Enterprise Linux #### Create the file `/etc/yum.repos.d/libmongocrypt.repo` with contents: ``` [libmongocrypt] name=libmongocrypt repository baseurl=https://libmongocrypt.s3.amazonaws.com/yum/redhat/$releasever/libmongocrypt/1.11/x86_64 gpgcheck=1 enabled=1 gpgkey=https://pgp.mongodb.com/libmongocrypt.asc ``` Then install the libmongocrypt packages: ``` sudo yum install -y libmongocrypt ``` #### Amazon Linux 2023 #### Create the file `/etc/yum.repos.d/libmongocrypt.repo` with contents: ``` [libmongocrypt] name=libmongocrypt repository baseurl=https://libmongocrypt.s3.amazonaws.com/yum/amazon/2023/libmongocrypt/1.11/x86_64 gpgcheck=1 enabled=1 gpgkey=https://pgp.mongodb.com/libmongocrypt.asc ``` Then install the libmongocrypt packages: ``` sudo yum install -y libmongocrypt ``` #### Amazon Linux 2 #### Create the file `/etc/yum.repos.d/libmongocrypt.repo` with contents: ``` [libmongocrypt] name=libmongocrypt repository baseurl=https://libmongocrypt.s3.amazonaws.com/yum/amazon/2/libmongocrypt/1.11/x86_64 gpgcheck=1 enabled=1 gpgkey=https://pgp.mongodb.com/libmongocrypt.asc ``` Then install the libmongocrypt packages: ``` sudo yum install -y libmongocrypt ``` #### Amazon Linux #### Create the file `/etc/yum.repos.d/libmongocrypt.repo` with contents: ``` [libmongocrypt] name=libmongocrypt repository baseurl=https://libmongocrypt.s3.amazonaws.com/yum/amazon/2013.03/libmongocrypt/1.11/x86_64 gpgcheck=1 enabled=1 gpgkey=https://pgp.mongodb.com/libmongocrypt.asc ``` Then install the libmongocrypt packages: ``` sudo yum install -y libmongocrypt ``` #### Suse #### First, import the public key used to sign the package repositories: ``` sudo rpm --import https://pgp.mongodb.com/libmongocrypt.asc ``` Second, add the repository (be sure to change `` to `12` or `15`, as appropriate to your system): ``` sudo zypper addrepo --gpgcheck "https://libmongocrypt.s3.amazonaws.com/zypper/suse//libmongocrypt/1.11/x86_64" libmongocrypt ``` Finally, install the libmongocrypt packages: ``` sudo zypper -n install libmongocrypt ``` libmongocrypt-1.11.0/bindings/000077500000000000000000000000001465326363200162715ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/cs/000077500000000000000000000000001465326363200166765ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/cs/.gitignore000066400000000000000000000001471465326363200206700ustar00rootroot00000000000000# C# binary directories bin/ obj/ # Rider settings .idea/ # VS settings .vs/ # Other /Scripts/Tools libmongocrypt-1.11.0/bindings/cs/CMakeLists.txt000066400000000000000000000022471465326363200214430ustar00rootroot00000000000000 configure_file(cs.sln cs.sln COPYONLY) configure_file(MongoDB.Driver.snk MongoDB.Driver.snk COPYONLY) configure_file(MongoDB.Libmongocrypt/MongoDB.Libmongocrypt.csproj MongoDB.Libmongocrypt/MongoDB.Libmongocrypt.csproj COPYONLY) configure_file(MongoDB.Libmongocrypt/Package.include.template.csproj MongoDB.Libmongocrypt/Package.csproj.include) configure_file(MongoDB.Libmongocrypt.Test/MongoDB.Libmongocrypt.Test.csproj MongoDB.Libmongocrypt.Test/MongoDB.Libmongocrypt.Test.csproj COPYONLY) configure_file(MongoDB.Libmongocrypt.Test/Package.include.template.csproj MongoDB.Libmongocrypt.Test/Package.csproj.include) configure_file(MongoDB.Libmongocrypt.Test/MongoDB.Libmongocrypt.Test.csproj MongoDB.Libmongocrypt.Test32/MongoDB.Libmongocrypt.Test32.csproj COPYONLY) configure_file(MongoDB.Libmongocrypt.Test/Package.include.template.csproj MongoDB.Libmongocrypt.Test32/Package.csproj.include) configure_file(MongoDB.Libmongocrypt.Example/MongoDB.Libmongocrypt.Example.csproj MongoDB.Libmongocrypt.Example/MongoDB.Libmongocrypt.Example.csproj COPYONLY) configure_file(MongoDB.Libmongocrypt.Example/Package.include.template.csproj MongoDB.Libmongocrypt.Example/Package.csproj.include) libmongocrypt-1.11.0/bindings/cs/MongoDB.Driver.snk000066400000000000000000000011241465326363200221300ustar00rootroot00000000000000$RSA25( 8ƒÀ uÈŽ Ú<é;bì½^’ JŒr8VOM/OhjÊ(ɲAÜ:‡vyÁEV++/_âÁbN”Óÿ{”¿o×*ïAþ%réÑÆcæŒÐígsJBË3;€Ž8gËæ1“rã.@Ÿ±úbý¶IL%0æJ@äÖîo{°Ús¿Â"Þ£íËÒ_„dõÀj/Ì•aqh-H3ÛKß"h£aÏNìPK=]¥j>bÐt2îË«õ÷›T«túÙ‘%ý ÔÊ;@„ â"jø8»ºó¢ d¿}€¤áØGu‹u -IœD»©U.ZW†p™P°”ö¡èi’›”VF,Ÿw±±$y³ð¤Ü*q…ÑX^¢.uœ«1ê²`÷iÒ8Æ4DC^f¨øÀŸœU×d2v¼,³b u·ø|¹È1‰‘¥ÜT/iµ·Ï¡<}¡’?÷—é<ókÏŽHÄ^b (úÖÚ?]7=§>ÜM³m1¶÷(Ùlibmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Example/000077500000000000000000000000001465326363200244045ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Example/MongoDB.Libmongocrypt.Example.csproj000066400000000000000000000013771465326363200333440ustar00rootroot00000000000000 Exe net472;netcoreapp2.1 net472;netcoreapp2.1 netcoreapp2.1 AnyCPU false libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Example/Package.include.template.csproj000066400000000000000000000004741465326363200324220ustar00rootroot00000000000000 false @CMAKE_CURRENT_LIST_DIR@/MongoDB.Libmongocrypt.Example libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Example/Program.cs000066400000000000000000000402051465326363200263430ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using MongoDB.Bson; using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Libmongocrypt; using MongoDB.Driver; using System; using System.IO; using System.Net.Security; using System.Net.Sockets; using System.Security.Cryptography.X509Certificates; namespace drivertest { class BsonUtil { public static BsonDocument ToDocument(Binary bin) { MemoryStream stream = new MemoryStream(bin.ToArray()); using (var jsonReader = new BsonBinaryReader(stream)) { var context = BsonDeserializationContext.CreateRoot(jsonReader); return BsonDocumentSerializer.Instance.Deserialize(context); } } public static byte[] ToBytes(BsonDocument doc) { BsonBinaryWriterSettings settings = new BsonBinaryWriterSettings() { // C# driver "magically" changes UUIDs underneath by default so tell it not to GuidRepresentation = GuidRepresentation.Standard }; return doc.ToBson(null, settings); } public static BsonDocument Concat(BsonDocument doc1, BsonDocument doc2) { BsonDocument dest = new BsonDocument(); BsonDocumentWriter writer = new BsonDocumentWriter(dest); var context = BsonSerializationContext.CreateRoot(writer); writer.WriteStartDocument(); foreach (var field in doc1) { writer.WriteName(field.Name); BsonValueSerializer.Instance.Serialize(context, field.Value); } foreach (var field in doc2) { writer.WriteName(field.Name); BsonValueSerializer.Instance.Serialize(context, field.Value); } writer.WriteEndDocument(); return writer.Document; } public static BsonDocument FromJSON(string str) { using (var jsonReader = new JsonReader(str)) { var context = BsonDeserializationContext.CreateRoot(jsonReader); return BsonDocumentSerializer.Instance.Deserialize(context); } } } class MongoCryptDController { MongoClient _clientCryptD; IMongoCollection _keyVault; Uri _kmsEndpoint; public MongoCryptDController(MongoUrl urlCryptD, IMongoCollection keyVault, Uri kmsEndpoint) { _clientCryptD = new MongoClient(urlCryptD); _keyVault = keyVault; _kmsEndpoint = kmsEndpoint; } public Guid GenerateKey(KmsCredentials credentials, KmsKeyId kmsKeyId) { var options = new CryptOptions(new[] { credentials }); BsonDocument key = null; using (var cryptClient = CryptClientFactory.Create(options)) using (var context = cryptClient.StartCreateDataKeyContext(kmsKeyId)) { key = ProcessState(context, _keyVault.Database, null); } _keyVault.InsertOne(key); Guid g = key["_id"].AsGuid; return g; } public BsonDocument EncryptCommand(KmsCredentials credentials, IMongoCollection coll, BsonDocument cmd) { var options = new CryptOptions(new[] { credentials }); using (var cryptClient = CryptClientFactory.Create(options)) using (var context = cryptClient.StartEncryptionContext(coll.Database.DatabaseNamespace.DatabaseName, command: BsonUtil.ToBytes(cmd))) { return ProcessState(context, coll.Database, cmd); } } public BsonDocument DecryptCommand(KmsCredentials credentials, IMongoDatabase db, BsonDocument doc) { var options = new CryptOptions(new[] { credentials }); using (var cryptClient = CryptClientFactory.Create(options)) using (var context = cryptClient.StartDecryptionContext(BsonUtil.ToBytes(doc))) { return ProcessState(context, db, null); } } public static bool ValidateServerCertificate( object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.None) return true; Console.WriteLine("Certificate error: {0}", sslPolicyErrors); // Ignore certificate errors when testing against localhost return true; } void DoKmsRequest(KmsRequest request) { TcpClient tcpClient = new TcpClient(); Console.WriteLine("KMS: " + request.Endpoint); // change me to use the mock if (_kmsEndpoint != null) { tcpClient.Connect(_kmsEndpoint.DnsSafeHost, _kmsEndpoint.Port); } else { tcpClient.Connect(request.Endpoint, 443); } SslStream stream = new SslStream(tcpClient.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate)); stream.AuthenticateAsClient("localhost"); Binary bin = request.Message; stream.Write(bin.ToArray()); byte[] buffer = new byte[4096]; while (request.BytesNeeded > 0) { MemoryStream memBuffer = new MemoryStream(); int read = stream.Read(buffer, 0, buffer.Length); if (read > 0) { memBuffer.Write(buffer, 0, read); } request.Feed(memBuffer.ToArray()); } } private BsonDocument ProcessState(CryptContext context, IMongoDatabase db, BsonDocument cmd) { BsonDocument ret = cmd; while (!context.IsDone) { Console.WriteLine("\n----------------------------------\nState:" + context.State); switch (context.State) { case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_COLLINFO: { var binary = context.GetOperation(); var doc = BsonUtil.ToDocument(binary); Console.WriteLine("ListCollections Query: " + doc); ListCollectionsOptions opts = new ListCollectionsOptions() { Filter = new BsonDocumentFilterDefinition(doc) }; var reply = db.ListCollections(opts); var replyDocs = reply.ToList(); Console.WriteLine("ListCollections Reply: " + replyDocs); foreach (var replyDoc in replyDocs) { Console.WriteLine("ListCollections Reply: " + replyDoc); context.Feed(BsonUtil.ToBytes(replyDoc)); } context.MarkDone(); break; } case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_MARKINGS: { var binary = context.GetOperation(); var commandWithSchema = BsonUtil.ToDocument(binary); Console.WriteLine("MongoCryptD Query: " + commandWithSchema); var cryptDB = _clientCryptD.GetDatabase(db.DatabaseNamespace.DatabaseName); var reply = cryptDB.RunCommand(new BsonDocumentCommand(commandWithSchema)); Console.WriteLine("MongoCryptD Reply: " + reply); context.Feed(BsonUtil.ToBytes(reply)); context.MarkDone(); break; } case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_KEYS: { var binary = context.GetOperation(); Console.WriteLine("Buffer:" + BitConverter.ToString(binary.ToArray())); var doc = BsonUtil.ToDocument(binary); Console.WriteLine("GetKeys Query: " + doc); var reply = _keyVault.Find(new BsonDocumentFilterDefinition(doc)); var replyDocs = reply.ToList(); Console.WriteLine("GetKeys Reply: " + replyDocs); foreach (var replyDoc in replyDocs) { context.Feed(BsonUtil.ToBytes(replyDoc)); } context.MarkDone(); break; } case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_KMS: { var requests = context.GetKmsMessageRequests(); foreach (var req in requests) { DoKmsRequest(req); } requests.MarkDone(); break; } case CryptContext.StateCode.MONGOCRYPT_CTX_READY: { Binary b = context.FinalizeForEncryption(); Console.WriteLine("Buffer:" + BitConverter.ToString(b.ToArray())); ret = BsonUtil.ToDocument(b); break; } case CryptContext.StateCode.MONGOCRYPT_CTX_DONE: { Console.WriteLine("DONE!!"); return ret; } case CryptContext.StateCode.MONGOCRYPT_CTX_ERROR: { throw new NotImplementedException(); } } } return ret; } } class Program { static IMongoCollection SetupKeyStore(MongoClient client) { var dbAdmin = client.GetDatabase("admin"); var collKeyVault = dbAdmin.GetCollection("datakeys"); // Clear the key vault collKeyVault.DeleteMany(new BsonDocumentFilterDefinition(new BsonDocument())); return collKeyVault; } static IMongoCollection SetupTestCollection(MongoClient client, Guid keyID) { var database = client.GetDatabase("test"); // Reset state database.DropCollection("test"); var s = new BsonDocument { { "$jsonSchema" , new BsonDocument { { "type", "object" }, { "properties" , new BsonDocument { { "ssn" , new BsonDocument { { "encrypt" , new BsonDocument { { "keyId" , new BsonArray( new BsonValue[] { keyID } ) }, { "bsonType" , "string"}, { "algorithm" , "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" }, } } } } } } } } }; database.CreateCollection("test", new CreateCollectionOptions() { Validator = new BsonDocumentFilterDefinition(s) }); return database.GetCollection("test"); } static string GetEnvironmenVariabletOrValue(string env, string def) { string value = Environment.GetEnvironmentVariable(env); if (value != null) { return value; } return def; } static void Main(string[] args) { // The C# driver transmutes data unless you specify this stupid line! BsonDefaults.GuidRepresentation = GuidRepresentation.Standard; Console.WriteLine("Using url: " + args); // or change me to use the mock Uri kmsURL = Environment.GetEnvironmentVariable("FLE_AWS_SECRET_ACCESS_KEY") != null ? null : new Uri("https://localhost:8000"); var cryptDUrl = new MongoUrl("mongodb://localhost:27020"); var client = new MongoClient("mongodb://localhost:27017"); IMongoCollection collKeyVault = SetupKeyStore(client); var controller = new MongoCryptDController(cryptDUrl, collKeyVault, kmsURL); var awsKeyId = new KmsKeyId( new BsonDocument { { "provider", "aws" }, { "region", "us-east-1" }, { "key", "arn:aws:kms:us-east-1:579766882180:key/0689eb07-d588-4bbf-a83e-42157a92576b" } }.ToBson()); var kmsCredentials = new KmsCredentials( new BsonDocument { { "aws", new BsonDocument { { "secretAccessKey", GetEnvironmenVariabletOrValue("FLE_AWS_SECRET_ACCESS_KEY", "us-east-1") }, { "accessKeyId", GetEnvironmenVariabletOrValue("FLE_AWS_ACCESS_KEY_ID", "us-east-1") } } } }.ToBson()); Guid keyID = controller.GenerateKey(kmsCredentials, awsKeyId); IMongoCollection collection = SetupTestCollection(client, keyID); var database = collection.Database; // Insert a document with SSN var insertDoc = new BsonDocument { { "ssn" , "123-45-6789" }, }; var insertDocCmd = new BsonDocument { { "insert" , "test" }, { "documents", new BsonArray(new BsonValue[] { insertDoc }) } }; var insertEncryptedDoc = new BsonDocument(controller.EncryptCommand(kmsCredentials, collection, insertDocCmd)); Console.WriteLine("Insert Doc: " + insertEncryptedDoc); insertEncryptedDoc.Remove("$db"); database.RunCommand(new BsonDocumentCommand(insertEncryptedDoc)); var findDoc = BsonUtil.FromJSON(@"{ 'find': 'test', 'filter' : { '$or': [{ '_id': 1},{ 'ssn': '123-45-6789'}]}, }"); var findCmd = new BsonDocumentCommand(controller.EncryptCommand(kmsCredentials, collection, findDoc)); Console.WriteLine("Find CMD: " + findCmd.Document); findCmd.Document.Remove("$db"); var commandResult = database.RunCommand(findCmd); Console.WriteLine("Find Result: " + commandResult); var decryptedDocument = controller.DecryptCommand(kmsCredentials, database, commandResult); Console.WriteLine("Find Result (DECRYPTED): " + decryptedDocument); } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/000077500000000000000000000000001465326363200237305ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/BasicTests.cs000066400000000000000000001004301465326363200263210ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using MongoDB.Bson; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using Xunit; using System.Text; using FluentAssertions; using Xunit.Abstractions; using MongoDB.Libmongocrypt.Test.Callbacks; namespace MongoDB.Libmongocrypt.Test { public class BasicTests { private static ITestOutputHelper _output; private const string AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"; private const string AEAD_AES_256_CBC_HMAC_SHA_512_Random = "AEAD_AES_256_CBC_HMAC_SHA_512-Random"; public BasicTests(ITestOutputHelper output) { _output = output; } [Fact] public void EncryptQuery() { using (var cryptClient = CryptClientFactory.Create(CreateOptions())) using (var context = cryptClient.StartEncryptionContext("test", command: BsonUtil.ToBytes(ReadJsonTestFile("cmd.json")))) { var (_, bsonCommand) = ProcessContextToCompletion(context); bsonCommand.Should().Equal((ReadJsonTestFile("encrypted-command.json"))); } } [Fact] public void EncryptQueryStepwise() { using (var cryptClient = CryptClientFactory.Create(CreateOptions())) using (var context = cryptClient.StartEncryptionContext("test", command: BsonUtil.ToBytes(ReadJsonTestFile("cmd.json")))) { var (state, _, operationSent) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); operationSent.Should().Equal((ReadJsonTestFile("list-collections-filter.json"))); (state, _, operationSent) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); operationSent.Should().Equal(ReadJsonTestFile("mongocryptd-command.json")); (state, _, operationSent) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_KEYS); operationSent.Should().Equal(ReadJsonTestFile("key-filter.json")); (state, _, _) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_NEED_KMS); // kms fluent assertions inside ProcessState() (state, _, operationSent) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_READY); operationSent.Should().Equal((ReadJsonTestFile("encrypted-command.json"))); } } [Fact] public void EncryptQueryWithSchemaStepwise() { var listCollectionsReply = ReadJsonTestFile("collection-info.json"); var schema = new BsonDocument("test.test", listCollectionsReply["options"]["validator"]["$jsonSchema"]); var options = new CryptOptions( new[] { CreateKmsCredentials("aws") }, BsonUtil.ToBytes(schema)); using (var cryptClient = CryptClientFactory.Create(options)) using (var context = cryptClient.StartEncryptionContext( db: "test", command: BsonUtil.ToBytes(ReadJsonTestFile("cmd.json")))) { var (state, _, operationSent) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); var mongoCryptdCommand = ReadJsonTestFile("mongocryptd-command.json"); mongoCryptdCommand["isRemoteSchema"] = false; operationSent.Should().Equal(mongoCryptdCommand); (state, _, operationSent) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_KEYS); operationSent.Should().Equal(ReadJsonTestFile("key-filter.json")); (state, _, _) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_NEED_KMS); // kms fluent assertions inside ProcessState() (state, _, operationSent) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_READY); operationSent.Should().Equal((ReadJsonTestFile("encrypted-command.json"))); } } [Fact] public void DecryptQuery() { using (var cryptClient = CryptClientFactory.Create(CreateOptions())) using (var context = cryptClient.StartDecryptionContext(BsonUtil.ToBytes(ReadJsonTestFile("encrypted-command-reply.json")))) { var (_, bsonCommand) = ProcessContextToCompletion(context); bsonCommand.Should().Equal(ReadJsonTestFile("command-reply.json")); } } [Fact] public void DecryptQueryStepwise() { using (var cryptClient = CryptClientFactory.Create(CreateOptions())) using (var context = cryptClient.StartDecryptionContext(BsonUtil.ToBytes(ReadJsonTestFile("encrypted-command-reply.json")))) { var (state, _, operationProduced) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_KEYS); operationProduced.Should().Equal(ReadJsonTestFile("key-filter.json")); (state, _, _) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_NEED_KMS); // kms fluent assertions inside ProcessState() (state, _, operationProduced) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_READY); operationProduced.Should().Equal(ReadJsonTestFile("command-reply.json")); (state, _, _) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_DONE); } } [Fact] public void EncryptBadBson() { using (var cryptClient = CryptClientFactory.Create(CreateOptions())) { Func startEncryptionContext = () => cryptClient.StartEncryptionContext("test", command: new byte[] { 0x1, 0x2, 0x3 }); // Ensure if we encrypt non-sense, it throws an exception demonstrating our exception code is good var exception = Record.Exception(startEncryptionContext); exception.Should().BeOfType(); } } [Fact] public void EncryptExplicit() { var keyDoc = ReadJsonTestFile("key-document.json"); var keyId = keyDoc["_id"].AsBsonBinaryData.Bytes; BsonDocument doc = new BsonDocument() { { "v" , "hello" }, }; var testData = BsonUtil.ToBytes(doc); byte[] encryptedBytes; using (var cryptClient = CryptClientFactory.Create(CreateOptions())) using (var context = StartExplicitEncryptionContextWithKeyId(cryptClient, keyId, AEAD_AES_256_CBC_HMAC_SHA_512_Random, testData)) { var (encryptedBinary, encryptedDocument) = ProcessContextToCompletion(context); encryptedBytes = encryptedBinary.ToArray(); // need to copy bytes out before the context gets destroyed } using (var cryptClient = CryptClientFactory.Create(CreateOptions())) using (var context = cryptClient.StartExplicitDecryptionContext(encryptedBytes)) { var (decryptedResult, _) = ProcessContextToCompletion(context); decryptedResult.ToArray().Should().Equal(testData); } } [Fact] public void EncryptExplicitStepwise() { var keyDoc = ReadJsonTestFile("key-document.json"); var keyId = keyDoc["_id"].AsBsonBinaryData.Bytes; var doc = new BsonDocument("v", "hello"); var testData = BsonUtil.ToBytes(doc); using (var cryptClient = CryptClientFactory.Create(CreateOptions())) { byte[] encryptedResult; using (var context = StartExplicitEncryptionContextWithKeyId( cryptClient, keyId: keyId, encryptionAlgorithm: AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic, message: testData)) { var (state, binaryProduced, operationProduced) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_KEYS); operationProduced.Should().Equal(ReadJsonTestFile("key-filter.json")); (state, _, _) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_NEED_KMS); // kms fluent assertions inside ProcessState() (state, binaryProduced, operationProduced) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_READY); operationProduced.Should().Equal(ReadJsonTestFile("encrypted-value.json")); encryptedResult = binaryProduced.ToArray(); // need to copy bytes out before the context gets destroyed (state, _, _) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_DONE); } using (var context = cryptClient.StartExplicitDecryptionContext(encryptedResult)) { var (state, decryptedBinary, _) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_READY); decryptedBinary.ToArray().Should().Equal(testData); (state, _, _) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_DONE); } } } [Fact] public void TestAwsKeyCreationWithEndPoint() { var endpoint = "kms.us-east-1.amazonaws.com"; var keyId = CreateKmsKeyId("aws", endpoint); var key = CreateKmsCredentials("aws"); using (var cryptClient = CryptClientFactory.Create(new CryptOptions(new[] { key }))) using (var context = cryptClient.StartCreateDataKeyContext(keyId)) { var (_, dataKeyDocument) = ProcessContextToCompletion(context, isKmsDecrypt: false); dataKeyDocument["masterKey"]["endpoint"].Should().Be(endpoint); } } [Fact] public void TestAwsKeyCreationWithEndpointStepwise() { var endpoint = "kms.us-east-1.amazonaws.com"; var keyId = CreateKmsKeyId("aws", endpoint); var key = CreateKmsCredentials("aws"); using (var cryptClient = CryptClientFactory.Create(new CryptOptions(new[] { key }))) using (var context = cryptClient.StartCreateDataKeyContext(keyId)) { BsonDocument dataKeyDocument; var (state, _, _) = ProcessState(context, isKmsDecrypt: false); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_NEED_KMS); (state, _, dataKeyDocument) = ProcessState(context, isKmsDecrypt: false); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_READY); dataKeyDocument["masterKey"]["endpoint"].Should().Be(endpoint); (state, _, _) = ProcessState(context, isKmsDecrypt: false); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_DONE); } } [Fact] public void TestAwsKeyCreationWithkeyAltNames() { var keyAltNames = new[] { "KeyMaker", "Architect" }; var keyAltNameDocuments = keyAltNames.Select(name => new BsonDocument("keyAltName", name)); var keyAltNameBuffers = keyAltNameDocuments.Select(BsonUtil.ToBytes); var keyId = CreateKmsKeyId("aws", keyAltNameBuffers: keyAltNameBuffers); var key = CreateKmsCredentials("aws"); using (var cryptClient = CryptClientFactory.Create(new CryptOptions(new[] { key }))) using (var context = cryptClient.StartCreateDataKeyContext(keyId)) { var (_, dataKeyDocument) = ProcessContextToCompletion(context, isKmsDecrypt: false); dataKeyDocument.Should().NotBeNull(); var actualKeyAltNames = dataKeyDocument["keyAltNames"].AsBsonArray.Select(x => x.AsString); var expectedKeyAltNames = keyAltNames.Reverse(); // https://jira.mongodb.org/browse/CDRIVER-3277? actualKeyAltNames.Should().BeEquivalentTo(expectedKeyAltNames); } } [Fact] public void TestAwsKeyCreationWithkeyAltNamesStepwise() { var keyAltNames = new[] { "KeyMaker", "Architect" }; var keyAltNameDocuments = keyAltNames.Select(name => new BsonDocument("keyAltName", name)); var keyAltNameBuffers = keyAltNameDocuments.Select(BsonUtil.ToBytes); var keyId = CreateKmsKeyId("aws", keyAltNameBuffers: keyAltNameBuffers); var key = CreateKmsCredentials("aws"); using (var cryptClient = CryptClientFactory.Create(new CryptOptions(new[] { key }))) using (var context = cryptClient.StartCreateDataKeyContext(keyId)) { BsonDocument dataKeyDocument; var (state, _, _) = ProcessState(context, isKmsDecrypt: false); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_NEED_KMS); (state, _, dataKeyDocument) = ProcessState(context, isKmsDecrypt: false); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_READY); dataKeyDocument.Should().NotBeNull(); var actualKeyAltNames = dataKeyDocument["keyAltNames"].AsBsonArray.Select(x => x.AsString); var expectedKeyAltNames = keyAltNames.Reverse(); // https://jira.mongodb.org/browse/CDRIVER-3277? actualKeyAltNames.Should().BeEquivalentTo(expectedKeyAltNames); (state, _, _) = ProcessState(context, isKmsDecrypt: false); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_DONE); } } [Fact] public void TestLocalKeyCreationWithkeyAltNames() { var keyAltNames = new[] { "KeyMaker", "Architect" }; var keyAltNameDocuments = keyAltNames.Select(name => new BsonDocument("keyAltName", name)); var keyAltNameBuffers = keyAltNameDocuments.Select(BsonUtil.ToBytes); var key = CreateKmsCredentials("local"); var keyId = CreateKmsKeyId("local", keyAltNameBuffers: keyAltNameBuffers); var cryptOptions = new CryptOptions(new[] { key }); using (var cryptClient = CryptClientFactory.Create(cryptOptions)) using (var context = cryptClient.StartCreateDataKeyContext(keyId)) { var (_, dataKeyDocument) = ProcessContextToCompletion(context); dataKeyDocument.Should().NotBeNull(); var actualKeyAltNames = dataKeyDocument["keyAltNames"].AsBsonArray.Select(x => x.AsString); var expectedKeyAltNames = keyAltNames.Reverse(); // https://jira.mongodb.org/browse/CDRIVER-3277? actualKeyAltNames.Should().BeEquivalentTo(expectedKeyAltNames); } } [Fact] public void TestLocalKeyCreationWithkeyAltNamesStepwise() { var keyAltNames = new[] { "KeyMaker", "Architect" }; var keyAltNameDocuments = keyAltNames.Select(name => new BsonDocument("keyAltName", name)); var keyAltNameBuffers = keyAltNameDocuments.Select(BsonUtil.ToBytes); var key = CreateKmsCredentials("local"); var keyId = CreateKmsKeyId("local", keyAltNameBuffers: keyAltNameBuffers); var cryptOptions = new CryptOptions(new[] { key }); using (var cryptClient = CryptClientFactory.Create(cryptOptions)) using (var context = cryptClient.StartCreateDataKeyContext(keyId)) { var (state, _, dataKeyDocument) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_READY); dataKeyDocument.Should().NotBeNull(); var actualKeyAltNames = dataKeyDocument["keyAltNames"].AsBsonArray.Select(x => x.AsString); var expectedKeyAltNames = keyAltNames.Reverse(); // https://jira.mongodb.org/browse/CDRIVER-3277? actualKeyAltNames.Should().BeEquivalentTo(expectedKeyAltNames); (state, _, _) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_DONE); } } [Fact] public void TestLocalKeyCreation() { var key = CreateKmsCredentials("local"); var keyId = CreateKmsKeyId("local"); var cryptOptions = new CryptOptions(new[] { key }); using (var cryptClient = CryptClientFactory.Create(cryptOptions)) using (var context = cryptClient.StartCreateDataKeyContext(keyId)) { var (_, dataKeyDocument) = ProcessContextToCompletion(context); dataKeyDocument.Should().NotBeNull(); } } [Fact] public void TestLocalKeyCreationStepwise() { var key = CreateKmsCredentials("local"); var keyId = CreateKmsKeyId("local"); var cryptOptions = new CryptOptions(new[] { key }); using (var cryptClient = CryptClientFactory.Create(cryptOptions)) using (var context = cryptClient.StartCreateDataKeyContext(keyId)) { var (state, _, dataKeyDocument) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_READY); dataKeyDocument.Should().NotBeNull(); (state, _, _) = ProcessState(context); state.Should().Be(CryptContext.StateCode.MONGOCRYPT_CTX_DONE); } } [Theory] [InlineData("aws")] [InlineData("azure")] #if NETCOREAPP3_0 [InlineData("gcp")] #endif [InlineData("kmip")] public void TestGetKmsProviderName(string kmsName) { var key = CreateKmsCredentials(kmsName); var keyId = CreateKmsKeyId(kmsName); var cryptOptions = new CryptOptions(new[] { key }); using (var cryptClient = CryptClientFactory.Create(cryptOptions)) using (var context = cryptClient.StartCreateDataKeyContext(keyId)) { var request = context.GetKmsMessageRequests().Single(); request.KmsProvider.Should().Be(kmsName); } } // private methods private static KmsCredentials CreateKmsCredentials(string kmsName) { BsonDocument kmsCredentialsDocument; switch (kmsName) { case "local": kmsCredentialsDocument = new BsonDocument { { "local", new BsonDocument { { "key", new BsonBinaryData(new byte[96]) } } } }; break; case "aws": kmsCredentialsDocument = new BsonDocument { { "aws", new BsonDocument { { "secretAccessKey", "dummy" }, { "accessKeyId", "dummy" } } } }; break; case "azure": kmsCredentialsDocument = new BsonDocument { { "azure", new BsonDocument { { "tenantId", "dummy" }, { "clientId", "dummy" }, { "clientSecret", "dummy" } } } }; break; case "gcp": kmsCredentialsDocument = new BsonDocument { { "gcp", new BsonDocument { { "email", "dummy" }, { "privateKey", SigningRSAESPKCSCallbackTests.PrivateKey } } } }; break; case "kmip": kmsCredentialsDocument = new BsonDocument { { "kmip", new BsonDocument { { "endpoint", "dummy" } } } }; break; default: throw new Exception($"Unsupported kms {kmsName}."); } return new KmsCredentials(kmsCredentialsDocument.ToBson()); } private static KmsKeyId CreateKmsKeyId(string kmsName, string endPoint = null, IEnumerable keyAltNameBuffers = null) { BsonDocument datakeyOptionsDocument; switch (kmsName) { case "local": datakeyOptionsDocument = new BsonDocument { { "provider", "local" }, }; break; case "aws": datakeyOptionsDocument = new BsonDocument { { "provider", "aws" }, { "key", "cmk" }, { "region", "us-east-1" }, { "endpoint", () => endPoint, endPoint != null } }; break; case "azure": datakeyOptionsDocument = new BsonDocument { { "provider", "azure" }, { "keyName", "dummy" }, { "keyVaultEndpoint", endPoint ?? "dummy.azure.net" } }; break; case "gcp": datakeyOptionsDocument = new BsonDocument { { "provider", "gcp" }, { "projectId", "dummy" }, { "location", "dummy" }, { "keyRing", "dummy" }, { "keyName", "dummy" }, { "endpoint", () => endPoint, endPoint != null } }; break; case "kmip": datakeyOptionsDocument = new BsonDocument { { "provider", "kmip" } }; break; default: throw new Exception($"Unsupported kms {kmsName}."); } return new KmsKeyId(datakeyOptionsDocument.ToBson(), keyAltNameBuffers); } private CryptOptions CreateOptions() { return new CryptOptions( new[] { CreateKmsCredentials("aws"), CreateKmsCredentials("local") }); } private (Binary binarySent, BsonDocument document) ProcessContextToCompletion(CryptContext context, bool isKmsDecrypt = true) { BsonDocument document = null; Binary binary = null; while (!context.IsDone) { (_, binary, document) = ProcessState(context, isKmsDecrypt); } return (binary, document); } /// /// Processes the current state, simulating the execution the operation/post requests needed to reach the next state /// Returns (stateProcessed, binaryOperationProduced, bsonOperationProduced) /// /// private (CryptContext.StateCode stateProcessed, Binary binaryProduced, BsonDocument bsonOperationProduced) ProcessState(CryptContext context, bool isKmsDecrypt = true) { _output.WriteLine("\n----------------------------------\nState:" + context.State); switch (context.State) { case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_COLLINFO: { var binary = context.GetOperation(); var doc = BsonUtil.ToDocument(binary); _output.WriteLine("ListCollections: " + doc); var reply = ReadJsonTestFile("collection-info.json"); _output.WriteLine("Reply:" + reply); context.Feed(BsonUtil.ToBytes(reply)); context.MarkDone(); return (CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_COLLINFO, binary, doc); } case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_MARKINGS: { var binary = context.GetOperation(); var doc = BsonUtil.ToDocument(binary); _output.WriteLine("Markings: " + doc); var reply = ReadJsonTestFile("mongocryptd-reply.json"); _output.WriteLine("Reply:" + reply); context.Feed(BsonUtil.ToBytes(reply)); context.MarkDone(); return (CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_MARKINGS, binary, doc); } case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_KEYS: { var binary = context.GetOperation(); var doc = BsonUtil.ToDocument(binary); _output.WriteLine("Key Document: " + doc); var reply = ReadJsonTestFile("key-document.json"); _output.WriteLine("Reply:" + reply); context.Feed(BsonUtil.ToBytes(reply)); context.MarkDone(); return (CryptContext.StateCode.MONGOCRYPT_CTX_NEED_MONGO_KEYS, binary, doc); } case CryptContext.StateCode.MONGOCRYPT_CTX_NEED_KMS: { var requests = context.GetKmsMessageRequests(); foreach (var req in requests) { var binary = req.Message; _output.WriteLine("Key Document: " + binary); var postRequest = binary.ToString(); // TODO: add different hosts handling postRequest.Should().Contain("Host:kms.us-east-1.amazonaws.com"); // only AWS var reply = ReadHttpTestFile(isKmsDecrypt ? "kms-decrypt-reply.txt" : "kms-encrypt-reply.txt"); _output.WriteLine("Reply: " + reply); req.Feed(Encoding.UTF8.GetBytes(reply)); req.BytesNeeded.Should().Be(0); } requests.MarkDone(); return (CryptContext.StateCode.MONGOCRYPT_CTX_NEED_KMS, null, null); } case CryptContext.StateCode.MONGOCRYPT_CTX_READY: { Binary binary = context.FinalizeForEncryption(); _output.WriteLine("Buffer:" + binary.ToArray()); var document = BsonUtil.ToDocument(binary); _output.WriteLine("Document:" + document); return (CryptContext.StateCode.MONGOCRYPT_CTX_READY, binary, document); } case CryptContext.StateCode.MONGOCRYPT_CTX_DONE: { _output.WriteLine("DONE!!"); return (CryptContext.StateCode.MONGOCRYPT_CTX_DONE, null, null); } case CryptContext.StateCode.MONGOCRYPT_CTX_ERROR: { // We expect exceptions are thrown before we get to this state throw new NotImplementedException(); } } throw new NotImplementedException(); } public CryptContext StartExplicitEncryptionContextWithKeyId(CryptClient client, byte[] keyId, string encryptionAlgorithm, byte[] message) { return client.StartExplicitEncryptionContext(keyId, keyAltName: null, queryType: null, contentionFactor: null, encryptionAlgorithm, message, rangeOptions: null); } static IEnumerable FindTestDirectories() { string[] searchPaths = new[] { Path.Combine("..", "test", "example"), Path.Combine("..", "test", "data") }; var assemblyLocation = Path.GetDirectoryName(typeof(BasicTests).GetTypeInfo().Assembly.Location); string cwd = Directory.GetCurrentDirectory(); // Assume we are in a child directory of the repo var searchDirectory = assemblyLocation ?? cwd; var testDirs = Enumerable.Range(1, 10) .Select(i => Enumerable.Repeat("..", i)) .Select(dotsSeq => dotsSeq.Aggregate(Path.Combine)) .SelectMany(previousDirectories => searchPaths.Select(searchPath => Path.Combine(searchDirectory, previousDirectories, searchPath))) .Where(Directory.Exists) .ToArray(); if (!testDirs.Any()) { throw new DirectoryNotFoundException("test/example"); } return testDirs; } static string ReadHttpTestFile(string file) { // The HTTP tests assume \r\n // And git strips \r on Unix machines by default so fix up the files var text = ReadTestFile(file); StringBuilder builder = new StringBuilder(text.Length); for (int i = 0; i < text.Length; i++) { if (text[i] == '\n' && text[i - 1] != '\r') builder.Append('\r'); builder.Append(text[i]); } return builder.ToString(); } static BsonDocument ReadJsonTestFile(string file) { var text = ReadTestFile(file); if (text == null) { throw new FileNotFoundException(file); } // Work around C# drivers and C driver have different extended json support text = text.Replace("\"$numberLong\"", "$numberLong"); return BsonUtil.FromJSON(text); } static string ReadTestFile(string fileName) { return FindTestDirectories() .Select(directory => Path.Combine(directory, fileName)) .Where(File.Exists) .Select(File.ReadAllText) .FirstOrDefault(); } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/BsonUtil.cs000066400000000000000000000054621465326363200260250ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using MongoDB.Bson; using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using System.IO; namespace MongoDB.Libmongocrypt.Test { class BsonUtil { public static BsonDocument ToDocument(Binary bin) { MemoryStream stream = new MemoryStream(bin.ToArray()); using (var jsonReader = new BsonBinaryReader(stream)) { var context = BsonDeserializationContext.CreateRoot(jsonReader); return BsonDocumentSerializer.Instance.Deserialize(context); } } public static byte[] ToBytes(BsonDocument doc) { BsonBinaryWriterSettings settings = new BsonBinaryWriterSettings() { // C# driver "magically" changes UUIDs underneath by default so tell it not to GuidRepresentation = GuidRepresentation.Standard }; return doc.ToBson(null, settings); } public static BsonDocument Concat(BsonDocument doc1, BsonDocument doc2) { BsonDocument dest = new BsonDocument(); BsonDocumentWriter writer = new BsonDocumentWriter(dest); var context = BsonSerializationContext.CreateRoot(writer); writer.WriteStartDocument(); foreach (var field in doc1) { writer.WriteName(field.Name); BsonValueSerializer.Instance.Serialize(context, field.Value); } foreach (var field in doc2) { writer.WriteName(field.Name); BsonValueSerializer.Instance.Serialize(context, field.Value); } writer.WriteEndDocument(); return writer.Document; } public static BsonDocument FromJSON(string str) { var jsonReaderSettings = new JsonReaderSettings { GuidRepresentation = GuidRepresentation.Unspecified }; using (var jsonReader = new JsonReader(str, jsonReaderSettings)) { var context = BsonDeserializationContext.CreateRoot(jsonReader); return BsonDocumentSerializer.Instance.Deserialize(context); } } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/CallbackUtils.cs000066400000000000000000000022521465326363200267750ustar00rootroot00000000000000/* * Copyright 2020–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; namespace MongoDB.Libmongocrypt.Test { internal static class CallbackUtils { public static byte[] GetBytesFromHex(string hex) { if (hex.Length % 2 != 0) { throw new ArgumentException("Hex string must contain an even number of hex digits."); } int length = hex.Length; byte[] bytes = new byte[length / 2]; for (int i = 0; i < length; i += 2) bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); return bytes; } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/CipherCallbacksTests.cs000066400000000000000000000035571465326363200303260ustar00rootroot00000000000000/* * Copyright 2020–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using FluentAssertions; using System.Security.Cryptography; using Xunit; namespace MongoDB.Libmongocrypt.Test { public class CipherCallbacksTests { [Theory] [InlineData(CipherMode.CBC, "671db60d464b09e9c3b03242dd29bdc5")] [InlineData(CipherMode.ECB, "ae6b200f30d6e8e424127e9c58affaf8")] public void CipherTest(CipherMode mode, string expectedHex) { var keyHex = "92faa793d717675e2be804584a8a98252083fe6bf16010546a92e2ef4bdd27fd"; var ivHex = "31164b2f661e41fed5df60bfcfa40baa"; var inputHex = "379ddb78c30e5e4bf19dd81ae705796f"; var keyBytes = CallbackUtils.GetBytesFromHex(keyHex); var ivBytes = CallbackUtils.GetBytesFromHex(ivHex); var inputBytes = CallbackUtils.GetBytesFromHex(inputHex); // decryptedBytes var expectedEncryptedBytes = CallbackUtils.GetBytesFromHex(expectedHex); var encryptedBytes = CipherCallbacks.AesCrypt(keyBytes, ivBytes, inputBytes, CryptMode.Encrypt, mode); encryptedBytes.Should().Equal(expectedEncryptedBytes); var decryptedBytes = CipherCallbacks.AesCrypt(keyBytes, ivBytes, encryptedBytes, CryptMode.Decrypt, mode); decryptedBytes.Should().Equal(inputBytes); } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/HashCallbackTests.cs000066400000000000000000000023251465326363200276040ustar00rootroot00000000000000/* * Copyright 2020–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using FluentAssertions; using Xunit; namespace MongoDB.Libmongocrypt.Test { public class HashCallbackTests { [Fact] public void HashTest() { var inputHex = "74657374206f66206d6163"; var expectedHex = "9ff3e52fa31c9e0fa0b08e19c40591553ea64b73709633271975bfab2db9d980"; var inputBytes = CallbackUtils.GetBytesFromHex(inputHex); var expectedBytes = CallbackUtils.GetBytesFromHex(expectedHex); var resultBytes = HashCallback.CalculateHash(inputBytes); resultBytes.Should().Equal(expectedBytes); } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/HmacShaCallbacksTests.cs000066400000000000000000000033161465326363200304110ustar00rootroot00000000000000/* * Copyright 2020–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using FluentAssertions; using Xunit; namespace MongoDB.Libmongocrypt.Test { public class HmacShaCallbacksTests { [Theory] [InlineData(256, "74657374206f66206d6163", "37626663386235656333306537336439386565666133653263633334643635376535323734623537656633326661353862663638313534396535663737303138", "ebfaa874ff7fcf5b48637a4aff49ed60f48b53a0802719d6ad85f96d315b2df2")] [InlineData(512, "74657374206f6620686d61630a", "06645237ece5638d1dcb66c70d8158c6ba5922dce3ae9f95242147fce0f989d9", "c8bc88465593980da5ed9bd213dcc4594106f6573d08eddc2b7cead3a642ef37dd848e8901a8c340f2a5d909057d28b1355fc9c82e7f7710e688f8c0c7635e9a")] public void HmacShaTest(int bitness, string inputHex, string keyHex, string expectedHex) { var keyBytes = CallbackUtils.GetBytesFromHex(keyHex); var inputBytes = CallbackUtils.GetBytesFromHex(inputHex); var expectedBytes = CallbackUtils.GetBytesFromHex(expectedHex); var resultBytes = HmacShaCallbacks.CalculateHash(keyBytes, inputBytes, bitness); resultBytes.Should().Equal(expectedBytes); } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/MongoDB.Libmongocrypt.Test.csproj000066400000000000000000000024301465326363200322030ustar00rootroot00000000000000 net472;netcoreapp2.1;netcoreapp3.0 netcoreapp2.1;netcoreapp3.0 AnyCPU false true ..\MongoDB.Driver.snk . PreserveNewest libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/Package.include.template.csproj000066400000000000000000000014351465326363200317440ustar00rootroot00000000000000 false @CMAKE_CURRENT_LIST_DIR@/MongoDB.Libmongocrypt.Test @CMAKE_CURRENT_BINARY_DIR@/MongoDB.Libmongocrypt.Test libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/SigningRSAESPKCSCallbackTests.cs000066400000000000000000000073761465326363200316110ustar00rootroot00000000000000/* * Copyright 2020–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Text; using FluentAssertions; using Xunit; namespace MongoDB.Libmongocrypt.Test.Callbacks { public class SigningRSAESPKCSCallbackTests { private static string DataToSign = "data to sign"; public static string PrivateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC4JOyv5z05cL18ztpknRC7CFY2gYol4DAKerdVUoDJ" + "xCTmFMf39dVUEqD0WDiw/qcRtSO1/FRut08PlSPmvbyKetsLoxlpS8lukSzEFpFK7+L+R4miFOl6HvECyg7lbC1H/WGAhIz9yZRlXhRo9qmO/fB6PV9IeYtU+1xY" + "uXicjCDPp36uuxBAnCz7JfvxJ3mdVc0vpSkbSb141nWuKNYR1mgyvvL6KzxO6mYsCo4hRAdhuizD9C4jDHk0V2gDCFBk0h8SLEdzStX8L0jG90/Og4y7J1b/cPo/" + "kbYokkYisxe8cPlsvGBf+rZex7XPxc1yWaP080qeABJb+S88O//LAgMBAAECggEBAKVxP1m3FzHBUe2NZ3fYCc0Qa2zjK7xl1KPFp2u4CU+9sy0oZJUqQHUdm5CM" + "prqWwIHPTftWboFenmCwrSXFOFzujljBO7Z3yc1WD3NJl1ZNepLcsRJ3WWFH5V+NLJ8Bdxlj1DMEZCwr7PC5+vpnCuYWzvT0qOPTl9RNVaW9VVjHouJ9Fg+s2DrS" + "hXDegFabl1iZEDdI4xScHoYBob06A5lw0WOCTayzw0Naf37lM8Y4psRAmI46XLiF/Vbuorna4hcChxDePlNLEfMipICcuxTcei1RBSlBa2t1tcnvoTy6cuYDqqIm" + "RYjp1KnMKlKQBnQ1NjS2TsRGm+F0FbreVCECgYEA4IDJlm8q/hVyNcPe4OzIcL1rsdYN3bNm2Y2O/YtRPIkQ446ItyxD06d9VuXsQpFp9jNACAPfCMSyHpPApqlx" + "dc8z/xATlgHkcGezEOd1r4E7NdTpGg8y6Rj9b8kVlED6v4grbRhKcU6moyKUQT3+1B6ENZTOKyxuyDEgTwZHtFECgYEA0fqdv9h9s77d6eWmIioP7FSymq93pC4u" + "mxf6TVicpjpMErdD2ZfJGulN37dq8FOsOFnSmFYJdICj/PbJm6p1i8O21lsFCltEqVoVabJ7/0alPfdG2U76OeBqI8ZubL4BMnWXAB/VVEYbyWCNpQSDTjHQYs54" + "qa2I0dJB7OgJt1sCgYEArctFQ02/7H5Rscl1yo3DBXO94SeiCFSPdC8f2Kt3MfOxvVdkAtkjkMACSbkoUsgbTVqTYSEOEc2jTgR3iQ13JgpHaFbbsq64V0QP3TAx" + "bLIQUjYGVgQaF1UfLOBv8hrzgj45z/ST/G80lOl595+0nCUbmBcgG1AEWrmdF0/3RmECgYAKvIzKXXB3+19vcT2ga5Qq2l3TiPtOGsppRb2XrNs9qKdxIYvHmXo/" + "9QP1V3SRW0XoD7ez8FpFabp42cmPOxUNk3FK3paQZABLxH5pzCWI9PzIAVfPDrm+sdnbgG7vAnwfL2IMMJSA3aDYGCbF9EgefG+STcpfqq7fQ6f5TBgLFwKBgCd7" + "gn1xYL696SaKVSm7VngpXlczHVEpz3kStWR5gfzriPBxXgMVcWmcbajRser7ARpCEfbxM1UJyv6oAYZWVSNErNzNVb4POqLYcCNySuC6xKhs9FrEQnyKjyk8wI4V" + "nrEMGrQ8e+qYSwYk9Gh6dKGoRMAPYVXQAO0fIsHF/T0a"; private static string ExpectedSignature = "VocBRhpMmQ2XCzVehWSqheQLnU889gf3dhU4AnVnQTJjsKx/CM23qKDPkZDd2A/BnQsp99SN7ksIX5Raj0TPw" + "yN5OCN/YrNFNGoOFlTsGhgP/hyE8X3Duiq6sNO0SMvRYNPFFGlJFsp1Fw3Z94eYMg4/Wpw5s4+Jo5Zm/qY7aTJIqDKDQ3CNHLeJgcMUOc9sz01/GzoUYKDVODHSx" + "rYEk5ireFJFz9vP8P7Ha+VDUZuQIQdXer9NBbGFtYmWprY3nn4D3Dw93Sn0V0dIqYeIo91oKyslvMebmUM95S2PyIJdEpPb2DJDxjvX/0LLwSWlSXRWy9gapWoBk" + "b4ynqZBsg=="; [Fact] public void GetSignatureTest() { byte[] privateKeyBytes = Convert.FromBase64String(PrivateKey); var dataBytes = Encoding.ASCII.GetBytes(DataToSign); #if NETCOREAPP3_0 byte[] signature = SigningRSAESPKCSCallback.HashAndSignBytes(dataBytes, privateKeyBytes); string output = Convert.ToBase64String(signature); output.Should().Be(ExpectedSignature); #else var ex = Record.Exception(() => SigningRSAESPKCSCallback.HashAndSignBytes(dataBytes, privateKeyBytes)); ex.Should().BeOfType(); #endif } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/test/000077500000000000000000000000001465326363200247075ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/test/example/000077500000000000000000000000001465326363200263425ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/test/example/collection-info.json000066400000000000000000000017311465326363200323230ustar00rootroot00000000000000{ "type": "collection", "name": "test", "idIndex": { "ns": "test.test", "name": "_id_", "key": { "_id": { "$numberInt": "1" } }, "v": { "$numberInt": "2" } }, "options": { "validator": { "$jsonSchema": { "properties": { "ssn": { "encrypt": { "keyId": { "$binary": { "base64": "YWFhYWFhYWFhYWFhYWFhYQ==", "subType": "04" } }, "type": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } } }, "bsonType": "object" } } } }libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/test/example/command-reply.json000066400000000000000000000002361465326363200320050ustar00rootroot00000000000000{ "cursor": { "firstBatch": [ { "_id": 1, "ssn": "457-55-5462" } ], "id": 0, "ns": "test.test" }, "ok": 1 } encrypted-command-reply.json000066400000000000000000000005251465326363200337220ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/test/example{ "cursor" : { "firstBatch" : [ { "_id": 1, "ssn": { "$binary": "AWFhYWFhYWFhYWFhYWFhYWECRTOW9yZzNDn5dGwuqsrJQNLtgMEKaujhs9aRWRp+7Yo3JK8N8jC8P0Xjll6C1CwLsE/iP5wjOMhVv1KMMyOCSCrHorXRsb2IKPtzl2lKTqQ=", "$type": "06" } } ], "id" : 0, "ns" : "test.test" }, "ok" : 1 }libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/test/example/encrypted-command.json000066400000000000000000000004101465326363200326410ustar00rootroot00000000000000{ "filter": { "ssn": { "$binary": { "base64": "AWFhYWFhYWFhYWFhYWFhYWECRTOW9yZzNDn5dGwuqsrJQNLtgMEKaujhs9aRWRp+7Yo3JK8N8jC8P0Xjll6C1CwLsE/iP5wjOMhVv1KMMyOCSCrHorXRsb2IKPtzl2lKTqQ=", "subType": "06" } } }, "find": "test" } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/test/example/encrypted-value.json000066400000000000000000000002461465326363200323460ustar00rootroot00000000000000{ "v": { "$binary": "AWFhYWFhYWFhYWFhYWFhYWECW+zDjR/69eS6VtuMD5+O2lZw6JyiWOw3avI7mnUkdpKzPfvy8F/nlZrgZa2cGmQsb0TmLZuk5trldosnGKD91w==", "$type": "06" } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/test/example/key-document.json000066400000000000000000000020731465326363200316430ustar00rootroot00000000000000{ "status": { "$numberInt": "1" }, "_id": { "$binary": { "base64": "YWFhYWFhYWFhYWFhYWFhYQ==", "subType": "04" } }, "masterKey": { "region": "us-east-1", "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", "provider": "aws" }, "updateDate": { "$date": { "$numberLong": "1557827033449" } }, "keyMaterial": { "$binary": { "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", "subType": "00" } }, "creationDate": { "$date": { "$numberLong": "1557827033449" } }, "keyAltNames": [ "altKeyName", "another_altname" ] } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/test/example/key-filter.json000066400000000000000000000003631465326363200313120ustar00rootroot00000000000000{ "$or": [ { "_id": { "$in": [ { "$binary": "YWFhYWFhYWFhYWFhYWFhYQ==", "$type": "04" } ] } }, { "keyAltNames": { "$in": [] } } ] }list-collections-filter.json000066400000000000000000000000241465326363200337240ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/test/example{ "name": "test" }libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/test/example/mongocryptd-command.json000066400000000000000000000006531465326363200332220ustar00rootroot00000000000000{ "find": "test", "filter": { "ssn": "457-55-5462" }, "jsonSchema": { "properties": { "ssn": { "encrypt": { "keyId": { "$binary": "YWFhYWFhYWFhYWFhYWFhYQ==", "$type": "04" }, "type": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } } }, "bsonType": "object" }, "isRemoteSchema": true }libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test/xunit.runner.json000066400000000000000000000002071465326363200273010ustar00rootroot00000000000000{ "$schema": "https://xunit.github.io/schema/current/xunit.runner.schema.json", "appDomain": "denied", "shadowCopy": false } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test32/000077500000000000000000000000001465326363200240755ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test32/BasicTests.cs000066400000000000000000000032111465326363200264650ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using Xunit; using FluentAssertions; using MongoDB.Bson; namespace MongoDB.Libmongocrypt.Test32 { public class BasicTests { BsonDocument CreateAwsCredentialsDocument() => new BsonDocument { { "aws", new BsonDocument { { "secretAccessKey", "us-east-1" }, { "accessKeyId", "us-east-1" } } } }; CryptOptions CreateOptions() => new CryptOptions( new[] { new KmsCredentials(CreateAwsCredentialsDocument().ToBson()) } ); [Fact] public void CryptClientShouldFailToiInitializeWhenTargetingX86() { var exception = Record.Exception(() => CryptClientFactory.Create(CreateOptions())); exception.Should().BeOfType(); } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test32/MongoDB.Libmongocrypt.Test32.csproj000066400000000000000000000031251465326363200325170ustar00rootroot00000000000000 net472;netcoreapp2.1;netcoreapp3.0 netcoreapp2.1;netcoreapp3.0 false true ..\MongoDB.Driver.snk . x86 x86 libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt.Test32/Package.include.template.csproj000066400000000000000000000014411465326363200321060ustar00rootroot00000000000000 false @CMAKE_CURRENT_LIST_DIR@/MongoDB.Libmongocrypt.Test32 @CMAKE_CURRENT_BINARY_DIR@/MongoDB.Libmongocrypt.Test32 libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/000077500000000000000000000000001465326363200230125ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/AssemblyInfo.cs000066400000000000000000000014771465326363200257450ustar00rootroot00000000000000using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("MongoDB.Libmongocrypt.Test, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")] [assembly: InternalsVisibleTo("MongoDB.Libmongocrypt.Test32, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")] libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/Binary.cs000066400000000000000000000100401465326363200245600ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.IO; using System.Runtime.InteropServices; namespace MongoDB.Libmongocrypt { /// /// A pointer and length pair the contains raw bytes to pass or retrive from libmongocrypt. /// /// public class Binary : IDisposable { private static readonly byte[] __empty = new byte[0]; private BinarySafeHandle _handle; internal Binary() { _handle = Library.mongocrypt_binary_new(); } internal Binary(BinarySafeHandle handle) { _handle = handle; } /// /// Gets the data. /// /// /// The data. /// public IntPtr Data { get { if (!_handle.IsInvalid) { return Marshal.ReadIntPtr(_handle.DangerousGetHandle()); } return IntPtr.Zero; } } /// /// Gets the length. /// /// /// The length. /// public uint Length { get { if (!_handle.IsInvalid) { return (uint)Marshal.ReadInt32(_handle.DangerousGetHandle(), IntPtr.Size); } return 0; } } internal BinarySafeHandle Handle => _handle; /// /// Converts to array. /// public byte[] ToArray() { if (Length > 0) { byte[] arr = new byte[Length]; Marshal.Copy(Data, arr, 0, arr.Length); return arr; } else { return __empty; } } /// /// Write bytes into Data. /// public void WriteBytes(byte[] bytes) { // The length of the new bytes can be smaller than allocated memory // because sometimes the allocated memory contains reserved blocks for future usage if (bytes.Length <= Length) { Marshal.Copy(bytes, 0, Data, bytes.Length); } else { // this code path is not expected, but it's worth doing it to avoid silent saving of corrupted data throw new InvalidDataException($"Incorrect bytes size {bytes.Length}. The bytes size must be less than or equal to {Length}."); } } /// /// Converts to string. /// /// /// A that represents this instance. /// public override string ToString() { return Marshal.PtrToStringAnsi(Data); } #region IDisposable public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { // Adapted from: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.safehandle?view=netcore-3.0 if (_handle != null && !_handle.IsInvalid) { // Free the handle _handle.Dispose(); } } #endregion } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/BinarySafeHandle.cs000066400000000000000000000033221465326363200265000ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; namespace MongoDB.Libmongocrypt { /// /// SafeHandle to manage the lifetime of a mongocrypt_binary_t. /// /// internal class BinarySafeHandle : SafeHandle { private BinarySafeHandle() : base(IntPtr.Zero, true) { } private BinarySafeHandle(IntPtr ptr) : base(ptr, false) { } public static BinarySafeHandle FromIntPtr(IntPtr ptr) { return new BinarySafeHandle(ptr); } public override bool IsInvalid { get { return handle == IntPtr.Zero; } } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] protected override bool ReleaseHandle() { // Here, we must obey all rules for constrained execution regions. Library.mongocrypt_binary_destroy(handle); return true; } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/CheckableSafeHandle.cs000066400000000000000000000026151465326363200271210ustar00rootroot00000000000000/* * Copyright 2010–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; namespace MongoDB.Libmongocrypt { /// /// SafeHandle to manage the lifetime of a mongocrypt_ctx_t. /// /// internal abstract class CheckableSafeHandle : SafeHandle { internal CheckableSafeHandle() : base(IntPtr.Zero, true) { } public override bool IsInvalid { get { return handle == IntPtr.Zero; } } public abstract void Check(Status status, bool success); [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] protected abstract override bool ReleaseHandle(); } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/CipherCallbacks.cs000066400000000000000000000140421465326363200263540ustar00rootroot00000000000000/* * Copyright 2020–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Security.Cryptography; namespace MongoDB.Libmongocrypt { internal enum CryptMode { Encrypt, Decrypt } internal static class CipherCallbacks { public static bool EncryptCbc( IntPtr ctx, IntPtr key, IntPtr iv, IntPtr @in, IntPtr @out, ref uint bytes_written, IntPtr statusPtr) { using (var status = new Status(StatusSafeHandle.FromIntPtr(statusPtr))) { try { var keyBinary = new Binary(BinarySafeHandle.FromIntPtr(key)); var inputBinary = new Binary(BinarySafeHandle.FromIntPtr(@in)); var outputBinary = new Binary(BinarySafeHandle.FromIntPtr(@out)); var ivBinary = new Binary(BinarySafeHandle.FromIntPtr(iv)); byte[] keyBytes = keyBinary.ToArray(); byte[] ivBytes = ivBinary.ToArray(); byte[] inputBytes = inputBinary.ToArray(); var outputBytes = AesCrypt(keyBytes, ivBytes, inputBytes, CryptMode.Encrypt, CipherMode.CBC); bytes_written = (uint)outputBytes.Length; outputBinary.WriteBytes(outputBytes); return true; } catch (Exception e) { status.SetStatus(1, e.Message); return false; } } } public static bool DecryptCbc( IntPtr ctx, IntPtr key, IntPtr iv, IntPtr @in, IntPtr @out, ref uint bytes_written, IntPtr statusPtr) { using (var status = new Status(StatusSafeHandle.FromIntPtr(statusPtr))) { try { var keyBinary = new Binary(BinarySafeHandle.FromIntPtr(key)); var inputBinary = new Binary(BinarySafeHandle.FromIntPtr(@in)); var outputBinary = new Binary(BinarySafeHandle.FromIntPtr(@out)); var ivBinary = new Binary(BinarySafeHandle.FromIntPtr(iv)); byte[] keyBytes = keyBinary.ToArray(); byte[] ivBytes = ivBinary.ToArray(); byte[] inputBytes = inputBinary.ToArray(); var outputBytes = AesCrypt(keyBytes, ivBytes, inputBytes, CryptMode.Decrypt, CipherMode.CBC); bytes_written = (uint)outputBytes.Length; outputBinary.WriteBytes(outputBytes); return true; } catch (Exception e) { status.SetStatus(1, e.Message); return false; } } } public static bool EncryptEcb( IntPtr ctx, IntPtr key, IntPtr iv, IntPtr @in, IntPtr @out, ref uint bytes_written, IntPtr statusPtr) { using (var status = new Status(StatusSafeHandle.FromIntPtr(statusPtr))) { try { var keyBinary = new Binary(BinarySafeHandle.FromIntPtr(key)); var inputBinary = new Binary(BinarySafeHandle.FromIntPtr(@in)); var outputBinary = new Binary(BinarySafeHandle.FromIntPtr(@out)); var ivBinary = new Binary(BinarySafeHandle.FromIntPtr(iv)); byte[] keyBytes = keyBinary.ToArray(); byte[] ivBytes = ivBinary.ToArray(); byte[] inputBytes = inputBinary.ToArray(); var outputBytes = AesCrypt(keyBytes, ivBytes, inputBytes, CryptMode.Encrypt, CipherMode.ECB); bytes_written = (uint)outputBytes.Length; outputBinary.WriteBytes(outputBytes); return true; } catch (Exception e) { status.SetStatus(1, e.Message); return false; } } } public static byte[] AesCrypt(byte[] keyBytes, byte[] ivBytes, byte[] inputBytes, CryptMode cryptMode, CipherMode cipherMode) { using (var aes = new RijndaelManaged()) { aes.Mode = cipherMode; aes.Key = keyBytes; if (ivBytes.Length > 0) { aes.IV = ivBytes; } aes.Padding = PaddingMode.None; // mongocrypt level is responsible for padding using (var encrypto = CreateCryptoTransform(aes)) { byte[] encryptedBytes = encrypto.TransformFinalBlock(inputBytes, 0, inputBytes.Length); return encryptedBytes; } ICryptoTransform CreateCryptoTransform(RijndaelManaged rijndaelManaged) { switch (cryptMode) { case CryptMode.Encrypt: return rijndaelManaged.CreateEncryptor(); case CryptMode.Decrypt: return rijndaelManaged.CreateDecryptor(); default: throw new InvalidOperationException($"Unsupported crypt mode {cryptMode}."); // should not be reached } } } } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/ContextSafeHandle.cs000066400000000000000000000030161465326363200267000ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System.Runtime.ConstrainedExecution; namespace MongoDB.Libmongocrypt { /// /// SafeHandle to manage the lifetime of a mongocrypt_ctx_t. /// /// internal class ContextSafeHandle : CheckableSafeHandle { private ContextSafeHandle() : base() { } public override void Check(Status status, bool success) { if (!success) { Library.mongocrypt_ctx_status(this, status.Handle); status.ThrowExceptionIfNeeded(); } } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] protected override bool ReleaseHandle() { // Here, we must obey all rules for constrained execution regions. Library.mongocrypt_ctx_destroy(handle); return true; } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/CryptClient.cs000066400000000000000000000220061465326363200256010ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Runtime.InteropServices; namespace MongoDB.Libmongocrypt { /// /// CryptClient represents a session with libmongocrypt. /// /// It can be used to encrypt and decrypt documents. /// /// public class CryptClient : IDisposable, IStatus { private MongoCryptSafeHandle _handle; private Status _status; internal CryptClient(MongoCryptSafeHandle handle, Status status) { _handle = handle ?? throw new ArgumentNullException(paramName: nameof(handle)); _status = status ?? throw new ArgumentNullException(paramName: nameof(status)); } /// /// Gets the crypt shared library version. /// /// A crypt shared library version. public string CryptSharedLibraryVersion { get { var versionPtr = Library.mongocrypt_crypt_shared_lib_version_string(_handle, out _); var result = Marshal.PtrToStringAnsi(versionPtr); return result; } } /// /// Starts the create data key context. /// /// The key identifier. /// A crypt context for creating a data key public CryptContext StartCreateDataKeyContext(KmsKeyId keyId) { ContextSafeHandle handle = Library.mongocrypt_ctx_new(_handle); keyId.SetCredentials(handle, _status); handle.Check(_status, Library.mongocrypt_ctx_datakey_init(handle)); return new CryptContext(handle); } /// /// Starts the encryption context. /// /// The database of the collection. /// The command. /// A encryption context. public CryptContext StartEncryptionContext(string db, byte[] command) { ContextSafeHandle handle = Library.mongocrypt_ctx_new(_handle); IntPtr stringPointer = (IntPtr)Marshal.StringToHGlobalAnsi(db); try { unsafe { fixed (byte* c = command) { var commandPtr = (IntPtr)c; using (var pinnedCommand = new PinnedBinary(commandPtr, (uint)command.Length)) { // Let mongocrypt run strlen handle.Check(_status, Library.mongocrypt_ctx_encrypt_init(handle, stringPointer, -1, pinnedCommand.Handle)); } } } } finally { Marshal.FreeHGlobal(stringPointer); } return new CryptContext(handle); } /// /// Starts an explicit encryption context. /// public CryptContext StartExplicitEncryptionContext(byte[] keyId, byte[] keyAltName, string queryType, long? contentionFactor, string encryptionAlgorithm, byte[] message, byte[] rangeOptions, bool isExpressionMode = false) { var handle = Library.mongocrypt_ctx_new(_handle); if (keyId != null) { PinnedBinary.RunAsPinnedBinary(handle, keyId, _status, (h, pb) => Library.mongocrypt_ctx_setopt_key_id(h, pb)); } else if (keyAltName != null) { PinnedBinary.RunAsPinnedBinary(handle, keyAltName, _status, (h, pb) => Library.mongocrypt_ctx_setopt_key_alt_name(h, pb)); } if (rangeOptions != null) { PinnedBinary.RunAsPinnedBinary(handle, rangeOptions, _status, (h, pb) => Library.mongocrypt_ctx_setopt_algorithm_range(h, pb)); } handle.Check(_status, Library.mongocrypt_ctx_setopt_algorithm(handle, encryptionAlgorithm, -1)); if (queryType != null) { handle.Check(_status, Library.mongocrypt_ctx_setopt_query_type(handle, queryType, -1)); } if (contentionFactor.HasValue) { var contentionFactorInt = contentionFactor.Value; handle.Check(_status, Library.mongocrypt_ctx_setopt_contention_factor(handle, contentionFactorInt)); } PinnedBinary.RunAsPinnedBinary( handle, message, _status, (h, pb) => { if (isExpressionMode) { // mongocrypt_ctx_explicit_encrypt_expression_init shares the same code as mongocrypt_ctx_explicit_encrypt_init. // The only difference is the validation of the queryType argument: // * mongocrypt_ctx_explicit_encrypt_expression_init requires queryType of "rangePreview". // * mongocrypt_ctx_explicit_encrypt_init rejects queryType of "rangePreview". return Library.mongocrypt_ctx_explicit_encrypt_expression_init(h, pb); } else { return Library.mongocrypt_ctx_explicit_encrypt_init(h, pb); } }); return new CryptContext(handle); } /// /// Starts the decryption context. /// /// The bson document to decrypt. /// A decryption context public CryptContext StartDecryptionContext(byte[] buffer) { ContextSafeHandle handle = Library.mongocrypt_ctx_new(_handle); unsafe { fixed (byte* p = buffer) { IntPtr ptr = (IntPtr)p; using (PinnedBinary pinned = new PinnedBinary(ptr, (uint)buffer.Length)) { handle.Check(_status, Library.mongocrypt_ctx_decrypt_init(handle, pinned.Handle)); } } } return new CryptContext(handle); } /// /// Starts an explicit decryption context. /// /// The buffer. /// A encryption context public CryptContext StartExplicitDecryptionContext(byte[] buffer) { ContextSafeHandle handle = Library.mongocrypt_ctx_new(_handle); unsafe { fixed (byte* p = buffer) { IntPtr ptr = (IntPtr)p; using (PinnedBinary pinned = new PinnedBinary(ptr, (uint)buffer.Length)) { // Let mongocrypt run strlen handle.Check(_status, Library.mongocrypt_ctx_explicit_decrypt_init(handle, pinned.Handle)); } } } return new CryptContext(handle); } public CryptContext StartRewrapMultipleDataKeysContext(KmsKeyId kmsKey, byte[] filter) { var handle = Library.mongocrypt_ctx_new(_handle); kmsKey.SetCredentials(handle, _status); PinnedBinary.RunAsPinnedBinary(handle, filter, _status, (h, pb) => Library.mongocrypt_ctx_rewrap_many_datakey_init(h, pb)); return new CryptContext(handle); } void IStatus.Check(Status status) { Library.mongocrypt_status(_handle, status.Handle); } #region IDisposable public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { // Adapted from: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.safehandle?view=netcore-3.0 if (_handle != null && !_handle.IsInvalid) { // Free the handle _handle.Dispose(); } // Free the status _status.Dispose(); } #endregion // private methods private void Check(bool success) { if (!success) { _status.Check(this); } } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/CryptClientFactory.cs000066400000000000000000000142411465326363200271330ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Linq; namespace MongoDB.Libmongocrypt { /// /// A factory for CryptClients. /// public class CryptClientFactory { // MUST be static fields since otherwise these callbacks can be collected via the garbage collector // regardless they're used by mongocrypt level or no private static Library.Delegates.CryptoCallback __cryptoAes256EcbEncryptCallback = new Library.Delegates.CryptoCallback(CipherCallbacks.EncryptEcb); private static Library.Delegates.CryptoCallback __cryptoAes256CbcDecryptCallback = new Library.Delegates.CryptoCallback(CipherCallbacks.DecryptCbc); private static Library.Delegates.CryptoCallback __cryptoAes256CbcEncryptCallback = new Library.Delegates.CryptoCallback(CipherCallbacks.EncryptCbc); private static Library.Delegates.HashCallback __cryptoHashCallback = new Library.Delegates.HashCallback(HashCallback.Hash); private static Library.Delegates.CryptoHmacCallback __cryptoHmacSha256Callback = new Library.Delegates.CryptoHmacCallback(HmacShaCallbacks.HmacSha256); private static Library.Delegates.CryptoHmacCallback __cryptoHmacSha512Callback = new Library.Delegates.CryptoHmacCallback(HmacShaCallbacks.HmacSha512); private static Library.Delegates.RandomCallback __randomCallback = new Library.Delegates.RandomCallback(SecureRandomCallback.GenerateRandom); private static Library.Delegates.CryptoHmacCallback __signRsaesPkcs1HmacCallback = new Library.Delegates.CryptoHmacCallback(SigningRSAESPKCSCallback.RsaSign); // mongocrypt_is_crypto_available is only available in libmongocrypt version >= 1.9 private static readonly Version __mongocryptIsCryptoAvailableMinVersion = Version.Parse("1.9"); /// Creates a CryptClient with the specified options. /// The options. /// A CryptClient public static CryptClient Create(CryptOptions options) { MongoCryptSafeHandle handle = null; Status status = null; var cryptoAvailable = Version.Parse(Library.Version.Split('-', '+').First()) >= __mongocryptIsCryptoAvailableMinVersion && Library.mongocrypt_is_crypto_available(); try { handle = Library.mongocrypt_new(); status = new Status(); if (!cryptoAvailable) { handle.Check( status, Library.mongocrypt_setopt_crypto_hooks( handle, __cryptoAes256CbcEncryptCallback, __cryptoAes256CbcDecryptCallback, __randomCallback, __cryptoHmacSha512Callback, __cryptoHmacSha256Callback, __cryptoHashCallback, IntPtr.Zero)); handle.Check( status, Library.mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5( handle, __signRsaesPkcs1HmacCallback, IntPtr.Zero)); handle.Check( status, Library.mongocrypt_setopt_aes_256_ecb( handle, __cryptoAes256EcbEncryptCallback, IntPtr.Zero)); } foreach (var kmsCredentials in options.KmsCredentials) { kmsCredentials.SetCredentials(handle, status); } if (options.Schema != null) { PinnedBinary.RunAsPinnedBinary(handle, options.Schema, status, (h, pb) => Library.mongocrypt_setopt_schema_map(h, pb)); } if (options.EncryptedFieldsMap != null) { PinnedBinary.RunAsPinnedBinary(handle, options.EncryptedFieldsMap, status, (h, pb) => Library.mongocrypt_setopt_encrypted_field_config_map(h, pb)); } if (options.BypassQueryAnalysis) { Library.mongocrypt_setopt_bypass_query_analysis(handle); } if (options.CryptSharedLibPath != null) { Library.mongocrypt_setopt_set_crypt_shared_lib_path_override(handle, options.CryptSharedLibPath); } if (options.CryptSharedLibSearchPath != null) { Library.mongocrypt_setopt_append_crypt_shared_lib_search_path(handle, options.CryptSharedLibSearchPath); } Library.mongocrypt_setopt_use_need_kms_credentials_state(handle); Library.mongocrypt_init(handle); if (options.IsCryptSharedLibRequired) { var versionPtr = Library.mongocrypt_crypt_shared_lib_version_string(handle, out _); if (versionPtr == IntPtr.Zero) { throw new CryptException(Library.StatusType.MONGOCRYPT_STATUS_ERROR_CLIENT, uint.MaxValue, "CryptSharedLib is required, but was not found or not loaded."); } } } catch { handle?.Dispose(); status?.Dispose(); throw; } return new CryptClient(handle, status); } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/CryptContext.cs000066400000000000000000000147121465326363200260140ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; namespace MongoDB.Libmongocrypt { /// /// A encryption or decryption session. It may not be reused. /// /// /// public class CryptContext : IDisposable, IStatus { /// /// States of the CryptContext state machine /// public enum StateCode { /// /// LibMongoCrypt hit an error /// MONGOCRYPT_CTX_ERROR = 0, /// /// LibMongoCrypt wants the collection information by running a OP_MSG command against the users' mongod. /// MONGOCRYPT_CTX_NEED_MONGO_COLLINFO = 1, /// /// LibMongoCrypt wants a command to be run against mongocryptd. /// MONGOCRYPT_CTX_NEED_MONGO_MARKINGS = 2, /// /// LibMongoCrypt wants a command to be run against mongod key vault. /// MONGOCRYPT_CTX_NEED_MONGO_KEYS = 3, /// /// LibMongoCrypt wants a request sent to KMS. /// MONGOCRYPT_CTX_NEED_KMS = 4, /// /// LibMongoCrypt is ready to do encryption, call Finish(). /// MONGOCRYPT_CTX_READY = 5, /// /// LibMongoCrypt is complete. /// MONGOCRYPT_CTX_DONE = 6, /// /// LibMongoCrypt requires new credentials. /// MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS = 7 } private ContextSafeHandle _handle; private Status _status; internal CryptContext(ContextSafeHandle handle) { _handle = handle; _status = new Status(); } /// /// Gets the state. /// /// /// The state. /// public StateCode State { get { return Library.mongocrypt_ctx_state(_handle); } } /// /// Gets a value indicating whether this instance is done. /// /// /// true if this instance is done; otherwise, false. /// public bool IsDone { get { return State == StateCode.MONGOCRYPT_CTX_DONE; } } /// /// Gets the operation. /// /// Binary payload to send to either KMS, mongod, or mongocryptd public Binary GetOperation() { Binary binary = new Binary(); Check(Library.mongocrypt_ctx_mongo_op(_handle, binary.Handle)); return binary; } /// /// Feeds the result from running a remote operation back to the libmongocrypt. /// /// The buffer. public void Feed(byte[] buffer) { unsafe { fixed (byte* p = buffer) { IntPtr ptr = (IntPtr)p; using (PinnedBinary pinned = new PinnedBinary(ptr, (uint)buffer.Length)) { Check(Library.mongocrypt_ctx_mongo_feed(_handle, pinned.Handle)); } } } } /// /// Signal the feeding is done. /// public void MarkDone() { Check(Library.mongocrypt_ctx_mongo_done(_handle)); } /// /// Finalizes for encryption. /// /// The encrypted or decrypted result. public Binary FinalizeForEncryption() { Binary binary = new Binary(); Check(Library.mongocrypt_ctx_finalize(_handle, binary.Handle)); return binary; } /// /// Gets a collection of KMS message requests to make /// /// Collection of KMS Messages public KmsRequestCollection GetKmsMessageRequests() { var requests = new List(); for (IntPtr request = Library.mongocrypt_ctx_next_kms_ctx(_handle); request != IntPtr.Zero; request = Library.mongocrypt_ctx_next_kms_ctx(_handle)) { requests.Add(new KmsRequest(request)); } return new KmsRequestCollection(requests, this); } public void SetCredentials(byte[] credentials) { PinnedBinary.RunAsPinnedBinary(_handle, credentials, _status, (h, b) => Library.mongocrypt_ctx_provide_kms_providers(h, b)); } void IStatus.Check(Status status) { Library.mongocrypt_ctx_status(_handle, status.Handle); } #region IDisposable public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { // Adapted from: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.safehandle?view=netcore-3.0 if (_handle != null && !_handle.IsInvalid) { // Free the handle _handle.Dispose(); } } #endregion internal void MarkKmsDone() { Check(Library.mongocrypt_ctx_kms_done(_handle)); } private void Check(bool success) { if (!success) { _status.Check(this); } } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/CryptException.cs000066400000000000000000000021541465326363200263230ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; namespace MongoDB.Libmongocrypt { /// /// An exception from libmongocrypt. /// /// public class CryptException : Exception { private readonly uint _code; private readonly Library.StatusType _statusType; internal CryptException(Library.StatusType statusType, uint code, string message) : base(message) { _code = code; _statusType = statusType; } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/CryptOptions.cs000066400000000000000000000045411465326363200260220ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; namespace MongoDB.Libmongocrypt { /// /// Options to configure mongocrypt with. /// public class CryptOptions { public bool BypassQueryAnalysis { get; } public string CryptSharedLibPath { get; } public string CryptSharedLibSearchPath { get; } public byte[] EncryptedFieldsMap { get; } public bool IsCryptSharedLibRequired { get; } public IReadOnlyList KmsCredentials { get; } public byte[] Schema { get; } public CryptOptions(IEnumerable credentials) : this(credentials, null) { } public CryptOptions( IEnumerable credentials, byte[] schema) : this(credentials, null, schema, false, null, null, false) { } public CryptOptions( IEnumerable credentials, byte[] encryptedFieldsMap, byte[] schema, bool bypassQueryAnalysis, string cryptSharedLibPath, string cryptSharedLibSearchPath, bool isCryptSharedLibRequired) { BypassQueryAnalysis = bypassQueryAnalysis; CryptSharedLibPath = cryptSharedLibPath; CryptSharedLibSearchPath = cryptSharedLibSearchPath; IsCryptSharedLibRequired = isCryptSharedLibRequired; EncryptedFieldsMap = encryptedFieldsMap; KmsCredentials = new ReadOnlyCollection((credentials ?? throw new ArgumentNullException(nameof(credentials))).ToList()); Schema = schema; } // TODO: - add configurable logging support } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/HashCallback.cs000066400000000000000000000035201465326363200256410ustar00rootroot00000000000000/* * Copyright 2020–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Security.Cryptography; namespace MongoDB.Libmongocrypt { internal static class HashCallback { public static bool Hash( IntPtr ctx, IntPtr @in, IntPtr @out, IntPtr statusPtr) { using (var status = new Status(StatusSafeHandle.FromIntPtr(statusPtr))) { try { var inputBinary = new Binary(BinarySafeHandle.FromIntPtr(@in)); var outBinary = new Binary(BinarySafeHandle.FromIntPtr(@out)); var outBytes = CalculateHash(inputBinary.ToArray()); outBinary.WriteBytes(outBytes); return true; } catch (Exception ex) { status.SetStatus(1, ex.Message); return false; } } } public static byte[] CalculateHash(byte[] inputBytes) { using (var sha256 = SHA256.Create()) { sha256.Initialize(); _ = sha256.TransformFinalBlock(inputBytes, 0, inputBytes.Length); return sha256.Hash; } } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/HmacShaCallbacks.cs000066400000000000000000000060541465326363200264520ustar00rootroot00000000000000/* * Copyright 2020–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Security.Cryptography; namespace MongoDB.Libmongocrypt { internal static class HmacShaCallbacks { public static bool HmacSha512( IntPtr ctx, IntPtr key, IntPtr @in, IntPtr @out, IntPtr statusPtr) { return Hmac(key, @in, @out, statusPtr, bitness: 512); } public static bool HmacSha256( IntPtr ctx, IntPtr key, IntPtr @in, IntPtr @out, IntPtr statusPtr) { return Hmac(key, @in, @out, statusPtr, bitness: 256); } public static byte[] CalculateHash(byte[] keyBytes, byte[] inputBytes, int bitness) { using (var hmac = GetHmacByBitness(bitness, keyBytes)) { hmac.Initialize(); _ = hmac.TransformFinalBlock(inputBytes, 0, inputBytes.Length); return hmac.Hash; } } private static HMAC GetHmacByBitness(int bitness, byte[] keyBytes) { switch (bitness) { case 256: return new HMACSHA256(keyBytes); case 512: return new HMACSHA512(keyBytes); default: throw new ArgumentOutOfRangeException($"The bitness {bitness} is unsupported."); // should not be reached } } private static bool Hmac( IntPtr key, IntPtr @in, IntPtr @out, IntPtr statusPtr, int bitness) { using (var status = new Status(StatusSafeHandle.FromIntPtr(statusPtr))) { try { var keyBinary = new Binary(BinarySafeHandle.FromIntPtr(key)); var inBinary = new Binary(BinarySafeHandle.FromIntPtr(@in)); var outBinary = new Binary(BinarySafeHandle.FromIntPtr(@out)); var keyBytes = keyBinary.ToArray(); var inBytes = inBinary.ToArray(); var outBytes = CalculateHash(keyBytes, inBytes, bitness: bitness); outBinary.WriteBytes(outBytes); return true; } catch (Exception ex) { // let mongocrypt level to handle the error status.SetStatus(1, ex.Message); return false; } } } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/IStatus.cs000066400000000000000000000015101465326363200247320ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace MongoDB.Libmongocrypt { /// /// Interface for checking the status of the various libmongocrypt options. /// internal interface IStatus { void Check(Status status); } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/KmsCredentials.cs000066400000000000000000000033631465326363200262560ustar00rootroot00000000000000/* * Copyright 2020–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; namespace MongoDB.Libmongocrypt { /// /// KMS Credentials. /// public class KmsCredentials { private readonly byte[] _credentialsBytes; /// /// Creates a class. /// /// The byte representation of credentials bson document. public KmsCredentials(byte[] credentialsBytes) { _credentialsBytes = credentialsBytes ?? throw new ArgumentNullException(nameof(credentialsBytes)); } // internal methods internal void SetCredentials(MongoCryptSafeHandle handle, Status status) { unsafe { fixed (byte* p = _credentialsBytes) { IntPtr ptr = (IntPtr)p; using (PinnedBinary pinned = new PinnedBinary(ptr, (uint)_credentialsBytes.Length)) { handle.Check(status, Library.mongocrypt_setopt_kms_providers(handle, pinned.Handle)); } } } } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/KmsKeyId.cs000066400000000000000000000064431465326363200250300ustar00rootroot00000000000000/* * Copyright 2020–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System.Collections.Generic; using System.Linq; namespace MongoDB.Libmongocrypt { /// /// Represent a kms key. /// public class KmsKeyId { private readonly IReadOnlyList _alternateKeyNameBytes; private readonly byte[] _dataKeyOptionsBytes; private readonly byte[] _keyMaterialBytes; /// /// Creates an class. /// /// The byte representation of dataOptions bson document. /// The byte representation of alternate keyName. public KmsKeyId( byte[] dataKeyOptionsBytes, IEnumerable alternateKeyNameBytes = null, byte[] keyMaterialBytes = null) { _dataKeyOptionsBytes = dataKeyOptionsBytes; _alternateKeyNameBytes = (alternateKeyNameBytes ?? Enumerable.Empty()).ToList().AsReadOnly(); _keyMaterialBytes = keyMaterialBytes; } /// /// Alternate key name bytes. /// public IReadOnlyList AlternateKeyNameBytes => _alternateKeyNameBytes; /// /// Data key options bytes. /// public byte[] DataKeyOptionsBytes => _dataKeyOptionsBytes; /// /// Key material bytes. /// public byte[] KeyMaterialBytes => _keyMaterialBytes; // internal methods internal void SetCredentials(ContextSafeHandle context, Status status) { if (_dataKeyOptionsBytes != null) { PinnedBinary.RunAsPinnedBinary(context, _dataKeyOptionsBytes, status, (h, pb) => Library.mongocrypt_ctx_setopt_key_encryption_key(h, pb)); } SetAlternateKeyNamesIfConfigured(context, status); SetKeyMaterialIfConfigured(context, status); } // private methods private void SetAlternateKeyNamesIfConfigured(ContextSafeHandle context, Status status) { foreach (var alternateKeyNameBytes in _alternateKeyNameBytes) { PinnedBinary.RunAsPinnedBinary(context, alternateKeyNameBytes, status, (h, pb) => Library.mongocrypt_ctx_setopt_key_alt_name(h, pb)); } } private void SetKeyMaterialIfConfigured(ContextSafeHandle context, Status status) { if (_keyMaterialBytes != null) { PinnedBinary.RunAsPinnedBinary(context, _keyMaterialBytes, status, (h, pb) => Library.mongocrypt_ctx_setopt_key_material(h, pb)); } } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/KmsRequest.cs000066400000000000000000000070151465326363200254470ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Runtime.InteropServices; namespace MongoDB.Libmongocrypt { /// /// Contains a KMS request to make to a remote server. /// /// public class KmsRequest : IStatus { private readonly Status _status; private readonly IntPtr _id; internal KmsRequest(IntPtr id) { _id = id; _status = new Status(); } /// /// Gets the bytes needed from the remote side. No more data is need when this returns 0. /// /// /// The number of bytes needed. /// public uint BytesNeeded { get { return Library.mongocrypt_kms_ctx_bytes_needed(_id); } } /// /// Gets the endpoint. /// /// /// The endpoint. /// public string Endpoint { get { IntPtr stringPointer = IntPtr.Zero; Check(Library.mongocrypt_kms_ctx_endpoint(_id, ref stringPointer)); return Marshal.PtrToStringAnsi(stringPointer); } } /// /// Gets the kms provider name. /// /// /// The kms provider name. /// public string KmsProvider { get { var kmsProviderNamePointer = Library.mongocrypt_kms_ctx_get_kms_provider(_id, length: out _); return Marshal.PtrToStringAnsi(kmsProviderNamePointer); } } /// /// Gets the message to send to KMS. /// /// The message public Binary Message { get { Binary binary = new Binary(); Check(Library.mongocrypt_kms_ctx_message(_id, binary.Handle)); return binary; } } /// /// Feeds the response back to the libmongocrypt /// /// The response. public void Feed(byte[] buffer) { unsafe { fixed (byte* p = buffer) { IntPtr ptr = (IntPtr)p; using (PinnedBinary pinned = new PinnedBinary(ptr, (uint)buffer.Length)) { Check(Library.mongocrypt_kms_ctx_feed(_id, pinned.Handle)); } } } } void IStatus.Check(Status status) { Library.mongocrypt_kms_ctx_status(_id, status.Handle); } private void Check(bool success) { if (!success) { _status.Check(this); } } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/KmsRequestCollection.cs000066400000000000000000000034531465326363200274650ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections; using System.Collections.Generic; namespace MongoDB.Libmongocrypt { /// /// A collection of kms requests to make. /// /// When all requests are done, MarkDone most be called. /// /// public class KmsRequestCollection : IReadOnlyCollection { private List _requests; private CryptContext _parent; internal KmsRequestCollection(List requests, CryptContext parent) { _requests = requests; _parent = parent; } int IReadOnlyCollection.Count => _requests.Count; IEnumerator IEnumerable.GetEnumerator() { return _requests.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _requests.GetEnumerator(); } /// /// Marks alls the KMS requests as complete. /// public void MarkDone() { _parent.MarkKmsDone(); } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/Library.cs000066400000000000000000001375771465326363200247710ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Runtime.InteropServices; namespace MongoDB.Libmongocrypt { /// /// The low-level interface to libmongocrypt. /// public class Library { static Library() { _mongocrypt_version = new Lazy( () => __loader.Value.GetFunction("mongocrypt_version"), true); _mongocrypt_new = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_new")), true); _mongocrypt_setopt_log_handler = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_setopt_log_handler")), true); _mongocrypt_init = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_init")), true); _mongocrypt_destroy = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_destroy")), true); _mongocrypt_status = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_status")), true); _mongocrypt_setopt_kms_providers = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_setopt_kms_providers")), true); _mongocrypt_ctx_setopt_key_encryption_key = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_setopt_key_encryption_key")), true); _mongocrypt_is_crypto_available = new Lazy( () => __loader.Value.GetFunction("mongocrypt_is_crypto_available"), true); _mongocrypt_setopt_aes_256_ecb = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_setopt_aes_256_ecb")), true); _mongocrypt_setopt_bypass_query_analysis = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_setopt_bypass_query_analysis")), true); _mongocrypt_setopt_crypto_hooks = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_setopt_crypto_hooks")), true); _mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5 = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5")), true); _mongocrypt_setopt_encrypted_field_config_map = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_setopt_encrypted_field_config_map")), true); _mongocrypt_setopt_schema_map = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_setopt_schema_map")), true); _mongocrypt_setopt_append_crypt_shared_lib_search_path = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_setopt_append_crypt_shared_lib_search_path")), true); _mongocrypt_setopt_set_crypt_shared_lib_path_override = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_setopt_set_crypt_shared_lib_path_override")), true); _mongocrypt_setopt_use_need_kms_credentials_state = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_setopt_use_need_kms_credentials_state")), true); _mongocrypt_crypt_shared_lib_version_string = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_crypt_shared_lib_version_string")), true); _mongocrypt_crypt_shared_lib_version = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_crypt_shared_lib_version")), true); _mongocrypt_status_new = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_status_new")), true); _mongocrypt_status_destroy = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_status_destroy")), true); _mongocrypt_status_type = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_status_type")), true); _mongocrypt_status_code = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_status_code")), true); _mongocrypt_status_message = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_status_message")), true); _mongocrypt_status_ok = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_status_ok")), true); _mongocrypt_status_set = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_status_set")), true); _mongocrypt_binary_new = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_binary_new")), true); _mongocrypt_binary_destroy = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_binary_destroy")), true); _mongocrypt_binary_new_from_data = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_binary_new_from_data")), true); _mongocrypt_binary_data = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_binary_data")), true); _mongocrypt_binary_len = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_binary_len")), true); _mongocrypt_ctx_new = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_ctx_new")), true); _mongocrypt_ctx_setopt_key_material = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_setopt_key_material")), true); _mongocrypt_ctx_setopt_masterkey_aws = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_setopt_masterkey_aws")), true); _mongocrypt_ctx_setopt_masterkey_aws_endpoint = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_setopt_masterkey_aws_endpoint")), true); _mongocrypt_ctx_setopt_masterkey_local = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_setopt_masterkey_local")), true); _mongocrypt_ctx_setopt_key_alt_name = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_setopt_key_alt_name")), true); _mongocrypt_ctx_setopt_key_id = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_setopt_key_id")), true); _mongocrypt_ctx_setopt_algorithm = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_setopt_algorithm")), true); _mongocrypt_ctx_setopt_algorithm_range = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_setopt_algorithm_range")), true); _mongocrypt_ctx_setopt_contention_factor = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_setopt_contention_factor")), true); _mongocrypt_ctx_setopt_query_type = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_setopt_query_type")), true); _mongocrypt_ctx_status = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_ctx_status")), true); _mongocrypt_ctx_encrypt_init = new Lazy( () => __loader.Value .GetFunction(("mongocrypt_ctx_encrypt_init")), true); _mongocrypt_ctx_decrypt_init = new Lazy( () => __loader.Value .GetFunction(("mongocrypt_ctx_decrypt_init")), true); _mongocrypt_ctx_explicit_encrypt_init = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_explicit_encrypt_init")), true); _mongocrypt_ctx_explicit_encrypt_expression_init = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_explicit_encrypt_expression_init")), true); _mongocrypt_ctx_explicit_decrypt_init = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_ctx_explicit_decrypt_init")), true); _mongocrypt_ctx_datakey_init = new Lazy( () => __loader.Value .GetFunction(("mongocrypt_ctx_datakey_init")), true); _mongocrypt_ctx_provide_kms_providers = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_ctx_provide_kms_providers")), true); _mongocrypt_ctx_state = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_ctx_state")), true); _mongocrypt_ctx_mongo_op = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_ctx_mongo_op")), true); _mongocrypt_ctx_mongo_feed = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_ctx_mongo_feed")), true); _mongocrypt_ctx_mongo_done = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_ctx_mongo_done")), true); _mongocrypt_ctx_next_kms_ctx = new Lazy( () => __loader.Value .GetFunction(("mongocrypt_ctx_next_kms_ctx")), true); _mongocrypt_ctx_rewrap_many_datakey_init = new Lazy( () => __loader.Value .GetFunction(("mongocrypt_ctx_rewrap_many_datakey_init")), true); _mongocrypt_kms_ctx_endpoint = new Lazy( () => __loader.Value .GetFunction(("mongocrypt_kms_ctx_endpoint")), true); _mongocrypt_kms_ctx_message = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_kms_ctx_message")), true); _mongocrypt_kms_ctx_bytes_needed = new Lazy( () => __loader.Value.GetFunction( ("mongocrypt_kms_ctx_bytes_needed")), true); _mongocrypt_kms_ctx_feed = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_kms_ctx_feed")), true); _mongocrypt_kms_ctx_status = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_kms_ctx_status")), true); _mongocrypt_ctx_kms_done = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_ctx_kms_done")), true); _mongocrypt_ctx_finalize = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_ctx_finalize")), true); _mongocrypt_ctx_destroy = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_ctx_destroy")), true); _mongocrypt_kms_ctx_get_kms_provider = new Lazy( () => __loader.Value.GetFunction(("mongocrypt_kms_ctx_get_kms_provider")), true); } /// /// Gets the version of libmongocrypt. /// /// /// The version. /// public static string Version { get { uint length; IntPtr p = mongocrypt_version(out length); return Marshal.PtrToStringAnsi(p); } } internal static Delegates.mongocrypt_version mongocrypt_version => _mongocrypt_version.Value; internal static Delegates.mongocrypt_new mongocrypt_new => _mongocrypt_new.Value; internal static Delegates.mongocrypt_setopt_log_handler mongocrypt_setopt_log_handler => _mongocrypt_setopt_log_handler.Value; internal static Delegates.mongocrypt_setopt_kms_providers mongocrypt_setopt_kms_providers => _mongocrypt_setopt_kms_providers.Value; internal static Delegates.mongocrypt_ctx_setopt_key_encryption_key mongocrypt_ctx_setopt_key_encryption_key => _mongocrypt_ctx_setopt_key_encryption_key.Value; internal static Delegates.mongocrypt_is_crypto_available mongocrypt_is_crypto_available => _mongocrypt_is_crypto_available.Value; internal static Delegates.mongocrypt_setopt_aes_256_ecb mongocrypt_setopt_aes_256_ecb => _mongocrypt_setopt_aes_256_ecb.Value; internal static Delegates.mongocrypt_setopt_bypass_query_analysis mongocrypt_setopt_bypass_query_analysis => _mongocrypt_setopt_bypass_query_analysis.Value; internal static Delegates.mongocrypt_setopt_crypto_hooks mongocrypt_setopt_crypto_hooks => _mongocrypt_setopt_crypto_hooks.Value; internal static Delegates.mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5 mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5 => _mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5.Value; internal static Delegates.mongocrypt_setopt_encrypted_field_config_map mongocrypt_setopt_encrypted_field_config_map => _mongocrypt_setopt_encrypted_field_config_map.Value; internal static Delegates.mongocrypt_setopt_schema_map mongocrypt_setopt_schema_map => _mongocrypt_setopt_schema_map.Value; internal static Delegates.mongocrypt_setopt_append_crypt_shared_lib_search_path mongocrypt_setopt_append_crypt_shared_lib_search_path => _mongocrypt_setopt_append_crypt_shared_lib_search_path.Value; internal static Delegates.mongocrypt_setopt_set_crypt_shared_lib_path_override mongocrypt_setopt_set_crypt_shared_lib_path_override => _mongocrypt_setopt_set_crypt_shared_lib_path_override.Value; internal static Delegates.mongocrypt_setopt_use_need_kms_credentials_state mongocrypt_setopt_use_need_kms_credentials_state => _mongocrypt_setopt_use_need_kms_credentials_state.Value; internal static Delegates.mongocrypt_crypt_shared_lib_version_string mongocrypt_crypt_shared_lib_version_string => _mongocrypt_crypt_shared_lib_version_string.Value; internal static Delegates.mongocrypt_crypt_shared_lib_version mongocrypt_crypt_shared_lib_version => _mongocrypt_crypt_shared_lib_version.Value; internal static Delegates.mongocrypt_init mongocrypt_init => _mongocrypt_init.Value; internal static Delegates.mongocrypt_destroy mongocrypt_destroy => _mongocrypt_destroy.Value; internal static Delegates.mongocrypt_status mongocrypt_status => _mongocrypt_status.Value; internal static Delegates.mongocrypt_status_new mongocrypt_status_new => _mongocrypt_status_new.Value; internal static Delegates.mongocrypt_status_destroy mongocrypt_status_destroy => _mongocrypt_status_destroy.Value; internal static Delegates.mongocrypt_status_type mongocrypt_status_type => _mongocrypt_status_type.Value; internal static Delegates.mongocrypt_status_code mongocrypt_status_code => _mongocrypt_status_code.Value; internal static Delegates.mongocrypt_status_message mongocrypt_status_message => _mongocrypt_status_message.Value; internal static Delegates.mongocrypt_status_ok mongocrypt_status_ok => _mongocrypt_status_ok.Value; internal static Delegates.mongocrypt_status_set mongocrypt_status_set => _mongocrypt_status_set.Value; internal static Delegates.mongocrypt_binary_new mongocrypt_binary_new => _mongocrypt_binary_new.Value; internal static Delegates.mongocrypt_binary_destroy mongocrypt_binary_destroy => _mongocrypt_binary_destroy.Value; internal static Delegates.mongocrypt_binary_new_from_data mongocrypt_binary_new_from_data => _mongocrypt_binary_new_from_data.Value; internal static Delegates.mongocrypt_binary_data mongocrypt_binary_data => _mongocrypt_binary_data.Value; internal static Delegates.mongocrypt_binary_len mongocrypt_binary_len => _mongocrypt_binary_len.Value; internal static Delegates.mongocrypt_ctx_new mongocrypt_ctx_new => _mongocrypt_ctx_new.Value; internal static Delegates.mongocrypt_ctx_setopt_key_material mongocrypt_ctx_setopt_key_material => _mongocrypt_ctx_setopt_key_material.Value; internal static Delegates.mongocrypt_ctx_setopt_masterkey_aws mongocrypt_ctx_setopt_masterkey_aws => _mongocrypt_ctx_setopt_masterkey_aws.Value; internal static Delegates.mongocrypt_ctx_setopt_masterkey_aws_endpoint mongocrypt_ctx_setopt_masterkey_aws_endpoint => _mongocrypt_ctx_setopt_masterkey_aws_endpoint.Value; internal static Delegates.mongocrypt_ctx_status mongocrypt_ctx_status => _mongocrypt_ctx_status.Value; internal static Delegates.mongocrypt_ctx_encrypt_init mongocrypt_ctx_encrypt_init => _mongocrypt_ctx_encrypt_init.Value; internal static Delegates.mongocrypt_ctx_decrypt_init mongocrypt_ctx_decrypt_init => _mongocrypt_ctx_decrypt_init.Value; internal static Delegates.mongocrypt_ctx_explicit_encrypt_init mongocrypt_ctx_explicit_encrypt_init => _mongocrypt_ctx_explicit_encrypt_init.Value; internal static Delegates.mongocrypt_ctx_explicit_encrypt_expression_init mongocrypt_ctx_explicit_encrypt_expression_init => _mongocrypt_ctx_explicit_encrypt_expression_init.Value; internal static Delegates.mongocrypt_ctx_explicit_decrypt_init mongocrypt_ctx_explicit_decrypt_init => _mongocrypt_ctx_explicit_decrypt_init.Value; internal static Delegates.mongocrypt_ctx_datakey_init mongocrypt_ctx_datakey_init => _mongocrypt_ctx_datakey_init.Value; internal static Delegates.mongocrypt_ctx_provide_kms_providers mongocrypt_ctx_provide_kms_providers => _mongocrypt_ctx_provide_kms_providers.Value; internal static Delegates.mongocrypt_ctx_setopt_masterkey_local mongocrypt_ctx_setopt_masterkey_local => _mongocrypt_ctx_setopt_masterkey_local.Value; internal static Delegates.mongocrypt_ctx_setopt_key_id mongocrypt_ctx_setopt_key_id => _mongocrypt_ctx_setopt_key_id.Value; internal static Delegates.mongocrypt_ctx_setopt_key_alt_name mongocrypt_ctx_setopt_key_alt_name => _mongocrypt_ctx_setopt_key_alt_name.Value; internal static Delegates.mongocrypt_ctx_setopt_algorithm mongocrypt_ctx_setopt_algorithm => _mongocrypt_ctx_setopt_algorithm.Value; internal static Delegates.mongocrypt_ctx_setopt_algorithm_range mongocrypt_ctx_setopt_algorithm_range => _mongocrypt_ctx_setopt_algorithm_range.Value; internal static Delegates.mongocrypt_ctx_setopt_contention_factor mongocrypt_ctx_setopt_contention_factor => _mongocrypt_ctx_setopt_contention_factor.Value; internal static Delegates.mongocrypt_ctx_setopt_query_type mongocrypt_ctx_setopt_query_type => _mongocrypt_ctx_setopt_query_type.Value; internal static Delegates.mongocrypt_ctx_state mongocrypt_ctx_state => _mongocrypt_ctx_state.Value; internal static Delegates.mongocrypt_ctx_mongo_op mongocrypt_ctx_mongo_op => _mongocrypt_ctx_mongo_op.Value; internal static Delegates.mongocrypt_ctx_mongo_feed mongocrypt_ctx_mongo_feed => _mongocrypt_ctx_mongo_feed.Value; internal static Delegates.mongocrypt_ctx_mongo_done mongocrypt_ctx_mongo_done => _mongocrypt_ctx_mongo_done.Value; internal static Delegates.mongocrypt_ctx_next_kms_ctx mongocrypt_ctx_next_kms_ctx => _mongocrypt_ctx_next_kms_ctx.Value; internal static Delegates.mongocrypt_ctx_rewrap_many_datakey_init mongocrypt_ctx_rewrap_many_datakey_init => _mongocrypt_ctx_rewrap_many_datakey_init.Value; internal static Delegates.mongocrypt_kms_ctx_endpoint mongocrypt_kms_ctx_endpoint => _mongocrypt_kms_ctx_endpoint.Value; internal static Delegates.mongocrypt_kms_ctx_message mongocrypt_kms_ctx_message => _mongocrypt_kms_ctx_message.Value; internal static Delegates.mongocrypt_kms_ctx_bytes_needed mongocrypt_kms_ctx_bytes_needed => _mongocrypt_kms_ctx_bytes_needed.Value; internal static Delegates.mongocrypt_kms_ctx_feed mongocrypt_kms_ctx_feed => _mongocrypt_kms_ctx_feed.Value; internal static Delegates.mongocrypt_kms_ctx_status mongocrypt_kms_ctx_status => _mongocrypt_kms_ctx_status.Value; internal static Delegates.mongocrypt_ctx_kms_done mongocrypt_ctx_kms_done => _mongocrypt_ctx_kms_done.Value; internal static Delegates.mongocrypt_ctx_finalize mongocrypt_ctx_finalize => _mongocrypt_ctx_finalize.Value; internal static Delegates.mongocrypt_ctx_destroy mongocrypt_ctx_destroy => _mongocrypt_ctx_destroy.Value; internal static Delegates.mongocrypt_kms_ctx_get_kms_provider mongocrypt_kms_ctx_get_kms_provider => _mongocrypt_kms_ctx_get_kms_provider.Value; private static readonly Lazy __loader = new Lazy( () => new LibraryLoader(), true); private static readonly Lazy _mongocrypt_version; private static readonly Lazy _mongocrypt_new; private static readonly Lazy _mongocrypt_setopt_log_handler; private static readonly Lazy _mongocrypt_setopt_kms_providers; private static readonly Lazy _mongocrypt_ctx_setopt_key_encryption_key; private static readonly Lazy _mongocrypt_is_crypto_available; private static readonly Lazy _mongocrypt_setopt_aes_256_ecb; private static readonly Lazy _mongocrypt_setopt_bypass_query_analysis; private static readonly Lazy _mongocrypt_setopt_crypto_hooks; private static readonly Lazy _mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5; private static readonly Lazy _mongocrypt_setopt_encrypted_field_config_map; private static readonly Lazy _mongocrypt_setopt_schema_map; private static readonly Lazy _mongocrypt_setopt_append_crypt_shared_lib_search_path; private static readonly Lazy _mongocrypt_setopt_set_crypt_shared_lib_path_override; private static readonly Lazy _mongocrypt_setopt_use_need_kms_credentials_state; private static readonly Lazy _mongocrypt_crypt_shared_lib_version_string; private static readonly Lazy _mongocrypt_crypt_shared_lib_version; private static readonly Lazy _mongocrypt_init; private static readonly Lazy _mongocrypt_destroy; private static readonly Lazy _mongocrypt_status; private static readonly Lazy _mongocrypt_status_new; private static readonly Lazy _mongocrypt_status_destroy; private static readonly Lazy _mongocrypt_status_type; private static readonly Lazy _mongocrypt_status_code; private static readonly Lazy _mongocrypt_status_message; private static readonly Lazy _mongocrypt_status_ok; private static readonly Lazy _mongocrypt_status_set; private static readonly Lazy _mongocrypt_binary_new; private static readonly Lazy _mongocrypt_binary_destroy; private static readonly Lazy _mongocrypt_binary_new_from_data; private static readonly Lazy _mongocrypt_binary_data; private static readonly Lazy _mongocrypt_binary_len; private static readonly Lazy _mongocrypt_ctx_new; private static readonly Lazy _mongocrypt_ctx_setopt_key_material; private static readonly Lazy _mongocrypt_ctx_setopt_masterkey_aws; private static readonly Lazy _mongocrypt_ctx_setopt_masterkey_aws_endpoint; private static readonly Lazy _mongocrypt_ctx_status; private static readonly Lazy _mongocrypt_ctx_encrypt_init; private static readonly Lazy _mongocrypt_ctx_decrypt_init; private static readonly Lazy _mongocrypt_ctx_explicit_encrypt_init; private static readonly Lazy _mongocrypt_ctx_explicit_encrypt_expression_init; private static readonly Lazy _mongocrypt_ctx_explicit_decrypt_init; private static readonly Lazy _mongocrypt_ctx_datakey_init; private static readonly Lazy _mongocrypt_ctx_provide_kms_providers; private static readonly Lazy _mongocrypt_ctx_setopt_masterkey_local; private static readonly Lazy _mongocrypt_ctx_setopt_key_id; private static readonly Lazy _mongocrypt_ctx_setopt_key_alt_name; private static readonly Lazy _mongocrypt_ctx_setopt_algorithm; private static readonly Lazy _mongocrypt_ctx_setopt_algorithm_range; private static readonly Lazy _mongocrypt_ctx_setopt_contention_factor; private static readonly Lazy _mongocrypt_ctx_setopt_query_type; private static readonly Lazy _mongocrypt_ctx_state; private static readonly Lazy _mongocrypt_ctx_mongo_op; private static readonly Lazy _mongocrypt_ctx_mongo_feed; private static readonly Lazy _mongocrypt_ctx_mongo_done; private static readonly Lazy _mongocrypt_ctx_next_kms_ctx; private static readonly Lazy _mongocrypt_ctx_rewrap_many_datakey_init; private static readonly Lazy _mongocrypt_kms_ctx_endpoint; private static readonly Lazy _mongocrypt_kms_ctx_message; private static readonly Lazy _mongocrypt_kms_ctx_bytes_needed; private static readonly Lazy _mongocrypt_kms_ctx_feed; private static readonly Lazy _mongocrypt_kms_ctx_status; private static readonly Lazy _mongocrypt_ctx_kms_done; private static readonly Lazy _mongocrypt_ctx_finalize; private static readonly Lazy _mongocrypt_ctx_destroy; private static readonly Lazy _mongocrypt_kms_ctx_get_kms_provider; // nested types internal enum StatusType { MONGOCRYPT_STATUS_OK = 0, MONGOCRYPT_STATUS_ERROR_CLIENT, MONGOCRYPT_STATUS_ERROR_KMS } internal class Delegates { // NOTE: Bool is expected to be 4 bytes during marshalling so we need to overwite it // https://blogs.msdn.microsoft.com/jaredpar/2008/10/14/pinvoke-and-bool-or-should-i-say-bool/ public delegate IntPtr mongocrypt_version(out uint length); public delegate MongoCryptSafeHandle mongocrypt_new(); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_is_crypto_available(); public delegate void LogCallback([MarshalAs(UnmanagedType.I4)] LogLevel level, IntPtr messasge, uint message_length, IntPtr context); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_setopt_log_handler(MongoCryptSafeHandle handle, [MarshalAs(UnmanagedType.FunctionPtr)] LogCallback log_fn, IntPtr log_ctx); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_setopt_kms_providers( MongoCryptSafeHandle handle, BinarySafeHandle kms_providers); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_setopt_key_encryption_key( ContextSafeHandle handle, BinarySafeHandle bin); [return: MarshalAs(UnmanagedType.I1)] public delegate bool HashCallback( IntPtr ctx, IntPtr @in, IntPtr @out, IntPtr status); [return: MarshalAs(UnmanagedType.I1)] public delegate bool CryptoHmacCallback( IntPtr ctx, IntPtr key, IntPtr @in, IntPtr @out, IntPtr status); /// /// typedef bool (*mongocrypt_crypto_fn) ( /// void *ctx, // mongocrypt_binary_t* key, // mongocrypt_binary_t *iv, // mongocrypt_binary_t*in, // mongocrypt_binary_t*out, // uint32_t* bytes_written, // mongocrypt_status_t *status); /// [return: MarshalAs(UnmanagedType.I1)] public delegate bool CryptoCallback( IntPtr ctx, IntPtr key, IntPtr iv, IntPtr @in, IntPtr @out, ref uint bytes_written, IntPtr status); [return: MarshalAs(UnmanagedType.I1)] public delegate bool RandomCallback( IntPtr ctx, IntPtr @out, uint count, IntPtr statusPtr); /// /// bool mongocrypt_setopt_aes_256_ecb(mongocrypt_t* crypt, mongocrypt_crypto_fn aes_256_ecb_encrypt, void* ctx); /// [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_setopt_aes_256_ecb( MongoCryptSafeHandle handle, [MarshalAs(UnmanagedType.FunctionPtr)] CryptoCallback aes_256_ecb_encrypt, IntPtr ctx); /// /// void mongocrypt_setopt_bypass_query_analysis(mongocrypt_t* crypt); /// public delegate void mongocrypt_setopt_bypass_query_analysis(MongoCryptSafeHandle handle); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_setopt_crypto_hooks( MongoCryptSafeHandle handle, [MarshalAs(UnmanagedType.FunctionPtr)] CryptoCallback aes_256_cbc_encrypt, [MarshalAs(UnmanagedType.FunctionPtr)] CryptoCallback aes_256_cbc_decrypt, [MarshalAs(UnmanagedType.FunctionPtr)] RandomCallback random, [MarshalAs(UnmanagedType.FunctionPtr)] CryptoHmacCallback hmac_sha_512, [MarshalAs(UnmanagedType.FunctionPtr)] CryptoHmacCallback hmac_sha_256, [MarshalAs(UnmanagedType.FunctionPtr)] HashCallback mongocrypt_hash_fn, IntPtr ctx); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5( MongoCryptSafeHandle handle, [MarshalAs(UnmanagedType.FunctionPtr)] CryptoHmacCallback sign_rsaes_pkcs1_v1_5, IntPtr sign_ctx); /// /// bool mongocrypt_setopt_encrypted_field_config_map(mongocrypt_t* crypt, mongocrypt_binary_t* efc_map) /// [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_setopt_encrypted_field_config_map(MongoCryptSafeHandle handle, BinarySafeHandle efc_map); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_setopt_schema_map(MongoCryptSafeHandle handle, BinarySafeHandle schema); /// /// void mongocrypt_setopt_append_crypt_shared_lib_search_path(mongocrypt_t* crypt, const char* path); /// public delegate void mongocrypt_setopt_append_crypt_shared_lib_search_path(MongoCryptSafeHandle handle, [MarshalAs(UnmanagedType.LPStr)] string path); /// /// void mongocrypt_setopt_set_crypt_shared_lib_path_override(mongocrypt_t* crypt, const char* path); /// public delegate void mongocrypt_setopt_set_crypt_shared_lib_path_override(MongoCryptSafeHandle handle, [MarshalAs(UnmanagedType.LPStr)] string path); /// /// void mongocrypt_setopt_use_need_kms_credentials_state(mongocrypt_t* crypt); /// /// public delegate void mongocrypt_setopt_use_need_kms_credentials_state(MongoCryptSafeHandle handle); /// /// const char * mongocrypt_crypt_shared_lib_version_string(const mongocrypt_t* crypt, uint32_t *len); /// public delegate IntPtr mongocrypt_crypt_shared_lib_version_string(MongoCryptSafeHandle handle, out uint length); /// /// uint64_t mongocrypt_crypt_shared_lib_version(const mongocrypt_t* crypt); /// public delegate ulong mongocrypt_crypt_shared_lib_version(MongoCryptSafeHandle handle); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_init(MongoCryptSafeHandle handle); public delegate void mongocrypt_destroy(IntPtr ptr); public delegate bool mongocrypt_status(MongoCryptSafeHandle handle, StatusSafeHandle ptr); public delegate StatusSafeHandle mongocrypt_status_new(); public delegate void mongocrypt_status_destroy(IntPtr ptr); public delegate StatusType mongocrypt_status_type(StatusSafeHandle ptr); public delegate uint mongocrypt_status_code(StatusSafeHandle ptr); public delegate IntPtr mongocrypt_status_message(StatusSafeHandle ptr, out uint length); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_status_ok(StatusSafeHandle ptr); // currently it does nothing due to MONGOCRYPT-257 public delegate void mongocrypt_status_set(StatusSafeHandle ptr, int type, uint code, IntPtr msg, int length); public delegate BinarySafeHandle mongocrypt_binary_new(); public delegate void mongocrypt_binary_destroy(IntPtr ptr); public delegate BinarySafeHandle mongocrypt_binary_new_from_data(IntPtr ptr, uint len); public delegate IntPtr mongocrypt_binary_data(BinarySafeHandle handle); public delegate uint mongocrypt_binary_len(BinarySafeHandle handle); public delegate ContextSafeHandle mongocrypt_ctx_new(MongoCryptSafeHandle handle); /// /// bool mongocrypt_ctx_setopt_key_material(mongocrypt_ctx_t* ctx, mongocrypt_binary_t* key_material) /// [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_setopt_key_material(ContextSafeHandle handle, BinarySafeHandle key_material); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_setopt_masterkey_aws(ContextSafeHandle handle, IntPtr region, int region_len, IntPtr cmk, int cmk_len); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_setopt_masterkey_aws_endpoint( ContextSafeHandle handle, IntPtr endpoint, int endpoint_len); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_status(ContextSafeHandle handle, StatusSafeHandle status); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_encrypt_init(ContextSafeHandle handle, IntPtr ns, int length, BinarySafeHandle binary); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_decrypt_init(ContextSafeHandle handle, BinarySafeHandle binary); /// /// bool mongocrypt_ctx_explicit_encrypt_init(mongocrypt_ctx_t* ctx, mongocrypt_binary_t* msg) /// [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_explicit_encrypt_init(ContextSafeHandle handle, BinarySafeHandle binary); /// /// bool mongocrypt_ctx_explicit_encrypt_expression_init(mongocrypt_ctx_t* ctx, mongocrypt_binary_t* msg) /// [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_explicit_encrypt_expression_init(ContextSafeHandle handle, BinarySafeHandle msg); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_explicit_decrypt_init(ContextSafeHandle handle, BinarySafeHandle binary); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_datakey_init(ContextSafeHandle handle); /// /// bool mongocrypt_ctx_provide_kms_providers(mongocrypt_ctx_t* ctx, mongocrypt_binary_t* kms_providers_definition); /// [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_provide_kms_providers(ContextSafeHandle handle, BinarySafeHandle kms_providers_definition); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_setopt_schema_map(ContextSafeHandle handle, BinarySafeHandle binary); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_setopt_masterkey_local(ContextSafeHandle handle); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_setopt_key_alt_name(ContextSafeHandle handle, BinarySafeHandle binary); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_setopt_key_id(ContextSafeHandle handle, BinarySafeHandle binary); /// /// bool mongocrypt_ctx_setopt_algorithm(mongocrypt_ctx_t* ctx, const char* algorithm, int len); /// [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_setopt_algorithm(ContextSafeHandle handle, [MarshalAs(UnmanagedType.LPStr)] string algorithm, int length); /// /// bool mongocrypt_ctx_setopt_algorithm_range(mongocrypt_ctx_t* ctx, mongocrypt_binary_t* opts); /// [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_setopt_algorithm_range(ContextSafeHandle handle, BinarySafeHandle opts); /// /// bool mongocrypt_ctx_setopt_contention_factor(mongocrypt_ctx_t* ctx, int64_t contention_factor); /// [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_setopt_contention_factor(ContextSafeHandle ctx, long contention_factor); /// /// bool mongocrypt_ctx_setopt_query_type(mongocrypt_ctx_t* ctx, const char* query_type, int len) /// [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_setopt_query_type(ContextSafeHandle ctx, [MarshalAs(UnmanagedType.LPStr)] string query_type, int length); public delegate CryptContext.StateCode mongocrypt_ctx_state(ContextSafeHandle handle); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_mongo_op(ContextSafeHandle handle, BinarySafeHandle bsonOp); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_mongo_feed(ContextSafeHandle handle, BinarySafeHandle reply); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_mongo_done(ContextSafeHandle handle); public delegate IntPtr mongocrypt_ctx_next_kms_ctx(ContextSafeHandle handle); /// /// bool mongocrypt_ctx_rewrap_many_datakey_init(mongocrypt_ctx_t* ctx, mongocrypt_binary_t* filter); /// [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_rewrap_many_datakey_init(ContextSafeHandle handle, BinarySafeHandle filter); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_kms_ctx_endpoint(IntPtr handle, ref IntPtr endpoint); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_kms_ctx_message(IntPtr handle, BinarySafeHandle binary); public delegate uint mongocrypt_kms_ctx_bytes_needed(IntPtr handle); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_kms_ctx_feed(IntPtr handle, BinarySafeHandle binary); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_kms_ctx_status(IntPtr handle, StatusSafeHandle status); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_kms_done(ContextSafeHandle handle); [return: MarshalAs(UnmanagedType.I1)] public delegate bool mongocrypt_ctx_finalize(ContextSafeHandle handle, BinarySafeHandle binary); public delegate void mongocrypt_ctx_destroy(IntPtr ptr); public delegate IntPtr mongocrypt_kms_ctx_get_kms_provider(IntPtr handle, out uint length); } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/LibraryLoader.cs000066400000000000000000000247131465326363200261030ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.InteropServices; namespace MongoDB.Libmongocrypt { /// /// LibraryLoader abstracts loading C functions from a shared library across OS /// internal class LibraryLoader { private ISharedLibraryLoader _loader; private static readonly string __libmongocryptLibPath = Environment.GetEnvironmentVariable("LIBMONGOCRYPT_PATH"); public LibraryLoader() { if (!Environment.Is64BitProcess) { throw new PlatformNotSupportedException($"{this.GetType().Namespace} needs to be run in a 64-bit process."); } // Windows: // https://stackoverflow.com/questions/2864673/specify-the-search-path-for-dllimport-in-net // // See for better ways // https://github.com/dotnet/coreclr/issues/930 // https://github.com/dotnet/corefx/issues/32015 List candidatePaths = new List(); // In the nuget package, get the shared library from a relative path of this assembly // Also, when running locally, get the shared library from a relative path of this assembly var assembly = typeof(LibraryLoader).GetTypeInfo().Assembly; var location = assembly.Location; string basepath = Path.GetDirectoryName(location); candidatePaths.Add(basepath); switch (OperatingSystemHelper.CurrentOperatingSystem) { case OperatingSystemPlatform.MacOS: _loader = new DarwinLibraryLoader(candidatePaths); break; case OperatingSystemPlatform.Linux: _loader = new LinuxLibrary(candidatePaths); break; case OperatingSystemPlatform.Windows: _loader = new WindowsLibrary(candidatePaths); break; default: // should not be reached. If we're here, then there is a bug in OperatingSystemHelper throw new PlatformNotSupportedException("Unsupported operating system."); } } private static string FindLibrary(IList basePaths, string[] suffixPaths, string library) { var candidates = new List(); foreach (var basePath in basePaths) { foreach (var suffix in suffixPaths) { string path = Path.Combine(basePath, suffix, library); if (File.Exists(path)) { return path; } candidates.Add(path); } } throw new FileNotFoundException("Could not find: " + library + " --\n Tried: " + string.Join(",", candidates)); } public T GetFunction(string name) { IntPtr ptr = _loader.GetFunction(name); if (ptr == IntPtr.Zero) { throw new FunctionNotFoundException(name); } return Marshal.GetDelegateForFunctionPointer(ptr); } public class FunctionNotFoundException : Exception { public FunctionNotFoundException(string message) : base(message) { } } private interface ISharedLibraryLoader { IntPtr GetFunction(string name); } /// /// macOS Dynamic Library loader using dlsym /// private class DarwinLibraryLoader : ISharedLibraryLoader { // See dlfcn.h // #define RTLD_LAZY 0x1 // #define RTLD_NOW 0x2 // #define RTLD_LOCAL 0x4 // #define RTLD_GLOBAL 0x8 public const int RTLD_GLOBAL = 0x8; public const int RTLD_NOW = 0x2; private static readonly string[] __suffixPaths = { "../../runtimes/osx/native/", "runtimes/osx/native/", string.Empty }; private readonly IntPtr _handle; public DarwinLibraryLoader(List candidatePaths) { var path = __libmongocryptLibPath ?? FindLibrary(candidatePaths, __suffixPaths, "libmongocrypt.dylib"); _handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW); if (_handle == IntPtr.Zero) { throw new FileNotFoundException(path); } } public IntPtr GetFunction(string name) { return dlsym(_handle, name); } #pragma warning disable IDE1006 // Naming Styles [DllImport("libdl")] public static extern IntPtr dlopen(string filename, int flags); [DllImport("libdl", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern IntPtr dlsym(IntPtr handle, string symbol); #pragma warning restore IDE1006 // Naming Styles } /// /// Linux Shared Object loader using dlsym /// private class LinuxLibrary : ISharedLibraryLoader { // See dlfcn.h // #define RTLD_LAZY 0x1 // #define RTLD_NOW 0x2 // #define RTLD_LOCAL 0x4 // #define RTLD_GLOBAL 0x100 public const int RTLD_GLOBAL = 0x100; public const int RTLD_NOW = 0x2; private static readonly bool _use_libdl1; static LinuxLibrary() { try { Libdl1.dlerror(); _use_libdl1 = true; } catch { _use_libdl1 = false; } } private static readonly string[] __suffixPaths = { "../../runtimes/linux/native/", "runtimes/linux/native/", string.Empty }; private readonly IntPtr _handle; public LinuxLibrary(List candidatePaths) { var path = __libmongocryptLibPath ?? FindLibrary(candidatePaths, __suffixPaths, "libmongocrypt.so"); _handle = _use_libdl1 ? Libdl1.dlopen(path, RTLD_GLOBAL | RTLD_NOW) : Libdl2.dlopen(path, RTLD_GLOBAL | RTLD_NOW); if (_handle == IntPtr.Zero) { throw new FileNotFoundException(path); } } public IntPtr GetFunction(string name) { return _use_libdl1 ? Libdl1.dlsym(_handle, name) : Libdl2.dlsym(_handle, name); } } /// /// Windows DLL loader using GetProcAddress /// private class WindowsLibrary : ISharedLibraryLoader { private static readonly string[] __suffixPaths = { @"..\..\runtimes\win\native\", @".\runtimes\win\native\", string.Empty }; private readonly IntPtr _handle; public WindowsLibrary(List candidatePaths) { var path = __libmongocryptLibPath ?? FindLibrary(candidatePaths, __suffixPaths, "mongocrypt.dll"); _handle = LoadLibrary(path); if (_handle == IntPtr.Zero) { var gle = Marshal.GetLastWin32Error(); // error code 193 indicates that a 64-bit OS has tried to load a 32-bit dll // https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499- throw new LibraryLoadingException(path + ", Windows Error: " + gle); } } public IntPtr GetFunction(string name) { var ptr = GetProcAddress(_handle, name); if (ptr == null) { var gle = Marshal.GetLastWin32Error(); throw new FunctionNotFoundException(name + ", Windows Error: " + gle); } return ptr; } [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)] public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName); [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] public static extern IntPtr GetProcAddress(IntPtr hModule, string procName); } private static class Libdl1 { private const string LibName = "libdl"; #pragma warning disable IDE1006 // Naming Styles [DllImport(LibName)] public static extern IntPtr dlopen(string filename, int flags); [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern IntPtr dlsym(IntPtr handle, string symbol); [DllImport(LibName)] public static extern string dlerror(); #pragma warning restore IDE1006 // Naming Styles } private static class Libdl2 { private const string LibName = "libdl.so.2"; #pragma warning disable IDE1006 // Naming Styles [DllImport(LibName)] public static extern IntPtr dlopen(string filename, int flags); [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern IntPtr dlsym(IntPtr handle, string symbol); #pragma warning restore IDE1006 // Naming Styles } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/LibraryLoadingException.cs000066400000000000000000000021301465326363200301160ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; namespace MongoDB.Libmongocrypt { /// /// An exception that indicates that an error occured while loading a library. /// public class LibraryLoadingException : Exception { /// /// Initializes an instance of a /// /// The message. public LibraryLoadingException(string message) : base(message) { } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/License.txt000066400000000000000000000011151465326363200251330ustar00rootroot00000000000000/* Copyright 2010–present MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/LogLevel.cs000066400000000000000000000015571465326363200250620ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace MongoDB.Libmongocrypt { public enum LogLevel { MONGOCRYPT_LOG_LEVEL_FATAL = 0, MONGOCRYPT_LOG_LEVEL_ERROR = 1, MONGOCRYPT_LOG_LEVEL_WARNING = 2, MONGOCRYPT_LOG_LEVEL_INFO = 3, MONGOCRYPT_LOG_LEVEL_TRACE = 4 }; } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/MongoCryptSafeHandle.cs000066400000000000000000000030101465326363200273470ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System.Runtime.ConstrainedExecution; namespace MongoDB.Libmongocrypt { /// /// SafeHandle to manage the lifetime of a mongocrypt_t. /// /// internal class MongoCryptSafeHandle : CheckableSafeHandle { private MongoCryptSafeHandle() : base() { } public override void Check(Status status, bool success) { if (!success) { Library.mongocrypt_status(this, status.Handle); status.ThrowExceptionIfNeeded(); } } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] protected override bool ReleaseHandle() { // Here, we must obey all rules for constrained execution regions. Library.mongocrypt_destroy(handle); return true; } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/MongoDB.Libmongocrypt.csproj000066400000000000000000000103131465326363200303460ustar00rootroot00000000000000 net472;netstandard2.0;netstandard2.1 netstandard2.0;netstandard2.1 AnyCPU 7.3 true MongoDB.Libmongocrypt.ruleset MongoDB.Libmongocrypt MongoDB.Libmongocrypt MongoDB Inc. Copyright © 2019–present MongoDB Inc. Libmongocrypt wrapper for the .NET driver. MongoDB Inc. http://jobs.mongodb.org/files/logos/889002/889002.png true Libmongocrypt wrapper for the .NET driver. http://www.mongodb.org/display/DOCS/CSharp+Language+Center License.txt mongodb;mongo;nosql en-US true true ..\MongoDB.Driver.snk ../../../cmake-build/$(Configuration) libmongocrypt.so Always libmongocrypt.dylib Always mongocrypt.dll Always mongocrypt.pdb Always true runtimes/win/native true runtimes/linux/native true runtimes/osx/native true $(PackageLicenseFile) true build 1.1.0 bin\x64\Debug\MongoDB.Libmongocrypt.xml true bin\x64\Release\MongoDB.Libmongocrypt.xml libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/MongoDB.Libmongocrypt.ruleset000066400000000000000000000076261465326363200305460ustar00rootroot00000000000000 libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/MongoDB.Libmongocrypt.targets000066400000000000000000000017241465326363200305250ustar00rootroot00000000000000 Always mongocrypt.dll Always libmongocrypt.so Always libmongocrypt.dylib libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/OperatingSystemHelper.cs000066400000000000000000000034231465326363200276400ustar00rootroot00000000000000/* * Copyright 2020–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if !NET472 using System; using System.Runtime.InteropServices; #endif namespace MongoDB.Libmongocrypt { internal enum OperatingSystemPlatform { Windows, Linux, MacOS } internal static class OperatingSystemHelper { public static OperatingSystemPlatform CurrentOperatingSystem { get { #if NET472 return OperatingSystemPlatform.Windows; #else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { return OperatingSystemPlatform.MacOS; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { return OperatingSystemPlatform.Linux; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return OperatingSystemPlatform.Windows; } // should not be reached. If we're here, then there is a bug in the library throw new PlatformNotSupportedException($"Unsupported platform '{RuntimeInformation.OSDescription}'."); #endif } } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/Package.include.template.csproj000066400000000000000000000032211465326363200310210ustar00rootroot00000000000000 false @CMAKE_CURRENT_LIST_DIR@/MongoDB.Libmongocrypt PreserveNewest x64/native/linux/libmongocrypt.so true PreserveNewest x64/native/osx/libmongocrypt.dylib true PreserveNewest x64/native/windows/mongocrypt.dll true PreserveNewest x64/native/windows/mongocrypt.dll true libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/PinnedBinary.cs000066400000000000000000000031421465326363200257230ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; namespace MongoDB.Libmongocrypt { /// /// A handle to a binary that must be either in unsafe code or pinned by the GC. /// /// internal class PinnedBinary : Binary { #region static internal static void RunAsPinnedBinary(THandle handle, byte[] bytes, Status status, Func handleFunc) where THandle : CheckableSafeHandle { unsafe { fixed (byte* map = bytes) { var ptr = (IntPtr)map; using (var pinned = new PinnedBinary(ptr, (uint)bytes.Length)) { handle.Check(status, handleFunc(handle, pinned.Handle)); } } } } #endregion internal PinnedBinary(IntPtr ptr, uint len) : base(Library.mongocrypt_binary_new_from_data(ptr, len)) { } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/SecureRandomCallback.cs000066400000000000000000000032021465326363200273420ustar00rootroot00000000000000/* * Copyright 2020–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Security.Cryptography; namespace MongoDB.Libmongocrypt { internal static class SecureRandomCallback { public static bool GenerateRandom( IntPtr ctx, IntPtr @out, uint count, IntPtr statusPtr) { using (var outBinary = new Binary(BinarySafeHandle.FromIntPtr(@out))) using (var status = new Status(StatusSafeHandle.FromIntPtr(statusPtr))) { try { using (var randomNumberGenerator = RandomNumberGenerator.Create()) { var bytes = new byte[count]; randomNumberGenerator.GetBytes(bytes); outBinary.WriteBytes(bytes); return true; } } catch (Exception e) { status.SetStatus(1, e.Message); return false; } } } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/SigningRSAESPKCSCallback.cs000066400000000000000000000047031465326363200276370ustar00rootroot00000000000000/* * Copyright 2020–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; #if NETSTANDARD2_1 using System.Security.Cryptography; #endif namespace MongoDB.Libmongocrypt { internal static class SigningRSAESPKCSCallback { public static bool RsaSign( IntPtr ctx, IntPtr key, IntPtr inData, IntPtr outData, IntPtr statusPtr) { using (var status = new Status(StatusSafeHandle.FromIntPtr(statusPtr))) { try { var keyBinary = new Binary(BinarySafeHandle.FromIntPtr(key)); var inputBinary = new Binary(BinarySafeHandle.FromIntPtr(inData)); var outBinary = new Binary(BinarySafeHandle.FromIntPtr(outData)); byte[] inputBytes = inputBinary.ToArray(); byte[] keyBytes = keyBinary.ToArray(); // Hash and sign the data. var signedData = HashAndSignBytes(inputBytes, keyBytes); outBinary.WriteBytes(signedData); return true; } catch (Exception e) { // let mongocrypt level to handle the error status.SetStatus(1, e.Message); return false; } } } public static byte[] HashAndSignBytes(byte[] dataToSign, byte[] key) { #if NETSTANDARD2_1 using (var rsaProvider = new RSACryptoServiceProvider()) { rsaProvider.ImportPkcs8PrivateKey(key, out _); return rsaProvider.SignData(dataToSign, SHA256.Create()); } #else throw new System.PlatformNotSupportedException("RSACryptoServiceProvider.ImportPkcs8PrivateKey is supported only on frameworks higher or equal to .netstandard2.1."); #endif } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/Status.cs000066400000000000000000000053621465326363200246320ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Runtime.InteropServices; namespace MongoDB.Libmongocrypt { /// /// A LibMongoCrypt Status /// /// internal class Status : IDisposable { private StatusSafeHandle _handle; public Status() { _handle = Library.mongocrypt_status_new(); } public Status(StatusSafeHandle handle) { _handle = handle; } public void Check(IStatus status) { status.Check(this); ThrowExceptionIfNeeded(); } public void SetStatus(uint code, string msg) { IntPtr stringPointer = (IntPtr)Marshal.StringToHGlobalAnsi(msg); try { Library.mongocrypt_status_set(_handle, (int)Library.StatusType.MONGOCRYPT_STATUS_ERROR_CLIENT, code, stringPointer, -1); } finally { Marshal.FreeHGlobal(stringPointer); } } #region IDisposable public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { // Adapted from: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.safehandle?view=netcore-3.0 if (_handle != null && !_handle.IsInvalid) { // Free the handle _handle.Dispose(); } } #endregion internal StatusSafeHandle Handle => _handle; internal void ThrowExceptionIfNeeded() { if (!Library.mongocrypt_status_ok(_handle)) { var statusType = Library.mongocrypt_status_type(_handle); var statusCode = Library.mongocrypt_status_code(_handle); uint length; IntPtr msgPtr = Library.mongocrypt_status_message(_handle, out length); var message = Marshal.PtrToStringAnsi(msgPtr); throw new CryptException(statusType, statusCode, message); } } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/StatusSafeHandle.cs000066400000000000000000000033221465326363200265370ustar00rootroot00000000000000/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; namespace MongoDB.Libmongocrypt { /// /// SafeHandle to manage the lifetime of a mongocrypt_status_t. /// /// internal class StatusSafeHandle : SafeHandle { private StatusSafeHandle() : base(IntPtr.Zero, true) { } private StatusSafeHandle(IntPtr ptr) : base(ptr, false) { } public static StatusSafeHandle FromIntPtr(IntPtr ptr) { return new StatusSafeHandle(ptr); } public override bool IsInvalid { get { return handle == IntPtr.Zero; } } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] protected override bool ReleaseHandle() { // Here, we must obey all rules for constrained execution regions. Library.mongocrypt_status_destroy(handle); return true; } } } libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/StyleCop.ruleset000066400000000000000000000007151465326363200261640ustar00rootroot00000000000000 libmongocrypt-1.11.0/bindings/cs/MongoDB.Libmongocrypt/stylecop.json000066400000000000000000000003731465326363200255520ustar00rootroot00000000000000{ "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", "settings": { "layoutRules": { "newlineAtEndOfFile": "require" } } } libmongocrypt-1.11.0/bindings/cs/README.md000066400000000000000000000037271465326363200201660ustar00rootroot00000000000000# Requirements __All__ CMake 3.12 or later __Windows__ Visual Studio 2017 15.9+ __Linux, macOS__ dotnet 2.1+ # Quick Instructions *Requires:* Cygwin ``` 1. bash ./libmongocrypt/.evergreen/compile.sh ``` *Note*: You must call this from the parent directory of the libmongocrypt repo. It will not work within the repo directory ## Developer Instructions ### Windows To build libmongocrypt on Windows. This example assumes kms-message and the c driver are installed to "d:/usr" ``` 1. mkdir build 2. "C:\Program Files\CMake\bin\cmake.exe" -Thost=x64 -G "Visual Studio 15 2017 Win64" -DCMAKE_INSTALL_PREFIX=d:/usr -DCMAKE_PREFIX_PATH=d:/usr -DCMAKE_BUILD_TYPE=Debug "-DCMAKE_C_FLAGS=-Id:/usr/include" .. 3. msbuild libmongocrypt.sln 4. cd bindings/cs 5. msbuild cs.sln ``` ### Troubleshooting If you see `Windows Error: 126` during tests, like the example below, it means that `libbson-1.0.dll` is not in your path. ``` System.TypeInitializationException : The type initializer for 'MongoDB.Libmongocrypt.Library' threw an exception. ---- System.IO.FileNotFoundException : D:\repo\libmongocrypt\build\bindings\cs\MongoDB.Libmongocrypt.Test\bin\x64\Debug\netcoreapp2.1\mongocrypt.dll, Windows Error: 126 ``` ### Linux and macOS *Note* Only building from the cmake build directory is supported ``` 1. Build libmongocrypt with CMake 2. cd /bindings/cs 3. dotnet build cs.build ``` *Note*: You can use the ```LIBMONGOCRYPT_PATH``` environment variable to load a locally installed libmongocrypt build. You should specify the absolute path to the libmongocrypt library itself, not just the containing folder. For example on Linux: ```$ export LIBMONGOCRYPT_PATH='/path/to/libmongocrypt.so'```. # Testing Do not modify xunit.runner.json - Be wary of https://github.com/xunit/xunit/issues/1654 ### Debugging on Linux To attach to a unit test with lldb, print the PID in the process and then attach. Tests always run in child processes and lldb, as of 7.0, cannot follow child processes. libmongocrypt-1.11.0/bindings/cs/Scripts/000077500000000000000000000000001465326363200203255ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/cs/Scripts/build.cake000066400000000000000000000177621465326363200222660ustar00rootroot00000000000000#addin nuget:?package=Cake.FileHelpers&version=5.0.0 #addin nuget:?package=Cake.Git&version=2.0.0 #addin nuget:?package=Cake.Incubator&version=7.0.0 #tool dotnet:?package=GitVersion.Tool&version=5.10.3 using System; using System.Linq; var target = Argument("target", "CreatePackage"); var configuration = Argument("configuration", "Release"); var gitVersion = GitVersion(); var buildDirectory = MakeAbsolute(Directory(GetSettingValue("buildDirectory", "c:\\build"))); var libmongocryptAllDirectory=buildDirectory.Combine("libmongocrypt-all"); var downloadedMongocryptDirectory=buildDirectory.Combine("downloadedMongocryptDirectory"); var localReleaseVersion = "0.0.0-local"; var releaseVersion = GetSettingValue("releaseVersion", localReleaseVersion); var fork = GetSettingValue("fork", "git@github.com:mongodb/libmongocrypt.git"); var branch = GetSettingValue("branch", "master"); // 1.10.0 - latest libmongocrypt release var libmongocryptAllUrl = GetSettingValue("url", "https://mciuploads.s3.amazonaws.com/libmongocrypt/all/1.10.0/libmongocrypt-all.tar.gz"); var csharpBindingsGitTagName = $"csharp-v{releaseVersion}"; var csharpBindingsDirectory = buildDirectory.Combine(csharpBindingsGitTagName); var libmongocryptRelWithDebInfoDirectory = csharpBindingsDirectory.Combine("cmake-build").Combine($"{configuration}"); var libmongocryptCsDirectory = csharpBindingsDirectory.Combine("bindings").Combine("cs"); var libmongocryptSolutionDirectory = libmongocryptCsDirectory.Combine("MongoDB.Libmongocrypt"); var libmongocryptSolutionFile = libmongocryptSolutionDirectory.CombineWithFilePath("MongoDB.Libmongocrypt.csproj"); var libmongocryptTestsSolutionDirectory = libmongocryptCsDirectory.Combine("MongoDB.Libmongocrypt.Test"); var artifactsDirectory = buildDirectory.Combine("artifacts"); Task("Prepare") .Does(() => { if (DirectoryExists(buildDirectory)) { DeleteDirectory( buildDirectory, new DeleteDirectorySettings { Recursive = true, Force = true }); } CreateDirectory(buildDirectory); Information($"Release version: {releaseVersion}"); Information($"Fork: {fork}"); Information($"Branch: {branch}"); Information($"Native libraries url: {libmongocryptAllUrl}"); Information("Downloading native libs.."); EnsureDirectoryExists(libmongocryptAllDirectory); var nativeLibrariesArchive = libmongocryptAllDirectory.CombineWithFilePath("libmongocrypt-all.tar"); DownloadFile(libmongocryptAllUrl, nativeLibrariesArchive); Information("Unzipping.."); UncompressToTheCurrentDirectory(nativeLibrariesArchive); Information("Cloning the libmongocrypt repo.."); EnsureDirectoryExists(csharpBindingsDirectory); Git(csharpBindingsDirectory, $"clone {fork} -b {branch} ."); Information("Done git clone.."); EnsureDirectoryExists(libmongocryptRelWithDebInfoDirectory); EnsureDirectoryExists(downloadedMongocryptDirectory); CopyFile( libmongocryptAllDirectory.Combine("windows-test").Combine("bin").CombineWithFilePath("mongocrypt.dll"), downloadedMongocryptDirectory.CombineWithFilePath("mongocrypt.dll")); CopyFile( libmongocryptAllDirectory.Combine("ubuntu1804-64").Combine("nocrypto").Combine("lib").CombineWithFilePath("libmongocrypt.so"), downloadedMongocryptDirectory.CombineWithFilePath("libmongocrypt.so")); CopyFile( libmongocryptAllDirectory.Combine("macos").Combine("lib").CombineWithFilePath("libmongocrypt.dylib"), downloadedMongocryptDirectory.CombineWithFilePath("libmongocrypt.dylib")); CopyDirectory(downloadedMongocryptDirectory, libmongocryptRelWithDebInfoDirectory); }); Task("Tests") .IsDependentOn("Prepare") .DoesForEach( () => { var monikersDetails = new List<(string Moniker, string Bitness)> { { ("net472", "x64") }, { ("netcoreapp2.1", "x64") }, { ("netcoreapp3.0", "x64") }, { ("net50", "x64") } }; return monikersDetails; }, (monikerInfo) => { Information($"Test running {monikerInfo.Moniker}.."); var settings = new DotNetTestSettings { Configuration = configuration, Framework = monikerInfo.Moniker, ArgumentCustomization = args => args.Append($"-- RunConfiguration.TargetPlatform={monikerInfo.Bitness}") }; var projectFullPath = libmongocryptTestsSolutionDirectory.CombineWithFilePath("MongoDB.Libmongocrypt.Test.csproj").FullPath; Information(projectFullPath); DotNetTest( projectFullPath, settings ); }) .DeferOnError(); Task("CreatePackage") .IsDependentOn("Tests") .Does(() => { var projectFullPath = libmongocryptSolutionFile.FullPath; Information($"Project path: {projectFullPath}. ReleaseVersion: {releaseVersion}"); var settings = new DotNetPackSettings { Configuration = configuration, OutputDirectory = artifactsDirectory, EnvironmentVariables = new Dictionary { { "Version", releaseVersion }, } }; DotNetPack( projectFullPath, settings); }); Task("NugetPush") .Does(() => { ThrowIfLocalRelease(); var nugetApi = GetSettingValue("NugetApiKey", null); var packageFilePath = artifactsDirectory.CombineWithFilePath($"{libmongocryptSolutionFile.GetFilenameWithoutExtension().ToString()}.{releaseVersion}.nupkg"); Information(packageFilePath); DotNetNuGetPush( packageFilePath, new DotNetNuGetPushSettings { ApiKey = nugetApi, Source = "https://api.nuget.org/v3/index.json" }); }); Task("CreateGitTag") .Does(() => { ThrowIfLocalRelease(); Information($"Directory: {libmongocryptSolutionDirectory}"); Information("Show origin:"); Git(libmongocryptSolutionDirectory, "remote -v"); Git(libmongocryptSolutionDirectory, $"tag -a {csharpBindingsGitTagName} -m {csharpBindingsGitTagName}"); Git(libmongocryptSolutionDirectory, $"push origin {csharpBindingsGitTagName}"); }); RunTarget(target); string GetSettingValue(string commandArgumentName, string defaultValue) { var optionValue = Argument(commandArgumentName, (string)null); if (optionValue != null) { return optionValue; } var environmentVariableName = $"LIBMONGOCRYPT_PACKAGING_{commandArgumentName.ToUpper()}"; var environmentVariable = Environment.GetEnvironmentVariable(environmentVariableName); if (environmentVariable == null) { if (defaultValue == null) { throw new Exception($"Neither {commandArgumentName} command argument nor {environmentVariableName} environmentVariable have been configured."); } else { return defaultValue; } } return environmentVariable; } void Git(DirectoryPath workingDirectory, string command) { CustomToolCall(workingDirectory, "git", command); } void UncompressToTheCurrentDirectory(FilePath archiveFilePath) { CustomToolCall(archiveFilePath.GetDirectory(), "tar", "xzvf", archiveFilePath.GetFilename().ToString()); } void CustomToolCall(DirectoryPath workingDirectory, string tool, params string[] arguments) { var argumentsBuilder = new ProcessArgumentBuilder(); foreach (var argument in arguments) { argumentsBuilder.Append(argument); } Information($"{tool} {string.Join(" ", arguments)}"); StartProcess(tool, new ProcessSettings { Arguments = argumentsBuilder, WorkingDirectory = workingDirectory }); } void ThrowIfLocalRelease() { if (releaseVersion == localReleaseVersion) { throw new Exception("Attempt to publish a local nuget."); } } libmongocrypt-1.11.0/bindings/cs/Scripts/build.config000066400000000000000000000000751465326363200226150ustar00rootroot00000000000000#!/usr/bin/env bash CAKE_VERSION=2.2.0 DOTNET_VERSION=6.0.400libmongocrypt-1.11.0/bindings/cs/Scripts/build.ps1000066400000000000000000000216311465326363200220540ustar00rootroot00000000000000########################################################################## # This is the Cake bootstrapper script for PowerShell. # This file was downloaded from https://github.com/cake-build/resources # Feel free to change this file to fit your needs. ########################################################################## <# .SYNOPSIS This is a Powershell script to bootstrap a Cake build. .DESCRIPTION This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) and execute your Cake build script with the parameters you provide. .PARAMETER Script The build script to execute. .PARAMETER Target The build script target to run. .PARAMETER Configuration The build configuration to use. .PARAMETER Verbosity Specifies the amount of information to be displayed. .PARAMETER ShowDescription Shows description about tasks. .PARAMETER DryRun Performs a dry run. .PARAMETER SkipToolPackageRestore Skips restoring of packages. .PARAMETER ScriptArgs Remaining arguments are added here. .LINK https://cakebuild.net #> [CmdletBinding()] Param( [string]$Script, [string]$Target, [string]$Configuration, [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] [string]$Verbosity, [switch]$ShowDescription, [Alias("WhatIf", "Noop")] [switch]$DryRun, [switch]$SkipToolPackageRestore, [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] [string[]]$ScriptArgs ) # This is an automatic variable in PowerShell Core, but not in Windows PowerShell 5.x if (-not (Test-Path variable:global:IsCoreCLR)) { $IsCoreCLR = $false } # Attempt to set highest encryption available for SecurityProtocol. # PowerShell will not set this by default (until maybe .NET 4.6.x). This # will typically produce a message for PowerShell v2 (just an info # message though) try { # Set TLS 1.2 (3072), then TLS 1.1 (768), then TLS 1.0 (192), finally SSL 3.0 (48) # Use integers because the enumeration values for TLS 1.2 and TLS 1.1 won't # exist in .NET 4.0, even though they are addressable if .NET 4.5+ is # installed (.NET 4.5 is an in-place upgrade). # PowerShell Core already has support for TLS 1.2 so we can skip this if running in that. if (-not $IsCoreCLR) { [System.Net.ServicePointManager]::SecurityProtocol = 3072 -bor 768 -bor 192 -bor 48 } } catch { Write-Output 'Unable to set PowerShell to use TLS 1.2 and TLS 1.1 due to old .NET Framework installed. If you see underlying connection closed or trust errors, you may need to upgrade to .NET Framework 4.5+ and PowerShell v3' } [Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null function MD5HashFile([string] $filePath) { if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) { return $null } [System.IO.Stream] $file = $null; [System.Security.Cryptography.MD5] $md5 = $null; try { $md5 = [System.Security.Cryptography.MD5]::Create() $file = [System.IO.File]::OpenRead($filePath) return [System.BitConverter]::ToString($md5.ComputeHash($file)) } finally { if ($file -ne $null) { $file.Dispose() } } } function GetProxyEnabledWebClient { $wc = New-Object System.Net.WebClient $proxy = [System.Net.WebRequest]::GetSystemWebProxy() $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials $wc.Proxy = $proxy return $wc } Write-Host "Preparing to run build script..." if(!$PSScriptRoot){ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent } if(!$Script){ $Script = Join-Path $PSScriptRoot "build.cake" } $TOOLS_DIR = Join-Path $PSScriptRoot "tools" $ADDINS_DIR = Join-Path $TOOLS_DIR "Addins" $MODULES_DIR = Join-Path $TOOLS_DIR "Modules" $NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" $CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" $NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" $PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" $PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" $ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config" $MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config" $env:CAKE_PATHS_TOOLS = $TOOLS_DIR $env:CAKE_PATHS_ADDINS = $ADDINS_DIR $env:CAKE_PATHS_MODULES = $MODULES_DIR # Make sure tools folder exists if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { Write-Verbose -Message "Creating tools directory..." New-Item -Path $TOOLS_DIR -Type Directory | Out-Null } # Make sure that packages.config exist. if (!(Test-Path $PACKAGES_CONFIG)) { Write-Verbose -Message "Downloading packages.config..." try { $wc = GetProxyEnabledWebClient $wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { Throw "Could not download packages.config." } } # Try find NuGet.exe in path if not exists if (!(Test-Path $NUGET_EXE)) { Write-Verbose -Message "Trying to find nuget.exe in PATH..." $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) } $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName } } # Try download NuGet.exe if not exists if (!(Test-Path $NUGET_EXE)) { Write-Verbose -Message "Downloading NuGet.exe..." try { $wc = GetProxyEnabledWebClient $wc.DownloadFile($NUGET_URL, $NUGET_EXE) } catch { Throw "Could not download NuGet.exe." } } # These are automatic variables in PowerShell Core, but not in Windows PowerShell 5.x if (-not (Test-Path variable:global:ismacos)) { $IsLinux = $false $IsMacOS = $false } # Save nuget.exe path to environment to be available to child processed $env:NUGET_EXE = $NUGET_EXE $env:NUGET_EXE_INVOCATION = if ($IsLinux -or $IsMacOS) { "mono `"$NUGET_EXE`"" } else { "`"$NUGET_EXE`"" } # Restore tools from NuGet? if(-Not $SkipToolPackageRestore.IsPresent) { Push-Location Set-Location $TOOLS_DIR # Check for changes in packages.config and remove installed tools if true. [string] $md5Hash = MD5HashFile $PACKAGES_CONFIG if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { Write-Verbose -Message "Missing or changed package.config hash..." Get-ChildItem -Exclude packages.config,nuget.exe,Cake.Bakery | Remove-Item -Recurse -Force } Write-Verbose -Message "Restoring tools from NuGet..." $NuGetOutput = Invoke-Expression "& $env:NUGET_EXE_INVOCATION install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" if ($LASTEXITCODE -ne 0) { Throw "An error occurred while restoring NuGet tools." } else { $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" } Write-Verbose -Message ($NuGetOutput | Out-String) Pop-Location } # Restore addins from NuGet if (Test-Path $ADDINS_PACKAGES_CONFIG) { Push-Location Set-Location $ADDINS_DIR Write-Verbose -Message "Restoring addins from NuGet..." $NuGetOutput = Invoke-Expression "& $env:NUGET_EXE_INVOCATION install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`"" if ($LASTEXITCODE -ne 0) { Throw "An error occurred while restoring NuGet addins." } Write-Verbose -Message ($NuGetOutput | Out-String) Pop-Location } # Restore modules from NuGet if (Test-Path $MODULES_PACKAGES_CONFIG) { Push-Location Set-Location $MODULES_DIR Write-Verbose -Message "Restoring modules from NuGet..." $NuGetOutput = Invoke-Expression "& $env:NUGET_EXE_INVOCATION install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`"" if ($LASTEXITCODE -ne 0) { Throw "An error occurred while restoring NuGet modules." } Write-Verbose -Message ($NuGetOutput | Out-String) Pop-Location } # Make sure that Cake has been installed. if (!(Test-Path $CAKE_EXE)) { Throw "Could not find Cake.exe at $CAKE_EXE" } $CAKE_EXE_INVOCATION = if ($IsLinux -or $IsMacOS) { "mono `"$CAKE_EXE`"" } else { "`"$CAKE_EXE`"" } # Build an array (not a string) of Cake arguments to be joined later $cakeArguments = @() if ($Script) { $cakeArguments += "`"$Script`"" } if ($Target) { $cakeArguments += "--target=`"$Target`"" } if ($Configuration) { $cakeArguments += "--configuration=$Configuration" } if ($Verbosity) { $cakeArguments += "--verbosity=$Verbosity" } if ($ShowDescription) { $cakeArguments += "--showdescription" } if ($DryRun) { $cakeArguments += "--dryrun" } $cakeArguments += $ScriptArgs # Start Cake Write-Host "Running build script..." Invoke-Expression "& $CAKE_EXE_INVOCATION --bootstrap" Invoke-Expression "& $CAKE_EXE_INVOCATION $($cakeArguments -join " ")" exit $LASTEXITCODE libmongocrypt-1.11.0/bindings/cs/Scripts/build.sh000077500000000000000000000052551465326363200217720ustar00rootroot00000000000000#!/usr/bin/env bash # Define varibles SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) source $SCRIPT_DIR/build.config TOOLS_DIR=$SCRIPT_DIR/tools CAKE_EXE=$TOOLS_DIR/dotnet-cake CAKE_PATH=$TOOLS_DIR/.store/cake.tool/$CAKE_VERSION if [ "$CAKE_VERSION" = "" ] || [ "$DOTNET_VERSION" = "" ]; then echo "An error occured while parsing Cake / .NET Core SDK version." exit 1 fi # Make sure the tools folder exist. if [ ! -d "$TOOLS_DIR" ]; then mkdir "$TOOLS_DIR" fi ########################################################################### # INSTALL .NET CORE CLI ########################################################################### export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 export DOTNET_CLI_TELEMETRY_OPTOUT=1 export DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0 export DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX=2 DOTNET_INSTALLED_VERSION=$(dotnet --version 2>&1) if [ "$DOTNET_VERSION" != "$DOTNET_INSTALLED_VERSION" ]; then echo "Installing .NET CLI..." if [ ! -d "$SCRIPT_DIR/.dotnet" ]; then mkdir "$SCRIPT_DIR/.dotnet" fi curl -Lsfo "$SCRIPT_DIR/.dotnet/dotnet-install.sh" https://dot.net/v1/dotnet-install.sh bash "$SCRIPT_DIR/.dotnet/dotnet-install.sh" --channel 1.1 --install-dir .dotnet --no-path bash "$SCRIPT_DIR/.dotnet/dotnet-install.sh" --channel 2.1 --install-dir .dotnet --no-path bash "$SCRIPT_DIR/.dotnet/dotnet-install.sh" --version $DOTNET_VERSION --install-dir .dotnet --no-path export PATH="$SCRIPT_DIR/.dotnet":$PATH export DOTNET_ROOT="$SCRIPT_DIR/.dotnet" fi ########################################################################### # INSTALL CAKE ########################################################################### CAKE_INSTALLED_VERSION=$(dotnet-cake --version 2>&1) if [ "$CAKE_VERSION" != "$CAKE_INSTALLED_VERSION" ]; then if [ ! -f "$CAKE_EXE" ] || [ ! -d "$CAKE_PATH" ]; then if [ -f "$CAKE_EXE" ]; then dotnet tool uninstall --tool-path $TOOLS_DIR Cake.Tool fi echo "Installing Cake $CAKE_VERSION..." dotnet tool install --tool-path $TOOLS_DIR --version $CAKE_VERSION Cake.Tool if [ $? -ne 0 ]; then echo "An error occured while installing Cake." exit 1 fi fi # Make sure that Cake has been installed. if [ ! -f "$CAKE_EXE" ]; then echo "Could not find Cake.exe at '$CAKE_EXE'." exit 1 fi else CAKE_EXE="dotnet-cake" fi ########################################################################### # RUN BUILD SCRIPT ########################################################################### # Start Cake (exec "$CAKE_EXE" build.cake --bootstrap) && (exec "$CAKE_EXE" build.cake "$@") libmongocrypt-1.11.0/bindings/cs/cs.sln000066400000000000000000000124361465326363200200270ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26124.0 MinimumVisualStudioVersion = 15.0.26124.0 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Libmongocrypt", "MongoDB.Libmongocrypt\MongoDB.Libmongocrypt.csproj", "{90EA4DBB-69E6-426D-985A-C66D65A2E63A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Libmongocrypt.Test", "MongoDB.Libmongocrypt.Test\MongoDB.Libmongocrypt.Test.csproj", "{F2D29C5D-DA83-456D-994F-57AB43EA9470}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Libmongocrypt.Example", "MongoDB.Libmongocrypt.Example\MongoDB.Libmongocrypt.Example.csproj", "{536E0590-7287-4D73-A5D7-5B8EFD2945B8}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Libmongocrypt.Test32", "MongoDB.Libmongocrypt.Test32\MongoDB.Libmongocrypt.Test32.csproj", "{EBD0FAFF-4794-4346-9313-A286E278EDA7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {90EA4DBB-69E6-426D-985A-C66D65A2E63A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {90EA4DBB-69E6-426D-985A-C66D65A2E63A}.Debug|Any CPU.Build.0 = Debug|Any CPU {90EA4DBB-69E6-426D-985A-C66D65A2E63A}.Debug|x64.ActiveCfg = Debug|Any CPU {90EA4DBB-69E6-426D-985A-C66D65A2E63A}.Debug|x64.Build.0 = Debug|Any CPU {90EA4DBB-69E6-426D-985A-C66D65A2E63A}.Debug|x86.ActiveCfg = Debug|Any CPU {90EA4DBB-69E6-426D-985A-C66D65A2E63A}.Debug|x86.Build.0 = Debug|Any CPU {90EA4DBB-69E6-426D-985A-C66D65A2E63A}.Release|Any CPU.ActiveCfg = Release|Any CPU {90EA4DBB-69E6-426D-985A-C66D65A2E63A}.Release|Any CPU.Build.0 = Release|Any CPU {90EA4DBB-69E6-426D-985A-C66D65A2E63A}.Release|x64.ActiveCfg = Release|Any CPU {90EA4DBB-69E6-426D-985A-C66D65A2E63A}.Release|x64.Build.0 = Release|Any CPU {90EA4DBB-69E6-426D-985A-C66D65A2E63A}.Release|x86.ActiveCfg = Release|Any CPU {90EA4DBB-69E6-426D-985A-C66D65A2E63A}.Release|x86.Build.0 = Release|Any CPU {F2D29C5D-DA83-456D-994F-57AB43EA9470}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F2D29C5D-DA83-456D-994F-57AB43EA9470}.Debug|Any CPU.Build.0 = Debug|Any CPU {F2D29C5D-DA83-456D-994F-57AB43EA9470}.Debug|x64.ActiveCfg = Debug|Any CPU {F2D29C5D-DA83-456D-994F-57AB43EA9470}.Debug|x64.Build.0 = Debug|Any CPU {F2D29C5D-DA83-456D-994F-57AB43EA9470}.Debug|x86.ActiveCfg = Debug|Any CPU {F2D29C5D-DA83-456D-994F-57AB43EA9470}.Debug|x86.Build.0 = Debug|Any CPU {F2D29C5D-DA83-456D-994F-57AB43EA9470}.Release|Any CPU.ActiveCfg = Release|Any CPU {F2D29C5D-DA83-456D-994F-57AB43EA9470}.Release|Any CPU.Build.0 = Release|Any CPU {F2D29C5D-DA83-456D-994F-57AB43EA9470}.Release|x64.ActiveCfg = Release|Any CPU {F2D29C5D-DA83-456D-994F-57AB43EA9470}.Release|x64.Build.0 = Release|Any CPU {F2D29C5D-DA83-456D-994F-57AB43EA9470}.Release|x86.ActiveCfg = Release|Any CPU {F2D29C5D-DA83-456D-994F-57AB43EA9470}.Release|x86.Build.0 = Release|Any CPU {536E0590-7287-4D73-A5D7-5B8EFD2945B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {536E0590-7287-4D73-A5D7-5B8EFD2945B8}.Debug|Any CPU.Build.0 = Debug|Any CPU {536E0590-7287-4D73-A5D7-5B8EFD2945B8}.Debug|x64.ActiveCfg = Debug|Any CPU {536E0590-7287-4D73-A5D7-5B8EFD2945B8}.Debug|x64.Build.0 = Debug|Any CPU {536E0590-7287-4D73-A5D7-5B8EFD2945B8}.Debug|x86.ActiveCfg = Debug|Any CPU {536E0590-7287-4D73-A5D7-5B8EFD2945B8}.Debug|x86.Build.0 = Debug|Any CPU {536E0590-7287-4D73-A5D7-5B8EFD2945B8}.Release|Any CPU.ActiveCfg = Release|Any CPU {536E0590-7287-4D73-A5D7-5B8EFD2945B8}.Release|Any CPU.Build.0 = Release|Any CPU {536E0590-7287-4D73-A5D7-5B8EFD2945B8}.Release|x64.ActiveCfg = Release|Any CPU {536E0590-7287-4D73-A5D7-5B8EFD2945B8}.Release|x64.Build.0 = Release|Any CPU {536E0590-7287-4D73-A5D7-5B8EFD2945B8}.Release|x86.ActiveCfg = Release|Any CPU {536E0590-7287-4D73-A5D7-5B8EFD2945B8}.Release|x86.Build.0 = Release|Any CPU {EBD0FAFF-4794-4346-9313-A286E278EDA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EBD0FAFF-4794-4346-9313-A286E278EDA7}.Debug|Any CPU.Build.0 = Debug|Any CPU {EBD0FAFF-4794-4346-9313-A286E278EDA7}.Debug|x64.ActiveCfg = Debug|Any CPU {EBD0FAFF-4794-4346-9313-A286E278EDA7}.Debug|x64.Build.0 = Debug|Any CPU {EBD0FAFF-4794-4346-9313-A286E278EDA7}.Debug|x86.ActiveCfg = Debug|Any CPU {EBD0FAFF-4794-4346-9313-A286E278EDA7}.Debug|x86.Build.0 = Debug|Any CPU {EBD0FAFF-4794-4346-9313-A286E278EDA7}.Release|Any CPU.ActiveCfg = Release|Any CPU {EBD0FAFF-4794-4346-9313-A286E278EDA7}.Release|Any CPU.Build.0 = Release|Any CPU {EBD0FAFF-4794-4346-9313-A286E278EDA7}.Release|x64.ActiveCfg = Release|Any CPU {EBD0FAFF-4794-4346-9313-A286E278EDA7}.Release|x64.Build.0 = Release|Any CPU {EBD0FAFF-4794-4346-9313-A286E278EDA7}.Release|x86.ActiveCfg = Release|Any CPU {EBD0FAFF-4794-4346-9313-A286E278EDA7}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C644578D-7C87-4AC7-A3E2-AA124E0911B1} EndGlobalSection EndGlobal libmongocrypt-1.11.0/bindings/java/000077500000000000000000000000001465326363200172125ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/000077500000000000000000000000001465326363200214135ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/.evergreen/000077500000000000000000000000001465326363200234535ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/.evergreen/publish.sh000077500000000000000000000020541465326363200254610ustar00rootroot00000000000000#!/bin/bash # DO NOT ECHO COMMANDS AS THEY CONTAIN SECRETS! set -o errexit # Exit the script with error if any of the commands fail ############################################ # Main Program # ############################################ echo ${ring_file_gpg_base64} | base64 -d > ${PROJECT_DIRECTORY}/secring.gpg trap "rm ${PROJECT_DIRECTORY}/secring.gpg; exit" EXIT HUP export ORG_GRADLE_PROJECT_nexusUsername=${nexus_username} export ORG_GRADLE_PROJECT_nexusPassword=${nexus_password} export ORG_GRADLE_PROJECT_signing_keyId=${signing_keyId} export ORG_GRADLE_PROJECT_signing_password=${signing_password} export ORG_GRADLE_PROJECT_signing_secretKeyRingFile=${PROJECT_DIRECTORY}/secring.gpg echo "Publishing snapshot with jdk11" export JAVA_HOME="/opt/java/jdk11" SYSTEM_PROPERTIES="-Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.internal.http.connectionTimeout=120000 -Dorg.gradle.internal.http.socketTimeout=120000" ./gradlew -version ./gradlew ${SYSTEM_PROPERTIES} --stacktrace --info publishToSonatype libmongocrypt-1.11.0/bindings/java/mongocrypt/.evergreen/test.sh000077500000000000000000000010471465326363200247730ustar00rootroot00000000000000#!/bin/bash # Test the Java bindings for libmongocrypt set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail if [ "Windows_NT" = "$OS" ]; then export JDK8="/cygdrive/c/java/jdk8" export JDK11="/cygdrive/c/java/jdk11" else export JDK8="/opt/java/jdk8" export JDK11="/opt/java/jdk11" fi if [ -d "$JDK11" ]; then export JAVA_HOME=$JDK11 else export JAVA_HOME=$JDK8 fi ./gradlew -version ./gradlew clean downloadJnaLibs check --info -DgitRevision=${GIT_REVISION} libmongocrypt-1.11.0/bindings/java/mongocrypt/.gitignore000066400000000000000000000005231465326363200234030ustar00rootroot00000000000000*~ .#* .git *# # os x stuff *Thumbs.db* *.DS_Store # Build artifacts build out # Eclipse files .classpath .project .settings # Intellij IDEA files *.ipr *.iws *.iml *.idea workspace.xml atlassian-ide-plugin.xml # gradle .gradle # local settings **/gradle.properties local.properties # jenv .java-version # bin /bin /benchmarks/bin libmongocrypt-1.11.0/bindings/java/mongocrypt/README.md000066400000000000000000000032441465326363200226750ustar00rootroot00000000000000# mongocrypt Java Wrapper # The Java wrapper for the companion C library for client side encryption in drivers. ### Testing ### `./gradlew check` runs the java test suite. By default it expects that libmongocrypt is in `./build/jnaLibs//` - where is the current platform architecture: eg: `linux-x86-64`. To test against a local build: `/gradlew check -DjnaLibsPath=../../../../libmongocrypt/cmake-build` Note: libmongocrypt and the java library are continuously built on evergreen. Submit patch builds to this evergreen project when making changes to test on supported platforms. ### Publishing #### First check the build artifacts locally (~/.m2/repository/org/mongodb/mongocrypt): `./gradlew clean downloadJnaLibs publishToMavenLocal` **Sonatype** `./gradlew publishToSonatype` Will push the latest snapshot or release version to sonatype repository. ### Custom gradle flags ### * `jnaLibsPath`: Custom local JNA library path for inclusion into the build (rather than downloading from s3)
Usage: `./gradlew publishToSonatype -DjnaLibsPath=../../../cmake-build-nocrypto` * `gitRevision`: Sets the Git Revision to download the built resources for from s3.
Usage: `./gradlew publishToSonatype -DgitRevision=` These flags can be combined with the `downloadJnaLibs` task: * Test without compiling libmongocrypt locally:
`./gradlew clean downloadJnaLibs test -DgitRevision=` * Test using a custom libmongocrypt path:
`./gradlew clean test -DjnaLibsPath=` ### Debugging errors ### * Use the info and jna debug flags to output debugging information when running tasks:
`./gradlew --info -Djna.debug_load=true` libmongocrypt-1.11.0/bindings/java/mongocrypt/benchmarks/000077500000000000000000000000001465326363200235305ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/benchmarks/build.gradle.kts000066400000000000000000000014511465326363200266100ustar00rootroot00000000000000/* * Copyright 2023-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ plugins { id("application") } application { mainClass.set("com.mongodb.crypt.benchmark.BenchmarkRunner") } dependencies { implementation(project(":")) // Reference to the parent project } libmongocrypt-1.11.0/bindings/java/mongocrypt/benchmarks/src/000077500000000000000000000000001465326363200243175ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/benchmarks/src/main/000077500000000000000000000000001465326363200252435ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/benchmarks/src/main/java/000077500000000000000000000000001465326363200261645ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/benchmarks/src/main/java/com/000077500000000000000000000000001465326363200267425ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/benchmarks/src/main/java/com/mongodb/000077500000000000000000000000001465326363200303675ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/benchmarks/src/main/java/com/mongodb/crypt/000077500000000000000000000000001465326363200315305ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/benchmarks/src/main/java/com/mongodb/crypt/benchmark/000077500000000000000000000000001465326363200334625ustar00rootroot00000000000000BenchmarkRunner.java000066400000000000000000000257531465326363200373460ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/benchmarks/src/main/java/com/mongodb/crypt/benchmark/* * Copyright 2023-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.benchmark; import com.mongodb.crypt.capi.*; import org.bson.*; import java.io.*; import java.net.URL; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.*; public class BenchmarkRunner { static final int NUM_FIELDS = 1500; static final int NUM_WARMUP_SECS = 2; static final int NUM_SECS = 10; static final byte[] LOCAL_MASTER_KEY = new byte[]{ -99, -108, 75, 13, -109, -48, -59, 68, -91, 114, -3, 50, 27, -108, 48, -112, 35, 53, 115, 124, -16, -10, -62, -12, -38, 35, 86, -25, -113, 4, -52, -6, -34, 117, -76, 81, -121, -13, -117, -105, -41, 75, 68, 59, -84, 57, -94, -58, 77, -111, 0, 62, -47, -6, 74, 48, -63, -46, -58, 94, -5, -84, 65, -14, 72, 19, 60, -101, 80, -4, -89, 36, 122, 46, 2, 99, -93, -58, 22, 37, 81, 80, 120, 62, 15, -40, 110, -124, -90, -20, -115, 45, 36, 71, -27, -81 }; private static String getFileAsString(final String fileName) { try { URL resource = BenchmarkRunner.class.getResource("/" + fileName); if (resource == null) { throw new RuntimeException("Could not find file " + fileName); } return new String(Files.readAllBytes(Paths.get(resource.toURI()))); } catch (Throwable t) { throw new RuntimeException("Could not parse file " + fileName, t); } } private static BsonDocument getResourceAsDocument(final String fileName) { return BsonDocument.parse(getFileAsString(fileName)); } private static MongoCrypt createMongoCrypt() { return MongoCrypts.create(MongoCryptOptions .builder() .localKmsProviderOptions(MongoLocalKmsProviderOptions.builder() .localMasterKey(ByteBuffer.wrap(LOCAL_MASTER_KEY)) .build()) .build()); } // DecryptTask decrypts a document repeatedly for a specified number of seconds and records ops/sec. private static class DecryptTask implements Runnable { public DecryptTask (MongoCrypt mongoCrypt, BsonDocument toDecrypt, int numSecs, CountDownLatch doneSignal) { this.mongoCrypt = mongoCrypt; this.toDecrypt = toDecrypt; this.opsPerSecs = new ArrayList(numSecs); this.numSecs = numSecs; this.doneSignal = doneSignal; } public void run() { for (int i = 0; i < numSecs; i++) { long opsPerSec = 0; long start = System.nanoTime(); // Run for one second. while (System.nanoTime() - start < 1_000_000_000) { try (MongoCryptContext ctx = mongoCrypt.createDecryptionContext(toDecrypt)) { assert ctx.getState() == MongoCryptContext.State.READY; ctx.finish(); opsPerSec++; } } opsPerSecs.add(opsPerSec); } doneSignal.countDown(); } public long getMedianOpsPerSecs () { if (opsPerSecs.size() == 0) { throw new IllegalStateException("opsPerSecs is empty. Was `run` called?"); } Collections.sort(opsPerSecs); return opsPerSecs.get(numSecs / 2); } private MongoCrypt mongoCrypt; private BsonDocument toDecrypt; private ArrayList opsPerSecs; private int numSecs; private CountDownLatch doneSignal; } public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { System.out.printf("BenchmarkRunner is using libmongocrypt version=%s, NUM_WARMUP_SECS=%d, NUM_SECS=%d%n", CAPI.mongocrypt_version(null).toString(), NUM_WARMUP_SECS, NUM_SECS); // `keyDocument` is a Data Encryption Key (DEK) encrypted with the Key Encryption Key (KEK) `LOCAL_MASTER_KEY`. BsonDocument keyDocument = getResourceAsDocument("keyDocument.json"); try (MongoCrypt mongoCrypt = createMongoCrypt()) { // `encrypted` will contain encrypted fields. BsonDocument encrypted = new BsonDocument(); { for (int i = 0; i < NUM_FIELDS; i++) { MongoExplicitEncryptOptions options = MongoExplicitEncryptOptions.builder() .keyId(new BsonBinary(BsonBinarySubType.UUID_STANDARD, Base64.getDecoder().decode("YWFhYWFhYWFhYWFhYWFhYQ=="))) .algorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic") .build(); BsonDocument toEncrypt = new BsonDocument("v", new BsonString(String.format("value %04d", i))); try (MongoCryptContext ctx = mongoCrypt.createExplicitEncryptionContext(toEncrypt, options)) { // If mongocrypt_t has not yet cached the DEK, supply it. if (MongoCryptContext.State.NEED_MONGO_KEYS == ctx.getState()) { ctx.addMongoOperationResult(keyDocument); ctx.completeMongoOperation(); } assert ctx.getState() == MongoCryptContext.State.READY; RawBsonDocument result = ctx.finish(); BsonValue encryptedValue = result.get("v"); String key = String.format("key%04d", i); encrypted.append(key, encryptedValue); } } } // Warm up benchmark and discard the result. DecryptTask warmup = new DecryptTask(mongoCrypt, encrypted, NUM_WARMUP_SECS, new CountDownLatch(1)); warmup.run(); // Decrypt `encrypted` and measure ops/sec. // Check with varying thread counts to measure impact of a shared pool of Cipher instances. int[] threadCounts = {1,2,8,64}; ArrayList totalMedianOpsPerSecs = new ArrayList(threadCounts.length); ArrayList createdAts = new ArrayList(threadCounts.length); ArrayList completedAts = new ArrayList(threadCounts.length); for (int threadCount : threadCounts) { ExecutorService executorService = Executors.newFixedThreadPool(threadCount); CountDownLatch doneSignal = new CountDownLatch(threadCount); ArrayList decryptTasks = new ArrayList(threadCount); createdAts.add(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); for (int i = 0; i < threadCount; i++) { DecryptTask decryptTask = new DecryptTask(mongoCrypt, encrypted, NUM_SECS, doneSignal); decryptTasks.add(decryptTask); executorService.submit(decryptTask); } // Await completion of all tasks. Tasks are expected to complete shortly after NUM_SECS. Time out `await` if time exceeds 2 * NUM_SECS. boolean ok = doneSignal.await(NUM_SECS * 2, TimeUnit.SECONDS); assert ok; completedAts.add(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); // Sum the median ops/secs of all tasks to get total throughput. long totalMedianOpsPerSec = 0; for (DecryptTask decryptTask : decryptTasks) { totalMedianOpsPerSec += decryptTask.getMedianOpsPerSecs(); } System.out.printf("threadCount=%d. Decrypting 1500 fields median ops/sec : %d%n", threadCount, totalMedianOpsPerSec); totalMedianOpsPerSecs.add(totalMedianOpsPerSec); executorService.shutdown(); ok = executorService.awaitTermination(NUM_SECS * 2, TimeUnit.SECONDS); assert ok; } // Print the results in JSON that can be accepted by the `perf.send` command. // See https://docs.devprod.prod.corp.mongodb.com/evergreen/Project-Configuration/Project-Commands#perfsend for the expected `perf.send` input. ArrayList resultsArray = new ArrayList(threadCounts.length); for (int i = 0; i < threadCounts.length; i++) { int threadCount = threadCounts[i]; long totalMedianOpsPerSec = totalMedianOpsPerSecs.get(i); String createdAt = createdAts.get(i); String completedAt = completedAts.get(i); resultsArray.add(new BsonDocument() .append("info", new BsonDocument() .append("test_name", new BsonString("java_decrypt_1500")) .append("args", new BsonDocument() .append("threadCount", new BsonInt32(threadCount)))) .append("created_at", new BsonString(createdAt)) .append("completed_at", new BsonString(completedAt)) .append("artifacts", new BsonArray()) .append("metrics", new BsonArray(Arrays.asList( new BsonDocument() .append("name", new BsonString("medianOpsPerSec")) .append("type", new BsonString("THROUGHPUT")) .append("value", new BsonInt64(totalMedianOpsPerSec)) ))) .append("sub_tests", new BsonArray())); } BsonDocument results = new BsonDocument().append("results", new BsonArray(resultsArray)); String resultsString = results.toJson(); // Remove the prefix and suffix when writing to a file so only the [ ... ] array is included. resultsString = resultsString.substring("{\"results\": ".length(), resultsString.length() - 1); String resultsFilePath = "results.json"; try (OutputStreamWriter fileWriter = new OutputStreamWriter(new FileOutputStream(resultsFilePath), StandardCharsets.UTF_8)) { fileWriter.write(resultsString); } System.out.println("Results written to file: " + resultsFilePath); } } } libmongocrypt-1.11.0/bindings/java/mongocrypt/benchmarks/src/main/resources/000077500000000000000000000000001465326363200272555ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/benchmarks/src/main/resources/keyDocument.json000066400000000000000000000011311465326363200324330ustar00rootroot00000000000000{ "_id": { "$binary": { "base64": "YWFhYWFhYWFhYWFhYWFhYQ==", "subType": "04" } }, "keyMaterial": { "$binary": { "base64": "ACR7Hm33dDOAAD7l2ubZhSpSUWK8BkALUY+qW3UgBAEcTV8sBwZnaAWnzDsmrX55dgmYHWfynDlJogC/e33u6pbhyXvFTs5ow9OLCuCWBJ39T/Ivm3kMaZJybkejY0V+uc4UEdHvVVz/SbitVnzs2WXdMGmo1/HmDRrxGYZjewFslquv8wtUHF5pyB+QDlQBd/al9M444/8bJZFbMSmtIg==", "subType": "00" } }, "creationDate": { "$date": "2023-08-21T14:28:20.875Z" }, "updateDate": { "$date": "2023-08-21T14:28:20.875Z" }, "status": 0, "masterKey": { "provider": "local" } }libmongocrypt-1.11.0/bindings/java/mongocrypt/build.gradle.kts000066400000000000000000000270201465326363200244730ustar00rootroot00000000000000/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ import de.undercouch.gradle.tasks.download.Download import java.io.ByteArrayOutputStream import java.net.URI buildscript { repositories { mavenCentral() google() } dependencies { "classpath"(group = "net.java.dev.jna", name = "jna", version = "5.11.0") } } plugins { `java-library` `maven-publish` signing id("de.undercouch.download") version "5.0.5" id("biz.aQute.bnd.builder") version "6.2.0" } allprojects { repositories { mavenCentral() google() } } group = "org.mongodb" version = "1.11.0-SNAPSHOT" description = "MongoDB client-side crypto support" java { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 registerFeature("loggingSupport") { usingSourceSet(sourceSets["main"]) } } val bsonRangeVersion = "[3.10,5.0)" dependencies { api("org.mongodb:bson:$bsonRangeVersion") api("net.java.dev.jna:jna:5.11.0") "loggingSupportImplementation"("org.slf4j:slf4j-api:1.7.36") // Tests testImplementation(platform("org.junit:junit-bom:5.8.2")) testImplementation("org.junit.jupiter:junit-jupiter") testRuntimeOnly("ch.qos.logback:logback-classic:1.2.11") } /* * Git version information */ // Returns a String representing the output of `git describe` val gitDescribe by lazy { val describeStdOut = ByteArrayOutputStream() exec { commandLine = listOf("git", "describe", "--tags", "--always", "--dirty") standardOutput = describeStdOut } describeStdOut.toString().trim() } val isJavaTag by lazy { gitDescribe.startsWith("java") } val gitVersion by lazy { gitDescribe.subSequence(gitDescribe.toCharArray().indexOfFirst { it.isDigit() }, gitDescribe.length).toString() } val defaultDownloadRevision: String by lazy { val gitCommandLine = if (gitVersion == version) { listOf("git", "rev-list", "-n", "1", gitVersion) } else { listOf("git", "rev-parse", "HEAD") } val describeStdOut = ByteArrayOutputStream() exec { commandLine = gitCommandLine standardOutput = describeStdOut } describeStdOut.toString().trim() } /* * Jna copy or download resources */ val jnaDownloadsDir = "$buildDir/jnaLibs/downloads/" val jnaResourcesDir = "$buildDir/jnaLibs/resources/" val jnaLibPlatform: String = if (com.sun.jna.Platform.RESOURCE_PREFIX.startsWith("darwin")) "darwin" else com.sun.jna.Platform.RESOURCE_PREFIX val jnaLibsPath: String = System.getProperty("jnaLibsPath", "${jnaResourcesDir}${jnaLibPlatform}") val jnaResources: String = System.getProperty("jna.library.path", jnaLibsPath) // Download jnaLibs that match the git to jnaResourcesBuildDir val downloadRevision: String = System.getProperties().computeIfAbsent("gitRevision") { k -> defaultDownloadRevision }.toString() val downloadUrl: String = "https://mciuploads.s3.amazonaws.com/libmongocrypt/java/$downloadRevision/libmongocrypt-java.tar.gz" val jnaMapping: Map = mapOf( "rhel-62-64-bit" to "linux-x86-64", "rhel72-zseries-test" to "linux-s390x", "rhel-71-ppc64el" to "linux-ppc64le", "ubuntu1604-arm64" to "linux-aarch64", "windows-test" to "win32-x86-64", "macos" to "darwin" ) tasks.register("downloadJava") { src(downloadUrl) dest("${jnaDownloadsDir}/libmongocrypt-java.tar.gz") overwrite(true) } // The `processResources` task (defined by the `java-library` plug-in) consumes files in the main source set. // Add a dependency on `unzipJava`. `unzipJava` adds libmongocrypt libraries to the main source set. tasks.processResources { mustRunAfter(tasks.named("unzipJava")) } tasks.register("unzipJava") { outputs.upToDateWhen { false } from(tarTree(resources.gzip("${jnaDownloadsDir}/libmongocrypt-java.tar.gz"))) include(jnaMapping.keys.flatMap { listOf("${it}/nocrypto/**/libmongocrypt.so", "${it}/lib/**/libmongocrypt.dylib", "${it}/bin/**/mongocrypt.dll" ) }) eachFile { path = "${jnaMapping[path.substringBefore("/")]}/${name}" } into(jnaResourcesDir) mustRunAfter("downloadJava") doLast { println("jna.library.path contents: \n ${fileTree(jnaResourcesDir).files.joinToString(",\n ")}") } } tasks.register("downloadJnaLibs") { dependsOn("downloadJava", "unzipJava") } tasks.test { systemProperty("jna.debug_load", "true") systemProperty("jna.library.path", jnaResources) useJUnitPlatform() testLogging { events("passed", "skipped", "failed") } doFirst { println("jna.library.path contents:") println(fileTree(jnaResources) { this.setIncludes(listOf("*.*")) }.files.joinToString(",\n ", " ")) } mustRunAfter("downloadJnaLibs", "downloadJava", "unzipJava") } tasks.withType { description = """$description | System properties: | ================= | | jnaLibsPath : Custom local JNA library path for inclusion into the build (rather than downloading from s3) | gitRevision : Optional Git Revision to download the built resources for from s3. """.trimMargin() } tasks.withType { sourceSets["main"].resources.srcDirs("resources", jnaResourcesDir) } /* * Publishing */ tasks.register("sourcesJar") { description = "Create the sources jar" from(sourceSets.main.get().allJava) archiveClassifier.set("sources") } tasks.register("javadocJar") { description = "Create the Javadoc jar" from(tasks.javadoc) archiveClassifier.set("javadoc") } tasks.jar { manifest { attributes( "-exportcontents" to "com.mongodb.crypt.capi.*;-noimport:=true", "Automatic-Module-Name" to "com.mongodb.crypt.capi", "Import-Package" to """org.bson.*;version="$bsonRangeVersion"""", "Build-Version" to gitVersion, "Bundle-Version" to gitVersion, "Bundle-Name" to "MongoCrypt", "Bundle-SymbolicName" to "com.mongodb.crypt.capi", "Private-Package" to "" ) } } publishing { publications { create("mavenJava") { artifactId = "mongodb-crypt" from(components["java"]) suppressPomMetadataWarningsFor("loggingSupportApiElements") suppressPomMetadataWarningsFor("loggingSupportRuntimeElements") artifact(tasks["sourcesJar"]) artifact(tasks["javadocJar"]) pom { name.set("MongoCrypt") description.set(project.description) url.set("http://www.mongodb.org") licenses { license { name.set("The Apache License, Version 2.0") url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") } } developers { developer { id.set("Various") organization.set("MongoDB") } } scm { url.set("https://github.com/mongodb/libmongocrypt") connection.set("scm:https://github.com/mongodb/libmongocrypt") developerConnection.set("scm:git@github.com:mongodb/libmongocrypt") } } } } repositories { maven { val snapshotsRepoUrl = URI("https://oss.sonatype.org/content/repositories/snapshots/") val releasesRepoUrl = URI("https://oss.sonatype.org/service/local/staging/deploy/maven2/") url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl credentials { val nexusUsername: String? by project val nexusPassword: String? by project username = nexusUsername ?: "" password = nexusPassword ?: "" } } } } signing { sign(publishing.publications["mavenJava"]) } tasks.javadoc { if (JavaVersion.current().isJava9Compatible) { (options as StandardJavadocDocletOptions).addBooleanOption("html5", true) } } tasks.register("publishToSonatype") { group = "publishing" description = """Publishes to Sonatype. | | - If the version string ends with SNAPSHOT then publishes to the Snapshots repo. | Note: Uses the JNA libs from the current build. | | - If is a release then publishes the release to maven central staging. | A release is when the current git tag is prefixed with java (eg: java-1.7.0) | AND the git tag version matches the version the build.gradle.kts. | Note: Uses the JNA libs from the associated tag. | Eg: Tag java-1.7.0 will use the JNA libs created by the 1.7.0 release tag. | | To override the JNA library downloaded use -DgitRevision= """.trimMargin() val isSnapshot = version.toString().endsWith("-SNAPSHOT") val isRelease = isSnapshot || (isJavaTag && gitVersion == version) doFirst { if (isSnapshot && isJavaTag) { throw GradleException(""" | Invalid Release | =============== | | Version: $version | GitVersion: $gitVersion | isJavaTag: $isJavaTag | |""".trimMargin()) } if (isRelease) { println("Publishing: ${project.name} : $gitVersion") } else { println(""" | Not a Java release: | | Version: | ======== | | $gitDescribe | | The project version does not match the git tag. |""".trimMargin()) } } if (isRelease) { dependsOn("downloadJnaLibs") finalizedBy(tasks.withType()) tasks.withType().forEach { t -> t.mustRunAfter("downloadJnaLibs", "downloadJava", "unzipJava") } } } /* For security we allow the signing-related project properties to be passed in as environment variables, which Gradle enables if they are prefixed with "ORG_GRADLE_PROJECT_". But since environment variables can not contain the '.' character and the signing-related properties contain '.', here we map signing-related project properties with '_' to ones with '.' that are expected by the signing plugin. */ gradle.taskGraph.whenReady { if (allTasks.any { it is Sign }) { val signing_keyId: String? by project val signing_secretKeyRingFile: String? by project val signing_password: String? by project allprojects { signing_keyId?.let { extra["signing.keyId"] = it } signing_secretKeyRingFile?.let { extra["signing.secretKeyRingFile"] = it } signing_password?.let { extra["signing.password"] = it } } } } libmongocrypt-1.11.0/bindings/java/mongocrypt/gradle/000077500000000000000000000000001465326363200226515ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/gradle/wrapper/000077500000000000000000000000001465326363200243315ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/gradle/wrapper/gradle-wrapper.jar000066400000000000000000001646551465326363200277640ustar00rootroot00000000000000PK A META-INF/PK Am±>=@?META-INF/MANIFEST.MFóMÌËLK-.Ñ K-*ÎÌϳR0Ô3àåòÌ-ÈIÍMÍ+I, ê†d–ä¤Z)¸%¦ä¤*„%¤ñrñrPK Aorg/PK A org/gradle/PK Aorg/gradle/wrapper/PK A•%Ó¦¹/org/gradle/wrapper/BootstrapMainStarter$1.classRËnÓ@=Ó¸u1¦„ôEy”@_IikÁ6ˆU‘@.,RuØLì!™ÊGã ü6 ±àø(ı ]t1ssÎÕ¹÷ÎÏ_ßxŠ½ó¸³ˆ»îá¾M|4ži£ÝsZ«}.à穸k£ÞŒ‡=eÏd/c¦ç‰ÌÎ¥Õeié0“c“ ”=<ÚO¦õ±b»í+7.Pÿ£ômïB%œÀÚßM• Ñ-°wźláƒ6i<øZ2³93Ööìèê³#ð‡Ò±w¹Úºl hÂãâòø¹æx8F×èE´‚v~ÿÄ—ê9à½P%pw8Ð.ÑR3êSò ѵ²ÜAcî+jŸgèQEoN SzéÝB£z÷±Œ•ªÄjÅ\Ã:­‡ÛØÀ zQ^ÅÁoPK Ai,«$ -org/gradle/wrapper/BootstrapMainStarter.classVÛSWÿsÙ°,ˆ1*‰‚±BI/µV°V(Ð-m´Ú.É!¬nvéf£Ðjï­½<÷·þ ö%Ø2µÓ—v¦“ãô;»IIb¼ÀÌÙ³ßõ÷]7ÿ>ýý1€£øIF2^à C˜”0%cïÊðA•0#aVF —d\Æ{2æǼŒd\ÁUq¼BNP®…p]ÂR2"¸!c7%|؉^|$A aQØÊ‹£ .aIÆ~ †¢„eeÊ4¹1´r™—‚§tSwN3øÉ+ þŒUà ÛUÝ䳕Ò"·çµEƒ(aÕÊkÆÍÖÅ{èw–u²‘T-»˜.ÚZÁàé»¶¶²Âíô9ËrʽÌhº™u4Ûáö8C ,® ‰ëê-펖64³˜Î:¶nÇ=Šn¥/èwñhv‘<ìl#Ì {.'­aénVfèð¸ÓšMèó–éðUÇ [µ´'bÔÓ0¹“^˜SXB¹D¨]ÃŽß.I¸üî,[†Xƒ€Í— žwÒ$w7'nm¥ž¼H«ÙSçI¾‹r•¿=£­¸btr6±šç+Žn™e ·¨:KºYPµŠ™_æ¶_¢%u­ÉPŒ-q iûõgôÅóºMÐ-{\f­Šç‚I‰jWË”0 `ƒ NãÊÂV8sÓÑKüØ «bâ¦åÄ Ê‡ÃãÎ2_t+¯c‹OŸ‹ëf\Ðɧ¾XâCƒå¡CÏ–“K‹·­„Û ”ò³ç9%¥9 ,¬HøX Ê©£ ‚; îŠc«Ö|‚OÜÃ}Ê.µwÊë¦TkÊ)¢à3|N­*Z‚RÛRU_àK_ákê¤zÒ3†U梾 ¾Á`\­4‹T ä[ßá‚ïñ€¦ì‡làˆ‚ð#ÃÐ+*0ô>¯iò¶X åìiFZ$K–]Òh²O&žÕÆñõêVoÑæ‰ÞÕFW¬€c-ÌM‘ßD²qh§Æ›ë:U“TŸ‘T…ñ–ÊÔ;#RäNv­ìðRózH$['tk=ÊeÍæ&Å›¬o²º§çh‰8ò6¿lsÜ•¯ØÂPý=ÒäÖ£ ðeîdÚ,±Xâî: º×¶Ø`»Ô¶Ùl"´zñϼ¤”žNòEë/¨›w¬Û¼¥-j=𒶨‘¨¨y1/ [Ö\ûf òUÚe÷“v¡S/7,¶ƒxBY|·šÍ™ZI,<ñJ¶ìG xâÏ&–¯Ó[šžŒžá °_é² Ct]b :OI Ó“a£$EÊì$úî>¶ÙCÿ w¾\Øïÿœo4ûÁ Hn"”#RGÎw¨ ¹ŠNb(Utm {ÌÿÛ£þ*z¢þðŽ*Âch ¼“¤#9_xW¶ŠÝcÁhyGè}ÏÕ¨ÿ/ô®CŽúC”A€ö» Sè¤s/A݇ô¡Ÿ~8Œ#Ž E¯Rü7q%нBÑß# ܤ@-8q;Dv˜{Kã0À*ŽÐÍG¶ÎÑ¢cäM%Ê8N¼›äãMœ „½UK•Ç;I¼1¢D°í ú%Ğↄ„ˆDvN¹˜Þ¦ŸDôí©Õâg¢ùèy|±Üpxïö©#Uô­c€ýëèÙÄþÜâU˜ý]£ý¿@õ}Ⱥ¥iˆP8T©(Õj@§ ö1*BŽ“Ü ºqg)øÔ—¾è“Ó_:#Bu¦}Ó™þ#þzÑÑqF=÷~t 8“ɹ7÷Üs¾ï»çìÝ'ýÀ+øÈDo4¢ÃÒŒH“5ÉœmÀ9çñf’¸ W.š¸„Ñ&ŒaÜ@ÎÀ[&¢x;raêc" i.˜4pÅÀCÄñ*á3t<¿’©ø¼ìˆÌªÏ——…Ÿ)(g–¡¡,Qá`8µ×Æ1oÕu<^¾ê{_T«»W…^öÅŠíÕªÛ{„_nÀÀò„Övíà<ÃåÔž ²o–!<ꕉksÁvÅ•ÚÒ‚ðgø‚C+-¯ÄYîÛò}1,ÚU†î1qƒ×œ`¿Ì VÞ¥qÔáÕª €sñ:þÙèh’庯ð V]änE”ZS…›|…g\d®Mç³R“ÁËe™€!ö´›!Zò\J„[ éd'Ì­ä2c”J·&ùr]qRru·JÁ+¢èå8 ÔS›Xm¥šï“çÙšÉàMxÛËä§Æo—Är`{.±h§“-Õê’gÂT^*wSàÜ٢ߡ¸µd½ÅälÉ2º•gPZèÂU m8l¡Ž ÓÂ) «AïX˜FÑ œ´è¹yÕÀŒ…k˜50'=ïÒ±îA›áˆZuèè3Ó57°—ĶS"ÎxÏÂû¸ná\7ð!CöTDïàM-Ü%:þçho-%+Ô±ïÓBÕfuN×I¡Q{ùEñqM¸%‘íÛ帨vËÆÈ>E¯ø¶[¡Æ[áNMLݠʧò»77PPb¯dÄ15º/Nûnj3‹¾·ªRZlÇ1ÉeShKü¶ì¡|^ö¶dSÙ:83ôÐm˜ñ…†Ù1týµÈ¦¡1$û†Æ0ù»p”ì1ú·@ë‰ô:Xº ¡ôÀ´´¶†ðÕM¶ :Ùï)ö4âGÄð!ýLx ŸŠG/Ž«ë6¡p™šIäÍ©7ëxŸ#B_`¤§ñî§8”þÚw0Ó=máuèdïÞC”C-‘¯`ÌI÷·ˆË¡ŸœÑd¥)VÇ`ý….û_ ë7R÷;!ýü‰aü¥Ø¥‰3¡m³ÁKH)v#è#oHÍúÕ¾šëÐñVZ¦ç«NùIr.n¦»{×Ñ7Å!=©ßÃIbNêŸá¨äœÔ7`íø‰‡h a.Ôéï£yDÿÑù}±Çø´ê2^@Ù#G£æe! ±†YY¦cœJÊ"#òª#KïµÓxY&·-/§D15“¢4%ªÚÐ%V颢®kšTÉèD¼¬õÞé¾ã%Ð|ë“ Ú@ËÛ¥ÈlÌܧÔgêh ¼¦Ðˆ¹Š|/ª7/]>(Bó_PK Až‚­Û¡~4org/gradle/wrapper/Download$ProxyAuthenticator.class•UÝsSEÿíMèMn74ÄJ©X©1IÛ$Eü E ¤ `úa¿ ´Û›ôâõÞxscé?ä3:š¢Ì8>é Ì8€:>øWøàÃÙÛ´“¤;éî9»¿söœß9»÷ÑóŸ~p%G1¥á´>¼«Ô3Q¼‡÷•ôqÖÀÆuœ3U€(>Šà¼š/tã"&t\Š Á¤ŽËzpÅ@+oŸè¸ªãC—¿nU“y†¢ë•seO”l™ÛðD¥"½Ü¤»áØ®(ðœåXþy†ÁTGdz‰!\pK’¡§h9rºöåšôÄšM+‰¢k {Ix–Ò‹aíÍzî½Í‰š¿.ß2…ïz üªãH¯`‹jU&ßéèä^wYú³d¾áz¥¦=ËuN¦ÒÅ»âk‘s¤ŸÛDbåwg[%ØØÂ)çæ}ÏrÊŠÈwM×fˆøÅª¤øcó¾0¿˜• WŸ2\èÌ_Ç Gzµ{y5Œ2œ8Í`Ì»5Ï”W,Åtlg+«2àx Ç9Ž¡_IEŽ)Ìè˜åø sóXбȱ„ë:np,ã&C_{æ—j–]’Ç Vé°ìnêŸ+Ã[·q‡!ÞnÈp8ÛÆ+(ŸªÁ!°¦¢59N"ÉýýÀpt÷„¶ŽL2„RŠú8uÓœüª&«d´°YQ¤¶é©æ¦j9$Ù‚¤â$_ÇphvnæÆ2é—õÛ%Q½8W¤¥æ¨h…P¼YgèVe·‰{wð­m~¼KTaš²ZMŽæ©A³¼Ûîk¾eçè~¨F!r3’Ú{ôÞh­§îžïî4U¬Å)U’"âšάݕ¦ßâ°±Døna]xž'6éaJ¥W Ôôû„³RH/aÞá>z«Y<®nI!hêRQ'¿NÚÒ4šÌÐÐ2[}Kš†»<Æ4ò@6poÑVÝðð/iašk™:ÂßáÐ7°HêªC/f¾‡ö‘‡ˆ.oÁª£;Ái¨#ö#kø=SÿblX¼6=òºG¦"±<ÇZÞ³ôÛJâDI²8^I Ø`ˆ+ñ’Xv‚Bx±žm%²$¤§,”%”¦{X ´,¥t¡„¥ÐÐ9Á@ - {éltöé´)3̾vhëþ÷¾'Y²…Iç›ï›|ñ}÷ž{î¹çžóŸsîµ_ÿÍs/Ñ*þQ)ÕÑxè?é¿<èý·h~©ÐÿxÈExèqú•—~M¿ñÒc4†Iaö’—KOáóÅ÷Ñ,ÍRÑ,óЛ¼ÜÃÕ¼B45 ת\ç¡Õ\ï"ñ¯‚ 7zèu¾På•^ʼnE«eµÂ+¼ÆCWÒ*¯Å—/Í¥*7‰¯CHjVø2¡éå¢iÍ¢¹R4ëDÓ*š6…×+Ü®òmáf¡ûU*wx(ÂA•7ª¼IåNAífíöÐuÜ£òfý”·¨Ü«pHúTîWy«B'Þæá«y@åíBÆ…¯Qx§Êת¼KåëTÖUÞ-t»‡U6TRyXå•#*ïQy¯XUxTᓌŌd[TO¥ŒÓ¹ë!=5×Ç÷Ç¢q=¼9N©Tg$e`dòtàິ9bÄÌÈ nÆA,ïïÞÔݳ­{×ÖöÞP°§l{ô}zcT 7†Ìd$6ÜÌTÖ¥L=fnÕ£ihgò¶öoØÐÞ»+ÜÞÎÄAQ51ÍÚÜÛsUo{(´«­²ÂcЮ­§»»½­;ìê vµ÷ô÷íê vvCí˜YÂâåLþÞöuë‹20¹£ñáaqŽ…ñäpãpRGÆýI=‘0’rš*w룓½­F2‰ÃZ‰iö¨/&çÃÌÉ©ƒèbŒfD½Ü²UÚŒD»ô˜JC‘á˜n¦“PàâÂÙ˦v:¥2Ü—Eb³…©µz†£ž´[™œmñ°!TÄŒîôèn#Ù§ïŽÂÑñA=ºUOFÄØ&:Í‘vÎL¶Šóã±}°BhšI–Wçzr¢yÅ4S¹ÃäA|Û­ïÜBŽ%’ >O"O|Uqé0¼ø Ž‚cLdÖ\L~¾Szvï1Íæéᔲ©îÅ:)Má„Â×+ uÝÏÚû7Ïèôß²g³ã¯À<òÿ¨ÀYZI¨¹Š #Ò¦æ5ðŽjÁ¤†mÝ‚l?Å ³±¿7hËÄ7D¢†”¨èá°ÐI¬É.l¤ÌHÌ–=«p- Ú~`ÐHˆI,®ÈF2¦G± 2’ë† ;­»ÓCC" •ìhÅÆ±ôh¯!”ôšqSv±as$O’Î’x#B9›ËÚâi±¢¶€^óóÕîDÊŽ½P 26=or:Ük˜}‘Q#ž6sʃÏq.ÊpÀž´™H›0¼¡bº$Ë*fƒ±üI%¥ýÉèûu¢à¦6N+¼Oáý È1G˜OqÌŠ©Æ?§€:3õ:§…˜*x¯UOE§"aEQÇO7’€€g07x„ׂ±!;m·ž2Ö¬n Êdº¬ºH®-V7+† ÓZ”ì2Ì‘8\¼ /i E±[£5~ÍÌY^Å& «²•`fA»¸'Ù®'£Á57+ßB’qm£[¢ yy+ä]¢SNÀeÈÈ•H¤ƒé¨ný9Kœ_Ü[…Ç––‹É*¬& t<‰Óø ÄÉp`šS]T‚Gж±°¸¤x­]Ê+'§r4wŒ+Ý ·¡UÖ À¯x“Ù4%Ñj|šÏØ€Î_»$·b–•ýûâ–§í}òk€Â¯jü¿ûõ÷m¨¿Dã7øÍ¾ìÒÙE S@P46ìŽÄ ëuS7qcn³n÷V 0-ÕZq7õùP+b×T`Ä™Áo‘T 7©t"Ç6áh‘`·vÁî>+4ìдòMU!q³]V¾ßÒømè²N4쳫†fìjPn G')J<Õ`)zd]Ö…KSKSꥩfùE^Wãò;HWE2Ip}îÒyÎLIr%®e(-ei§Ÿáë>§Ø#¾v:ÌrM¹¶ÁtÅo<ù9,–ÇžŸ:  Ó7’Œï·^Ss‹Þ ±'‡8  _éùÕùE¶à§Ê7aÈÀÅ ²€ ¤æSI5’3PU{ÖpâV:¢§º¦|lÇ]9&…÷ŽÜ•Ê ]7À¸jæÂN;·;âz|Iõô¥Ó)Eåoú?{\‰ëªcXXaYuŠn~ÅÌWŸ™&—¬”N"iÊï‘<)ôoˆ›¼;bŸ”!á 'A´@[‘õÄä{Ê=º7I*.3.1˜ãÉ>)>¦¿àü“´‚‡‹˜›˜ÅòÁ¿`ŠÌ‚÷’çé5®OãÙgôàäï6>ú—.•Xn˳k8€W”zHÉz8GŸ{Äß¼<ƒ¾°Äsb3û ¨ƒ”ÏGWõŽV1¬(Y9U†ú(lžâߢŠ‹¤‚“—„y±—NQû;@R²•8„ú’Nµ@š>{ÊcbãF!Ûµ?‰¸Fäâ4Ai3ÿ‡Æ #F]ƒÑxJ<¬Åd ¢ëÏê‰fßžš§ð ¢©ü53c!—)¥µJá·Ðàˆ!j‚~G<*ßI‰³ÂÞtJð·Lhíþõhj ²¶Ùn)+“¿ðd¾±$±Ù‚vAuðOg³œ0’ˆ-néGx/»0lö±|e‘5;¦­É—2íù=ÿÃæ`ŒHl_|/üwicì˜;¹, ÖzД¿È,vBñË EÕm3áN bò5îŠ'GusŠVEÿ¡ˆn¦ó¨Ž bº<ä§[èú·Q }œÐmô‰Üø0ÆŸÌ ãOç?ƒñg Æ>ñTEß'^«ò{»ýŃS~ñvÿÝ’ÿÒп—¾ˆöK ì 79ñ-¯©åºúTr‚cä|F2߇փ/ÑE4‹VÓýèÕXìô=(ÿZT.·gÙ ”ÈžPÁµx©ƒ‚رX¹yœ\cäî¬Ér’T¦®º“TʾÓKäí®­?IãáZ†Î,¦3xÆ%Í€z’Ê´íèÄ™Úc锚V‘øûÕZRéZJ—Ò&j¢nj–Z°ûRZF_¡¯¢-èkôu|Uê oHó<"%”Ø\ß—5wæÅ\9M>…Ž*ôØ­ §B[#…¼T"»‘ ,*œpXøÿKÌY>xBzàIË08 > ª«£ŠšÚãTYSœ|5~çqš]ãw'®§9µuc4÷8UmžpCú|H%j ® RºnZGs¨(i£å´žj©] ÅÚ#綺œÛê$NJdïˆt›è :eO Ç%Í£ÙüwÁ(.û,ßÂÏSô´&kÏŠšg‰}óO’¿®«”£rtšÊÇiá@ žÁ‹NÐ9“™%7î E´‘ª©S*mm¸ÂVúQéé’E^P¿MÇlóõ“C®,¯ËÐâ »­F*0 `Kpì´ý-98‚øúŽ âïÒ³Xy\nÆ´ýLv3ÇXQü±mws“«ö—¡ó›ÜãtÁÀ8-ÀÆKÇhY·ß¡åMΚZ¿sŒªá°MŠß —*­ryE†êíoƒß™¡Æ&We5=¯6©btáOéZoéÚ2¿Ë¯fhåÀšÒ’‡iç Z•¡‹î§²qZ=à»xŒÖœªòÎ-=¬¯õV•ÉoYUÙZ;ZzÏC¤aÊsøžh¤kËà„ªZЪ¼'éR7öWsK3ÔttâALUúš3t™ßušT¿+C—ן¦žú µ¥Ž&El8NW"l×ùZ3Ô&ηÞ׎^†6ø•1ºêTSyq!Šâ/?õ ,>‹Þ¦÷S|¹ö}Ÿg˯€xÂ%´ èº\Ûi1íD@î殣U¤#˜w׃í0õm4Œ™P"4_™´—n¢(²f¨NÀgIÄY >5é{´ûßHï‚ãÏèfú þsdÑ÷é ý#ÝMnäEtŸG7ó2:Ä5t+7Ðm¼ÙV`æ>`cÚÖ)Ø9M'ù »\KϧšÄh=ôÙKÏÓ ˆÿ!h÷"ze8Ç:…äæÄnÐËÐGHÊb=ƒèY,á éûôr@¶×º¸ž^A¹—@â«@¤ŒwÈ;ÍʪS¨C¡×z]¡7zS¡·d ;ÑÿL\,¹.¨š€òJQ>”” œ±`’ì)V芰BoO Uc°ÿÍùa{äE *~wig˜›`g‘«êÇ©c%$Èh6âg~DMéÂO÷õë§-¾ÞÚ1 ’¡@Þ\mnå¤Ð;¥ƒEö?§~™~$ùëé÷à+︉u«KÄï<íÌóœ RdK öèë®?ƒ²é믅NÚúi2 ¶! ê|Wg£g1SS?FÛ­ØA:˜Ì€‹ PÜ(Îìà…Vó@w9êèdõmÉ%®–\âj¡?@J°úú#™Æ…Þ0Ö¯È ÏÎÉÙs5˜Þ¥[öä(6•á̶#C×tÕùvfèZß.Ç t]†ôî:ßn1tb<àð…C 69ëóF††š\~§ß…IcÀQëÎІ^¢È1¬Ü+VF Wú\Œ»É)Ý5*2&üU"Óõ8¿¡z ¾–j`BH«°þ|”T‚K‘ž·À½›Î-8ê­HÚÂ^×ÀóÁñÇô'ЀÀûSôœ ÌGøsxp6¶h·¢Þüý%z½H4…žÀÈ‘œ­H»â†‰KÚO诡£°p-•L`{‡„1è§"öL=Î IÅ’Ÿ!çXH•S8³MVǘ¬Ž°D—ƳÃîºÓt.òèBA¨rmMJÔ[:¼],‡!ëô Š4Úv‡»9œ×ûñ°ÂÀƒç¡O˜Äª.r%ãÐJ[™ÍM Ç„ñ,Èä]Š‚­8Ÿökߟ_ÃPU:â]š3aºý©G­ÍÆ©±\°^¶&a¡t"-ãœE­eY²ÿÂè›Ë›¼8\3ެK tÐŽBNûÐkØûPK A!9|¶„ 3org/gradle/wrapper/ExclusiveFileAccessManager.class•WÛsWÿYÒÚ«u|iªVÍMNZ*;±•JŠlB×NåKœÆŽ[—t-دvÅjÇÜSšB[(·¶ÐP`x¡ 3íL«$x†ô©Ì0à }á…0¿³+9¾%L=öÙs¾óÝ¿ß÷íúOÿýýÁ¯t<ŠgZ ãYµÌjxNG_ÔpNGϨ×Ô Íx^mMEœSKA-EµH ›1¯¶ ::`éÔvIÃb3lIÅžDIGŽºqu”ñåfxJ_¥~O¡ªc—u,áJ ê§íÄñ–ñ _Õð5öñÉ¡± #ùñá SgGFòÏ tŽ_2/›YÛtæ³S¾g9óý­C®SñMÇŸ1íªhñ­’t«þDE@äv”]ÛÎ;¾ô.›¶"Æ,Çò Ä2ù|÷Œ@tÈ-R°mÜrä©jiNzÓæœ-•=·`Ú3¦g©sõ,jÉŽ»Þ|vÞ3‹¶Ì.yf¹,½ìð•‚]­X—åˆeËÁBAV*¦cÎKŽÆÍ€ 0˜ ã°Ü¬âëOUß²³×)T=O:~vÈ´me±¿{]Ô“s—dÁWÊ䕲å-3ÄQºd»…EÝ!£C½…Óq¤] 0ŠE•(¹Þ;&f£*2³B5ûþ?ÍÊ^¨¤£±}Òò虫\j÷L§è–ÂøC¶‡ÖlÙtGuZÝÛ5Ó[" äMn,Ér¹Q–‡ïíõÀôtÿ1•„)ß,,N˜å@LÃ×5|CÃ75|K@gùdÙ·ˆ'ÂhÊšwL¿êQ÷ÄÀtnkŽ}¢2†ts¥óÒŸ&J',ÛVXjÊt³Š%syNÙnE>]µ¤o3•É;6‚‹ÄlK¡q¸oF3åV½B½ÖûîŽÌ>%l W Ä!½8$`¬ÍÀ ø¶À›»ïDÕ²‹Ò3ð"®x ßèýD]AÌõÙ…EßU úð²Wðªï©åûx•À¹cóLÕQ­½V$ÃCnÕ.¦×O#€&¤A7zxŠ N5@¸ïT3„Ï(ïúåz˜§Yò4©}Ï ˆž] Ò³û4½?ˆE¹vqÝÀ<Ì ŠáÓøLø¥˜ÁNŠpÿ8>K.š‰ü1´â‰DgÖ[A|ö4n›khéLp©Á¸ÖS½¼ÍESÑv\ÇcêÙöêÙ~]+蘭ËvvRˆÜ÷5dwÞ¹˜ÈÅÊý=ï#rÍ<ª‰\KªåT´¤öúÛ8º‚äloç7ð`.–ŠÕÊÅSñ WÿšŠßÄ®TŒ U4]»‰Ýï¬~¨Tô®7½‡6•‰övîãþà7ÝBZ §§Hè Ò«@'¼c ¥¿›KlÏ“¸3Ö1·™ÿ¿ãcÑÆ¶‰õDQDDwp>¨žäPõzp}”ÕÊ@8B gmγ*& _$W™Ô ëö+ôkôŽrÖ}¿F¿A?~‹Ô(µ‚AZÆÇ8‰ðÃñŸü:üưŠqÁ¤Ð8­ Ó›“"‰¼Ø…Q±câï?… z5)“çqj…™sDP·hí hô F›9Òˆ‹ޏë§uì>cÄÑ~êþiMȈvz5ÀHMü¾ ªŠø †ð$?b‡)n¬IŽPò$)SÐþƒã¢üݳŠhÑ ǧB¢†¤†<£À¿q¢ÏÒ0¶Ê.Ò¶åƒÃx½dÐ(§øÇWW½§Žw@óMì߉¥ß­5S< Ÿ ’a„<õÀuõ.«ËŸç3ôäGhí¹…GÞAtü=’£dl¥Ù¦@]± …ùßéçysŽýùü:õmŒšO• ‘ ²¼8x4ó?PK Aì„,y†-org/gradle/wrapper/GradleUserHomeLookup.classSÛNÛ@= $vŒÔ”K J)$´ÄÚÒ E¢`@"\”@¤Õ-Þsc-ÂÄg¥ØOˆN™QMž} (1ŠáìÁ#Šj€ RŽ`뛿Í€i­õm¹õßP/ÊQ«ðWM:‡Ü‰â;"¢¬+) Q¤g4·óæÍ+ÿ{óÞ >ñÐekÅ"ÏT±ÏR¡âÙrxŽž«ày*J$¹ÏWp—‚øñB?^$ /Vñ¼Ôs~¼LÁËUTIÆ*¼B.¾RÅ«p^Á«UÌqɯQñZ¼Nн[÷Èáõ*îżÑ7ùñfoQðVux›ŠZ¼]Á;T,•îÅ;ÜçÇ»T„ðnïÁýòë½rxŸÞïÇü¸ ¢ÈùU|ªø0R*F1¦â"R0®à#*6á’Š;pÙ+rÃGýxXÁ#òócrñã*>O–áSø´‚ÏHÎG¥H’?‹ÏÉáó*¾€/ªø¾¬à+*vâ«swìki ·éínßw¤£kWû‘®==]»áãú)½1ªÇ‡»m+j˜Ùjƶ·÷ëѤ!,ØÞÖÞÓÒnoËÈ©N³ìíílïÉPæP 6•lŽÄ#ö¢Pý~_«9@máHÜØŒ3¬ýXÔFšýzt¿nEä D*ämpn˜rg2ⵡâ$¿‚¯ ¬ MÞS·NkÓõb©v›I«ßpó|NÁA[-2Eå­š‰Zx•ÊÇ´0Íœ×-N7J3s¦àD²ç^ž²ìÖå}Q³Œ‘¨.oV‚ü›BÓŠµ—ÌåÓÛJT*&©Nåu]§Ó6‹6«G›é> ê&ŒO0¤VÄ>Û˜ÏÓRÓâ#€3øÛPSX—Âú6¤póm÷afx›úVŒâ–+TÑhNaó=˜'‰[}—°¥¯¨¡{ [Gñ¤+„ªå"¶ \§ÍjEûGrSh#nÅv"×J´¤mË"в ŸR5h!Rˆ‰q+mÜÁdè nÒö†¯‚û’8ÅY5wžfŠ ®kü:˯…L8wõ©ü«‚oŸ‚£TÁÁN…JUùM;ÜçdPÛ(KaûݘåX,';Rèf¡SÂX”tƒj1ŸAž„³ÖÉDWiø¬QåC7­fSZMù8vRzUâ¶üèD³Ä•§Å <ÃáºóPK AúâæªÛ"org/gradle/wrapper/IDownload.classEÁ Â0 †ÿÌéæ¼ ^õbÁë®* AÑ{ÝÊØ(í¨Óùl|JìTf $_òçÏóuX ï¡ë! ø‰®”Ô±ŠJ±YBÑÆû@k½oÑV­G=ëöSEýýfv“ÝÍ’óùä½yïýîß÷÷{oÏýçÁ‡¬Á?æ¡)^ȃÍCšGF 2ËaTÂ22¼8Ê_·…ð"ž_Ì;/áá¥<ãávI¼LF7^ÎÃóp'^Á_wÉx%^Å$¯–ñÜÂk™ôu!¼že½AÆñ&Þys%îÁ[˜ð­¼|[%bx{%âxc!ÜËÛï”ñ.¼[Æ[‘Ä{xx¯„÷…ðþ>ÂCøŒ&|˜>ÂÒŽKø¨Œu¸O&?&áãNHø„@ÕaÕXaX1Õè×S7ë†&° sX=¬Fu+Êë •L×ÓN»n ,ʯl} ãè–¹Ç6¦˜L͉îéî ¦Ë˜,f™ƒz"c«L'P×iÙ‰hÂVㆵÕTJ³£½ÞÜVHJüáR5=Cêšµëz2IjO™¡š‰h˜ b:CzzÅ*åå´t˜iG5 ¦Û¨›º³IàÎÈl„ÅA(·ÊûzÉNÍ´ºn¯€¿ÍŠSÔvê¦Ö•Ihönu€óPÝÉiÙ«Ú:¯s›~öR@é0Mo¨é´FË«fñdÅjrÚO’(KU‘ºÒä*ºGÖ6¤ÅF$|Ò•=½s‘¤åe’’0ÙI¦¦pä‹3\}-žRÚ±sÛ‘˜–ÊåXNªöˆf{äóMM‹§Û­QÓ°Ô81öÖÒê Ö^Š5űRÚaÍ <’óUžt:7¢DK‚kŠCw4•_m íÆâpl"Þù=ŽÙ¡¦\ Ÿ’pRÂýdí”éi §.ÏÓÍèÎa-ƺçõè Su26©Û2“ ÀªŽXƶ5Ó‰¶QY]{ä+cÇ4/HùÜ41f›3¬4Ai‡æ Yq ŸVðÆlÃÍ 6¢UÁ&žƒÍ ¶`«‚6´+ØŽ,É*T¥à4v ,)…èÖŒnÄ5[ÁÎ(xg)¯MÖˆ‚Ïðz;>«à!L*øŸç½/à‹ ¾„/+ø ¾*ák ¾Žs ¾oJxXÁ·ðˆ‚ocRÂw|ß4¥TÛQð}ü€ŒÊ€tײÂJø‘‚3×OðS ?SðsüBÁyüRÁ¯ð¨‚Çðk¿aý¿E‚0Ó®šÃì„?Џe%Aãw~¯àø£‚'ð'Æ_ˆ¸ 0 QmVƈך–S›1oÓSµT@µŽE“hukjÚ2[Hê_Ùá¿áï žÄ¤ÀÒéèugLGOjSB9VäÂNòòÙŠ•´—bFàÊYA#pý%–h>é¹ÖEm»¸¨éLot85.ËÎGɵ¨ JK/®”P³5ÕqkW ¹l§-Û#gô'_„›äü„æìRÙk¯$Zw©I­´ §o–mRY)Óvglå`NŒ!Çò¶®”kû¥ý»RO·çæšK}+¨§=;’[Ò–‘q´]ª3DQc1-MÕ*ºªs¾‚ŠÝ˜CgΩ]ÍjgS[ÌÉÞäy×0où\–ç-Íe²{ަ®rŸfÛ…Ä.òÌ!ÿ45Y`õ ¬¹uΚ‹!±¨ŒBRŠWáyq9¤P‚ƒqn(”ÌeeÔOßWßU{lnãHñ¡®ôm”wëÆg hùwZ‰„ Ö"pç.˜ÙÀ¾¨0Ê„a%¦M[˦mœ»iù€l¸HŸ›X(>õyuIÄŠÃIQíS½ï¶èeYR–…]÷Ìf—0Ï|<„ô©ÆW)<Ï7D¢‘†Ôt—v„z›ßt§¼7±+çb@ùö]®;zý¤ð=T𤛠¯õlË-—`K!â/¥åå4³‚ ÿ÷3ÚEí Yj‚ ¬rºIÍ5Š|GxWN—6Ê[¨¥_:- û¬ªâ§@ó¦ÜL"w¦7‘;Ó³ÈéÝD¿}ô¿Ï%îúêG$š¯«o‡¨oGEýÊqøêÃþqøëÃqêÃÁqëOCºŸ(+ð<ƒÄÒø|kh$ ]€ûÅšèAÁO:#=¾ƒ°ž ù,B}õ "‹yg!÷F¥·R²˜_½€†,ž¦w/íú²¸l 벨ÃjÚ¼é,šÀå;'°x !šjNžÂš¯È"LôK{=¡Õ÷Bò‡ß×Jkÿ–u-ÃȬ&,Ÿ2¡ÅöçD‰ \™#­¾ŠVfq5eQë^ÃâÃþ3x–a¿'íÚÞ¼ÅXÑâž>[ %œÁuchå¯ë=/C-Á%R’›ž59Eáàêzÿw2'9E} ¬þé°1wPá©]y‡Z%¢£$Ò³…W¯ò–¾Üru‘¶5l)¼aŠ ÈÛá£x4PBØ97%K]ké»f7R>Ööº‹“g±®¿®8›&!Ä‘)ú1ïw1u®¡q3"„ÜfÂn'!·‡°»ð:@ˆMÚFi÷áìÂÖ B×)Ü‚GÐG‰ò ìÅSèK°O¬GŸØŠ~± ûÅIÄIÓ!aC÷a@œCL<ŒAqžžÕcH< ]üÃâ’.¦!“¦e$}7!øÕÔª.?Én -­’¤[ÑK¶Õ9ìGÄcè£SQqÕÖ­Ä{LÜýä•O‰j¼HÊy4º’8H\ Ñ{g‡(*í¬†|û$„$t?ó7“]Ž0p‹%Ä$ÄŸFÛ°„¦aÿ¿%*hÄæ'AƒU[(4 ¯ìuËTÃY¬?Y¶z çÁ”‡\zÃî<Ã=KÂÄúª¦½fxÝ´ÛùPK A¬ààÇ}-org/gradle/wrapper/Install$InstallCheck.class•”]OA†ßi·]ºÝÖoüB©Òdˇ$QCÕ`RôÓï¦ËP¶-ÙmÕä šH4šxé…?ÊxfviK©¡MÓ3svç}Î{vf÷Ïß¿,`Ù@yffex(Ó99ÎH`AÇ"ƒQõøŽ+65Á0ZÚçï¹å4¬—Ž+VéÂ.wÜ–'6…ïó*­H+\^¯Z[MÏ©Wi•®b0_Õý&wÝâž°TZ^Ñå¾/|†µìYu®ÔðªV`ÂúàñÃCáY!%ÓM£:Z±±CEÆJN]¼nÕ*Â{Ë+®rÕ°¹[æž#óð¢^;1­û-Û¦„a%{ºÃaªÇ;u§ù„aªÒ§©2™mî9Tq˜ †ã—…çì:b‡!šÍ½cHm5¹}°Éæ ®:ÉÌ ³Ùá’ùXè$`e@ïÑ8-JÐÚРÓ'(yÒ–ê«)“ÆV£åÙB–í°9 1qWMŒâ‚ )’&nâ–Ž%†é™¸†ë2xï›{Ï=÷,ÿsî¹7O¿þÀÃDT㚬Ó>OšÒI³PšEyhŠ¥)‘Ÿ¥:•p™Æånâ×Iç ™«”¦JçÅ\-MÎKx©Nwó2i–k¼B§™|¾Ð¯Ô¸ÖÏu:=Ä«4~“Ngñjæ däÍòU/_k4nÐ)Èe:¯åFxü¼PšõÒ4M¢§xƒŸ/Ò¸Y¦7êt=·Èà&?o–þ-:oáV?o•™m"ýv!lÓ©ßêçvéwh¼S§|±ÆoÓi%¶ÃàÛ¥¹Dš]ÂÇ”¥~.-»ýÜãç^é´†/•æ2~Ïa#Gå3¦ÓEܧÓ~‡Æq6 ÷ œð³-?’Ò4i|¹NÛx·Æý:ðÒ\©S›Œ¼S§\æçwIÿništ¾Š¯öó5:_ËïÉãëx¨t½Ÿß+ý "Ðû4¾Q§^±j/¿3ß$Í4þ NþhóaùÚ%Ô7küoÑ)! âüQYµWh>¦³K|Ñ+Íþ¸ÆŸðó>®ä‹e/˜~¿ô·úù“~¾ÍÏŸúÛ5þ´Æw0MÑ„m†Ã ½VçeêgÔŠ7„ÍDÂJ0Ö6®«ßÖ¼õ’µM­[·4­Ù¶µiSË%›ë·®gÊo¾Ô¼Ü¬ ›ÑžªV;ŠöÔ1Mnˆ ¿¨½Ý '-?ßÉä Çzz¬8ÓœæX¼§ª'nv…­ªÝq³¯ÏŠW5«I¬ôwÅvGÃ1³‹i~.¦µ©y٥ϴ{ë!b¤#,œÏ͵`s6 eõw†“‰ÐåÖºPتïì´‰fÔT²UåâÐxÒ`ç[ІìÕLo/~½ÞX“S‹]²ÉÓ벘¦6‡¢VK2ÒaÅ·š˜Ä:Íðv3’ß©AÝ‚çææÜÙñ5¤×;ã–i[kC ›ieN Úœíõ$㦊EëJ§‡bUbqEgöêHÊïmñ0Ó‡}Ô²«¶miIA6Ik¯Y³lyk2Â4=,ª¯ÍšÔø. 7fZzJ+/˜° ;k²óÚP<#ԨΆÚ|G¨O~ÖÀ‰Õ'Ëß ·`²3†y³>·x,—’\Ñ×›€­Ždw·ÀÒµs “»×êÇx¾íVº"’yƒ„Õ™Œ‡ìª@' ¹6Ôc%lðrw 2»6Eû’6v²ÌˆD[ǼoÚ&SØ;0Íž Õ%‰8ºÕ6;/Ûhö)œiüïÑè°Æ˜f]nÅCÝÙÜ‹YÓz¢Ò9ñ’Âé‚ìÜ ³Á°ÖJtÆC}Ž=]¡8´æðÇ|¸ª9¤Ì ;¬×Ç"0ܬ±3Зšà¸…«ÆŠ½ºNãÏŽª™ _%VBœ»¬x¢b§T‘­E§Á f§4à *y‰X2Þi©€˜dõ÷Y¶Õ¥füa“P5˜OÙª{- ºs,©FßÇ&­¡ž¨i'ãØ|ñ)xM°€’°ìÆ~`Ïn¶â‘P"!€Ï Šº‹³3㨬®-–Ùå$Ó„ÝKÚ¼ª­×ÅâÓ¶'Œä>}HäYÆÜIZ^“ …NÜÇ4c"ÌXcÂaS&jë2þW+š¢Ø2žìƒÑ³I&;@jˆE"fñg€(OEÆŸƒIC‰¶PÇtu—ì€Z±D‹)ÀËë²Â–¤Ûxû€PK$Õñ)ñËßÙ uâ€=cg®<áÜ5z.NF¯Aã³sÆY¶¼VÔŽdœ  Œ¥UÈb2£N`d'¥pF&]HܤùmÊ—$)\C²Â,¾ÑdÄÊdy·’Ð#̱àŠtÖ,œ(H*½Öäfµªìd¢Kx~^ã/ $Ìn+=î˜~aŽØÌ™|=QE?3”ØȦ øjjg¬o +·2UŽú";çæ6¡p´[Áß§ë¦Âŋ3õä<œÓ'ùÿgzuõ/–¦ZššQ)–йK„´9wÉTviF˄Ѫ3g”]ù¥y-?5¯SæÇ4¯«âLxí]|¾,~Ëi,>Ó³ÁÕ¿dt—•²KÝ#!;LJ±ª^|ÆêbµÞªÎ¤TvHÑU ™AÏгýþaÐÓôuƒþH2è;ô]ƒ>D6èôAƒ¡G Ú˱ñÕÙ²è‹ÝB5èfÂèKߡ >Ì÷iüeùñƒïçAƒ‡xUï ½Z˜1ø(?²5DZj]__RÍàa~¹){6+ˆÁºòCü°ÁÇø¸ÁðAƒåÇ"sNÕà¯ñã?ÁOü?-Í× þßgð7éE¦]*yƒÙÅMpQQbQ°+f%‚јDm›¡hÐŒ€,Ž‚ &Y·2ؘª‚v,س'hõ£«3t•H‹£Âmê¸Ã‹¿mðwø»ŸdzÛI…HíÀ±`ä“Ààïó4þ¡Á?âg˜6œZcq¦݃9Vó³ücƒÒ þ ÿÔàç`RîÝ.…Z¨SÁXw®¥ÁnÎí:§(Zm¸sÒDÌ`¯y¹ì°¬hÐ6#}R¶w‡ìÞÊ¢¨ºÏÄ#A»×´ÑXÁE9o+‹‚}ñÚAè1 {9­HA´25ƒ¥f †P;.փ˻dIÐŒC´TºÔv©åÁîx,ûØñdB<ᔕ¢X0»$¢¢¬ %Т鄔zX¦œáŒ/;S•m­ò ØëUy:aÂàŸñ}¨ÈFñµ%µC+S9IÐýuÌhö­ÇÍIÁÿ‚^4ø—ü+ƒ-_¿é‰ ½#Mű0xuËÉj¾1èNßc¼½‘Š4÷ŠeË þ-b \~gðïùƒ_ÀÏÊ]‹2rÞΜÁà? £?IóÒ¥2µªÁ‹xÄžeI“­9 ~YÈæ¿qÙ©ñ_ þÿÝàHî,œ˜cR&(mˆ%Ã]*rP˜#Ó•y°o´4vÇâµAÉ?ÿÔø_ÿ[£Å•Røhüƒ_aƯü_>aðkü:¦w;­Á#.2\ìr¡ÊY¸ôªËm¸7{ —_|=w¼'6©=ggçâì)8Á•Ÿ¸tƒýŒ/k¸ggY4¶zÌp}¼5dÔÎXD*Ù„R©&(Õ^2Us ir•áš$,ùbœÆ•2Rk¸ >¼Ÿü˜aZtš®éiI¨¡kÎü¡".¥p–†sÞàq ‘Ù…k§­½ñØnçj6«§áIvlýè YAqSN ùpsë±{¶eO±<Ì)n˜HŸyT+?­Ëi†ÜoÇÒrh¡Dc¤ÏÆÞ×­ÎuG›ÀlçD ç?s;¨–ÛÁ›rŠuú7IO"t¬ë†''X,ãç\a¿&³fßF”|­¶·ÅS¥°l6“Q”ñ &Fæç~±’Œ>5©Ûë8òÓ×Åg½•ObÜ @Ú–òÈã¼í8Ù©¾# 'mKâý$/V¿“ñóäAoóL7œ F(±6]EÞfuÞ©ßT±Å4Ó`FcQTÁaGšYÅ9“T4$ÄÒ"n¶£F_δÝfÈF…ƒÃ@ÅfV&/ÌJPc_˜gç~‘ýfŒN¥^eÔ/QÛ¬žùV’'<JŠÜ˜~Yͪqª©Ä09•ˆÒ¿Ç Îh¼ç¥K2u_>­@M?CNú "<±ž±Uëêöˆ“ù6§® içà•óBž?·µfþî–5Q§’Tsl7²µ™ÈzóʦÉöþôíNUAC¯oð-ä`rOXýŒŽå(ÎöÅØ÷¿©½fbc,n5†-)ðդ¨Õo§~Ž·~&=h0†óôæ‹\æ<ïFq3á­*[å1¯ƒ'¨®PŸh Ilxwã$±èÚC%D䥽n$¦÷ã—‹n¢|yÈÀw¾¼j¨þfúˆêo¡¢/í^úÚã×ÕààA¿ tˆòJ‡IoÏŸ4ž"ã~š\Zv?i¥å÷“¯´â~šrXíð ´g‘íb¬¬¤™T jh>-¡óh)íÃL©Ã“öÓ­DêKdbõ%R¹Ô—ÈåÆè'é6Œˆ4GH' ýê²AšºÍ´–Ò¯Ð|L¯õ<ƒ”_ë•nF­ã“¾ašÙ^ð¼åeCT0H³ŽSá¡qr®€Žçƒs-d­£9´ŠÎ¥ÕJÎõÎn9WÓ§èvH䥕ôiº\tht'ìëÆÚRº‹îfs çú,¨Î¥¹ô9|ùèóXíÁÊ/` îøŽ>üeŒù1³7ö l¦³ÚˆhN‹{¹gú4zÐ_ë-ð¸n§¹ï Í]î)ð|jäåò€×]%çy¾bæ £Ö'ß±òA:»Ö3LÁö!:§Öë^î+ð<ßI‹§ÓHÀSà[òî#tn­Ðé<ϧiRÀ;mñ -h xe¨¨í:ù–l·ð„œ Ã\/ zÕ»•Ù¶$D6ÔJ‚b7 ÓÐÙt-¢+©œÞ‰uWÃ×`ÕÕÔˆ~=½‡Zè:j0;èzê£÷bÅ ˜¹Ý·@™¼&ͧ…ô%ºÆ €ç!: Söáû>Ðj´ƒ–Ñ—1+®Û›qÍ^ú §ûiPÉ~= 2nì{!v_MÐ0ø=ˆ5KI[ŸF{4*Ôè!f޽Bó×itÜÿ:MÇo‚|‚jÔð MãÊGèÑT Œ€§Wä/…½-GiC¡™ùÅž‡¨¤Ý]Þz„JPÙ!Ì”# ÝŽ©ŠñSî£Té"@TÐ|„ªžÑâqD2Q}HÉ ¾XHyho†ÞÆ·P–(EøÖaó aM°Ï.Ð>¥¯’0c³nSV_Á¶.pÙE_¥¯ÁfÂòcÖCO`ÞP–•¹'1'¶›JîÔ詳NÐX‹Ÿ¦¯§âôil$îi¨xœêKˇ¨¦ÖS!¹d?U£KÛò—iJ­²Öv–·¶{+ZÛUQ³Ö;L+ÚÞ!:ÿØá êMï€DwÑ$º÷8ïŒß‹Ôrw˜ÖûT úTHZyA½‚¾‰/I: íè[*1Ê—©K}}[óƒ*uòÁ0ÛÝß¡ï¦4A/‘»a˜V"Öj%Õí£UèVµ@ë%⇗;!XནΑð«qBïMûÈ(hGiµ‹œûyùx—ÿ˜ù(}€f´Õk%=™†Nf\ZMÓø5P.¥ïÑ÷¡$Ë(º!åf?VŠs]—:#ObD.#÷R—–‡§4úþ1L4_àíÎL€ø‡*‰þÿ?CÏ:1ú”èá°¸`ySa{Yþ›‡¨~#· ÓšvßCÔÐîÎ_ ¯ç7ÂçpýºÖ!ºÐÉÞ둽‘yšöѺaÚÐ>LµËïæ!Ú8D-µÈæ›`ëͰ¡oÞÒ^ëœ Zþ'BþÖAjmCVom9@s¶Ûñ‰óá½uÚe`‡x(ˆB¦àxqþÛéíCtƒtÉ í: m –n mª¿©Ãáš…öqXû Øï)š´hK±Z@j Ô¤ì‚'.ƒ/®‚©öÐsàô  õ,N·çÀíÇÓŸÀ??  ÿþü¥òhàÚ†sóǘ—+ÍsØ­—æòF칄¶€þ@K-]„U¿‚oní¯é7Û ÏþšžW`,ƒÇT0£bE:ý­{Rìï2`o$¿ûúÓ>Æ¿Öhô{6hH#t‚æcL€àÉ&"!Ú’¶ÉA°}^LeÄ‹ðKbjF¾y„:î£ÎAêj.Ë·©û`æÖÉo óóJûYÎ’”Üôþƒ R—ü5&Åø8t•DVW¦"©]ÏÆòǩĽz^9κsJîÊçÕxCä‘ss?yݯs#Ò~ò¥Çe•°Ñ‹Øî4 ÍÆV%ôœðg1¤åôÏL°•€ò%Œ{pJ-PçëJé/ô²½.cò:ú«2¹˜w2¹_£|þÆó^—ü•)U<‚ß:Hn¦^9ýC-8Ë/ä¥Ëä±ä+ÌP;"‰±°½\‚"z„bP¯Ö'?úO$&Þô?=Lq„N¢=à"{ˆ’µZ©ª.hC´[b£ÿM®õ«¯€ÿØ‘cÇ)#òä#wLŽÊ8¢+ DJŸ‡ƒýZô×â¿6“«¶ çÈq™GÿE®z ùu*BÂX¬q»¨‘Ý´ž}´ƒýÔÍ:4šDQôIôýlЕ<…®â©t-úпŸ§)So΋¨†ÿì³åÇ¿Uµuä°Ÿ†ÝÂô*vœß”1úM€©s¤Ýiçy(<^G¾vg²žZÉ¢¸¦ž´×h*âKc~Î×(\`óìPIgFƒRø<þÊ{•\ªHÈÛH—çàLÛ!¤2Çöûhö0]ÙžÿN'W•Ê17Dï:Vz(ƒÄ)’¶y.i<æòÙÊ †Ã%ÀI‰ë]žˆSÛ\ …¨ºtÞ½Ÿ•æ_5HWïǶùר‚ÒüksûÉ(Í>ö‘æ9@÷h ¨2˜ÏÛ4ƒ‹°ûB8q-ÆØ¨ÕYRøÈ]æ~3ÂR¬SGâm°„eÑtÖßR,Ím_¦”W¨‚õº#/!øæ#Ñö·yù¸’¦s6¯A¹µ„ðÒ¬¢¥(ãá" çˆ¨zE-N‘è† ©{Sž5ÈuBŠ»c'¨€G4ÍÏ“6ÇzX%§¥VZ†2Å?z5ð©-J”A‡ðtDÐRdO—º ,óyFŠez™óÊ“›¡cP¯Ã‹grAŽÅ¾Ó[<‹ S‹kS×§jÐÜ«ëËèâstŸÙÈÅÇsð ùœÅsRˆØ ƒKxúa\\¿Ü‡srr.ƒþ '?89u™Öuê2?@/GU¦Ã>óx~jŸ±NtåÞæ(Ûd#älæ2çæ}c <Îz>§¿ Ý+É\|t•5å¿»ôÏPÞÿPK Að¿:öo4org/gradle/wrapper/Logger.class…“koÒ`Çÿ—UncŒá@Ø&s*]7¼‹11$KHð’°`²wÏÊ“®³´¬_ÅO¡Fgâ ?€ÊxžRŽ5KÓÓçrÎÿw.éï??h G ·b¸‚Û1TP£†º4w¤¹+ͶUÁŽ‚]†èÉØ.;`XxfX†ûœ!R9¨öèÓ²û‚!Ý1,ñj<8Î>?4éd¹ckÜìqÇ{ÿ0â#†bÇvtUwxßꇇÂQ;¶® §É6m!Wéó÷\5¹¥«]×1,½)Ê@ŒF\÷s ©®Ëµw/ùÐ'.Hq«Ï°3«×:âNWœŒ…¥‰fuæâ…ç-Ce"Úè„!ÇÐÔl·U£#—;²›m"x©*­@o¦ÑÛbˆwí±£‰=C•˜ôj[Æ$‘B#‰’ î%qŸc”‰±I![3ŒÌ”‘¡JgŒ´ÇXó&Õ¡ovÂHIFií ó” Qª¤V÷(µIØ”’õ)rµŽ /‡,®Ó*üœñÈåàꊧPæ¹*qw(¤PÝ&nü_Ý–7Û›PK Aé`˜Žï8org/gradle/wrapper/PathAssembler$LocalDistribution.class•QÛJÃ@=›¤­ÑÖx¿+øP«ßAA(*(‚¾mۥݓºMÕÏRPü?JœÝ±*ˆ/3sfæÌœÙ}{y°Žù,RÏÀÁ„6“.¦]Ì0¸UÙJ.d“a°Ôà7¸Òp]Ì1¬ÿ_ 1*BÕ‚£rCT» _qá¯iX¤OLÑÏZðµŠ|-ˆ¼ Fú²dû S‡M>W|+®<Á*®>Á~0TÏвu²’h â”YèÐ&Ò㙉ôB‹bÃÝ5y]KaÝO›äµèuºF~%ÛßÉw¿-Œ;† ãVZG‘‡Õ0T\“u…‡e/ë<©ˆx<Œ6¬ðŠÁ–‚ÅO;Œ®òò5ÖD\£ß ã[øvßa‡8¾Â÷Âø>žã~ÀÖ“"nðó©0úñ4ψxVÄs!<Æ~ÂØù^ä@?fë'"^ áe6_ áÕ^ áuöCÄ›n›Òóri\5-CÍÙ–ªk¤Œ¦)ÆXI6MŰÿìì™ñ©‰å…¹‰ÙåÉ™ìÄòÜülfú¬€ÈÔeùªœ*ÉZ15G´â¨€ö1]3-Y³å’­è8?;snbl¾¾«£hÈ…’²`*Ƥ^f7Œª§TK …èªúe%o«ºq]@𔪩ÖicÛ½·Ï†øÇôEíœR5eÚ.çc^Ε¦Ë¹.ʆÊsoÑo­ª”äÀ”nS.³Ô5C®T#u^¶VÏeò4ˆWgQ±¶Kµk¶ïa÷IB¬¨EÛÙwtèsŽ|æ,XÎüÖ(š†i ( ”“MeZfC ëšm†®³´îLä4ó¬ jEÀLì³û%òlR¢m”&es•,ÒеŽ6Aiº¹½¬˜¦\TÆÕ¢bZú]'SÉÛ†j]Oe·¾&ÿ@îºÅ…Ûr1-@ ÷n‰:±–W*ž>AÓ „9KÎ_Éʯ(: ¥¬_U&Ö,E3Ùýš£–@êÒЫWÃ/M±R ³™]$`yŒR½Þ7½)x…Ê@Ä[Â7M‡æÈÀî5¾?Ÿ1mœÓm#¯ð"ú¶²áFñ¶„¯â> 'qŸˆŸJHã ñˆ„‡1-aÑ·¿5¼„Ÿá] 2rÔvRIÛj© ~Î>¿À/I™”„_ñl¿–ð¶~‹wÿò•Ï1N‰ø„ßã=Å´_vü„ˆ?Jøþ,á/ø«„¿a]@·Ã®L1Siµ˜Ñ,¥ÈÔÞg‡QüiýCÀž&e  ·±:kk–ZV¶¼ìÓíR!ªéVt•ª6ªjÛŠºu3±? ´É¸‰ª„nIø'§]c¸èç¥Mngo•ð!6¨X¼¦I5Êåp2J%Uͨ­]ÑôkŽ:ÿ¢Ý æ39n˜Û–æ¼âöŸ+~Áï—BĆvèž/íÔ\w¬i¡ïtæ”)†Ò †¿ÐgïU71KßÌäpÓÞ¿-Тû Qs9z—ÃM4'9KºLÄDS^Q UÀæßsCiëœâþŸ~äöŠŒóKÌ¡c»§¿kC qWp{š?6Ä]-hW ²E᱋iN:XðЂ±Œ»²7–iz<ñfͽ±2¿jè׸ :Z¶Ñ%€È”µ™Ù„;åßjÚ¹ÍVº/–iŽËß+åq[.™;â¹<:taœE¢{Ñ1ºùу»qî¡Y 4¿wË|ntdG¸×ÑS¤wÔOh¼ŸfKäã£gg¼!ž¸‰–xò&|ï;›O;Ûü4 ñ ZEAV¢î6<€3€c1ŒàX ÔBvç0p#ž¨Â_C OÖœŽ'jOú7ZâW­5„7жTƒD³ö*:"4ôøi¨¢«†ÛN6}#Û|÷lóu¬dcSpÝK=ž` {×ë¹õ"Hã å#ÖCØO¢Ž‘„kH:9Nºœë9ÞÀ8&(£Vºž>H"·Ð.gÉòÑÞ2ùŸ ÆÈ;C (Ž„sdÉ“þ(ž&ÍXÓÁ8ôß¾*ö×pût#—þ°K¿A7LOà.=æÐ‹»aêô*‚c1Q¦w;¦z-üÏð¼GûxçH¤çz³xÇt’Ðú6пä'Rj8Øu¤ŠèzvK‘ÃtVG>q"¢Ûò!Š×ïÏÐ]>.J}€6ó»›$¢38Oøm$Ñ×1K{“=‡y'›‘:û,8ìÉBȉ„ÓÂcõeÚÉ%׈ÜYÅÑûûÞA ±žðõU1Èù¶”ë9:¸‡e í´¿Q®Ýu´n|ÃAÉc ÉÃýÚé¶ÄW÷ ÚÉ1{I§X6ÉGsôt?'דýþKU 5Ð÷QÆ ”ŸDvQNÊ¡qZ½u½xF{±ì“Dsñ9\Z!ü—˜];<:ÏSîT"B„’o!ÿ-ë‰Èp}æ[çSóÊ)2BeäÔTjós¸ë“„/Ø#þ(Ñct`—Âû\œ:áSÈ׈8t´Óû‚Sœ ¾â”'ý)ÍãhýPK A„ÍëÂ| 0org/gradle/wrapper/SystemPropertiesHandler.classVÝSUÿ]’°!,-Ð Ò‹-á3­ŠTR°–‰ò%A(õ£.a›,„ݸٔâWý~ì“ãL}ðÍÁÇ™ú’2cÇWÿ¤Ú±þî& $¤µ9÷Üs~çÜsçÞ›ýûß?þð"¾  QÔ ÀÞP0€Oc(xSNÞ’Ú”‚i3 fh@Ô99¾-żñT,Hø;õXÄR=.âŠËr‘¸‚«~¼À{x_Ф¸&ÑÖcš‚æør|!:}mn~vŽ":»BãÔšvC §53Ž;¶a&# ã–™u4ÓYÔÒ9] ö‚aΘ€'Ô³(à·Vi=g:Ɔ¾ÏÙV¹¥K9#½ªÛ]QÛ¶ìÎÍ”nv¦-m•¾Î½†v^g-£*6`Ja©Èà#Y­" GANÅ lª¸‰”Š-|,Ðûì÷ƒg+[ò *øDŧøLÅ縥â |©â+|­â|+ÐXyvyÊ) î'ð1MnÄBʶ6‹w{/(æè¶æX,£Ö(~> WÙ¹Ê## IŽÀ±=×þ›(¾DÚÊÊWFîÙ$v tð$õ0;©À/èÓð~Ç*˜x¤BDôV©`ª -nýµ|/âº#·¿ÿŽÐ)ãÚÅøy­eðǤ2FIiÙý&Ñ^ÓÊ«,=A•5ò²ñÙ¶ì’áð¾´Tã‘mªMëfRص/}6·’-Æ·„bU ñ$eñgþ‡èRevXà|ø3%Àóò_ ๡~Šcg5hçOÈW‚ò -aŽ‚£¯÷Äï.¤›²Ö5¢T ô —cúÐOƒÅ_ð ü¶‹šå{ðLõæáý¾¾»»ðÑP;½ e™™ý3ýyÔñ؆:â•JÐ{3»P—wÑ@ô¡æÃy42ESÍ÷pä~GwÐ"03°ƒV;¸L¥M`Äôæq¬¹=çî ¿4éÈãøˆ/è£öZú‚>×u‚Þœô`iûÑNß]xÈG7Yø κcÃA=·#7?£”ÇáÇ ÆI4¹lv1ê4ýÝ$ Ĩn¼Ìq˜³R!9K€MÏ-²z›™À9üBÔ¯r‰œäWÊ)´5È"è î,µÛìÊ9z|Œ~…_=/±’ÊÈ!Ž~üLë0›Ä÷8WIþH±-_„Ú÷{ÉÿM F1µWÁU>…Ë ¯=€ÿ’‚úއ¨SpñL<`¦×Ý–_b†qW»üPK Aª=©°?-org/gradle/wrapper/WrapperConfiguration.class“mOAÇg¡ôÚãJKŸ|iᤠ" HULCß-œåH¹’»«&~*M$&¾ðø¡Œ3w ”e›˜&3³3óŸýíîõÏß_¿ Ë:¤ÀÒàaæ’`@EƒG xLá<™2OÈ<%³¨Á’ÏŽxN£8m—ÁPíˆæ–kÖöÖÖ3Ýõ5îÛ ²QO‹»M«Ž5·)÷½çÁ!ƒBwª~È+ó õÎ1í«sM¢(ê/;®¬0è/•wÄ^´°ž®9®ý®sܰ½¼Ñ ÷nïóÖ÷Z‹d,8t|åZÛkZM´lë‹ÇONlÏÚü‹¶ûÉiv,.âsñmâìî£nsúô =ÌN æN8¡u‰ Ñ½ÐÆØq$&ƒL*AîÂ=HL)£ÆìBCO*A4dF r_ ¢É s¨©ôÉ )%È  2¯)©AeEÔ,õÉ ²$!ƒÂçX Ìþywã ¬âyõ%^}9„¯°úÏ3à 2¦y~žÉOȸ¨`;¾Êä¯)Hãƒ^V0ƒYWðõ^”а¿;98ÐÝ14ØÝß724Ð3’èOt K÷×Njí-;Þž´-#;¾[ÂüN3›·µ¬}HËt eû’]„rbbßàAqy1ypßÈ–mÛG’C½–éNŒ$ûº*=” 8%g™9ݲ =/a©£zÁ62í‰â9©¿ ÄuÀÈþ NÃlç=qÔ¤Ìì˜1.aCi·[Z:£·Ÿ²´Ýk?ìÌ‚§`i¶aféRݘi‘œãzÊÞoX4šÖ”„­ÑrðÛ!vÖSºF`N3Mš-ì1²z_arT·µQÖ5Üc¦´Ì!Í2xï²Ý®\ò)éá&* Ÿ´µÔ‰^-çÞ«Ùcd {¯„õZú»nÃ! ]«÷$E×锞s=°' r|Ë™¸4gé9ÍÒ÷yJ¬Ñƒ Y†„EÑ Ž€¬n· ts@òfÁJ•BU¢(Eò2æÈDK×ÒÒ²2t!cjé„'-BF–Y×&‹vÑÝÙ\ÁvŽwËø†Œ—d¼Lî×m¯z¤”^B<úÿd‰¬ )G£Go..?¤n.¶LÆ—Öaš6é§åz5¶K³lÝq hÖ8Y[ç#ƒ”0H M·(aɨþ-ÊÂW ÃvМ$›ç‘ûÜ`Pm¬‹Þ¬Ü?}U·b§ú4FÙásïN‘Òú˜VÈÜè\;ïéˆ/TÈÒ,P¡§©(ŽHždHW)¯(±MËî5òyb-Ù«$E;µ¸¤¢"6² Íÿ»vÈ o±JˆVð;Û6w»±ÔîT â›$Ú¯º™ö-†T|ß¡Æ]²y µI½XjZ]"%ðÈ)Y¿6¿>’6i›5íˆ~šªg#•M «”;•Šïâ{,í5Ÿ;¬¯ÃëUÀkUD· u=‚£*®ãû$$í)Õ-¯«ø^Q‘ÇI?dIe ÍžPñ#æø1ë½Ää„F/Q²0©â'Æi?e6õ!#—¤(莄Ÿ1õçeøLø%ê|º%y°Ó,dÒÂKÜ¢"§|j™“¡ÙS¿RqŒmý5ÿ¿Uñ;^ýG©Q¥Ëšh†&Ÿ…}#YÜŽI¯§7w<}EüAÅñ'æLÇQQñWüMÆßUüÿ”°¯ÏŒˆDœ2ì‰È }ʉx>§§Œ1COGŒ¬¯)7rƒ’a…W¡äTÖÖN{üRçÓ“Ë|88a™§œ÷«ÄÛïAXTY¬Öø¾oeÝ‚zfu”Ç‘´y±¥º®¡çtR³ý{…·»:‰íßvêý:ÉZ˜¯|`GË_8檫x†8󨊣¾¢êò~Ì•œ£7ó:§Ë+x‹µ@¤ü-I Ý:bäqJÞ»q(¸Kq6±Û·ßb¤…j &™šÐù˜Ïï};dm§?JßpõEö¤“›)º@a Ú¦¨ƒÅ•führ%’•Qßæ¦2&ÛÔxëg“lL¿->lDÚÜé×ÁM6øuF¿g–ôÊÛºߊ C±šþ!Ì£BµhÀ^ÜG»×Ю ›h¿Ï³_FûÏ~í;=ûU´ßïÙ7Ӿ˳_‹0·kZ‡¹c‹™z8ÍóIvz‰³v¨¡Ð0ixUñpõ,sÏ¢fò´€ë§Ña\‡ªs oе(ŽC´ÖØ BÏbùj‡ÃJà%Ì®Ž%¯@Åü«,,V.£ZÈX@3#Œ8šÐæ‘Õêš‘¼RMô`:B¥ûéB€N¦c³X@À xÑe,޵^F8¿Œº8isOÆ[¯`IìQfQ?ƒ¥b^ÆÓ –Ï¢aÎÙ ç¬Iœ­tÎV9gw‘‡"3Xí6;‡kc‹s¶Ö9['ÎÖ_@cŸpÃÇ qvCÛ,bW/’þ<…guÐE4n"kÖÐÿÅÍXBÿ™èeÛ(¦Û‰rÅ}îÇNLbÅnº¿—öà<îÅ ÿ„pa€öKq‡…K§éÆ0 VìHI¬8Cª„K—¢ê?RMÁ“Q%Ó¿Vš£tʯ<Z‹0«hn!çÅ{È£­×9o(g.¡nmt²‘rgíÓñRHÃ"2„¸ü ÑLòŽDÆrõ â.<€7’^¬MÒ«h–Éî7Ñ.@§#Ä}¬¨Éâ "áð¦l¾%Þ4‹-‡çp÷°XnŶÊÌê%úPG ”2kµ«‚›Yu™ è¸2Ÿ&"[²rÛ‡É÷ôÆ[g°ƒ~;/@éã¹M´–dÕ客ÔäT­¥P, Ia’UOs#ÍMä\Ö#"t[éf8¯80Œ´£HyCTÏ!âøÈHsˆôš¢ºcô£/··ÐÌÖ…œTÜUYÇÇ<¹0ýßîÞòýÊËãžËÁâåã8áú*C9ö­ŽôÝ»mñÊŒ=‹HN@N3XL¹Ìˆ[[Å\ mRH # SdL9¾\ö¸ÙŠÅ¥l¥ 9O†ŠC(ˆ.ÊH']¤„Tí µú!Ùž ތīS´ª˜§]ÌçhµDL…³yW !p 5 éÖk¶N¯<ÚXœzZ*%q3a0LQwxˆ|q†,8‹åx˜’é¢?æñcKQ—–¢.-®.¼š"öc#ÞLg‘d ª_EXÆ™`-q-z3AiÌ·šD#»7è6²á×þ¶^á—Ç=n*êÒäê"á-‚ÿáÿPK AÔe‹ #gradle-wrapper-classpath.properties+(ÊÏJM.)¶M/JLÉIÕMÎÉä**Í+ÉÌMµåPK A)gradle-wrapper-parameter-names.propertiesPK Aorg/gradle/cli/PK AÕÜ?®<S1org/gradle/cli/AbstractCommandLineConverter.class•T]oA= ‹ëÚ"¶µ~C?”R*O¦Òh4!­ÒÄÇaY×m`— C£Âߢ/4ÑÄà2ÞP–´ôaçÞ9{ï¹sæÞÝ?þPFÙ@;:v D°c@ÇóÀ{xY9y†xÕõ\Ycˆfs§ Ú‘ß±V®g{m[´x»KHªá[¼{Ê…ì' &?»†bÃNɼӵKV×-ÕÛ)¸%ü^{€ìÈ÷Îm!mQaظÌõµÿŸ¯|¢j«U©›n†Ãl㌟óR—{Né…¬•ì¤}f[²’ C¤… ‡´¬-¢ k’ôÚ–Á=,È÷¹Ø‚ak^ÀÌÁß«Š^tÊê Ö”Âõ¥-JŒ×_,»/]ßèØc¸ÕtË¡ +;Xš¨rŠîCµuVQ CWˆ uÁhúCaÙoÜ ™«ú¶Ô1aà6Cúºë2Qľ‰LÜÃK†Â &„!9¯‰a{ Qá23Quá {¶'§M¡†Ð~rÕÝìõ3|i153 ¯mnžDevf¨èÎ߆J…£–š~-C…Hý;"d©9´š´«“edcù °äDq‡Ö¸SX¡Õ`I²w/!)²Œ:·FyÝ7²ÙÍ_ˆ|¼@ô8_AË #ÄöFˆŸVX! ÊK`öªR~œ;©xëô†)ï>=ŠNâRnpŽ´âØœœcÿhÿ˜âŸ¯òÏ”ô4=c/ƒ-e·ÿPK A׃µ³Xì ;org/gradle/cli/AbstractPropertiesCommandLineConverter.class­V[WUþN2ÉÀ0å H¡°Ô„¤ÄKKµIQJ©†‹¦‚Ø;L†0fâÌáOøîZ¾ûZ_¢t­ºúìÿñA—·}N.iÊ2Y9çì}öÞç;ûvòëßOð6¾Q0Œ÷e| `ó|¸£`w,â'?ä«û ÒøHÁÇÈô` Ë=˜Å V»ð‰>íB¶ƒxÀ‰Ïø°&cë.cCÆ Á”i™Þƒ?]cì¼ÁЗ1-c¹¼·i8´Í"qB[׊kšcrºÆ”¼mÓe¸™±B¢àhù¢‘Ћfb~ÓõM÷V»d8ži¸ öÞžfå¹ÙÛÚ'¦á$ F]èp¥ä™¶Å0‰fv´}-QÔ¬B"ë9¦U ёѻ†§™E#Ï0ÖfÏÕ³f±[·­-³PvòTä4ØÐV5Ç%\ÜÁ’X3L¾Xž¤íÚQgIW‘‘´¬W]Àp§0™?¡•¬:£ì™ÅÄ’VJFOѹ’MA`i Ò®q¸¦ËÆâAÉ1\W@ µó¦\ì¶AÜŠ€A)5"É“ã4‚¡æä8,ÕäF³hªJ+gŽ ^Èzš¾KÂŽŒ‡añ@7ª e<¢ fÍ‚¥y"¨ß¾´;D='þûš+›;†î%£­,†üW»’J /G¬dí²£÷L¶Xg<Ãm©x# ý§íªx ã*&0.ãKo 'ã+A“|gºŒ<ß¡o©(`[†©b»*ŠØSaÁ¦¼¾­¢„¯ Â«ÂC™û”%M—UÅ4¥Ü¹zÝù%ÜLEu|tššg·1qBuÞ)”÷ Ëk$1Ãø‹ú 5ÖÈÃÖxE;i1g¯÷Yu[së°¨ª¯D:2ÜKZMÍu6ò?Al©†T'¶[ô'\íL’z ½¢o’B‘“EŸ1]^„½Í†.³õ¡&…z6ðK®Z6<ñ¶ÒS+Y‚h~ßu.›VÞ8XÙb·»uš÷ù2©¿iÕî°•t»ežÔd£N§Û¾³áH;¾4A†Á?2/y/• ™jéŸÀ~¤…£43Œ1𺸄ˀ$ñ¾ æ‰Ú<Ég’yWjFK$í§ùj,ð ¾ ÿtþì†D“”­ °¯ ¸'R® kýøÔ$G è}/aŠNäƫ֪ÄjŠ~Œäú¨ýDH›ñæARüôßèô ͹?·‚î ”#ô0,_;‚Êðiqá9|·¤)Ô[Aßl øq"û0àÇú%ÊT‘Âéq¯Ô¶þù9þ„NêËäR7¦È3ä…wÈó„oƒ="\ü× Ó bôÓjŠèkDóÛæ·ÊQ0Þ¾Îá-úé#KuïsÎuâÜQ‘þÄ€ŒÙ¿ác¿cøÚº)Q‚á=áÐ[ýótx’V¿p¢2‹?Ç`á'g[©:¶é«YMᶘçþPK A}­ÎyGK1org/gradle/cli/CommandLineArgumentException.class•‘ÍJ1…Oú3£µ¶Zm+êÂî´UÜV " Âà–îÓi˜FfĘ́¯åªàÂð¡Ä$-U´fq“{rïwOÈûÇë€34K(`Ë„mu çœ žöê‡þ=}¤^DEèõSÅEØ=.å˜T}.Øm˜ÐQ¤•š/ ©â&Ÿ‹…t‚_ªÐ GÌ "î]Ê8¦bl *Ìb&Ò«ç€=¤\Š.³$¡¡¥þrAÐ^âí›2˜(ùdæ[ÃÅ€f‰&Õ—V”ú2S»æÆoë/c§PFŽ ‚Î?^E°û5ÿ.)Ùâ-äõ/˜•1ttuÖÓyNïN»3y±÷+:–¬ÚÔ•;XէƬJëk–â ŒuÍ0¬Êœu£gäõî¶;ÇSä~ÂötÓ¾…ÌÊ0w3§*6¬ÅMÛ]ûPK A³ßâúg)org/gradle/cli/CommandLineConverter.classQMKÃ@}ÓÖÆÔ¯ª'Ï"4 F<6¥ EQ($xߦë²%ÝÈvSúÛ<øüQâ6…L ]XvæÍ¾÷†™Ÿß¯o÷8wÐupJp’L-¸6„~/œ²óS¦„ÿb¸fã”%ìu<å‰ ¼*Dè<.þid¦æÎn$…b&לpW'<(a‘ÑR‰`ÄqàÙKxî…™¾Ðl’r?I¥ÿÆôœOFÙlÆÔ$”jçήwÚøºvRm_Uˆ%J¡¡ïÐÄýªñ°vJQ–ë„?ÉÔê_”äFë%p}»b.·;o¾ºÿ-7Û‰Zä3®ÌfSm¡Õi¶M´l¶g³–ÅÛplÔÀ~Qqk*[9Àa¯‘#ïÉPK ASf Õg&org/gradle/cli/CommandLineOption.classV[wUÝ“¦4™^ˆ´i¡\ä"iBµ´ ­ÜZ.Å^ÐÖŠÓdL¦™0™pïwü¼ø¦¼ð .UYË哾ùü.—¸Ïd:™Ü¤Ë‡œós¾³¿ÛþNæ÷~þÀËø&Œm8'ã|œkE–Zqo é¢Þ‰à.Eð .‹A•±AšŒwÃh/ÝÊ iEHzWœ¯Š…ª8ɉÁC^ܾ&KFA†-A6ó¶næ :¦®¨×ÕTÑÖÔœfJhÓ³9Õ.Zš„Ý•§c¥¥¡æ²©9ÛÒsÙÑü¡¨V¶¸ªåìù[y^ÚäÓ7ÔB*›«÷Æâf$£Ò–î8#!Z /!¬çÒÅeÕæJ‚´Dÿ²–YÌ/êöŠ„¡jÿL+›ÊZjÆÐRiCO›««j.3¥ç´YLjão8£å--­ÚZFB˘žÓíÃbqŸùI[³ÔeCí_73šHafŠ«Ëš5/΄ÃfZ5TKkw³Åtà Ú+:3¼ëÙNUæÇ³-¡»ÒÓë©çkƒê´ÍÙjúê´šw®Ê(ʸ.!¹a‘pV³g×)³)Þ_Cš½Õ{ œ‰¬¨…c.[$ Çk¨Ò¿‘lª¹'è´¡«{âRS|~2ävÆ?á§êæõx+ÉÚbi…¢ÁÈzkNu#£Y¢ j>¯å2ÓZ¡ fYËT¼¡òR­QŽ–ûxu¤Wx8R‹º± Eë1Ã0oøÐïgëmñަ¥ž74ŸŠ¢Ór_q9éë\…WO•w¸–/jÝh¼Šz"#ñÿåÐzÎ,Zií¤.Zª»FkP *Ø$}ÙÂiµ°B+ ¶c‡Œ› na·‚]bèÇïá¶‚÷1£à|(¡³º 2>Rð1>aÑÊ Sz´‰5 ‚‚½xAÁ$>UDœé¼P~Ã.*8…Ó ö•Êï%>Ä‚Ïñ…¸û¥‚¯ðµ‚;ÂôÎg¥¨ÂñÙå+ZšþEkߌõM' gÓ6-‡0 ë:ú ¦NVçÏŸ=!!¤{ŠÝLX`©e2zF»I«Áœ3Uö\É%ÑNµ§e5CC]ñZ]AáºmѸYC¶YÚb×Z.+ÈËØ&%ôÅÇÿëb Ý`¯ð)ð³sÜ4 º"((¼á{±j^×ð<ÿ¸·ñë QÁ*°>\¸ÄòÖ{ø#™åæœóÎü%ýNîíÇ׃\ý&9ŸI<†”x‚ÀùÇhzˆ`âG4?DKyGN®!$azÿZ%ÜÅV a ¿"2“ø Á5(,Þ{ú碑⸠!ŽÛ¹Š¡=èÆVú½£ôé$¥Ij¼Hôa¼Dÿ›„/üi;ÐßaÊ çÒÎ¥ƒ”»xÊšdôÉ8$ó‹¬ð«TŘfŠ+q½Yøúƒ£r²*6÷:^”ð›]Û%׸wG\788ˉ¤H€ir`ÂÎv?/'¨î’š†ì–ª†ØÙãç¨cæGaf„;B'”ˆFÖí|vévÊçrȵ#áx=Œ¶zCÄ8Pc.ÆÎÑ}‚vr cйëü JR̰i1!¤hô¹ÇØìˆ]ÑnŠÉGˆ•S³…†À¯Ö«ÓÁ¢ô0§»ì ƒ.§jÈ5"GO¥ú† ý™ªñ޹nÝæJ0¶·ï.b4Öó-ÂÉÎл˜n=ðŒw³"`´á‚~´r<ña³s>Ìã)C—ÓÕ0Œ9y®mjú®V!:«©|¸Šk‚Ø"%²£ƒ…*ðÕý5&˜@TZ¥[AkI )†áª±Zb²=Níʆr2¦jŠÁ³ å¾sš¶噜É(…B`4JY:TCaôÙeºcªùU•¨°*çœb2ô”vŒTzCɘ‡gKEËÔ·N„ö¶R¯9‡r,m:µïBM}¯V´Î÷{"O.6¸ÿu1á³ ¢‹~è-ôëg~¿hW´ªƒKt/ÐO‘vs´¯£Ù }„+ ï£î=í]h§±YèØ,êÙ¼l$ë Ùã®ÖŠúÉ®“7õ½ Ü4O?Àõ îðgԻ𠞥þïh;_‘¦!ÈöѸwiýÞõP˜¶¾þCEÓžEVÐh`l­l í,…[±¨m'GT&p ÝDA¬nÓÊE‡ÀÂé!iØ/8<~Ù[$›"­ÀáVôì8z€b3%®ø‘+Ž>gÖ*hÅ/V!r'î·ßÂÀeš§Ém3=³:Irƒæ›n w„¿NÄ0ñ¾Š!ñØŠuñ2‹aÚíÂÍI·ôPK A¥D£¢&3org/gradle/cli/CommandLineParser$AfterOptions.class­•mOAÇÿ{-½r-´¨ >W+p€Š"ÆDð!$MFxa²´g9½î™í¡øü.¾D%ÑÄà‡2Î^ÏrÒ’cšìÎÌÎþffwnûó×·fqÛ€ŽQiŒu“4®£h ‰IS°tLë˜aÈT¼z‹jÉ6ÃPÉ“5«&yÕµ­ŠëXO¹lØÕ¥}Ÿ†ÔG8þ]†‘±x÷ñ2CrÉ«<§ +ÛõM[>ã›.YN”¼ wË\:JIËi0dï½ômùäïxB©ËBØrÉå†Mªu0r$f„Žî§¬óuþ~Ó^õ¹ô›F†þ±Ò+þ–[.5k՗ލ-Œo0$¸¬©äÚz<Aè˜eèkÊͨ´èS ÈbÅÑÆVçï…ùg<±â‰?ÕdþÊ`±Smññ¢‘t\cX>ÂÇcg‚>Ðv¦Õ@]7|”- ƪ·-+öCGõÅ@›Ï”ª0‹ ²j¸žE7 7æcékâµðÞ‰W7xØ’Š1§ãf·0Ï0y¬d˜8ÎÙ3Ì¿5èó?U†Ñ¶=ì¾ q~ :5úh˜hþkºmqéóåÕêƒ_ò2w·íC^€2 ô\¦é ¥G@õI]ÐTŸ‘¥‡´G¤i4gL¶Í,~Ab—T ½4ö"A;Ÿ£‹­Ã`È‘m éŽò:CóÙ¤ú÷3q‘æ‚äÓôhbÆoPK AŒ‹Müu <org/gradle/cli/CommandLineParser$BeforeFirstSubCommand.classÅVërÛTþޭ䏲Ò:¦I à§I|‰sk›ØiK’^‰Üœr“Õ¨±¥Ž,Ó¾À[”˜2ÐþƒáxöHnb×Nä0áϹìÙ³ûí§=«ýóŸ_~0‡‡2Ncñ K2†°È‘“!aYF—ø‚«ŠÍ ǪP»&CÆuŽ!Üä¸%ã6>’1€u޼Œ(68 wúoŒz|†a,oÙ•LÅV·«zF«™5«VSÍí¼aêwU»®Û9Ò^6LùÂpsÒ_ýu W¼Ý¢—›ÚdÖ¬má”l4jeݾ§–«$‰æ-M­nª¶!öM¡$à2 ­ê-[¿aØu§Ø(7m2(·MS·×ªj½®“Ú¢/ÈxWCiX;PíBNg, –YtTÛ)§âò}›ø”ã3%l1ÄüøTðŸ3,ùzºoî˜Ö³Kfž=ìHÁ9Œ T_1$w°bW5Ýt®?ÕôfœkšŒ5s$]%½˜—€±‰ñúÄ4Cä Y åGºæp|­@EYxÔ.ù†´~H@ÃÝ„]*ÿ[qèçrå‰jëí€;˜;þk§G柮G&ާİÞSEêõQɪ¦éõz|q†×|ïyÊóÕpŒj†Š( mªjÝa8ß ÓË”Ww[E–‚ñ^lqŸá6v¿ëÆÊ(=­»WN#¯#¡rN©YS‰–¥.8ÍÔ~éêrWøûß´ö¿€¹ÿ¿¨KÇ*bÔ; QËÅ"Q¼iD@Ôr0¼M»[´Ò¬$’?!H¦vüö¼CãIqÆæÑÇfð.ɆéŒô1J¶á®¨–’ŒáœoZý }4«{JÉÛEßFâGž£?õ3x/ÊJ#Òï˜õÄ'¾Gtr)IÛp‚ô•g{(EOJ¿âT)˜.>Gdƒ/ö-¥G¤WZo=sPß#—`K3‹Q–Ã[FŠ]FŽ]¥¶pÕ…¾àÚ‡®b“Y¬¦h@˜~R ¤Èæ(®!ijJ3n¿‘ã8B§# g›¡HW¢™»Ü±îú…a6ç:Nx*ûŽ9µÀg\Çó.{bµ€ î×¹èÚ¸„÷i^Eˆ¾`– Nó¸$úä,’ÔÏS‘DŸ¼Ñgq¢ŸÎâc)€/hþR’ÿPK A´*«ZMïForg/gradle/cli/CommandLineParser$CaseInsensitiveStringComparator.class¥S]OA=wû±P·RˇŠ"ˆUhAx1¦„¨MLšÔ¤„÷¡êàv—Ìn‰ÅÿÀ‹/˜ø`|öñãÎîƒEkâCçÎÜ9÷Ü{Ng?ÿðÀ&6 °Q)`Ì,9Ü5Ë=K&½l£fcÅÆ*!¿¥|m2ËÕ]B¶t%a¢¥|ù|Ðß“zGìyœ)·‚Žðv…Væœ&³Ñ+æ"”M?”~¨"u$Û‘V~¯ô…Q  NÓ÷¥nx" %œ©6mÜÁ#¥nÔóÖ›uBå_Єñ¶êù"ñ[šf)ÏýåØÖ°àm¦*´ƒîȧÊH›j·fŠpÉÁ\ëp ¥ß©LbÊûúèÿÙsì‰ ÂÔEŠ‹£Ý"L¦ïd'höü@KÓŸ0}Á›1/dü MXEÏnØü…qsYXÆ'>9|r9Ç\í=¬w¼±Pä5o’ô—yï$L Ì‘Œ…i±ft–cyeõ™í¹·ÈÍ›}ö˜³™˜©lôy:E¾Á¡1k-©LYÍn3q§2®òÎâ\Ãuæ™M&:åâÒcî#íÿ€ï2‹µ•OÈ­òïù㿈(&íJ`æR’‡­ÔºØ™p6k·0Ï÷,ÄøÛXŒã\‰ç·Øî*w™ÅM/ýPK A|ìRÎÐ&=org/gradle/cli/CommandLineParser$KnownOptionParserState.classÍXéwUÿ½6ͤÓK‘*EqDè’t‚;VkE¬´E­+. ɤ3ufÒ‚ŠHQpCqPð![ÿ>žäu¿\|ÂÿŸIø\@-V< á°À¥gØZ§YÍ“ˆæ€5ͨ-4Τ¦j§×ª¨ 窬ÓÕm͵løÅ Z n­ÍïÔpi S¬5ê¿—˜$뻦 —b^¡)ÄÌSº™tçÐd%f³ùâsT‹CPÅž`Åg^íá •€ôt ¤µÒÎH‘@Ú'ÙØ„N‚rŒ"#ÁŸ^häÛÁN°oGQ7AUß‘çt$‹ åYFRkº|²ôžÃyÞaCè@Æçg‚²°pPÆÉëèn'»Iì<:\(ð=õÄšÆpÑÁÿòÙ,§œÊá›Á«ía…µîà¿Ò±<çÔV²â8æŠoßSTÀ=âGŒˆŸ°KüŒQñ ½’~Ãqñ;~àWqÂóW”|²‹ò¶›â\Šãä¹ÊTÎÏÛ°kqS Žä'×Í'Q.á–¿QsŠw8¿Th·áÚDL)Ù GcMóCG!O Ø+žm>V6ådÜŒ¾ hd¬ ŠFÆí^Ñð©wŒ¬÷øÞ‰&Ï aÄà ‘îWÐ~qˆÿªpÐN߽̾2BIî þ7ÄÁ³!ù?PK A$ľ¢¥ô<org/gradle/cli/CommandLineParser$MissingOptionArgState.class•mOÓPÇÿwÝÖ*ˆLDÙ² ‘!¨ ·'š`0ÁWÖÌšîo;¢ñoôÓøB…Ä~?”ñܶÌKË’îœÛs~ç±íŸ¿¿~˜Å’Žr:’È'I*(uZG 7ÕÙŒ’Šq”ã˜eМ-ÏrD·†_øòK.]S®zÜ3Œ§B˜²js×5]†¹š#ņäuÛ,nÚV±ê4›\Ôk–0¿É#%Šr×–wŸ¡’í[cˆU:å3¤ WZÍ S¾â6œ®9›Ü^ãÒRzxóÞZ”îÈsËu-Ñ˲VµÐ;‹®žTJºÉ?n˜¤I/¸GQ²µw|›m.ÅUO’ÛRn!ÊeCåwä&à# Ö» º@ûë~Ê+ŽØ•:0ßÝrïæ`€´#:L‰:՞ͭÅ1Ç𦯉÷ö)û[ùPR—2Ãäq\ôU§%7ÍÇ–Ú’Ñ#63ª†V—Ûtœ201,¸ˆKî`<ŽE†ùþ–ˆaú$ýe˜=y&z·ƒaêà °ÜýÒýioÙ¦ SÊžx[t¿­¦)<†L/gdè핤÷=Ij$iˆ¨ ÑÉ0iOH‹Ð*ÏöÉ~"ºCj„ÌAæQòÜÂ{Iœ¡³ÑÀgI‚/),£ß9Œ…ÐÅªå »ˆ}kó4º¶ÝÁÑÚ çqÁçЖ„œgŸ2À`þ¢»(LïBû~÷ÉÇeÃ6n0Ä)I')BòeŒ‡à{a‚I¦㇡Ÿ;rL¶¡ÉvŽ\ Q_Q”ãëÿíÓ•;û‚ûêãŒÀ0À¥AS¸B’e4hØØÎ¡dšv6lÒo¼’®ã†_єš Äh8%1õ+aêûUÂÒ' øPK ATK>ªÄ=org/gradle/cli/CommandLineParser$OptionAwareParserState.class­UÛnÓ@=›¤qâ¸$”6\Ê%¤)MÝKÚ@)½p)E¡ E*oÇÓĮօOá xá$ ˆJ|…˜MÝ’*A./Þ™³çŒgf퟿¾ÿPĽ8È©Ð0*w×TzŒ©Èc\…Ž “*L+(¨ˆcVAQÁu†„á4›Ü®•,ÛdÈ–Q/Ô¯5̂Ѱ O¹pÍÚêÌCÔ{i¹¹™è\û èe˶¼; óÁð`ùñ CdÕ©Q²IéØh5«¦xÆ« ò ”ƒ7*\XÒö™.Cúɶg9öʾZÙãŵuÛ6Åjƒ»®I¸…À,s½™è]SMþ¶j’%¼} ÃP¾ôŠ¿æ…·ë…²',»¾4þœ!ÌE]&ܤ–8ö†c$Ž${¿]pÆGÓì§±õ˜oûRËNKæš%t×éi©¨!‰”†Ó˜ÓÐSnbXÁ¼†[XP°¨a Ë s™¬¼ðL±f ×+·ª~˜a°—[ªÝf˜:ç~½¨Z§)9höæOØS†É©­‚» cÁsž›mÏqÌrºœ |ê¯Õ¼ñ¯ðFËüËdUº©ºÔ©áÜ0L×ÍÍÍÐ-=ƽ”»õ_îïqk³Þ¥vr®l0.’¡Ï¥FÒå|©”œxò„¡!òJ„ÓšÒ'vÁtö!}ráOþYÐYг,T6‚$Ëaˆ|iŠÑZÏíÔç ûÌ‹dKTTŸø‚ȇC¾(ÅÁò<ÑCž(.âÅ.#ãóì ¯*êŸ&ª>ZÙ7Dß!½eSZ2B™ÇÞ#¹‡ø¦oªÛo+5UÉÀ¦cÓºÅCÝ¢¯{•ö B£*^ÙvÒ#8G«Ni$èy6¢˜Ž+ùÿÑ1Eˆ8­3$r£]‹ØoPK A˜%àÌ»ª7org/gradle/cli/CommandLineParser$OptionComparator.class•TmOÓP~îÖÑQ:¯ ¾€ Ý ƒ2@Š.Ñ,YÀd†Äe4³¤kIÛ†?„/~#‰á³ÿƨ_ç¶ N6).]ÏË}Îsî=çô~ýõù €E”%d0#¡Ÿ¿ú0+bN‚UÂJ"E,IHs;'"V8|UÄSk"Öz6LÛô7’eA(;íªi;­æ¾á¾Ñ÷-ò Vºníé®ÉíÈ)øïL!»{䛎]všGº«ûŽË WlÛpË–îy!–ªŽÛP®~`jÝ2UÂ6uû€§y­»žáN_åÐÄz`Q¢W…kÂH-¡TˆÓ ôÃT|À%|‘ÎÚ4yÔ`õP?ÖUK·jÍwM»¡…kÉÚw÷º¯uz”Š-ÇÖ¤¤ñž$Þ/0LßÍÐ[3¶î·xѪÿÚMË7-õO¥7â ±IÔRÍi¹uã¥É;?Ú‘~žSËÈb@Æž‰ ™Z½a×ÃB¶ÏÏh÷Οñ\ƶið®ö‚a+6eY÷ŒŠí¶gúæ±Ñ™{"!c /&ãªÆqã ¥ÿý¿vŽa¸[ëhŠãÇ‚Z×0ü0 }‹¥m j†¯]{–…a¤=¿eÑžBº$Í>•½Pí¶Þ}à4¥s2¯|=ѧÕéQ*t±e躣KŠ.@ >rd ’¥’d$S3gH|$%!z÷p'û†aÒå€Ü!Éx‹¢àD–"¹2{Šä9„·ì ©Oè¹€¸Sìp­ çHs»wnL8…tr™­I"þŽ!öyö3Ⱥ2GY¹v÷‚¬à>i<2‡˜ Ø<l’4!»M»{ín•Vˆ™™Ù ôé ùäš#fÂdYþä"’5’‰¨>¬{}FCÀåNS˜Æ#ZOâq€Ï£H·INQÍ2(RÔ8éô˦ÉSÄ<Ùi’Ëÿ PK AäfC˜§£8org/gradle/cli/CommandLineParser$OptionParserState.class•’ßJAÆ¿³Y³º¦ÿ4Õ¶Ö¨£×JoJ¤P¥… …H.¼›$Ã:²™•Ù‰ø }¯/ú}¨Ò3›€ˆ…4»ß™³ßùΜýýçá€#ÔB°ÂÇF€ÍUBñXie? õ½Áo¦}IXl)-O‡ƒ®4碛pf¹•öDÒF¹ó8éÛK•–ή­Jõa2iÚVXþTú®µ4ÍDd™dËÇVjâ(6¢ŸÈ¨—¨¨™B÷]ŸQ]í¤AXH5‡ÆžÊ[ûÅĶóOúÖ÷&£ŸBÃT3k8ÚNê­+q#¢Dè8j[£tܘš¸KûMdT¾Ì‹¼W^'ÒÊÛ„Ýúdð‡†[ƒw{H¨ý›»´Ó¡éɯÊm¤òÌsàÆ+aÅ;„£é÷@(?^ÑY÷JöxÂ÷Ó\a{ò(„ê$“_åÿׇ{ŠðÜL |ŠX‰ufÿÞfs'é'æ8. ñðygXÊu+¹®âe®—/;çÚþ‰ÕÃéßðÊÈ0‚çÑ:^çeorÿ[nÎø}‡y?Ä"k™õ•³—gÿPK A¢Æ÷E«¶3org/gradle/cli/CommandLineParser$OptionString.class•TÿNAþözåÊq”ZDQ‹´GËQÄŸ kLŒ&(ÿ[®—rx½kî£âø/$‰&>€ï¤qv[l“B“ÎîÌÎ|óÍÌîýúóý'€9<éE?LÄ´Ž4ŠB-¥0£ã, ³:4…( 1—Âmá;¯á®†{ Ö²ËÛü#·<î׬µ8týÚCOЈÝÀ§Í¢ë»ñÃT¾Ý¯ÝRXgP+AÕaXv}ge§¾é„oø¦çˆLͽuºBoÕxËŒU™° Cê ßwŠǣȡSk9kV-äUϱlϵ*A½ÎýªHñš‡‘æNÆSéš?s£†Ç?¯ð:幘/t*´-æö‡W¼!éh¸ÏŠƒæ±† /ÏTww~eÙåÓ¬e!ærg‰cèã¶íDQ®ä¹ŽÀOE„–;McBÒ»…ÛÉ-Ü!¹%Œá.ÕÌ"‡{ä©äN'Möë¬zz‹ÆÇY%¼B65[ümŽ~çèkÿE“T‡BZÆ“q‘5²<”]/h¦¸äŸÀ}LѾ‚>‡‡‘ÆM²c”ïGÃäMHxº¦) ˆ±ïPK A`M~U¸2org/gradle/cli/CommandLineParser$ParserState.class•SßoÒPþN) s€ÛÔ97Õ½Œ&MLÈf‚ÙÃÞ.а.åÖÜvFÿ'_|ÑÄÿÿ(ã¹-›Ý Aš´çG¿óïœÛþþóó€´mdQ³‘C-Ç6êxbaÇBƒ{áI/zIÈ4šÇ³Œ\ÂjÏ“îáùdàªbàs¦Ò †Â?ÊÓñ4iF§^H(¼*tU?'‹ï¤tU×aèòËv/Pcg¬ÄÈw¡ï9Ý`2r¤;$uõTy‡Pšˆ/—#}Œ¼@Ö½3ñI8¾c§)OŽ;ÍBÞ / ¡ÆZå Ž°È›…&¡œøWtŸÌi2§íâqf¸YC!‡¼ûzÞPÚ•h&ß—ûP2£»e²»gÆv¡nÓ‚$Ù$T@|„*>AŸÑ%¾ W|Å):ËT Ð3€¿â‚Â_qIÅ_q3!ŠžÅ¹ t–¯^= xÎc @椚ÙCäÍ!ð÷:°Z_ eªàYòÊqà>8YM¨ÝHÅEÿF‚Ÿw@³@9\"žÙ!µvÚC”œzÀ¨1‹ø‰vñ«®¥x••&Òƒá€k$}ËŒfÇö!¶uõÁÇÏTsj]Åp9Ð9†+Î1Œø:ó*…4ñ*4fEù!Š´“æ¿Ëœ¦./1YœŸÍ ®‡µ?PK A£=l)&org/gradle/cli/CommandLineParser.classYi`\Å‘þJš™7zz¶eÙ²=`láë–1¶°åS>K6–±‘ÌXz’Fψ™¶8B¸ÂŽŽ``‡‚¹d ÙM¸ÂÈîØÍ²aÙƒ=€ !lÇÇ~ýÞ›ÑÌè‰üPwOwUuUuÕ×ÕO¯{ö€YòT:ñ±jþW5¿×±Ÿhøƒ/>Ññ)þ¨sú3 ÿ§áOùø >סã yøRÃa#ñç|ÁÑ|ìÇ1ÕׄW‹ø%GÇÉÕÄ£c¼xýâS¿5ÕøEžŽ]¢û%_ͪ¡fFúeu‘¿ŒÖ¤PÇt|ÂeŒ&cu”࿱—qª¯8&¨& œ¤äž¬š‰JO‹ï”|7#ñP"t‰™M$(°¹ÓùÎL8?²=ݱ×cq3Ö”&LMÖsÇsO°¶A0ÚeúAQC(çÖöj]¬ÝZ¢-um 3fÏÆ5iŒµfÎ Å≦îmÔkG0ÒJKͶhÌÌš×dcÊu;ƒ13cßM‚üŒ‰ÍÜ0Ý[‚1«×¬«_ݸµ±®aÅÖ5uëÖ­XÛ(¬ê ^¬îN„ÂÕ1³ÝÜU½&˜ V‘ù‚QQ[Ù¥=I£Ò¨‚]¤Ék µG‚‰î-\‘¹ºÀþFÚ«móWEcíÕí±`kجn ‡ªÛV…"¦­ìüE”9:Gw6„v™­Ž»Êú1Ö|ÆyqeÌ41ë×òP<¸-lÒ‰¾¡H(±H[RÊsô,‹¶šJîÔØ½c›[§…«¢-Áðú`,¤~;“žDGˆ’§|…º¶³©¬·Kg–lloi¶‹­5M%ä· ü¤9.bˆI+vµ˜ÉÐÙ"˜[’FUÏóRŠo;ÃRØñ¬`öFNç”â3#­ŒmL=ƒ šŒ4åPõ%$Ðl¢ÓÉuöÎ * cÝLate+ïr"n꣓uUC›—iظ̀èéJ…›Ç]B\ð kÙΰX5¹P°jØìÃ:ÄÉ)Bˆp(^H˜i%ƒ¹…¯n ZÍükn »‰Ý’É_>N¶§¢‚ Ïœ&3A†32g R4ìÑd«Š Z”8?lçyÒO¤®«‹m'áˆf@çØh¬ÕŒ%sÆžUÊuÅÌ6ë’3iÊ­ Å•¾¹ÛÍ¢Ä%Áp77õš‘DLý^a÷E™9ÍšV\ÑEW ™p¼ vX8)â¬ä4iFf(Må¼aú„}îŽà.ÁÔl?ºFò´,ƒN@6ßÍ 7üwåž3ô½á§ÉEš5ÙF¼îŒ†p JÒ-‹†Ãf‹n1íR^¢¾:ít[½­“BÞY‹ñÔ™dïÁ3‰›©R÷­»­M΄A-µVÔvmê‚ϼ.(SžYìn‘Z¦Q_;¥S™©[ZÌx|Úœ™3ÓK†FR^Ñ9»fpÎUœg ‡sPY‘1O‰ð/ ›}›ëMÑîX k#…ÈãIªRr ÜŠ[ Ü€ ܬFßÁíD¨-Î Æ;¸&-†´Šià{¸OP<ì’Á´1¤MÚ¹ƒt¨†·\Í×ku§¸;5ÙnHXv‘¨!]r1%ûð ‰ Ã0§²Ò„t *‡Ü1½ðT]BØ­¬ÜtáÂ-å†ì”¸!»¤ÇKå2C.—+%‹ã¥Ū2C¾!W*¢or•\Mx´ÖÕ²ZÅm¸…UŒ3W¹¥ªŒqŸ\ÉêlE,rRzüà´…[UÆíºV®3ä[r½!7(GÜ(Wr“|Û›åjCnÁí†Ü*·ò%*ûÜŲ!·ËwYX¹À¤Š2Îu]Ì4y®‚Ó‡Y <'”kïP͆Ü%w't°3²ÝluY9LáÙC¾'÷d˜R‹{23$*Š ¼ƒ0d·\/€!{ä^C¾/÷hrŸ7å†ÜŸÅžkCPáæ™ŸɈ: ù¡\lȃò÷™nÑEñâbÅ`ÈÃ*ÅÆ¹c&{ý>Vi%±¬=f Ù½ƒwbª¼eic›^ÏRĉ^ÒÉw÷w¶`Ö× „OðFŸ3<,ôdn>g?Ü_çy2°Ï|ô—Ÿ˜Þ%õ €Áz¢Xç>"£Nd1ìV“fY72³pLbÊh1s}Á¸½6=£JqŠ®ÒÁÅ´Ï*£É9¡¤ôDuXàU ªëÇ»?›¹²}eÊг¡›§[»Ö‚eN(åóqæ%ÏB=—:‚ñFsWÂú®Áz˱~Œ-)u+Z v{¶©—p,‘|”•¸”ƒÕ{þâî`8žE< ÔrÐ_n¾ÆÛ·¥Cc^¼{[܉բ’z×v„ ç46º˜ð—<[]¿kŒt6SN¶¾oÌÆ;:낊´š»ÔƒÚC“êÕqÖ»›¦[àc¥¡`©ÛÑ|ݽóÛ(~®zvú‚V†7\eŸ £"šzü–¸ª>²ÝL°žP_·k¡°©pÊ6#í‰+Lé€üh¤1I`E™4c…Ò/·]AËin±çع¼™<í±hw׆ڧ0=ëÕ—g3†Nj'"³@#yëYk>nV²0=tziÎH_û»…ò×r3Þ %?~u©'þ\“‡éßv³ÇBä‘‹ Aå ¯Š7ºÝo}m°hüÜ~½ý ÂÇ¡öW„‡sú Èé_&º%î@,yÛÂÝñŽäÅ‘å<ހà MçÙ<ïkéš³®àÇÖ­²0nGRZÕžñA<[1ëQ; hK½&§i13|d³7ØLó]$7$åJ“¦þÙAÈh5㡘ٚz=©ïæ‚ÖÂè´ž¿_‘Ó.Ÿóq*:±€'©ª—£õF†à&kümþñ¹loU}Áõ²ãï¤ášíwùkr9ârÙxÊúám>ß3ÈyÂ⼃­Î˜æâNŽ ›wánöWñ¹})”¬…ìm^YùAh½ðïO ñYL+,ãl"G€íÆ®ß˱‡ý÷ùÇ7<£ÐÜ7hb>Åxú‘×ܽ¹ìiäô!_pÆŒhèÇÈæ² 9€Qå}(à Âðôa´`·¼®F…‚¿Â˜ZoeÀÛ‹±»å±€·°¨ãv£ ã›ë„Æ}r§½8i7N"eÀKâ“{1±Öðõâ\N‚IAUÀ[°°“k|6e)Š­Ðüå¹Èâ=•Lg“iŠÅtªEëñ:¤ðúRt“ŸÄÔ=("õ4RïA~?¦ó(N{,$ªõ)³¾>ÌÈ¡»Æ)Y>gGK;¼åÈ®Õ,JÍ¡¼ª²%TZXÖ‹rE\Þ‹ ÕO¬õü½¨Ü€?i.UÁMjºªÑ[“W”§\Vý æÒ*þRv×ê™"uG¤žYÕxmžì;þâ>,¦.’®®³¾Ó‡ÒKéÖ‘ÍlÜwlfe/N¯ØoEˆŠ§'QÁöÛõb¶ãô Wb#Ó`cm3Æ< ñרŠ_ã"¼KÊ÷° Ÿ£ÇÑ*#`Êx´É)h—btH):åLl—&„evH'¢Ò….¹ËMˆÉ^ÄåQþ~;å9ôÈ˸TÞÄ7äC\)À5ò®“?ãz9†sr˜–*öÅhêåÃp?Û»0à‡=ŒQÖœFÍ {•ºØtw›‚ñt‰c1~DŽÌÎÁ†k½ŒûßUôaŽ ±Ò!Œ¯t0¨F!SE/ÎÜwüƒ²XžÂSýá'æMâ©Íd_ø8ç¼ç¾‘g¦ôMÍ'¡Ð9Íóø×K ô(=SXº-,õ3úð,-Nž¡=ÓÏu†Sá9ÎPôièÔðœ†çÙ Ýñ¦Q³ûc"™áÛ%¹Ïp;°üªs›Ë`q·–x<¿™ð¹à6V¦€¹‹è‹~,¦ï–Ôz*-wÔü‡¼®FŽG|¶˜:%f)ÅXJ¨X–²œBV4[J^ Ï‘²^l×úT{À”€ß œúp…íÃäå¢ÁËÇ÷ü…gÄ9Ü…*Ô+±/#ß’½ZáJNxy½çæ*ú™ŒuìR6+í|*,í&©‘£VäUÀV} 5^ƇbiÌÒ•bY­¼Ð‡5»µùÉ…çyžÇÚæ\µÐ$hêÅ:4¯"iÏù4¥ˆh¹¾pƒm”7ƒ¼ÙãH´ßÌ8¼à‰T ^ÊÈRè”Çx 0ÓK%³°k˜ŸAæg„鵓r7sä~ÆÝ!ÆÙo_ÿŒçðžÇÇœ9Ì`9†Ÿ‹Ž_K_”¼$³ñ²,Á+² ¯J;~);ñšÜ†×å%¼!¯âMyxw§•Ø#){9í%ÊqÇGˆÒÏ2wR»ŸãŒÞ0 /r5{‚—,º5¤ÙËðqÃBH»\ˆ—‰ƒš Öd^pôK¼ÆPΓñ7xY§ñ+òçb–Ü‹7X:y¨ñóx“Yçµ²F园ɯSšü-1ÍÞáï8gËèOÉø{zSe× yµNv½¥a®•`¿aZx¼úà 5Öøm‹èCãd"æQL´ðtLîq:ɛŠeÍc%,3w„…Çä]}sÚêê²Sž}ÆÞÇ~e?š2<‹Ê_¯p媲>lJ¯›0Ý©›j½§ìA^Ãió† uoQ£ÜEûŽ¿Ãø¹pê8Ð~?ÞâžoSÑw/¿å-ýOijw‰g¿ÃÞ¶Kñ/´ÿýžU°üGÒy•^¤}×B±•Œ«‡,ÌZJ¾÷,;–ó–ô;É¢Ÿ½òøxŽb´†f9Ír¶öKêaß2ÿJ|ß‹sð=ijSž8TÞPqhQn§ÈsʃØYQä™Uëµ@Ýë”O~lm.¼ÈI=oÓA`‹2/-ÉõÖìõ'a*oµõ¢}CÓ‘Ms­‡wÅý¨iVÕò„*,ØK¿:&U¦@Äcéå©HbÏ{V5”ky¿†E=ð!Æâ#Þ&³Pÿ==÷ k Oц?âr®]?1Ë>gŽAäù’y{8u cÑaÝ*^®Ž°òHÝ*‡R·Ê!çV¹•g©ò-y‡hÇà·.Ž#¨f€N>Œ©_À{EV43$§øñïøçf®f¯N¹8÷Ѭ·Áœ´;ÙËlçÎdþOü— sNöÃÂù¿]w–aìÌÈûŸÔi‰µ ;{±g<¹Oajaø v<sð[©€Gò¸%.ÇX"œüÐ"ùQ kGOa©XÇg\Ÿp³±ŸÏ>Î>Á¾›â.a¿“ý.ö=¼¸Œ¿Ç³¿œýì¿AÉ#Ù_Éþ›ì¯òäð´;q é¯eéV)^ñåý?PK A‹å>É&org/gradle/cli/ParsedCommandLine.class•Wiwg~FÛÈòÄ‹ê%v“TMc[–å’ñR·Ž›8¶SâÆÆ)-L¬‰¬TÖ(£‘·”.PhÙ¡liÙ7 ’`rX¾Áá;ßøÆŸ œœ˜ç}g$KÖ¸1GçÌÜ÷Î}Ÿ÷Þç.3úǽ?þÀü.‚v˜*òø`Ö!‰‹*¬‚΢ .¶ŠbuŽf¹¸T“¸,.+*žWñBM0#hÄ'ëñ".©øT=^ÂËa¼¢âÕ·}:‚|FÅkt ã³âþ¹0^÷7„ÅçÅÎ/Ô㋸$–__Vñ•0¾A¾V¯ãMaó qù¦¸¼©â[ ͼ1s…#+3¶•É¥©™¼ /ëE;“˜Òóà êf2éœn-CÁÉê§#Î2«çÒÀð¤i¥Ò–žÊ ÙÌÀ“ºU0RãæÒ’žKMfrÆ)yâð(‘ò–Q0r¶£*T>cØ4y¤Zãq ²Œ%sÙH•ŒË¶¥Yéâñ©hªÀ™Ìô¾Mª-°C#™\ÆUЯ08a–~.k ÷Î*Œ›)CxÏð¦‹Kç ë)ñLAtÒ\г³º•kWYçpÎ#„AÍ™ ´¼äÌ FA|»”ÒWÓݳwó/뀽˜)xØÖàÓV5KÔ¶x±  ­:Ô•|)ÜÃö#÷wOP¿cÆÖžcI(ßVñÃ^yØ¢ÈUØ6K¥Þïõ¤ÿbÑ´±\jÂÌú½Óîµ3Tp‘UG(ˆŒí|ÑVÐQ³áH1“M– 7S8–± ´RΊ|{…çY›#Û¶õô·nQ/”ª¬5^kÑKošu·O;=F‚¸m,·RÚÙ¯h¤q3›5$ßbwcÖLOËF¶Ü™mÞÆ ž¶¼ßûLïÐÏn"ªÝöûª9mØG7M”h©z*gJwr‹vè©”DœÕ³Ec úY®ÁeçyíK„?ëa{ÿòÿ?ÂÕœqZ:¯«fy Ó×ÈŒY´ŒcÑöm5ðû…Óã Ý é¸^Xd‹kèÇþšùÞဂ6žŽY–¾"Öð|PÃ[x[Ãwñ= ßÇÄîç1sµ=>4ü?Rñc¶ÂfÖUüDÃOñ3Ýñ8ë*$cÕ/GWý†º*ÀSç.°„5œÂ“~ŽU¾n¶˜ |ɘ†_à—=¦0­a ç4ü WU\Ó0³~ßp´WLöHZÏ–¼:zyÁpyØéøëé*ôÄr¦Kç}j¿Ècü­†ë¸ªážÑð®Ö’[û£v.•”2}Ri›ŒÆ—c9SV´UõPÉPŒIÎir+÷°©9¹¨ã‘´Ž°gËS§¹ Óù´ØQ¥¨Z³yˆœÛ‡ãµàµOBçMkI'Æ GÃ>ýÞ ï=Ÿ7r©‘W=¶~©„Ìœ­gDô­1[¼f(O :º½6y…ÙP=𸟳J8žJe³œÒÇÃü2mç‡sQÑëP0À•ïãš-^^äúЦ5[¼¼þêy?ŒAÊC€2?TjÞH܆’¸ßümøo"@1H1tꆦXG1rõ}kÐL%×°CÁœ¤Ð à¯hœ¾ƒ&Ú4úo!º† ;‚®]LHÒ°e(”ø=¡ŽÀZý˜[]ÿ×êú;7dÃò?‚Æk'W­ü¾o£ÔÎÏñ ùAþØ…ì†=xá5Äð:IáŽCüa£b!ZÀcxœ(DÃÌp1Ž')Å1ÒóaÊïŽæ8¥”÷!°NÎü*’*&TþïÀ=t«hTÑÄÕÐý_éP;É=œ'¼’XœáÙ­/ÚúÚçý F«ÞÆÎ™ù€ë¥bXˆ@Çu #Bw¶vÉp§ú\‡}bÈ9¹Ã»¼‡x?}düÁ©À¨“•¡€àTò}HH.ßÁÝo!’Œîº…ÝsÉèyëV¬ü£«ëOÞÂC×ËIØ/ë¥a$¡qÖa’xA1c¬¾ã¤x‚š)R_J@{ñ& (ü+“}š?Av˜ö3xŠþG¸û f™”«97­ðßCTE§Bºï"¦¢å]t¸Œ”Fœ×.ã'¨ññޜ軅؜ ›t<ìõ2¯i Êâ1éi›³¡ì_3ã%œ‚§ß6ì ;AØ“÷ýžq“÷6ïA-ÁöV4Rg©‘Z¦l G® ¸¶ºþoÿµrNÚ$«gسdyŽE:ú+ŽŽ‘ÉN:$ôËÌ•œèųøxU¡ Í'\ž5øïB%Ç»6 Zç3¾]^ᜈ¢kéô>lšJþ ;ï k>ÚeÞ'*ù6zþ’Eä—Ge¤)ö¤Aù<],;[í¢ÃS;\ô¬Oº†r=l8>Y ŠÃ߀äŠ^ÚÜ9ÙŠÎ ºðNL¯ç‘vczÂÍ­&@S܇¹›Òšg\¬H«VvWc£òŒ .¸ˆ97­{ªXšŘ”ã°—GôoøÛ )ãªÈ‘¶,ÏI8åsöÈQ¦HI 0­›$AbïsŒÖ9ûŠ{ö`_ið–«*^QUt¥ Õ ¢š¹èó‰ñûÏåŒ9%ö<'ì tçE¾B^âKãårÖvs?ê–Ø`ÙÑAé^EAEXP QP –dȹÿPK AyßtÚE,org/gradle/cli/ParsedCommandLineOption.classS]OÔ@=ݯîGeùPa„eQª¨ø"ˆhHV1YƒÁ·awR»í¦íá§ðl⋘¨IÔg”ñN[`Y$ñ¡Ó™Û{Ï=çÜéï?ߘ“4²(ª˜H#‚b ¸ž¦å†ŠÉ$ô4¸™Á-L%q[¾ï¨¸+ßÓr¹§â¾Š [ÌlpWA¶´É¶˜Þð„©—„ëÍ(H•…a1¯áp#-Ÿgƒ³É,C/{ްŒ™9*IÌ Kxs ¢…ñU±E»JÅ%añ—Ú:w^³u“"¹’]aæ*s„<‡Á˜·!ˆI¡d;†n8¬jr½b ýs\^]´k5fU%ÔJݶEí’÷V¥Ý…ñ³”´•=Vy÷‚Õé£ j”;*i=z&xŽÔ «V£Qã–§ §p6K:dÇ)¹ñKn07T@–½U.Û §ÂŸ Évàé“ICzt°]p¶-)kèDNÃ(Æ t]6Mn0“,ñøÒû ÷±(#ÍWmîæ-ÛËo°-žgÖvÞ¿“²Ñ°Š‡f0« ?L'æùZÃôDÝäA¦K©@Ó϶*Õðó$¡Ñÿï)”•õM^!ÛO†îŒ+vï–i¥áÊQ,7_… ”¬ŽÒÀZ~“¾«Â]ªÕ½m\¡(K? LºHï.:EÐ8íÉrZ/PdQÚÙâ>”â!"kûˆ~E쳟}‘Vù_‚*bTÓG;-ÈÇ%ôûø¸bí„XÓÅoˆï¢í‰µœºäÏâÄ"¡Âpú(=@&‚_Ðö¨2êwì%Ž ^*õè$üAêPÀPS÷é°û =1D:¥š!䉩ä¡ÓIfÅ%þÞ±„n‚‰‡05W(v•¾bžRD ×$ÈÄÚ"xÓjÊ2D¬Ï§ìç†xr7‚k> º½!âóV.p£]Á.ÔØG²àÓ±ô€ãDÇ\“Ô8"Ùy Rð‰ŒÿPK A\vÆB| :org/gradle/cli/ProjectPropertiesCommandLineConverter.class’KOÂ@…ÏD|?PâìÀšuã#QŒ+¢$÷C;–1m‡  ÿJW&.üþ(ãª1ØDã,îéœ9ßôv¦oï/¯ö±[@yl汕G)‡ívÙ }FHWkw„LSºœ°Ü!¿]®nY×7ÎZK:Ì¿cJDóØÌ螎ZRy¶§˜ësÛñ…ÝVò;ÚHŸ+-ø )ƒ€…n´kS†#cruLXõøgh|Ó×B†„j­õÀFÌöYèÙ­Dè™èÎè%×LøÜ%”ÖŽñŽ…Ž*‡_‰¨å½?õÖˆ:("‡<Ú„bJÕö ®­ØŠtòfë^*K÷¸Õ ßµ¦ XUÞðV½Œ£Üi01Èk ÂÁp8ƒwZ±ß8T0gî?Pôa¦Î›™m”ŒÎí=ƒžÌC S³s ¦§£‹| Ë1\áôZêq-}CÓ_èJšžEˉèjš™E+ ¨ùw'©õPK A Ï8=|ü9org/gradle/cli/SystemPropertiesCommandLineConverter.class’ËJÃ@†ÏØ«mµ¶ÖjÕEÜ5BPÄ…R/Pé~šÓ‘$&ÓBÞJW‚ À‡'i©AÄYœ3óÏÿÍœ¹¼¼¾Àl— "l¡Y„Íl E Ê<&Ï dÚú@¶ËÇH ÚgÞLÝŠ{:r”Rïs‹:C*X4NĬœ°€ÀQŸ Û´;hZ3a ѽÜG!]îºÔG‹v¹7S"Š5eb o}ɸG ÑÖûtFM‡z¶9‚y¶²¶~X{()spL`7e.°KV, øTXxÉ¢Šõ¿”fDT E¤G ÄPÇWãJm®h~²­Æ49Aíjx­µÑ° ­ÓsÃhöÌ gÔ™¢n8üÇ5©Û] .FÔ’¿s°9õàQˉ΢ⲙ*•sû/@žUg J*æc±e+sƒÊ+1¾ Õî$p¦¾ô´€6¿¡™/t-Í,¢;©h-Í.¢Z ª>kìZÿPK A íAMETA-INF/PK Am±>=@?¤)META-INF/MANIFEST.MFPK AíA›org/PK A íA¿org/gradle/PK AíAêorg/gradle/wrapper/PK A•%Ó¦¹/¤org/gradle/wrapper/BootstrapMainStarter$1.classPK Ai,«$ -¤#org/gradle/wrapper/BootstrapMainStarter.classPK AhQþ}¢Ò#¤org/gradle/wrapper/Download$1.classPK Ay´[À4ØA¤p org/gradle/wrapper/Download$DefaultDownloadProgressListener.classPK Až‚­Û¡~4¤org/gradle/wrapper/Download$ProxyAuthenticator.classPK ApOÌ)¨&!¤öorg/gradle/wrapper/Download.classPK AyL¢¡Ê1¤^$org/gradle/wrapper/DownloadProgressListener.classPK A!9|¶„ 3¤N%org/gradle/wrapper/ExclusiveFileAccessManager.classPK Aì„,y†-¤U,org/gradle/wrapper/GradleUserHomeLookup.classPK APrº™« -*¤/org/gradle/wrapper/GradleWrapperMain.classPK AúâæªÛ"¤ 9org/gradle/wrapper/IDownload.classPK A$P™[U†"¤ö9org/gradle/wrapper/Install$1.classPK A¬ààÇ}-¤‹Borg/gradle/wrapper/Install$InstallCheck.classPK AVÌ„‰¾/ ¤SEorg/gradle/wrapper/Install.classPK Að¿:öo4¤O[org/gradle/wrapper/Logger.classPK Aé`˜Žï8¤û]org/gradle/wrapper/PathAssembler$LocalDistribution.classPK A á¶;+&¤ß_org/gradle/wrapper/PathAssembler.classPK A„ÍëÂ| 0¤'gorg/gradle/wrapper/SystemPropertiesHandler.classPK Aª=©°?-¤7lorg/gradle/wrapper/WrapperConfiguration.classPK AGü¨ (¤2oorg/gradle/wrapper/WrapperExecutor.classPK AÔe‹ #¤xgradle-wrapper-classpath.propertiesPK A)¤íxgradle-wrapper-parameter-names.propertiesPK AíA6yorg/gradle/cli/PK AÕÜ?®<S1¤eyorg/gradle/cli/AbstractCommandLineConverter.classPK A׃µ³Xì ;¤ð{org/gradle/cli/AbstractPropertiesCommandLineConverter.classPK A}­ÎyGK1¤¡€org/gradle/cli/CommandLineArgumentException.classPK A³ßâúg)¤7‚org/gradle/cli/CommandLineConverter.classPK ASf Õg&¤—ƒorg/gradle/cli/CommandLineOption.classPK Aü튯¥å(¤Ý‰org/gradle/cli/CommandLineParser$1.classPK A$f{K¿ ;¤ÈŠorg/gradle/cli/CommandLineParser$AfterFirstSubCommand.classPK A¥D£¢&3¤lŽorg/gradle/cli/CommandLineParser$AfterOptions.classPK AŒ‹Müu <¤_‘org/gradle/cli/CommandLineParser$BeforeFirstSubCommand.classPK A´*«ZMïF¤µ•org/gradle/cli/CommandLineParser$CaseInsensitiveStringComparator.classPK A|ìRÎÐ&=¤f˜org/gradle/cli/CommandLineParser$KnownOptionParserState.classPK A$ľ¢¥ô<¤‘Ÿorg/gradle/cli/CommandLineParser$MissingOptionArgState.classPK ATK>ªÄ=¤¢org/gradle/cli/CommandLineParser$OptionAwareParserState.classPK A˜%àÌ»ª7¤•¥org/gradle/cli/CommandLineParser$OptionComparator.classPK AäfC˜§£8¤¥¨org/gradle/cli/CommandLineParser$OptionParserState.classPK A¢Æ÷E«¶3¤¢ªorg/gradle/cli/CommandLineParser$OptionString.classPK AgAq²”x=¤ž­org/gradle/cli/CommandLineParser$OptionStringComparator.classPK A`M~U¸2¤°org/gradle/cli/CommandLineParser$ParserState.classPK ApÍX Ýk?¤á²org/gradle/cli/CommandLineParser$UnknownOptionParserState.classPK A£=l)&¤¶org/gradle/cli/CommandLineParser.classPK A‹å>É&¤uÈorg/gradle/cli/ParsedCommandLine.classPK AyßtÚE,¤‚Ðorg/gradle/cli/ParsedCommandLineOption.classPK A\vÆB| :¤¦Óorg/gradle/cli/ProjectPropertiesCommandLineConverter.classPK A Ï8=|ü9¤zÕorg/gradle/cli/SystemPropertiesCommandLineConverter.classPK44JM×libmongocrypt-1.11.0/bindings/java/mongocrypt/gradle/wrapper/gradle-wrapper.properties000066400000000000000000000003101465326363200313550ustar00rootroot00000000000000distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists libmongocrypt-1.11.0/bindings/java/mongocrypt/gradlew000077500000000000000000000176061465326363200230000ustar00rootroot00000000000000#!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in # double quotes to make sure that they get re-expanded; and # * put everything else in single quotes, so that it's not re-expanded. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" libmongocrypt-1.11.0/bindings/java/mongocrypt/gradlew.bat000066400000000000000000000053131465326363200235320ustar00rootroot00000000000000@rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega libmongocrypt-1.11.0/bindings/java/mongocrypt/settings.gradle.kts000066400000000000000000000000261465326363200252310ustar00rootroot00000000000000include("benchmarks") libmongocrypt-1.11.0/bindings/java/mongocrypt/src/000077500000000000000000000000001465326363200222025ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/000077500000000000000000000000001465326363200231265ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/000077500000000000000000000000001465326363200240475ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/000077500000000000000000000000001465326363200246255ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/000077500000000000000000000000001465326363200262525ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/000077500000000000000000000000001465326363200274135ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/000077500000000000000000000000001465326363200303275ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/BinaryHolder.java000066400000000000000000000026041465326363200335560ustar00rootroot00000000000000/* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.mongodb.crypt.capi.CAPI.mongocrypt_binary_t; import static com.mongodb.crypt.capi.CAPI.mongocrypt_binary_destroy; // Wrap JNA memory and a mongocrypt_binary_t that references that memory, in order to ensure that the JNA Memory is not GC'd before the // mongocrypt_binary_t is destroyed class BinaryHolder implements AutoCloseable { private final DisposableMemory memory; private final mongocrypt_binary_t binary; BinaryHolder(final DisposableMemory memory, final mongocrypt_binary_t binary) { this.memory = memory; this.binary = binary; } mongocrypt_binary_t getBinary() { return binary; } @Override public void close() { mongocrypt_binary_destroy(binary); memory.dispose(); } } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/CAPI.java000066400000000000000000001273031465326363200317140ustar00rootroot00000000000000/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.sun.jna.Callback; import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.PointerType; import com.sun.jna.ptr.PointerByReference; //CHECKSTYLE:OFF /** * For internal use only. Not part of the public API. */ @SuppressWarnings("WeakerAccess") public class CAPI { public static class cstring extends PointerType { public cstring() { super(); } public cstring(String string) { Pointer m = new Memory(string.length() + 1); m.setString(0, string); setPointer(m); } public String toString() { return getPointer().getString(0); } } /** * Indicates success or contains error information. *

* Functions like @ref mongocrypt_ctx_encrypt_init follow a pattern to expose a * status. A boolean is returned. True indicates success, and false indicates * failure. On failure a status on the handle is set, and is accessible with a * corresponding status function. E.g. @ref mongocrypt_ctx_status. */ public static class mongocrypt_status_t extends PointerType { } /** * Contains all options passed on initialization of a @ref mongocrypt_ctx_t. */ public static class mongocrypt_opts_t extends PointerType { } /** * A non-owning view of a byte buffer. *

* Functions returning a mongocrypt_binary_t* expect it to be destroyed with * mongocrypt_binary_destroy. */ public static class mongocrypt_binary_t extends PointerType { // The `mongocrypt_binary_t` struct layout is part of libmongocrypt's ABI: // typedef struct _mongocrypt_binary_t { // void *data; // uint32_t len; // } mongocrypt_binary_t; // To improve performance, fields are read directly using `getPointer` and `getInt`. // This results in observed performance improvements over using of `mongocrypt_binary_data` and `mongocrypt_binary_len`. Refer: MONGOCRYPT-589. public mongocrypt_binary_t() { super(); } public Pointer data() { return this.getPointer().getPointer(0); } public int len() { int len = this.getPointer().getInt(Native.POINTER_SIZE); // mongocrypt_binary_t represents length as an unsigned `uint32_t`. // Representing `uint32_t` values greater than INT32_MAX is represented as a negative `int`. // Throw an exception. mongocrypt_binary_t is not expected to use lengths greater than INT32_MAX. if (len < 0) { throw new AssertionError( String.format("Expected mongocrypt_binary_t length to be non-negative, got: %d", len)); } return len; } } /** * The top-level handle to libmongocrypt. *

* Create a mongocrypt_t handle to perform operations within libmongocrypt: * encryption, decryption, registering log callbacks, etc. *

* Functions on a mongocrypt_t are thread safe, though functions on derived * handle (e.g. mongocrypt_encryptor_t) are not and must be owned by a single * thread. See each handle's documentation for thread-safety considerations. *

* Multiple mongocrypt_t handles may be created. */ public static class mongocrypt_t extends PointerType { } /** * Manages the state machine for encryption or decryption. */ public static class mongocrypt_ctx_t extends PointerType { } /** * Manages a single KMS HTTP request/response. */ public static class mongocrypt_kms_ctx_t extends PointerType { } /** * Returns the version string x.y.z for libmongocrypt. * * @param len an optional length of the returned string. May be NULL. * @return the version string x.y.z for libmongocrypt. */ public static native cstring mongocrypt_version(Pointer len); /** * Create a new non-owning view of a buffer (data + length). *

* Use this to create a mongocrypt_binary_t used for output parameters. * * @return A new mongocrypt_binary_t. */ public static native mongocrypt_binary_t mongocrypt_binary_new(); /** * Create a new non-owning view of a buffer (data + length). * * @param data A pointer to an array of bytes. This is not copied. data must outlive the binary object. * @param len The length of the @p data byte array. * @return A new mongocrypt_binary_t. */ public static native mongocrypt_binary_t mongocrypt_binary_new_from_data(Pointer data, int len); /** * Get a pointer to the referenced data. * * @param binary The @ref mongocrypt_binary_t. * @return A pointer to the referenced data. */ public static native Pointer mongocrypt_binary_data(mongocrypt_binary_t binary); /** * Get the length of the referenced data. * * @param binary The @ref mongocrypt_binary_t. * @return The length of the referenced data. */ public static native int mongocrypt_binary_len(mongocrypt_binary_t binary); /** * Free the @ref mongocrypt_binary_t. *

* This does not free the referenced data. Refer to individual function * documentation to determine the lifetime guarantees of the underlying * data. * * @param binary The mongocrypt_binary_t destroy. */ public static native void mongocrypt_binary_destroy(mongocrypt_binary_t binary); public static final int MONGOCRYPT_STATUS_OK = 0; public static final int MONGOCRYPT_STATUS_ERROR_CLIENT = 1; public static final int MONGOCRYPT_STATUS_ERROR_KMS = 2; /** * Create a new status object. *

* Use a new status object to retrieve the status from a handle by passing * this as an out-parameter to functions like @ref mongocrypt_ctx_status. * When done, destroy it with @ref mongocrypt_status_destroy. * * @return A new status object. */ public static native mongocrypt_status_t mongocrypt_status_new(); /** * Set a status object with message, type, and code. *

* Use this to set the mongocrypt_status_t given in the crypto hooks. * * @param status The status. * @param type The status type. * @param code The status code. * @param message The message. * @param message_len The length of @p message. Pass -1 to determine the * string length with strlen (must * be NULL terminated). */ public static native void mongocrypt_status_set(mongocrypt_status_t status, int type, int code, cstring message, int message_len); /** * Indicates success or the type of error. * * @param status The status object. * @return A @ref mongocrypt_status_type_t. */ public static native int mongocrypt_status_type(mongocrypt_status_t status); /** * Get an error code or 0. * * @param status The status object. * @return An error code. */ public static native int mongocrypt_status_code(mongocrypt_status_t status); /** * Get the error message associated with a status, or an empty string. * * @param status The status object. * @param len an optional length of the returned string. May be NULL. * @return An error message or an empty string. */ public static native cstring mongocrypt_status_message(mongocrypt_status_t status, Pointer len); /** * Returns true if the status indicates success. * * @param status The status to check. * @return A boolean indicating success. */ public static native boolean mongocrypt_status_ok(mongocrypt_status_t status); /** * Free the memory for a status object. * * @param status The status to destroy. */ public static native void mongocrypt_status_destroy(mongocrypt_status_t status); public static final int MONGOCRYPT_LOG_LEVEL_FATAL = 0; public static final int MONGOCRYPT_LOG_LEVEL_ERROR = 1; public static final int MONGOCRYPT_LOG_LEVEL_WARNING = 2; public static final int MONGOCRYPT_LOG_LEVEL_INFO = 3; public static final int MONGOCRYPT_LOG_LEVEL_TRACE = 4; /** * A log callback function. Set a custom log callback with mongocrypt_setopt_log_handler. */ public interface mongocrypt_log_fn_t extends Callback { void log(int level, cstring message, int message_len, Pointer ctx); } public interface mongocrypt_crypto_fn extends Callback { boolean crypt(Pointer ctx, mongocrypt_binary_t key, mongocrypt_binary_t iv, mongocrypt_binary_t in, mongocrypt_binary_t out, Pointer bytesWritten, mongocrypt_status_t status); } public interface mongocrypt_hmac_fn extends Callback { boolean hmac(Pointer ctx, mongocrypt_binary_t key, mongocrypt_binary_t in, mongocrypt_binary_t out, mongocrypt_status_t status); } public interface mongocrypt_hash_fn extends Callback { boolean hash(Pointer ctx, mongocrypt_binary_t in, mongocrypt_binary_t out, mongocrypt_status_t status); } public interface mongocrypt_random_fn extends Callback { boolean random(Pointer ctx, mongocrypt_binary_t out, int count, mongocrypt_status_t status); } /** * Allocate a new @ref mongocrypt_t object. *

* Initialize with @ref mongocrypt_init. When done, free with @ref * mongocrypt_destroy. * * @return A new @ref mongocrypt_t object. */ public static native mongocrypt_t mongocrypt_new(); /** * Set a handler to get called on every log message. * * @param crypt The @ref mongocrypt_t object. * @param log_fn The log callback. * @param log_ctx A context passed as an argument to the log callback every * invokation. * @return A boolean indicating success. */ public static native boolean mongocrypt_setopt_log_handler(mongocrypt_t crypt, mongocrypt_log_fn_t log_fn, Pointer log_ctx); public static native boolean mongocrypt_setopt_crypto_hooks(mongocrypt_t crypt, mongocrypt_crypto_fn aes_256_cbc_encrypt, mongocrypt_crypto_fn aes_256_cbc_decrypt, mongocrypt_random_fn random, mongocrypt_hmac_fn hmac_sha_512, mongocrypt_hmac_fn hmac_sha_256, mongocrypt_hash_fn sha_256, Pointer ctx); /** * Set a crypto hook for the AES256-CTR operations. * * @param crypt The @ref mongocrypt_t object. * @param aes_256_ctr_encrypt The crypto callback function for encrypt * operation. * @param aes_256_ctr_decrypt The crypto callback function for decrypt * operation. * @param ctx A context passed as an argument to the crypto callback * every invocation. * @return A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_status * */ public static native boolean mongocrypt_setopt_aes_256_ctr (mongocrypt_t crypt, mongocrypt_crypto_fn aes_256_ctr_encrypt, mongocrypt_crypto_fn aes_256_ctr_decrypt, Pointer ctx); /** * Set a crypto hook for the RSASSA-PKCS1-v1_5 algorithm with a SHA-256 hash. * *

See: https://tools.ietf.org/html/rfc3447#section-8.2

* *

Note: this function has the wrong name. It should be: * mongocrypt_setopt_crypto_hook_sign_rsassa_pkcs1_v1_5

* * @param crypt The @ref mongocrypt_t object. * @param sign_rsaes_pkcs1_v1_5 The crypto callback function. * @param sign_ctx A context passed as an argument to the crypto callback * every invocation. * @return A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_status */ public static native boolean mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5( mongocrypt_t crypt, mongocrypt_hmac_fn sign_rsaes_pkcs1_v1_5, Pointer sign_ctx); /** * Set a handler to get called on every log message. * * @param crypt The @ref mongocrypt_t object. * @param aws_access_key_id The AWS access key ID used to generate KMS * messages. * @param aws_access_key_id_len The string length (in bytes) of @p * * aws_access_key_id. Pass -1 to determine the string length with strlen (must * * be NULL terminated). * @param aws_secret_access_key The AWS secret access key used to generate * KMS messages. * @param aws_secret_access_key_len The string length (in bytes) of @p * aws_secret_access_key. Pass -1 to determine the string length with strlen * (must be NULL terminated). * @return A boolean indicating success. */ public static native boolean mongocrypt_setopt_kms_provider_aws(mongocrypt_t crypt, cstring aws_access_key_id, int aws_access_key_id_len, cstring aws_secret_access_key, int aws_secret_access_key_len); /** * Configure a local KMS provider on the @ref mongocrypt_t object. * * @param crypt The @ref mongocrypt_t object. * @param key A 64 byte master key used to encrypt and decrypt key vault keys. * @return A boolean indicating success. */ public static native boolean mongocrypt_setopt_kms_provider_local(mongocrypt_t crypt, mongocrypt_binary_t key); /** * Configure KMS providers with a BSON document. * * @param crypt The @ref mongocrypt_t object. * @param kms_providers A BSON document mapping the KMS provider names to credentials. * @return A boolean indicating success. If false, an error status is set. * @since 1.1 */ public static native boolean mongocrypt_setopt_kms_providers(mongocrypt_t crypt, mongocrypt_binary_t kms_providers); /** * Set a local schema map for encryption. * * @param crypt The @ref mongocrypt_t object. * @param schema_map A BSON document representing the schema map supplied by * the user. The keys are collection namespaces and values are JSON schemas. * @return A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_status */ public static native boolean mongocrypt_setopt_schema_map (mongocrypt_t crypt, mongocrypt_binary_t schema_map); /** * Opt-into setting KMS providers before each KMS request. * * If set, before entering the MONGOCRYPT_CTX_NEED_KMS state, * contexts will enter the MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS state * and then wait for credentials to be supplied through @ref mongocrypt_ctx_provide_kms_providers. * * @param crypt The @ref mongocrypt_t object to update */ public static native void mongocrypt_setopt_use_need_kms_credentials_state (mongocrypt_t crypt); /** * Set a local EncryptedFieldConfigMap for encryption. * * @param crypt The @ref mongocrypt_t object. * @param encryptedFieldConfigMap A BSON document representing the EncryptedFieldConfigMap * supplied by the user. The keys are collection namespaces and values are * EncryptedFieldConfigMap documents. The viewed data copied. It is valid to * destroy @p efc_map with @ref mongocrypt_binary_destroy immediately after. * @return A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_status */ public static native boolean mongocrypt_setopt_encrypted_field_config_map (mongocrypt_t crypt, mongocrypt_binary_t encryptedFieldConfigMap); /** * Opt-into skipping query analysis. * *

If opted in: *

    *
  • The crypt_shared shared library will not attempt to be loaded.
  • *
  • A mongocrypt_ctx_t will never enter the MONGOCRYPT_CTX_NEED_MARKINGS state.
  • *
* * @param crypt The @ref mongocrypt_t object to update * @since 1.5 */ public static native void mongocrypt_setopt_bypass_query_analysis (mongocrypt_t crypt); /** * Set the contention factor used for explicit encryption. * The contention factor is only used for indexed Queryable Encryption. * * @param ctx The @ref mongocrypt_ctx_t object. * @param contention_factor the contention factor * @return A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status. * @since 1.5 */ public static native boolean mongocrypt_ctx_setopt_contention_factor (mongocrypt_ctx_t ctx, long contention_factor); /** * Set the index key id to use for Queryable Encryption explicit encryption. * * If the index key id not set, the key id from @ref mongocrypt_ctx_setopt_key_id is used. * * @param ctx The @ref mongocrypt_ctx_t object. * @param key_id The binary corresponding to the _id (a UUID) of the data key to use from * the key vault collection. Note, the UUID must be encoded with RFC-4122 byte order. * The viewed data is copied. It is valid to destroy key_id with @ref mongocrypt_binary_destroy immediately after. * @return A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status * @since 1.5 */ public static native boolean mongocrypt_ctx_setopt_index_key_id (mongocrypt_ctx_t ctx, mongocrypt_binary_t key_id); /** * Append an additional search directory to the search path for loading * the crypt_shared dynamic library. * * @param crypt The @ref mongocrypt_t object to update * @param path A null-terminated sequence of bytes for the search path. On * some filesystems, this may be arbitrary bytes. On other filesystems, this may * be required to be a valid UTF-8 code unit sequence. If the leading element of * the path is the literal string "$ORIGIN", that substring will be replaced * with the directory path containing the executable libmongocrypt module. If * the path string is literal "$SYSTEM", then libmongocrypt will defer to the * system's library resolution mechanism to find the crypt_shared library. * *

If no crypt_shared dynamic library is found in any of the directories * specified by the search paths loaded here, @ref mongocrypt_init() will still * succeed and continue to operate without crypt_shared.

* *

The search paths are searched in the order that they are appended. This * allows one to provide a precedence in how the library will be discovered. For * example, appending known directories before appending "$SYSTEM" will allow * one to supersede the system's installed library, but still fall-back to it if * the library wasn't found otherwise. If one does not ever append "$SYSTEM", * then the system's library-search mechanism will never be consulted.

* *

If an absolute path to the library is specified using @ref mongocrypt_setopt_set_crypt_shared_lib_path_override, * then paths appended here will have no effect.

* @since 1.5 */ public static native void mongocrypt_setopt_append_crypt_shared_lib_search_path (mongocrypt_t crypt, cstring path); /** * Set a single override path for loading the crypt_shared dynamic library. * @param crypt The @ref mongocrypt_t object to update * @param path A null-terminated sequence of bytes for a path to the crypt_shared * dynamic library. On some filesystems, this may be arbitrary bytes. On other * filesystems, this may be required to be a valid UTF-8 code unit sequence. If * the leading element of the path is the literal string `$ORIGIN`, that * substring will be replaced with the directory path containing the executable * libmongocrypt module. * *

This function will do no IO nor path validation. All validation will * occur during the call to @ref mongocrypt_init.

*

If a crypt_shared library path override is specified here, then no paths given * to @ref mongocrypt_setopt_append_crypt_shared_lib_search_path will be consulted when * opening the crypt_shared library.

*

If a path is provided via this API and @ref mongocrypt_init fails to * initialize a valid crypt_shared library instance for the path specified, then * the initialization of mongocrypt_t will fail with an error.

* @since 1.5 */ public static native void mongocrypt_setopt_set_crypt_shared_lib_path_override(mongocrypt_t crypt, cstring path); /** * Set the query type to use for Queryable Encryption explicit encryption. * The query type is only used for indexed Queryable Encryption. * * @param ctx The @ref mongocrypt_ctx_t object. * @param query_type the query type * @param len the length * @return A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ public static native boolean mongocrypt_ctx_setopt_query_type (mongocrypt_ctx_t ctx, cstring query_type, int len); /** * Set options for explicit encryption with the "range" algorithm. * NOTE: "range" is currently unstable API and subject to backwards breaking changes. * * opts is a BSON document of the form: * { * "min": Optional<BSON value>, * "max": Optional<BSON value>, * "sparsity": Int64, * "precision": Optional<Int32> * "trimFactor": Optional<Int32> * } * * @param ctx The @ref mongocrypt_ctx_t object. * @param opts BSON. * @return A boolean indicating success. If false, an error status is set. * @since 1.7 */ public static native boolean mongocrypt_ctx_setopt_algorithm_range (mongocrypt_ctx_t ctx, mongocrypt_binary_t opts); /** * Initialize new @ref mongocrypt_t object. * * @param crypt The @ref mongocrypt_t object. * @return A boolean indicating success. Failure may occur if previously set options are invalid. */ public static native boolean mongocrypt_init(mongocrypt_t crypt); /** * Get the status associated with a @ref mongocrypt_t object. * * @param crypt The @ref mongocrypt_t object. * @param status Receives the status. * @return A boolean indicating success. */ public static native boolean mongocrypt_status(mongocrypt_t crypt, mongocrypt_status_t status); /** * Returns true if libmongocrypt was built with native crypto support. * *

* If libmongocrypt was not built with native crypto support, setting crypto hooks is required. *

* * @return true if libmongocrypt was built with native crypto support */ public static native boolean mongocrypt_is_crypto_available(); /** * Destroy the @ref mongocrypt_t object. * * @param crypt The @ref mongocrypt_t object to destroy. */ public static native void mongocrypt_destroy(mongocrypt_t crypt); /** * Obtain a nul-terminated version string of the loaded crypt_shared dynamic library, * if available. * * If no crypt_shared was successfully loaded, this function returns NULL. * * @param crypt The mongocrypt_t object after a successful call to mongocrypt_init. * @param len an optional length of the returned string. May be NULL. * * @return A nul-terminated string of the dynamically loaded crypt_shared library. * @since 1.5 */ public static native cstring mongocrypt_crypt_shared_lib_version_string (mongocrypt_t crypt, Pointer len); /** * Call in response to the MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS state * to set per-context KMS provider settings. These follow the same format * as @ref mongocrypt_setopt_kms_providers. If no keys are present in the * BSON input, the KMS provider settings configured for the @ref mongocrypt_t * at initialization are used. * * @param ctx The @ref mongocrypt_ctx_t object. * @param kms_providers A BSON document mapping the KMS provider names * to credentials. * @return A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status. */ public static native boolean mongocrypt_ctx_provide_kms_providers (mongocrypt_ctx_t ctx, mongocrypt_binary_t kms_providers); /** * Set the key id to use for explicit encryption. * * @param ctx The @ref mongocrypt_ctx_t object. * @param key_id The key_id to use. * @return A boolean indicating success. */ public static native boolean mongocrypt_ctx_setopt_key_id (mongocrypt_ctx_t ctx, mongocrypt_binary_t key_id); /** * Set the keyAltName to use for explicit encryption. * keyAltName should be a binary encoding a bson document * with the following format: { "keyAltName" : >BSON UTF8 value< } * *

It is an error to set both this and the key id.

* * @param ctx The @ref mongocrypt_ctx_t object. * @param key_alt_name The name to use. * @return A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ public static native boolean mongocrypt_ctx_setopt_key_alt_name (mongocrypt_ctx_t ctx, mongocrypt_binary_t key_alt_name); /** * Set the keyMaterial to use for encrypting data. * *

* Pass the binary encoding of a BSON document like the following: * { "keyMaterial" : (BSON BINARY value) } *

* * @param ctx The @ref mongocrypt_ctx_t object. * @param key_material The data encryption key to use. The viewed data is * copied. It is valid to destroy @p key_material with @ref * mongocrypt_binary_destroy immediately after. * @return A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ public static native boolean mongocrypt_ctx_setopt_key_material (mongocrypt_ctx_t ctx, mongocrypt_binary_t key_material); /** * Set the algorithm used for encryption to either * deterministic or random encryption. This value * should only be set when using explicit encryption. * * If -1 is passed in for "len", then "algorithm" is * assumed to be a null-terminated string. * * Valid values for algorithm are: * "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" * "AEAD_AES_256_CBC_HMAC_SHA_512-Randomized" * * @param ctx The @ref mongocrypt_ctx_t object. * @param algorithm A string specifying the algorithm to * use for encryption. * @param len The length of the algorithm string. * @return A boolean indicating success. */ public static native boolean mongocrypt_ctx_setopt_algorithm (mongocrypt_ctx_t ctx, cstring algorithm, int len); /** * Create a new uninitialized @ref mongocrypt_ctx_t. *

* Initialize the context with functions like @ref mongocrypt_ctx_encrypt_init. * When done, destroy it with @ref mongocrypt_ctx_destroy. * * @param crypt The @ref mongocrypt_t object. * @return A new context. */ public static native mongocrypt_ctx_t mongocrypt_ctx_new(mongocrypt_t crypt); /** * Get the status associated with a @ref mongocrypt_ctx_t object. * * @param ctx The @ref mongocrypt_ctx_t object. * @param status Receives the status. * @return A boolean indicating success. */ public static native boolean mongocrypt_ctx_status(mongocrypt_ctx_t ctx, mongocrypt_status_t status); /** * Identify the AWS KMS master key to use for creating a data key. * * @param ctx The @ref mongocrypt_ctx_t object. * @param region The AWS region. * @param region_len The string length of @p region. Pass -1 to determine * the string length with strlen (must be NULL terminated). * @param cmk The Amazon Resource Name (ARN) of the customer master key * (CMK). * @param cmk_len The string length of @p cmk_len. Pass -1 to determine the * string length with strlen (must be NULL terminated). * @return A boolean indicating success. */ public static native boolean mongocrypt_ctx_setopt_masterkey_aws (mongocrypt_ctx_t ctx, cstring region, int region_len, cstring cmk, int cmk_len); /** * Identify a custom AWS endpoint when creating a data key. * This is used internally to construct the correct HTTP request * (with the Host header set to this endpoint). This endpoint * is persisted in the new data key, and will be returned via * mongocrypt_kms_ctx_endpoint. * * @param ctx The @ref mongocrypt_ctx_t object. * @param endpoint The endpoint. * @param endpoint_len The string length of @p endpoint. Pass -1 to * determine the string length with strlen (must be NULL terminated). * @return A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ public static native boolean mongocrypt_ctx_setopt_masterkey_aws_endpoint (mongocrypt_ctx_t ctx, cstring endpoint, int endpoint_len); /** * Set the master key to "local" for creating a data key. * * @param ctx The @ref mongocrypt_ctx_t object. * @return A boolean indicating success. */ public static native boolean mongocrypt_ctx_setopt_masterkey_local (mongocrypt_ctx_t ctx); /** * Set key encryption key document for creating a data key. * * @param ctx The @ref mongocrypt_ctx_t object. * @param keyDocument BSON representing the key encryption key document. * @return A boolean indicating success. If false, and error status is set. * @since 1.1 */ public static native boolean mongocrypt_ctx_setopt_key_encryption_key(mongocrypt_ctx_t ctx, mongocrypt_binary_t keyDocument); /** * Initialize a context to create a data key. * * Set options before using @ref mongocrypt_ctx_setopt_masterkey_aws and * mongocrypt_ctx_setopt_masterkey_local. * * @param ctx The @ref mongocrypt_ctx_t object. * @return A boolean indicating success. * * Assumes a master key option has been set, and an associated KMS provider * has been set on the parent @ref mongocrypt_t. */ public static native boolean mongocrypt_ctx_datakey_init (mongocrypt_ctx_t ctx); /** * Initialize a context for encryption. * * Associated options: * - @ref mongocrypt_ctx_setopt_cache_noblock * - @ref mongocrypt_ctx_setopt_schema * * @param ctx The @ref mongocrypt_ctx_t object. * @param db The database name. * @param db_len The byte length of @p db. Pass -1 to determine the string length with strlen (must be NULL terminated). * @param cmd The BSON command to be encrypted. * @return A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ public static native boolean mongocrypt_ctx_encrypt_init(mongocrypt_ctx_t ctx, cstring db, int db_len, mongocrypt_binary_t cmd); /** * Explicit helper method to encrypt a single BSON object. Contexts * created for explicit encryption will not go through mongocryptd. * * To specify a key_id, algorithm, or iv to use, please use the * corresponding mongocrypt_setopt methods before calling this. * * This method expects the passed-in BSON to be of the form: * { "v" : BSON value to encrypt } * * @param ctx A @ref mongocrypt_ctx_t. * @param msg A @ref mongocrypt_binary_t the plaintext BSON value. * @return A boolean indicating success. */ public static native boolean mongocrypt_ctx_explicit_encrypt_init (mongocrypt_ctx_t ctx, mongocrypt_binary_t msg); /** * Explicit helper method to encrypt a Match Expression or Aggregate Expression. * Contexts created for explicit encryption will not go through mongocryptd. * Requires query_type to be "range". * NOTE: "range" is currently unstable API and subject to backwards breaking changes. * * This method expects the passed-in BSON to be of the form: * { "v" : FLE2RangeFindDriverSpec } * * FLE2RangeFindDriverSpec is a BSON document with one of these forms: * * 1. A Match Expression of this form: * {$and: [{<field>: {<op>: <value1>, {<field>: {<op>: <value2> }}]} * 2. An Aggregate Expression of this form: * {$and: [{<op>: [<fieldpath>, <value1>]}, {<op>: [<fieldpath>, <value2>]}] * * may be $lt, $lte, $gt, or $gte. * * The value of "v" is expected to be the BSON value passed to a driver * ClientEncryption.encryptExpression helper. * * Associated options for FLE 1: * - @ref mongocrypt_ctx_setopt_key_id * - @ref mongocrypt_ctx_setopt_key_alt_name * - @ref mongocrypt_ctx_setopt_algorithm * * Associated options for Queryable Encryption: * - @ref mongocrypt_ctx_setopt_key_id * - @ref mongocrypt_ctx_setopt_index_key_id * - @ref mongocrypt_ctx_setopt_contention_factor * - @ref mongocrypt_ctx_setopt_query_type * - @ref mongocrypt_ctx_setopt_algorithm_range * * An error is returned if FLE 1 and Queryable Encryption incompatible options * are set. * * @param ctx A @ref mongocrypt_ctx_t. * @param msg A @ref mongocrypt_binary_t the plaintext BSON value. * @return A boolean indicating success. * @since 1.7 */ public static native boolean mongocrypt_ctx_explicit_encrypt_expression_init (mongocrypt_ctx_t ctx, mongocrypt_binary_t msg); /** * Initialize a context for decryption. * * @param ctx The mongocrypt_ctx_t object. * @param doc The document to be decrypted. * @return A boolean indicating success. */ public static native boolean mongocrypt_ctx_decrypt_init(mongocrypt_ctx_t ctx, mongocrypt_binary_t doc); /** * Explicit helper method to decrypt a single BSON object. * * @param ctx A @ref mongocrypt_ctx_t. * @param msg A @ref mongocrypt_binary_t the encrypted BSON. * @return A boolean indicating success. */ public static native boolean mongocrypt_ctx_explicit_decrypt_init (mongocrypt_ctx_t ctx, mongocrypt_binary_t msg); /** * Initialize a context to rewrap datakeys. * * Associated options {@link #mongocrypt_ctx_setopt_key_encryption_key(mongocrypt_ctx_t, mongocrypt_binary_t)} * * @param ctx The @ref mongocrypt_ctx_t object. * @param filter The filter to use for the find command on the key vault collection to retrieve datakeys to rewrap. * @return A boolean indicating success. If false, and error status is set. * @since 1.5 */ public static native boolean mongocrypt_ctx_rewrap_many_datakey_init (mongocrypt_ctx_t ctx, mongocrypt_binary_t filter); public static final int MONGOCRYPT_CTX_ERROR = 0; public static final int MONGOCRYPT_CTX_NEED_MONGO_COLLINFO = 1; /* run on main MongoClient */ public static final int MONGOCRYPT_CTX_NEED_MONGO_MARKINGS = 2; /* run on mongocryptd. */ public static final int MONGOCRYPT_CTX_NEED_MONGO_KEYS = 3; /* run on key vault */ public static final int MONGOCRYPT_CTX_NEED_KMS = 4; public static final int MONGOCRYPT_CTX_READY = 5; /* ready for encryption/decryption */ public static final int MONGOCRYPT_CTX_DONE = 6; public static final int MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS = 7; /* fetch/renew KMS credentials */ public static final int MONGOCRYPT_INDEX_TYPE_NONE = 1; public static final int MONGOCRYPT_INDEX_TYPE_EQUALITY = 2; public static final int MONGOCRYPT_QUERY_TYPE_EQUALITY = 1; /** * Get the current state of a context. * * @param ctx The @ref mongocrypt_ctx_t object. * @return A @ref mongocrypt_ctx_state_t. */ public static native int mongocrypt_ctx_state(mongocrypt_ctx_t ctx); /** * Get BSON necessary to run the mongo operation when mongocrypt_ctx_t * is in MONGOCRYPT_CTX_NEED_MONGO_* states. * *

* op_bson is a BSON document to be used for the operation. * - For MONGOCRYPT_CTX_NEED_MONGO_COLLINFO it is a listCollections filter. * - For MONGOCRYPT_CTX_NEED_MONGO_KEYS it is a find filter. * - For MONGOCRYPT_CTX_NEED_MONGO_MARKINGS it is a JSON schema to append. *

* * @param ctx The @ref mongocrypt_ctx_t object. * @param op_bson A BSON document for the MongoDB operation. * @return A boolean indicating success. */ public static native boolean mongocrypt_ctx_mongo_op(mongocrypt_ctx_t ctx, mongocrypt_binary_t op_bson); /** * Feed a BSON reply or result when when mongocrypt_ctx_t is in * MONGOCRYPT_CTX_NEED_MONGO_* states. This may be called multiple times * depending on the operation. *

* op_bson is a BSON document to be used for the operation. * - For MONGOCRYPT_CTX_NEED_MONGO_COLLINFO it is a doc from a listCollections * cursor. * - For MONGOCRYPT_CTX_NEED_MONGO_KEYS it is a doc from a find cursor. * - For MONGOCRYPT_CTX_NEED_MONGO_MARKINGS it is a reply from mongocryptd. * * @param ctx The @ref mongocrypt_ctx_t object. * @param reply A BSON document for the MongoDB operation. * @return A boolean indicating success. */ public static native boolean mongocrypt_ctx_mongo_feed(mongocrypt_ctx_t ctx, mongocrypt_binary_t reply); /** * Call when done feeding the reply (or replies) back to the context. * * @param ctx The @ref mongocrypt_ctx_t object. * @return A boolean indicating success. */ public static native boolean mongocrypt_ctx_mongo_done(mongocrypt_ctx_t ctx); /** * Get the next KMS handle. *

* Multiple KMS handles may be retrieved at once. Drivers may do this to fan * out multiple concurrent KMS HTTP requests. Feeding multiple KMS requests * is thread-safe. *

* Is KMS handles are being handled synchronously, the driver can reuse the same * TLS socket to send HTTP requests and receive responses. * * @param ctx A @ref mongocrypt_ctx_t. * @return a new @ref mongocrypt_kms_ctx_t or NULL. */ public static native mongocrypt_kms_ctx_t mongocrypt_ctx_next_kms_ctx(mongocrypt_ctx_t ctx); /** * Get the KMS provider identifier associated with this KMS request. * * This is used to conditionally configure TLS connections based on the KMS * request. It is useful for KMIP, which authenticates with a client * certificate. * * @param kms The mongocrypt_kms_ctx_t object. * @param len Receives the length of the returned string. * * @return The name of the KMS provider */ public static native cstring mongocrypt_kms_ctx_get_kms_provider(mongocrypt_kms_ctx_t kms, Pointer len); /** * Get the HTTP request message for a KMS handle. * * @param kms A @ref mongocrypt_kms_ctx_t. * @param msg The HTTP request to send to KMS. * @return A boolean indicating success. */ public static native boolean mongocrypt_kms_ctx_message(mongocrypt_kms_ctx_t kms, mongocrypt_binary_t msg); /** * Get the hostname from which to connect over TLS. *

* The storage for @p endpoint is not owned by the caller, but * is valid until calling @ref mongocrypt_ctx_kms_done on the * parent @ref mongocrypt_ctx_t. * * @param kms A @ref mongocrypt_kms_ctx_t. * @param endpoint The output hostname. * @return A boolean indicating success. */ public static native boolean mongocrypt_kms_ctx_endpoint(mongocrypt_kms_ctx_t kms, PointerByReference endpoint); /** * Indicates how many bytes to feed into @ref mongocrypt_kms_ctx_feed. * * @param kms The @ref mongocrypt_kms_ctx_t. * @return The number of requested bytes. */ public static native int mongocrypt_kms_ctx_bytes_needed(mongocrypt_kms_ctx_t kms); /** * Feed bytes from the HTTP response. *

* Feeding more bytes than what has been returned in @ref * mongocrypt_kms_ctx_bytes_needed is an error. * * @param kms The @ref mongocrypt_kms_ctx_t. * @param bytes The bytes to feed. * @return A boolean indicating success. */ public static native boolean mongocrypt_kms_ctx_feed(mongocrypt_kms_ctx_t kms, mongocrypt_binary_t bytes); /** * Get the status associated with a @ref mongocrypt_kms_ctx_t object. * * @param kms The @ref mongocrypt_kms_ctx_t object. * @param status Receives the status. * @return A boolean indicating success. */ public static native boolean mongocrypt_kms_ctx_status(mongocrypt_kms_ctx_t kms, mongocrypt_status_t status); /** * Call when done handling all KMS contexts. * * @param ctx The @ref mongocrypt_ctx_t object. * @return A boolean indicating success. */ public static native boolean mongocrypt_ctx_kms_done(mongocrypt_ctx_t ctx); /** * Perform the final encryption or decryption. * * @param ctx A @ref mongocrypt_ctx_t. * @param out The final BSON to send to the server. * @return a boolean indicating success. */ public static native boolean mongocrypt_ctx_finalize(mongocrypt_ctx_t ctx, mongocrypt_binary_t out); /** * Destroy and free all memory associated with a @ref mongocrypt_ctx_t. * * @param ctx A @ref mongocrypt_ctx_t. */ public static native void mongocrypt_ctx_destroy(mongocrypt_ctx_t ctx); static final String NATIVE_LIBRARY_NAME = "mongocrypt"; static { Native.register(CAPI.class, NATIVE_LIBRARY_NAME); } } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/CAPIHelper.java000066400000000000000000000071401465326363200330500ustar00rootroot00000000000000/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.mongodb.crypt.capi.CAPI.mongocrypt_binary_t; import com.sun.jna.Pointer; import org.bson.BsonBinaryWriter; import org.bson.BsonDocument; import org.bson.RawBsonDocument; import org.bson.codecs.BsonValueCodecProvider; import org.bson.codecs.Codec; import org.bson.codecs.EncoderContext; import org.bson.codecs.configuration.CodecRegistries; import org.bson.codecs.configuration.CodecRegistry; import org.bson.io.BasicOutputBuffer; import java.nio.ByteBuffer; import static com.mongodb.crypt.capi.CAPI.mongocrypt_binary_data; import static com.mongodb.crypt.capi.CAPI.mongocrypt_binary_len; import static com.mongodb.crypt.capi.CAPI.mongocrypt_binary_new_from_data; import static java.lang.String.format; final class CAPIHelper { private static final CodecRegistry CODEC_REGISTRY = CodecRegistries.fromProviders(new BsonValueCodecProvider()); @SuppressWarnings("unchecked") static BinaryHolder toBinary(final BsonDocument document) { BasicOutputBuffer buffer = new BasicOutputBuffer(); BsonBinaryWriter writer = new BsonBinaryWriter(buffer); ((Codec) CODEC_REGISTRY.get(document.getClass())).encode(writer, document, EncoderContext.builder().build()); DisposableMemory memory = new DisposableMemory(buffer.size()); memory.write(0, buffer.getInternalBuffer(), 0, buffer.size()); return new BinaryHolder(memory, mongocrypt_binary_new_from_data(memory, buffer.getSize())); } static RawBsonDocument toDocument(final mongocrypt_binary_t binary) { ByteBuffer byteBuffer = toByteBuffer(binary); byte[] bytes = new byte[byteBuffer.remaining()]; byteBuffer.get(bytes); return new RawBsonDocument(bytes); } static BinaryHolder toBinary(final ByteBuffer buffer) { byte[] message = new byte[buffer.remaining()]; buffer.get(message, 0, buffer.remaining()); DisposableMemory memory = new DisposableMemory(message.length); memory.write(0, message, 0, message.length); return new BinaryHolder(memory, mongocrypt_binary_new_from_data(memory, message.length)); } static ByteBuffer toByteBuffer(final mongocrypt_binary_t binary) { Pointer pointer = binary.data(); int length = binary.len(); return pointer.getByteBuffer(0, length); } static byte[] toByteArray(final mongocrypt_binary_t binary) { ByteBuffer byteBuffer = toByteBuffer(binary); byte[] byteArray = new byte[byteBuffer.remaining()]; byteBuffer.get(byteArray); return byteArray; } static void writeByteArrayToBinary(final mongocrypt_binary_t binary, byte[] bytes) { if (binary.len() < bytes.length) { throw new IllegalArgumentException(format("mongocrypt binary of length %d is not large enough to hold %d bytes", binary.len(), bytes.length)); } Pointer outPointer = binary.data(); outPointer.write(0, bytes, 0, bytes.length); } private CAPIHelper() { } } CipherCallback.java000066400000000000000000000066031465326363200337470ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.mongodb.crypt.capi.CAPI.cstring; import com.mongodb.crypt.capi.CAPI.mongocrypt_binary_t; import com.mongodb.crypt.capi.CAPI.mongocrypt_crypto_fn; import com.mongodb.crypt.capi.CAPI.mongocrypt_status_t; import com.sun.jna.Pointer; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.security.NoSuchAlgorithmException; import java.util.concurrent.ConcurrentLinkedDeque; import static com.mongodb.crypt.capi.CAPI.MONGOCRYPT_STATUS_ERROR_CLIENT; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status_set; import static com.mongodb.crypt.capi.CAPIHelper.toByteArray; import static com.mongodb.crypt.capi.CAPIHelper.writeByteArrayToBinary; class CipherCallback implements mongocrypt_crypto_fn { private final String algorithm; private final String transformation; private final int mode; private final CipherPool cipherPool; CipherCallback(final String algorithm, final String transformation, final int mode) { this.algorithm = algorithm; this.transformation = transformation; this.mode = mode; this.cipherPool = new CipherPool(); } @Override public boolean crypt(final Pointer ctx, final mongocrypt_binary_t key, final mongocrypt_binary_t iv, final mongocrypt_binary_t in, final mongocrypt_binary_t out, final Pointer bytesWritten, final mongocrypt_status_t status) { Cipher cipher = null; try { IvParameterSpec ivParameterSpec = new IvParameterSpec(toByteArray(iv)); SecretKeySpec secretKeySpec = new SecretKeySpec(toByteArray(key), algorithm); cipher = cipherPool.get(); cipher.init(mode, secretKeySpec, ivParameterSpec); byte[] result = cipher.doFinal(toByteArray(in)); writeByteArrayToBinary(out, result); bytesWritten.setInt(0, result.length); return true; } catch (Exception e) { mongocrypt_status_set(status, MONGOCRYPT_STATUS_ERROR_CLIENT, 0, new cstring(e.toString()), -1); return false; } finally { if (cipher != null) { cipherPool.release(cipher); } } } private class CipherPool { private final ConcurrentLinkedDeque available = new ConcurrentLinkedDeque<>(); Cipher get() throws NoSuchAlgorithmException, NoSuchPaddingException { Cipher cipher = available.pollLast(); if (cipher != null) { return cipher; } return Cipher.getInstance(transformation); } void release(final Cipher cipher) { available.addLast(cipher); } } } DisposableMemory.java000066400000000000000000000016271465326363200343770ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.sun.jna.Memory; // Subclass of JNA's Memory class so that we can call its protected dispose method class DisposableMemory extends Memory { DisposableMemory(final int size) { super(size); } public void dispose() { super.dispose(); } } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/JULLogger.java000066400000000000000000000056561465326363200330000ustar00rootroot00000000000000 /* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import java.util.logging.Level; import static java.util.logging.Level.FINE; import static java.util.logging.Level.FINER; import static java.util.logging.Level.INFO; import static java.util.logging.Level.SEVERE; import static java.util.logging.Level.WARNING; class JULLogger implements Logger { private final java.util.logging.Logger delegate; JULLogger(final String name) { this.delegate = java.util.logging.Logger.getLogger(name); } @Override public String getName() { return delegate.getName(); } @Override public boolean isTraceEnabled() { return isEnabled(FINER); } @Override public void trace(final String msg) { log(FINER, msg); } @Override public void trace(final String msg, final Throwable t) { log(FINER, msg, t); } @Override public boolean isDebugEnabled() { return isEnabled(FINE); } @Override public void debug(final String msg) { log(FINE, msg); } @Override public void debug(final String msg, final Throwable t) { log(FINE, msg, t); } @Override public boolean isInfoEnabled() { return delegate.isLoggable(INFO); } @Override public void info(final String msg) { log(INFO, msg); } @Override public void info(final String msg, final Throwable t) { log(INFO, msg, t); } @Override public boolean isWarnEnabled() { return delegate.isLoggable(WARNING); } @Override public void warn(final String msg) { log(WARNING, msg); } @Override public void warn(final String msg, final Throwable t) { log(WARNING, msg, t); } @Override public boolean isErrorEnabled() { return delegate.isLoggable(SEVERE); } @Override public void error(final String msg) { log(SEVERE, msg); } @Override public void error(final String msg, final Throwable t) { log(SEVERE, msg, t); } private boolean isEnabled(final Level level) { return delegate.isLoggable(level); } private void log(final Level level, final String msg) { delegate.log(level, msg); } public void log(final Level level, final String msg, final Throwable t) { delegate.log(level, msg, t); } } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/Logger.java000066400000000000000000000073741465326363200324240ustar00rootroot00000000000000 /* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; /** * Not part of the public API */ public interface Logger { /** * Return the name of this Logger instance. * * @return name of this logger instance */ String getName(); /** * Is the logger instance enabled for the TRACE level? * * @return True if this Logger is enabled for the TRACE level, false otherwise. */ boolean isTraceEnabled(); /** * Log a message at the TRACE level. * * @param msg the message string to be logged */ void trace(String msg); /** * Log an exception (throwable) at the TRACE level with an accompanying message. * * @param msg the message accompanying the exception * @param t the exception (throwable) to log */ void trace(String msg, Throwable t); /** * Is the logger instance enabled for the DEBUG level? * * @return True if this Logger is enabled for the DEBUG level, false otherwise. */ boolean isDebugEnabled(); /** * Log a message at the DEBUG level. * * @param msg the message string to be logged */ void debug(String msg); /** * Log an exception (throwable) at the DEBUG level with an accompanying message. * * @param msg the message accompanying the exception * @param t the exception (throwable) to log */ void debug(String msg, Throwable t); /** * Is the logger instance enabled for the INFO level? * * @return True if this Logger is enabled for the INFO level, false otherwise. */ boolean isInfoEnabled(); /** * Log a message at the INFO level. * * @param msg the message string to be logged */ void info(String msg); /** * Log an exception (throwable) at the INFO level with an accompanying message. * * @param msg the message accompanying the exception * @param t the exception (throwable) to log */ void info(String msg, Throwable t); /** * Is the logger instance enabled for the WARN level? * * @return True if this Logger is enabled for the WARN level, false otherwise. */ boolean isWarnEnabled(); /** * Log a message at the WARN level. * * @param msg the message string to be logged */ void warn(String msg); /** * Log an exception (throwable) at the WARN level with an accompanying message. * * @param msg the message accompanying the exception * @param t the exception (throwable) to log */ void warn(String msg, Throwable t); /** * Is the logger instance enabled for the ERROR level? * * @return True if this Logger is enabled for the ERROR level, false otherwise. */ boolean isErrorEnabled(); /** * Log a message at the ERROR level. * * @param msg the message string to be logged */ void error(String msg); /** * Log an exception (throwable) at the ERROR level with an accompanying message. * * @param msg the message accompanying the exception * @param t the exception (throwable) to log */ void error(String msg, Throwable t); } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/Loggers.java000066400000000000000000000024601465326363200325760ustar00rootroot00000000000000/* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; /** * This class is not part of the public API. */ public final class Loggers { private static final String NAME = "org.mongodb.driver.crypt"; private static final boolean USE_SLF4J = shouldUseSLF4J(); /** * @return the logger */ public static Logger getLogger() { if (USE_SLF4J) { return new SLF4JLogger(NAME); } else { return new JULLogger(NAME); } } private Loggers() { } private static boolean shouldUseSLF4J() { try { Class.forName("org.slf4j.Logger"); return true; } catch (ClassNotFoundException e) { return false; } } } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/MacCallback.java000066400000000000000000000041151465326363200333100ustar00rootroot00000000000000/* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.mongodb.crypt.capi.CAPI.cstring; import com.mongodb.crypt.capi.CAPI.mongocrypt_binary_t; import com.mongodb.crypt.capi.CAPI.mongocrypt_hmac_fn; import com.mongodb.crypt.capi.CAPI.mongocrypt_status_t; import com.sun.jna.Pointer; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import static com.mongodb.crypt.capi.CAPI.MONGOCRYPT_STATUS_ERROR_CLIENT; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status_set; import static com.mongodb.crypt.capi.CAPIHelper.toByteArray; import static com.mongodb.crypt.capi.CAPIHelper.writeByteArrayToBinary; class MacCallback implements mongocrypt_hmac_fn { private final String algorithm; MacCallback(final String algorithm) { this.algorithm = algorithm; } @Override public boolean hmac(final Pointer ctx, final mongocrypt_binary_t key, final mongocrypt_binary_t in, final mongocrypt_binary_t out, final mongocrypt_status_t status) { try { Mac mac = Mac.getInstance(algorithm); SecretKeySpec keySpec = new SecretKeySpec(toByteArray(key), algorithm); mac.init(keySpec); mac.update(toByteArray(in)); byte[] result = mac.doFinal(); writeByteArrayToBinary(out, result); return true; } catch (Exception e) { mongocrypt_status_set(status, MONGOCRYPT_STATUS_ERROR_CLIENT, 0, new cstring(e.toString()), -1); return false; } } } MessageDigestCallback.java000066400000000000000000000037411465326363200352610ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.mongodb.crypt.capi.CAPI.cstring; import com.mongodb.crypt.capi.CAPI.mongocrypt_binary_t; import com.mongodb.crypt.capi.CAPI.mongocrypt_hash_fn; import com.mongodb.crypt.capi.CAPI.mongocrypt_status_t; import com.sun.jna.Pointer; import java.security.MessageDigest; import static com.mongodb.crypt.capi.CAPI.MONGOCRYPT_STATUS_ERROR_CLIENT; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status_set; import static com.mongodb.crypt.capi.CAPIHelper.toByteArray; import static com.mongodb.crypt.capi.CAPIHelper.writeByteArrayToBinary; class MessageDigestCallback implements mongocrypt_hash_fn { private final String algorithm; MessageDigestCallback(final String algorithm) { this.algorithm = algorithm; } @Override public boolean hash(final Pointer ctx, final mongocrypt_binary_t in, final mongocrypt_binary_t out, final mongocrypt_status_t status) { try { MessageDigest messageDigest = MessageDigest.getInstance(algorithm); messageDigest.update(toByteArray(in)); byte[] digest = messageDigest.digest(); writeByteArrayToBinary(out, digest); return true; } catch (Exception e) { mongocrypt_status_set(status, MONGOCRYPT_STATUS_ERROR_CLIENT, 0, new cstring(e.toString()), -1); return false; } } } MongoAwsKmsProviderOptions.java000066400000000000000000000052261465326363200364140ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import static org.bson.assertions.Assertions.notNull; /** * The options for configuring the AWS KMS provider. */ public class MongoAwsKmsProviderOptions { private final String accessKeyId; private final String secretAccessKey; /** * Construct a builder for the options * * @return the builder */ public static Builder builder() { return new Builder(); } /** * Gets the access key id * * @return the access key id, which may not be null */ public String getAccessKeyId() { return accessKeyId; } /** * Gets the secret access key * * @return the secret access key, which may not be null */ public String getSecretAccessKey() { return secretAccessKey; } /** * The builder for the options */ public static class Builder { private String accessKeyId; private String secretAccessKey; private Builder() { } /** * Sets the access key id. * * @param accessKeyId the access key id * @return this */ public Builder accessKeyId(final String accessKeyId) { this.accessKeyId = accessKeyId; return this; } /** * Sets the secret access key. * * @param secretAccessKey the secret access key * @return this */ public Builder secretAccessKey(final String secretAccessKey) { this.secretAccessKey = secretAccessKey; return this; } /** * Build the options. * * @return the options */ public MongoAwsKmsProviderOptions build() { return new MongoAwsKmsProviderOptions(this); } } private MongoAwsKmsProviderOptions(final Builder builder) { this.accessKeyId = notNull("AWS KMS provider accessKeyId", builder.accessKeyId); this.secretAccessKey = notNull("AWS KMS provider secretAccessKey", builder.secretAccessKey); } } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/MongoCrypt.java000066400000000000000000000063201465326363200332740ustar00rootroot00000000000000/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import org.bson.BsonDocument; import java.io.Closeable; /** * A context for encryption/decryption operations. */ public interface MongoCrypt extends Closeable { /** * Create a context to use for encryption * * @param database the namespace * @param command the document representing the command to encrypt * @return the context */ MongoCryptContext createEncryptionContext(String database, final BsonDocument command); /** * Create a context to use for decryption * * @param document the document to decrypt * @return the context */ MongoCryptContext createDecryptionContext(BsonDocument document); /** * Create a context to use for creating a data key * @param kmsProvider the KMS provider * @param options the data key options * @return the context */ MongoCryptContext createDataKeyContext(String kmsProvider, MongoDataKeyOptions options); /** * Create a context to use for encryption * * @param document the document to encrypt, which must be in the form { "v" : BSON value to encrypt } * @param options the explicit encryption options * @return the context */ MongoCryptContext createExplicitEncryptionContext(BsonDocument document, MongoExplicitEncryptOptions options); /** * Create a context to use for encryption * * @param document the document to encrypt, which must be in the form { "v" : BSON value to encrypt } * @param options the expression encryption options * @return the context * @since 1.7 */ MongoCryptContext createEncryptExpressionContext(BsonDocument document, MongoExplicitEncryptOptions options); /** * Create a context to use for encryption * * @param document the document to decrypt,which must be in the form { "v" : encrypted BSON value } * @return the context */ MongoCryptContext createExplicitDecryptionContext(BsonDocument document); /** * Create a context to use for encryption * * @param filter The filter to use for the find command on the key vault collection to retrieve datakeys to rewrap. * @param options the rewrap many data key options * @return the context * @since 1.5 */ MongoCryptContext createRewrapManyDatakeyContext(BsonDocument filter, MongoRewrapManyDataKeyOptions options); /** * @return the version string of the loaded crypt shared dynamic library if available or null * @since 1.5 */ String getCryptSharedLibVersionString(); @Override void close(); } MongoCryptContext.java000066400000000000000000000065071465326363200345710ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import org.bson.BsonDocument; import org.bson.RawBsonDocument; import java.io.Closeable; /** * An interface representing the lifecycle of an encryption or decryption request. It's modelled as a state machine. */ public interface MongoCryptContext extends Closeable { /** * The possible states. */ enum State { /** * Needs collection information from the cluster encrypting to */ NEED_MONGO_COLLINFO(CAPI.MONGOCRYPT_CTX_NEED_MONGO_COLLINFO), /** * Need to mark command with encryption markers */ NEED_MONGO_MARKINGS(CAPI.MONGOCRYPT_CTX_NEED_MONGO_MARKINGS), /** * Need keys from the key vault */ NEED_MONGO_KEYS(CAPI.MONGOCRYPT_CTX_NEED_MONGO_KEYS), /** * Need the key management service */ NEED_KMS(CAPI.MONGOCRYPT_CTX_NEED_KMS), /** * Need to fetch/renew KMS credentials * @since 1.4 */ NEED_KMS_CREDENTIALS(CAPI.MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS), /** * Ready for encryption/decryption */ READY(CAPI.MONGOCRYPT_CTX_READY), /** * Done */ DONE(CAPI.MONGOCRYPT_CTX_DONE); private final int index; State(final int index) { this.index = index; } static State fromIndex(final int index) { for (State state : State.values()) { if (state.index == index) { return state; } } throw new MongoCryptException("Unknown context state " + index); } } /** * Gets the current state. * * @return the current state */ State getState(); /** * * @return the operation to execute */ RawBsonDocument getMongoOperation(); /** * * @param document a result of the operation */ void addMongoOperationResult(BsonDocument document); /** * Signal completion of the operation */ void completeMongoOperation(); /** * Provide KMS credentials on demand, in response to NEED_KMS_CREDENTIALS state * * @param credentialsDocument document containing all credentials * @since 1.4 */ void provideKmsProviderCredentials(BsonDocument credentialsDocument); /** * * @return the next key decryptor, or null if there are no more */ MongoKeyDecryptor nextKeyDecryptor(); /** * Indicate that all key decryptors have been completed */ void completeKeyDecryptors(); /** * * @return the encrypted or decrypted document */ RawBsonDocument finish(); @Override void close(); } MongoCryptContextImpl.java000066400000000000000000000125631465326363200354120ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.mongodb.crypt.capi.CAPI.mongocrypt_binary_t; import com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_t; import com.mongodb.crypt.capi.CAPI.mongocrypt_kms_ctx_t; import org.bson.BsonDocument; import org.bson.RawBsonDocument; import static com.mongodb.crypt.capi.CAPI.mongocrypt_binary_destroy; import static com.mongodb.crypt.capi.CAPI.mongocrypt_binary_new; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_destroy; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_finalize; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_kms_done; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_mongo_done; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_mongo_feed; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_mongo_op; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_next_kms_ctx; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_provide_kms_providers; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_state; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_status; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status_destroy; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status_new; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status_t; import static com.mongodb.crypt.capi.CAPIHelper.toBinary; import static com.mongodb.crypt.capi.CAPIHelper.toDocument; import static org.bson.assertions.Assertions.isTrue; import static org.bson.assertions.Assertions.notNull; class MongoCryptContextImpl implements MongoCryptContext { private final mongocrypt_ctx_t wrapped; private volatile boolean closed; MongoCryptContextImpl(final mongocrypt_ctx_t wrapped) { notNull("wrapped", wrapped); this.wrapped = wrapped; } @Override public State getState() { isTrue("open", !closed); return State.fromIndex(mongocrypt_ctx_state(wrapped)); } @Override public RawBsonDocument getMongoOperation() { isTrue("open", !closed); mongocrypt_binary_t binary = mongocrypt_binary_new(); try { boolean success = mongocrypt_ctx_mongo_op(wrapped, binary); if (!success) { throwExceptionFromStatus(); } return toDocument(binary); } finally { mongocrypt_binary_destroy(binary); } } @Override public void addMongoOperationResult(final BsonDocument document) { isTrue("open", !closed); try (BinaryHolder binaryHolder = toBinary(document)) { boolean success = mongocrypt_ctx_mongo_feed(wrapped, binaryHolder.getBinary()); if (!success) { throwExceptionFromStatus(); } } } @Override public void completeMongoOperation() { isTrue("open", !closed); boolean success = mongocrypt_ctx_mongo_done(wrapped); if (!success) { throwExceptionFromStatus(); } } @Override public void provideKmsProviderCredentials(final BsonDocument credentialsDocument) { try (BinaryHolder binaryHolder = toBinary(credentialsDocument)) { boolean success = mongocrypt_ctx_provide_kms_providers(wrapped, binaryHolder.getBinary()); if (!success) { throwExceptionFromStatus(); } } } @Override public MongoKeyDecryptor nextKeyDecryptor() { isTrue("open", !closed); mongocrypt_kms_ctx_t kmsContext = mongocrypt_ctx_next_kms_ctx(wrapped); if (kmsContext == null) { return null; } return new MongoKeyDecryptorImpl(kmsContext); } @Override public void completeKeyDecryptors() { isTrue("open", !closed); boolean success = mongocrypt_ctx_kms_done(wrapped); if (!success) { throwExceptionFromStatus(); } } @Override public RawBsonDocument finish() { isTrue("open", !closed); mongocrypt_binary_t binary = mongocrypt_binary_new(); try { boolean success = mongocrypt_ctx_finalize(wrapped, binary); if (!success) { throwExceptionFromStatus(); } return toDocument(binary); } finally { mongocrypt_binary_destroy(binary); } } @Override public void close() { mongocrypt_ctx_destroy(wrapped); closed = true; } static void throwExceptionFromStatus(final mongocrypt_ctx_t wrapped) { mongocrypt_status_t status = mongocrypt_status_new(); mongocrypt_ctx_status(wrapped, status); MongoCryptException e = new MongoCryptException(status); mongocrypt_status_destroy(status); throw e; } private void throwExceptionFromStatus() { throwExceptionFromStatus(wrapped); } } MongoCryptException.java000066400000000000000000000035461465326363200351030ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.mongodb.crypt.capi.CAPI.mongocrypt_status_t; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status_code; import static org.bson.assertions.Assertions.isTrue; /** * Top level Exception for all Mongo Crypt CAPI exceptions */ public class MongoCryptException extends RuntimeException { private static final long serialVersionUID = -5524416583514807953L; private final int code; /** * @param msg the message */ public MongoCryptException(final String msg) { super(msg); this.code = -1; } /** * @param msg the message * @param cause the cause */ public MongoCryptException(final String msg, Throwable cause) { super(msg, cause); this.code = -1; } /** * Construct an instance from a {@code mongocrypt_status_t}. * * @param status the status */ MongoCryptException(final mongocrypt_status_t status) { super(CAPI.mongocrypt_status_message(status, null).toString()); isTrue("status not ok", !CAPI.mongocrypt_status_ok(status)); code = mongocrypt_status_code(status); } /** * @return the error code for the exception. */ public int getCode() { return code; } } MongoCryptImpl.java000066400000000000000000000473071465326363200340510ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.mongodb.crypt.capi.CAPI.cstring; import com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_t; import com.mongodb.crypt.capi.CAPI.mongocrypt_log_fn_t; import com.mongodb.crypt.capi.CAPI.mongocrypt_status_t; import com.mongodb.crypt.capi.CAPI.mongocrypt_t; import com.sun.jna.Pointer; import org.bson.BsonBinary; import org.bson.BsonDocument; import org.bson.BsonString; import javax.crypto.Cipher; import java.nio.ByteBuffer; import java.security.SecureRandom; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; import static com.mongodb.crypt.capi.CAPI.MONGOCRYPT_LOG_LEVEL_ERROR; import static com.mongodb.crypt.capi.CAPI.MONGOCRYPT_LOG_LEVEL_FATAL; import static com.mongodb.crypt.capi.CAPI.MONGOCRYPT_LOG_LEVEL_INFO; import static com.mongodb.crypt.capi.CAPI.MONGOCRYPT_LOG_LEVEL_TRACE; import static com.mongodb.crypt.capi.CAPI.MONGOCRYPT_LOG_LEVEL_WARNING; import static com.mongodb.crypt.capi.CAPI.mongocrypt_crypt_shared_lib_version_string; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_datakey_init; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_decrypt_init; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_encrypt_init; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_explicit_decrypt_init; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_explicit_encrypt_expression_init; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_explicit_encrypt_init; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_new; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_rewrap_many_datakey_init; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_setopt_algorithm; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_setopt_algorithm_range; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_setopt_contention_factor; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_setopt_key_alt_name; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_setopt_key_encryption_key; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_setopt_key_id; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_setopt_key_material; import static com.mongodb.crypt.capi.CAPI.mongocrypt_ctx_setopt_query_type; import static com.mongodb.crypt.capi.CAPI.mongocrypt_destroy; import static com.mongodb.crypt.capi.CAPI.mongocrypt_init; import static com.mongodb.crypt.capi.CAPI.mongocrypt_is_crypto_available; import static com.mongodb.crypt.capi.CAPI.mongocrypt_new; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_aes_256_ctr; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_append_crypt_shared_lib_search_path; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_bypass_query_analysis; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_crypto_hooks; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_encrypted_field_config_map; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_kms_provider_aws; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_kms_provider_local; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_kms_providers; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_log_handler; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_schema_map; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_set_crypt_shared_lib_path_override; import static com.mongodb.crypt.capi.CAPI.mongocrypt_setopt_use_need_kms_credentials_state; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status_destroy; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status_new; import static com.mongodb.crypt.capi.CAPIHelper.toBinary; import static org.bson.assertions.Assertions.isTrue; import static org.bson.assertions.Assertions.notNull; class MongoCryptImpl implements MongoCrypt { private static final Logger LOGGER = Loggers.getLogger(); private final mongocrypt_t wrapped; // Keep a strong reference to all the callbacks so that they don't get garbage collected @SuppressWarnings("FieldCanBeLocal") private final LogCallback logCallback; @SuppressWarnings("FieldCanBeLocal") private final CipherCallback aesCBC256EncryptCallback; @SuppressWarnings("FieldCanBeLocal") private final CipherCallback aesCBC256DecryptCallback; @SuppressWarnings("FieldCanBeLocal") private final CipherCallback aesCTR256EncryptCallback; @SuppressWarnings("FieldCanBeLocal") private final CipherCallback aesCTR256DecryptCallback; @SuppressWarnings("FieldCanBeLocal") private final MacCallback hmacSha512Callback; @SuppressWarnings("FieldCanBeLocal") private final MacCallback hmacSha256Callback; @SuppressWarnings("FieldCanBeLocal") private final MessageDigestCallback sha256Callback; @SuppressWarnings("FieldCanBeLocal") private final SecureRandomCallback secureRandomCallback; @SuppressWarnings("FieldCanBeLocal") private final SigningRSAESPKCSCallback signingRSAESPKCSCallback; private final AtomicBoolean closed; MongoCryptImpl(final MongoCryptOptions options) { closed = new AtomicBoolean(); wrapped = mongocrypt_new(); if (wrapped == null) { throw new MongoCryptException("Unable to create new mongocrypt object"); } logCallback = new LogCallback(); configure(() -> mongocrypt_setopt_log_handler(wrapped, logCallback, null)); if (mongocrypt_is_crypto_available()) { LOGGER.debug("libmongocrypt is compiled with cryptography support, so not registering Java callbacks"); aesCBC256EncryptCallback = null; aesCBC256DecryptCallback = null; aesCTR256EncryptCallback = null; aesCTR256DecryptCallback = null; hmacSha512Callback = null; hmacSha256Callback = null; sha256Callback = null; secureRandomCallback = null; signingRSAESPKCSCallback = null; } else { LOGGER.debug("libmongocrypt is compiled without cryptography support, so registering Java callbacks"); // We specify NoPadding here because the underlying C library is responsible for padding prior // to executing the callback aesCBC256EncryptCallback = new CipherCallback("AES", "AES/CBC/NoPadding", Cipher.ENCRYPT_MODE); aesCBC256DecryptCallback = new CipherCallback("AES", "AES/CBC/NoPadding", Cipher.DECRYPT_MODE); aesCTR256EncryptCallback = new CipherCallback("AES", "AES/CTR/NoPadding", Cipher.ENCRYPT_MODE); aesCTR256DecryptCallback = new CipherCallback("AES", "AES/CTR/NoPadding", Cipher.DECRYPT_MODE); hmacSha512Callback = new MacCallback("HmacSHA512"); hmacSha256Callback = new MacCallback("HmacSHA256"); sha256Callback = new MessageDigestCallback("SHA-256"); secureRandomCallback = new SecureRandomCallback(new SecureRandom()); configure(() -> mongocrypt_setopt_crypto_hooks(wrapped, aesCBC256EncryptCallback, aesCBC256DecryptCallback, secureRandomCallback, hmacSha512Callback, hmacSha256Callback, sha256Callback, null)); signingRSAESPKCSCallback = new SigningRSAESPKCSCallback(); configure(() -> mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5(wrapped, signingRSAESPKCSCallback, null)); configure(() -> mongocrypt_setopt_aes_256_ctr(wrapped, aesCTR256EncryptCallback, aesCTR256DecryptCallback, null)); } if (options.getLocalKmsProviderOptions() != null) { try (BinaryHolder localMasterKeyBinaryHolder = toBinary(options.getLocalKmsProviderOptions().getLocalMasterKey())) { configure(() -> mongocrypt_setopt_kms_provider_local(wrapped, localMasterKeyBinaryHolder.getBinary())); } } if (options.getAwsKmsProviderOptions() != null) { configure(() -> mongocrypt_setopt_kms_provider_aws(wrapped, new cstring(options.getAwsKmsProviderOptions().getAccessKeyId()), -1, new cstring(options.getAwsKmsProviderOptions().getSecretAccessKey()), -1)); } if (options.isNeedsKmsCredentialsStateEnabled()) { mongocrypt_setopt_use_need_kms_credentials_state(wrapped); } if (options.getKmsProviderOptions() != null) { try (BinaryHolder binaryHolder = toBinary(options.getKmsProviderOptions())) { configure(() -> mongocrypt_setopt_kms_providers(wrapped, binaryHolder.getBinary())); } } if (options.getLocalSchemaMap() != null) { BsonDocument localSchemaMapDocument = new BsonDocument(); localSchemaMapDocument.putAll(options.getLocalSchemaMap()); try (BinaryHolder localSchemaMapBinaryHolder = toBinary(localSchemaMapDocument)) { configure(() -> mongocrypt_setopt_schema_map(wrapped, localSchemaMapBinaryHolder.getBinary())); } } if (options.isBypassQueryAnalysis()) { mongocrypt_setopt_bypass_query_analysis(wrapped); } if (options.getEncryptedFieldsMap() != null) { BsonDocument localEncryptedFieldsMap = new BsonDocument(); localEncryptedFieldsMap.putAll(options.getEncryptedFieldsMap()); try (BinaryHolder localEncryptedFieldsMapHolder = toBinary(localEncryptedFieldsMap)) { configure(() -> mongocrypt_setopt_encrypted_field_config_map(wrapped, localEncryptedFieldsMapHolder.getBinary())); } } options.getSearchPaths().forEach(p -> mongocrypt_setopt_append_crypt_shared_lib_search_path(wrapped, new cstring(p))); if (options.getExtraOptions().containsKey("cryptSharedLibPath")) { mongocrypt_setopt_set_crypt_shared_lib_path_override(wrapped, new cstring(options.getExtraOptions().getString("cryptSharedLibPath").getValue())); } configure(() -> mongocrypt_init(wrapped)); } @Override public MongoCryptContext createEncryptionContext(final String database, final BsonDocument commandDocument) { isTrue("open", !closed.get()); notNull("database", database); notNull("commandDocument", commandDocument); mongocrypt_ctx_t context = mongocrypt_ctx_new(wrapped); if (context == null) { throwExceptionFromStatus(); } try (BinaryHolder commandDocumentBinaryHolder = toBinary(commandDocument)) { configure(() -> mongocrypt_ctx_encrypt_init(context, new cstring(database), -1, commandDocumentBinaryHolder.getBinary()), context); return new MongoCryptContextImpl(context); } } @Override public MongoCryptContext createDecryptionContext(final BsonDocument document) { isTrue("open", !closed.get()); mongocrypt_ctx_t context = mongocrypt_ctx_new(wrapped); if (context == null) { throwExceptionFromStatus(); } try (BinaryHolder documentBinaryHolder = toBinary(document)){ configure(() -> mongocrypt_ctx_decrypt_init(context, documentBinaryHolder.getBinary()), context); } return new MongoCryptContextImpl(context); } @Override public MongoCryptContext createDataKeyContext(final String kmsProvider, final MongoDataKeyOptions options) { isTrue("open", !closed.get()); mongocrypt_ctx_t context = mongocrypt_ctx_new(wrapped); if (context == null) { throwExceptionFromStatus(); } BsonDocument keyDocument = new BsonDocument("provider", new BsonString(kmsProvider)); BsonDocument masterKey = options.getMasterKey(); if (masterKey != null) { masterKey.forEach(keyDocument::append); } try (BinaryHolder masterKeyHolder = toBinary(keyDocument)) { configure(() -> mongocrypt_ctx_setopt_key_encryption_key(context, masterKeyHolder.getBinary()), context); } if (options.getKeyAltNames() != null) { for (String cur : options.getKeyAltNames()) { try (BinaryHolder keyAltNameBinaryHolder = toBinary(new BsonDocument("keyAltName", new BsonString(cur)))) { configure(() -> mongocrypt_ctx_setopt_key_alt_name(context, keyAltNameBinaryHolder.getBinary()), context); } } } if (options.getKeyMaterial() != null) { try (BinaryHolder keyMaterialBinaryHolder = toBinary(new BsonDocument("keyMaterial", new BsonBinary(options.getKeyMaterial())))) { configure(() -> mongocrypt_ctx_setopt_key_material(context, keyMaterialBinaryHolder.getBinary()), context); } } if (!mongocrypt_ctx_datakey_init(context)) { MongoCryptContextImpl.throwExceptionFromStatus(context); } return new MongoCryptContextImpl(context); } @Override public MongoCryptContext createExplicitEncryptionContext(final BsonDocument document, final MongoExplicitEncryptOptions options) { isTrue("open", !closed.get()); mongocrypt_ctx_t context = configureExplicitEncryption(options); try (BinaryHolder documentBinaryHolder = toBinary(document)) { configure(() -> mongocrypt_ctx_explicit_encrypt_init(context, documentBinaryHolder.getBinary()), context); } return new MongoCryptContextImpl(context); } @Override public MongoCryptContext createEncryptExpressionContext(final BsonDocument document, final MongoExplicitEncryptOptions options) { isTrue("open", !closed.get()); mongocrypt_ctx_t context = configureExplicitEncryption(options); try (BinaryHolder documentBinaryHolder = toBinary(document)) { configure(() -> mongocrypt_ctx_explicit_encrypt_expression_init(context, documentBinaryHolder.getBinary()), context); } return new MongoCryptContextImpl(context); } @Override public MongoCryptContext createExplicitDecryptionContext(final BsonDocument document) { isTrue("open", !closed.get()); mongocrypt_ctx_t context = mongocrypt_ctx_new(wrapped); if (context == null) { throwExceptionFromStatus(); } try (BinaryHolder binaryHolder = toBinary(document)) { configure(() -> mongocrypt_ctx_explicit_decrypt_init(context, binaryHolder.getBinary()), context); } return new MongoCryptContextImpl(context); } @Override public MongoCryptContext createRewrapManyDatakeyContext(final BsonDocument filter, final MongoRewrapManyDataKeyOptions options) { isTrue("open", !closed.get()); mongocrypt_ctx_t context = mongocrypt_ctx_new(wrapped); if (context == null) { throwExceptionFromStatus(); } if (options != null && options.getProvider() != null) { BsonDocument keyDocument = new BsonDocument("provider", new BsonString(options.getProvider())); BsonDocument masterKey = options.getMasterKey(); if (masterKey != null) { masterKey.forEach(keyDocument::append); } try (BinaryHolder binaryHolder = toBinary(keyDocument)) { configure(() -> mongocrypt_ctx_setopt_key_encryption_key(context, binaryHolder.getBinary()), context); } } try (BinaryHolder binaryHolder = toBinary(filter)) { configure(() -> mongocrypt_ctx_rewrap_many_datakey_init(context, binaryHolder.getBinary()), context); } return new MongoCryptContextImpl(context); } @Override public String getCryptSharedLibVersionString() { cstring versionString = mongocrypt_crypt_shared_lib_version_string(wrapped, null); return versionString == null ? null : versionString.toString(); } @Override public void close() { if (!closed.getAndSet(true)) { mongocrypt_destroy(wrapped); } } private mongocrypt_ctx_t configureExplicitEncryption(final MongoExplicitEncryptOptions options) { mongocrypt_ctx_t context = mongocrypt_ctx_new(wrapped); if (context == null) { throwExceptionFromStatus(); } if (options.getKeyId() != null) { try (BinaryHolder keyIdBinaryHolder = toBinary(ByteBuffer.wrap(options.getKeyId().getData()))) { configure(() -> mongocrypt_ctx_setopt_key_id(context, keyIdBinaryHolder.getBinary()), context); } } else if (options.getKeyAltName() != null) { try (BinaryHolder keyAltNameBinaryHolder = toBinary(new BsonDocument("keyAltName", new BsonString(options.getKeyAltName())))) { configure(() -> mongocrypt_ctx_setopt_key_alt_name(context, keyAltNameBinaryHolder.getBinary()), context); } } if (options.getAlgorithm() != null) { configure(() -> mongocrypt_ctx_setopt_algorithm(context, new cstring(options.getAlgorithm()), -1), context); } if (options.getQueryType() != null) { configure(() -> mongocrypt_ctx_setopt_query_type(context, new cstring(options.getQueryType()), -1), context); } if (options.getContentionFactor() != null) { configure(() -> mongocrypt_ctx_setopt_contention_factor(context, options.getContentionFactor()), context); } if (options.getRangeOptions() != null) { try (BinaryHolder rangeOptionsHolder = toBinary(options.getRangeOptions())) { configure(() -> mongocrypt_ctx_setopt_algorithm_range(context, rangeOptionsHolder.getBinary()), context); } } return context; } private void configure(final Supplier successSupplier) { if (!successSupplier.get()) { throwExceptionFromStatus(); } } private void configure(final Supplier successSupplier, final mongocrypt_ctx_t context) { if (!successSupplier.get()) { MongoCryptContextImpl.throwExceptionFromStatus(context); } } private void throwExceptionFromStatus() { mongocrypt_status_t status = mongocrypt_status_new(); mongocrypt_status(wrapped, status); MongoCryptException e = new MongoCryptException(status); mongocrypt_status_destroy(status); throw e; } static class LogCallback implements mongocrypt_log_fn_t { @Override public void log(final int level, final cstring message, final int messageLength, final Pointer ctx) { if (level == MONGOCRYPT_LOG_LEVEL_FATAL) { LOGGER.error(message.toString()); } if (level == MONGOCRYPT_LOG_LEVEL_ERROR) { LOGGER.error(message.toString()); } if (level == MONGOCRYPT_LOG_LEVEL_WARNING) { LOGGER.warn(message.toString()); } if (level == MONGOCRYPT_LOG_LEVEL_INFO) { LOGGER.info(message.toString()); } if (level == MONGOCRYPT_LOG_LEVEL_TRACE) { LOGGER.trace(message.toString()); } } } } MongoCryptOptions.java000066400000000000000000000215241465326363200345740ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import org.bson.BsonDocument; import java.util.List; import java.util.Map; import static java.util.Collections.emptyList; import static org.bson.assertions.Assertions.isTrue; /** * The options for configuring MongoCrypt. */ public class MongoCryptOptions { private final MongoAwsKmsProviderOptions awsKmsProviderOptions; private final MongoLocalKmsProviderOptions localKmsProviderOptions; private final BsonDocument kmsProviderOptions; private final Map localSchemaMap; private final boolean needsKmsCredentialsStateEnabled; private final Map encryptedFieldsMap; private final BsonDocument extraOptions; private final boolean bypassQueryAnalysis; private final List searchPaths; /** * Construct a builder for the options * * @return the builder */ public static Builder builder() { return new Builder(); } /** * Gets the AWS KMS provider options. * * @return the AWS KMS provider options, which may be null */ public MongoAwsKmsProviderOptions getAwsKmsProviderOptions() { return awsKmsProviderOptions; } /** * Gets the local KMS provider options. * * @return the local KMS provider options, which may be null */ public MongoLocalKmsProviderOptions getLocalKmsProviderOptions() { return localKmsProviderOptions; } /** * Returns the KMS provider options. * * @return the KMS provider options, which may be null * @since 1.1 */ public BsonDocument getKmsProviderOptions() { return kmsProviderOptions; } /** * Gets the local schema map. * * @return the local schema map */ public Map getLocalSchemaMap() { return localSchemaMap; } /** * Gets whether the MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS is enabled. Defaults to false * * @return whether the MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS is enabled * @since 1.4 */ public boolean isNeedsKmsCredentialsStateEnabled() { return needsKmsCredentialsStateEnabled; } /** * Gets the encrypted fields map. * * @since 1.5 * @return the encrypted fields map */ public Map getEncryptedFieldsMap() { return encryptedFieldsMap; } /** * Gets whether automatic analysis of outgoing commands should be disabled. * * @since 1.5 * @return true if bypassing query analysis */ public boolean isBypassQueryAnalysis() { return bypassQueryAnalysis; } /** * The extraOptions that relate to the mongocryptd process or shared library. * @return the extra options * @since 1.5 */ public BsonDocument getExtraOptions() { return extraOptions; } /** * Gets the search paths * @return this * @since 1.5 */ public List getSearchPaths() { return searchPaths; } /** * The builder for the options */ public static class Builder { private MongoAwsKmsProviderOptions awsKmsProviderOptions; private MongoLocalKmsProviderOptions localKmsProviderOptions; private BsonDocument kmsProviderOptions = null; private Map localSchemaMap = null; private boolean needsKmsCredentialsStateEnabled; private Map encryptedFieldsMap = null; private boolean bypassQueryAnalysis; private BsonDocument extraOptions = new BsonDocument(); private List searchPaths = emptyList(); private Builder() { } /** * Sets the AWS KMS provider options. * * @param awsKmsProviderOptions the AWS KMS provider options * @return this */ public Builder awsKmsProviderOptions(final MongoAwsKmsProviderOptions awsKmsProviderOptions) { this.awsKmsProviderOptions = awsKmsProviderOptions; return this; } /** * Sets the local KMS provider options. * * @param localKmsProviderOptions the local KMS provider options * @return this */ public Builder localKmsProviderOptions(final MongoLocalKmsProviderOptions localKmsProviderOptions) { this.localKmsProviderOptions = localKmsProviderOptions; return this; } /** * Sets the KMS provider options. * * @param kmsProviderOptions the KMS provider options document * @return this * @since 1.1 */ public Builder kmsProviderOptions(final BsonDocument kmsProviderOptions) { this.kmsProviderOptions = kmsProviderOptions; return this; } /** * Sets the local schema map. * * @param localSchemaMap local schema map * @return this */ public Builder localSchemaMap(final Map localSchemaMap) { this.localSchemaMap = localSchemaMap; return this; } /** * Sets whether the MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS is enabled. Defaults to false * * @param needsKmsCredentialsStateEnabled whether the MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS is enabled * @return this * @since 1.4 */ public Builder needsKmsCredentialsStateEnabled(final boolean needsKmsCredentialsStateEnabled) { this.needsKmsCredentialsStateEnabled = needsKmsCredentialsStateEnabled; return this; } /** * Sets the encrypted fields map. * * @param encryptedFieldsMap the encrypted fields map * @since 1.5 * @return this */ public Builder encryptedFieldsMap(final Map encryptedFieldsMap) { this.encryptedFieldsMap = encryptedFieldsMap; return this; } /** * Sets whether automatic analysis of outgoing commands should be disabled. * *

Set bypassQueryAnalysis to true to use explicit encryption on indexed fields * without the MongoDB Enterprise Advanced licensed crypt shared library.

* * @param bypassQueryAnalysis whether the analysis of outgoing commands should be disabled. * @since 1.5 * @return this */ public Builder bypassQueryAnalysis(final boolean bypassQueryAnalysis) { this.bypassQueryAnalysis = bypassQueryAnalysis; return this; } /** * The extraOptions that relate to the mongocryptd process or shared library. * @param extraOptions the extraOptions * @return this * @since 1.5 */ public Builder extraOptions(final BsonDocument extraOptions) { this.extraOptions = extraOptions; return this; } /** * Sets search paths * @param searchPaths sets search path * @return this * @since 1.5 */ public Builder searchPaths(final List searchPaths) { this.searchPaths = searchPaths; return this; } /** * Build the options. * * @return the options */ public MongoCryptOptions build() { return new MongoCryptOptions(this); } } private MongoCryptOptions(final Builder builder) { isTrue("at least one KMS provider is configured", builder.awsKmsProviderOptions != null || builder.localKmsProviderOptions != null || builder.kmsProviderOptions != null ); this.awsKmsProviderOptions = builder.awsKmsProviderOptions; this.localKmsProviderOptions = builder.localKmsProviderOptions; this.kmsProviderOptions = builder.kmsProviderOptions; this.localSchemaMap = builder.localSchemaMap; this.needsKmsCredentialsStateEnabled = builder.needsKmsCredentialsStateEnabled; this.encryptedFieldsMap = builder.encryptedFieldsMap; this.bypassQueryAnalysis = builder.bypassQueryAnalysis; this.extraOptions = builder.extraOptions; this.searchPaths = builder.searchPaths; } } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/MongoCrypts.java000066400000000000000000000021411465326363200334540ustar00rootroot00000000000000/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; /** * The entry point to the MongoCrypt library. */ public class MongoCrypts { /** * Create a {@code MongoCrypt} instance. * *

* Make sure that JNA is able to find the shared library, most likely by setting the jna.library.path system property *

* * @param options the options * @return the instance */ public static MongoCrypt create(MongoCryptOptions options) { return new MongoCryptImpl(options); } } MongoDataKeyOptions.java000066400000000000000000000061101465326363200350070ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import org.bson.BsonDocument; import java.util.List; /** * The options for creation of a data key */ public class MongoDataKeyOptions { private final List keyAltNames; private final BsonDocument masterKey; private final byte[] keyMaterial; /** * Options builder */ public static class Builder { private List keyAltNames; private BsonDocument masterKey; private byte[] keyMaterial; /** * Add alternate key names * @param keyAltNames the alternate key names * @return this */ public Builder keyAltNames(final List keyAltNames) { this.keyAltNames = keyAltNames; return this; } /** * Add the master key. * * @param masterKey the master key * @return this */ public Builder masterKey(final BsonDocument masterKey) { this.masterKey = masterKey; return this; } /** * Add the key material * * @param keyMaterial the optional custom key material for the data key * @return this * @since 1.5 */ public Builder keyMaterial(final byte[] keyMaterial) { this.keyMaterial = keyMaterial; return this; } /** * Build the options. * * @return the options */ public MongoDataKeyOptions build() { return new MongoDataKeyOptions(this); } } /** * Create a builder for the options. * * @return the builder */ public static Builder builder() { return new Builder(); } /** * Gets the alternate key names for the data key. * * @return the alternate key names */ public List getKeyAltNames() { return keyAltNames; } /** * Gets the master key for the data key. * * @return the master key */ public BsonDocument getMasterKey() { return masterKey; } /** * Gets the custom key material if set. * * @return the custom key material for the data key or null * @since 1.5 */ public byte[] getKeyMaterial() { return keyMaterial; } private MongoDataKeyOptions(final Builder builder) { keyAltNames = builder.keyAltNames; masterKey = builder.masterKey; keyMaterial = builder.keyMaterial; } } MongoExplicitEncryptOptions.java000066400000000000000000000144421465326363200366220ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import org.bson.BsonBinary; import org.bson.BsonDocument; import java.util.Objects; /** * Options for explicit encryption. */ public class MongoExplicitEncryptOptions { private final BsonBinary keyId; private final String keyAltName; private final String algorithm; private final Long contentionFactor; private final String queryType; private final BsonDocument rangeOptions; /** * The builder for the options */ public static class Builder { private BsonBinary keyId; private String keyAltName; private String algorithm; private Long contentionFactor; private String queryType; private BsonDocument rangeOptions; private Builder() { } /** * Add the key identifier. * * @param keyId the key idenfifier * @return this */ public Builder keyId(final BsonBinary keyId) { this.keyId = keyId; return this; } /** * Add the key alternative name. * * @param keyAltName the key alternative name * @return this */ public Builder keyAltName(final String keyAltName) { this.keyAltName = keyAltName; return this; } /** * Add the encryption algorithm. * *

To insert or query with an "Indexed" encrypted payload, use a MongoClient configured with {@code AutoEncryptionSettings}. * {@code AutoEncryptionSettings.bypassQueryAnalysis} may be true. * {@code AutoEncryptionSettings.bypassAutoEncryption must be false}.

* * @param algorithm the encryption algorithm * @return this */ public Builder algorithm(final String algorithm) { this.algorithm = algorithm; return this; } /** * The contention factor. * *

It is an error to set contentionFactor when algorithm is not "Indexed". * @param contentionFactor the contention factor * @return this * @since 1.5 */ public Builder contentionFactor(final Long contentionFactor) { this.contentionFactor = contentionFactor; return this; } /** * The QueryType. * *

It is an error to set queryType when algorithm is not "Indexed".

* * @param queryType the query type * @return this * @since 1.5 */ public Builder queryType(final String queryType) { this.queryType = queryType; return this; } /** * The Range Options. * *

It is an error to set rangeOptions when the algorithm is not "range".

* * @param rangeOptions the range options * @return this * @since 1.7 */ public Builder rangeOptions(final BsonDocument rangeOptions) { this.rangeOptions = rangeOptions; return this; } /** * Build the options. * * @return the options */ public MongoExplicitEncryptOptions build() { return new MongoExplicitEncryptOptions(this); } } /** * Create a builder for the options. * * @return the builder */ public static Builder builder() { return new Builder(); } /** * Gets the key identifier * @return the key identifier */ public BsonBinary getKeyId() { return keyId; } /** * Gets the key alternative name * @return the key alternative name */ public String getKeyAltName() { return keyAltName; } /** * Gets the encryption algorithm * @return the encryption algorithm */ public String getAlgorithm() { return algorithm; } /** * Gets the contention factor * @return the contention factor * @since 1.5 */ public Long getContentionFactor() { return contentionFactor; } /** * Gets the query type * @return the query type * @since 1.5 */ public String getQueryType() { return queryType; } /** * Gets the range options * @return the range options * @since 1.7 */ public BsonDocument getRangeOptions() { return rangeOptions; } private MongoExplicitEncryptOptions(Builder builder) { this.keyId = builder.keyId; this.keyAltName = builder.keyAltName; this.algorithm = builder.algorithm; this.contentionFactor = builder.contentionFactor; this.queryType = builder.queryType; this.rangeOptions = builder.rangeOptions; if (!(Objects.equals(algorithm, "Indexed") || Objects.equals(algorithm, "Range"))) { if (contentionFactor != null) { throw new IllegalStateException( "Invalid configuration, contentionFactor can only be set if algorithm is 'Indexed' or 'Range'"); } else if (queryType != null) { throw new IllegalStateException( "Invalid configuration, queryType can only be set if algorithm is 'Indexed' or 'Range'"); } } } @Override public String toString() { return "MongoExplicitEncryptOptions{" + "keyId=" + keyId + ", keyAltName='" + keyAltName + '\'' + ", algorithm='" + algorithm + '\'' + ", contentionFactor=" + contentionFactor + ", queryType='" + queryType + '\'' + ", rangeOptions=" + rangeOptions + '}'; } } MongoKeyDecryptor.java000066400000000000000000000044131465326363200345410ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import java.nio.ByteBuffer; /** * An interface representing a key decryption operation using a key management service. */ public interface MongoKeyDecryptor { /** * Gets the name of the KMS provider, e.g. "aws" or "kmip" * * @return the KMS provider name */ String getKmsProvider(); /** * Gets the host name of the key management service. * * @return the host name */ String getHostName(); /** * Gets the message to send to the key management service. * *

* Clients should call this method first, and send the message on a TLS connection to a configured KMS server. *

* * @return the message to send */ ByteBuffer getMessage(); /** * Gets the number of bytes that should be received from the KMS server. * *

* After sending the message to the KMS server, clients should call this method in a loop, receiving {@code bytesNeeded} from * the KMS server and feeding those bytes to this decryptor, until {@code bytesNeeded} is 0. *

* * @return the actual number of bytes that clients should be prepared receive */ int bytesNeeded(); /** * Feed the received bytes to the decryptor. * *

* After sending the message to the KMS server, clients should call this method in a loop, receiving the number of bytes indicated by * a call to {@link #bytesNeeded()} from the KMS server and feeding those bytes to this decryptor, until {@link #bytesNeeded()} * returns 0. *

* * @param bytes the received bytes */ void feed(ByteBuffer bytes); } MongoKeyDecryptorImpl.java000066400000000000000000000073051465326363200353660ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.mongodb.crypt.capi.CAPI.mongocrypt_binary_t; import com.mongodb.crypt.capi.CAPI.mongocrypt_kms_ctx_t; import com.mongodb.crypt.capi.CAPI.mongocrypt_status_t; import com.sun.jna.Pointer; import com.sun.jna.ptr.PointerByReference; import java.nio.ByteBuffer; import static com.mongodb.crypt.capi.CAPI.mongocrypt_binary_destroy; import static com.mongodb.crypt.capi.CAPI.mongocrypt_binary_new; import static com.mongodb.crypt.capi.CAPI.mongocrypt_kms_ctx_bytes_needed; import static com.mongodb.crypt.capi.CAPI.mongocrypt_kms_ctx_endpoint; import static com.mongodb.crypt.capi.CAPI.mongocrypt_kms_ctx_feed; import static com.mongodb.crypt.capi.CAPI.mongocrypt_kms_ctx_get_kms_provider; import static com.mongodb.crypt.capi.CAPI.mongocrypt_kms_ctx_message; import static com.mongodb.crypt.capi.CAPI.mongocrypt_kms_ctx_status; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status_destroy; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status_new; import static com.mongodb.crypt.capi.CAPIHelper.toBinary; import static com.mongodb.crypt.capi.CAPIHelper.toByteBuffer; import static org.bson.assertions.Assertions.notNull; class MongoKeyDecryptorImpl implements MongoKeyDecryptor { private final mongocrypt_kms_ctx_t wrapped; MongoKeyDecryptorImpl(final mongocrypt_kms_ctx_t wrapped) { notNull("wrapped", wrapped); this.wrapped = wrapped; } @Override public String getKmsProvider() { return mongocrypt_kms_ctx_get_kms_provider(wrapped, null).toString(); } @Override public String getHostName() { PointerByReference hostNamePointerByReference = new PointerByReference(); boolean success = mongocrypt_kms_ctx_endpoint(wrapped, hostNamePointerByReference); if (!success) { throwExceptionFromStatus(); } Pointer hostNamePointer = hostNamePointerByReference.getValue(); return hostNamePointer.getString(0); } @Override public ByteBuffer getMessage() { mongocrypt_binary_t binary = mongocrypt_binary_new(); try { boolean success = mongocrypt_kms_ctx_message(wrapped, binary); if (!success) { throwExceptionFromStatus(); } return toByteBuffer(binary); } finally { mongocrypt_binary_destroy(binary); } } @Override public int bytesNeeded() { return mongocrypt_kms_ctx_bytes_needed(wrapped); } @Override public void feed(final ByteBuffer bytes) { try (BinaryHolder binaryHolder = toBinary(bytes)) { boolean success = mongocrypt_kms_ctx_feed(wrapped, binaryHolder.getBinary()); if (!success) { throwExceptionFromStatus(); } } } private void throwExceptionFromStatus() { mongocrypt_status_t status = mongocrypt_status_new(); mongocrypt_kms_ctx_status(wrapped, status); MongoCryptException e = new MongoCryptException(status); mongocrypt_status_destroy(status); throw e; } } MongoLocalKmsProviderOptions.java000066400000000000000000000040611465326363200367100ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import java.nio.ByteBuffer; import static org.bson.assertions.Assertions.notNull; /** * The options for configuring a local KMS provider. */ public class MongoLocalKmsProviderOptions { private final ByteBuffer localMasterKey; /** * Construct a builder for the options * * @return the builder */ public static Builder builder() { return new Builder(); } /** * Gets the local master key * * @return the local master key */ public ByteBuffer getLocalMasterKey() { return localMasterKey; } /** * The builder for the options */ public static class Builder { private ByteBuffer localMasterKey; private Builder() { } /** * Sets the local master key. * * @param localMasterKey the local master key * @return this */ public Builder localMasterKey(final ByteBuffer localMasterKey) { this.localMasterKey = localMasterKey; return this; } /** * Build the options. * * @return the options */ public MongoLocalKmsProviderOptions build() { return new MongoLocalKmsProviderOptions(this); } } private MongoLocalKmsProviderOptions(final Builder builder) { this.localMasterKey = notNull("Local KMS provider localMasterKey", builder.localMasterKey); } } MongoRewrapManyDataKeyOptions.java000066400000000000000000000046751465326363200370330ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.mongodb.crypt.capi; import org.bson.BsonDocument; /** * The rewrap many data key options * *

* The masterKey document MUST have the fields corresponding to the given provider as specified in masterKey. *

* * @since 1.5 */ public class MongoRewrapManyDataKeyOptions { private final String provider; private final BsonDocument masterKey; /** * Options builder */ public static class Builder { private String provider; private BsonDocument masterKey; /** * The provider * * @param provider the provider * @return this */ public Builder provider(final String provider) { this.provider = provider; return this; } /** * Add the master key. * * @param masterKey the master key * @return this */ public Builder masterKey(final BsonDocument masterKey) { this.masterKey = masterKey; return this; } /** * Build the options. * * @return the options */ public MongoRewrapManyDataKeyOptions build() { return new MongoRewrapManyDataKeyOptions(this); } } /** * Create a builder for the options. * * @return the builder */ public static Builder builder() { return new Builder(); } /** * @return the provider name */ public String getProvider() { return provider; } /** * Gets the master key for the data key. * * @return the master key */ public BsonDocument getMasterKey() { return masterKey; } private MongoRewrapManyDataKeyOptions(final Builder builder) { provider = builder.provider; masterKey = builder.masterKey; } } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/SLF4JLogger.java000066400000000000000000000046441465326363200331640ustar00rootroot00000000000000 /* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import org.slf4j.LoggerFactory; class SLF4JLogger implements Logger { private final org.slf4j.Logger delegate; SLF4JLogger(final String name) { this.delegate = LoggerFactory.getLogger(name); } @Override public String getName() { return delegate.getName(); } @Override public boolean isTraceEnabled() { return delegate.isTraceEnabled(); } @Override public void trace(final String msg) { delegate.trace(msg); } @Override public void trace(final String msg, final Throwable t) { delegate.trace(msg, t); } @Override public boolean isDebugEnabled() { return delegate.isDebugEnabled(); } @Override public void debug(final String msg) { delegate.debug(msg); } @Override public void debug(final String msg, final Throwable t) { delegate.debug(msg, t); } @Override public boolean isInfoEnabled() { return delegate.isInfoEnabled(); } @Override public void info(final String msg) { delegate.info(msg); } @Override public void info(final String msg, final Throwable t) { delegate.info(msg, t); } @Override public boolean isWarnEnabled() { return delegate.isWarnEnabled(); } @Override public void warn(final String msg) { delegate.warn(msg); } @Override public void warn(final String msg, final Throwable t) { delegate.warn(msg, t); } @Override public boolean isErrorEnabled() { return delegate.isErrorEnabled(); } @Override public void error(final String msg) { delegate.error(msg); } @Override public void error(final String msg, final Throwable t) { delegate.error(msg, t); } } SecureRandomCallback.java000066400000000000000000000035121465326363200351200ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.mongodb.crypt.capi.CAPI.cstring; import com.mongodb.crypt.capi.CAPI.mongocrypt_binary_t; import com.mongodb.crypt.capi.CAPI.mongocrypt_random_fn; import com.mongodb.crypt.capi.CAPI.mongocrypt_status_t; import com.sun.jna.Pointer; import java.security.SecureRandom; import static com.mongodb.crypt.capi.CAPI.MONGOCRYPT_STATUS_ERROR_CLIENT; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status_set; import static com.mongodb.crypt.capi.CAPIHelper.writeByteArrayToBinary; class SecureRandomCallback implements mongocrypt_random_fn { private final SecureRandom secureRandom; SecureRandomCallback(final SecureRandom secureRandom) { this.secureRandom = secureRandom; } @Override public boolean random(final Pointer ctx, final mongocrypt_binary_t out, final int count, final mongocrypt_status_t status) { try { byte[] randomBytes = new byte[count]; secureRandom.nextBytes(randomBytes); writeByteArrayToBinary(out, randomBytes); return true; } catch (Exception e) { mongocrypt_status_set(status, MONGOCRYPT_STATUS_ERROR_CLIENT, 0, new cstring(e.toString()), -1); return false; } } } SigningRSAESPKCSCallback.java000066400000000000000000000056411465326363200354130ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/* * Copyright 2008-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.mongodb.crypt.capi.CAPI.cstring; import com.mongodb.crypt.capi.CAPI.mongocrypt_binary_t; import com.mongodb.crypt.capi.CAPI.mongocrypt_hmac_fn; import com.mongodb.crypt.capi.CAPI.mongocrypt_status_t; import com.sun.jna.Pointer; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.Signature; import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.security.spec.PKCS8EncodedKeySpec; import static com.mongodb.crypt.capi.CAPI.MONGOCRYPT_STATUS_ERROR_CLIENT; import static com.mongodb.crypt.capi.CAPI.mongocrypt_status_set; import static com.mongodb.crypt.capi.CAPIHelper.toByteArray; import static com.mongodb.crypt.capi.CAPIHelper.writeByteArrayToBinary; class SigningRSAESPKCSCallback implements mongocrypt_hmac_fn { private static final String KEY_ALGORITHM = "RSA"; private static final String SIGN_ALGORITHM = "SHA256withRSA"; SigningRSAESPKCSCallback() { } @Override public boolean hmac(final Pointer ctx, final mongocrypt_binary_t key, final mongocrypt_binary_t in, final mongocrypt_binary_t out, final mongocrypt_status_t status) { try { byte[] result = getSignature(toByteArray(key), toByteArray(in)); writeByteArrayToBinary(out, result); return true; } catch (Exception e) { mongocrypt_status_set(status, MONGOCRYPT_STATUS_ERROR_CLIENT, 0, new cstring(e.toString()), -1); return false; } } static byte[] getSignature(final byte[] privateKeyBytes, final byte[] dataToSign) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException { KeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PrivateKey privateKey = keyFactory.generatePrivate(keySpec); Signature privateSignature = Signature.getInstance(SIGN_ALGORITHM); privateSignature.initSign(privateKey); privateSignature.update(dataToSign); return privateSignature.sign(); } } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/package-info.java000066400000000000000000000011771465326363200335240ustar00rootroot00000000000000/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/resources/000077500000000000000000000000001465326363200251405ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/resources/META-INF/000077500000000000000000000000001465326363200263005ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/resources/META-INF/native-image/000077500000000000000000000000001465326363200306465ustar00rootroot00000000000000jni-config.json000066400000000000000000000163421465326363200335130ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/resources/META-INF/native-image[ { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_crypto_fn", "methods":[{"name":"crypt","parameterTypes":["com.sun.jna.Pointer","com.mongodb.crypt.capi.CAPI$mongocrypt_binary_t","com.mongodb.crypt.capi.CAPI$mongocrypt_binary_t","com.mongodb.crypt.capi.CAPI$mongocrypt_binary_t","com.mongodb.crypt.capi.CAPI$mongocrypt_binary_t","com.sun.jna.Pointer","com.mongodb.crypt.capi.CAPI$mongocrypt_status_t"] }] }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_hash_fn", "methods":[{"name":"hash","parameterTypes":["com.sun.jna.Pointer","com.mongodb.crypt.capi.CAPI$mongocrypt_binary_t","com.mongodb.crypt.capi.CAPI$mongocrypt_binary_t","com.mongodb.crypt.capi.CAPI$mongocrypt_status_t"] }] }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_hmac_fn", "methods":[{"name":"hmac","parameterTypes":["com.sun.jna.Pointer","com.mongodb.crypt.capi.CAPI$mongocrypt_binary_t","com.mongodb.crypt.capi.CAPI$mongocrypt_binary_t","com.mongodb.crypt.capi.CAPI$mongocrypt_binary_t","com.mongodb.crypt.capi.CAPI$mongocrypt_status_t"] }] }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_log_fn_t", "methods":[{"name":"log","parameterTypes":["int","com.mongodb.crypt.capi.CAPI$cstring","int","com.sun.jna.Pointer"] }] }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_random_fn", "methods":[{"name":"random","parameterTypes":["com.sun.jna.Pointer","com.mongodb.crypt.capi.CAPI$mongocrypt_binary_t","int","com.mongodb.crypt.capi.CAPI$mongocrypt_status_t"] }] }, { "name":"com.sun.jna.Callback" }, { "name":"com.sun.jna.CallbackReference", "methods":[{"name":"getCallback","parameterTypes":["java.lang.Class","com.sun.jna.Pointer","boolean"] }, {"name":"getFunctionPointer","parameterTypes":["com.sun.jna.Callback","boolean"] }, {"name":"getNativeString","parameterTypes":["java.lang.Object","boolean"] }, {"name":"initializeThread","parameterTypes":["com.sun.jna.Callback","com.sun.jna.CallbackReference$AttachOptions"] }] }, { "name":"com.sun.jna.CallbackReference$AttachOptions" }, { "name":"com.sun.jna.FromNativeConverter", "methods":[{"name":"nativeType","parameterTypes":[] }] }, { "name":"com.sun.jna.IntegerType", "fields":[{"name":"value"}] }, { "name":"com.sun.jna.JNIEnv" }, { "name":"com.sun.jna.Native", "methods":[{"name":"dispose","parameterTypes":[] }, {"name":"fromNative","parameterTypes":["com.sun.jna.FromNativeConverter","java.lang.Object","java.lang.reflect.Method"] }, {"name":"fromNative","parameterTypes":["java.lang.Class","java.lang.Object"] }, {"name":"fromNative","parameterTypes":["java.lang.reflect.Method","java.lang.Object"] }, {"name":"nativeType","parameterTypes":["java.lang.Class"] }, {"name":"toNative","parameterTypes":["com.sun.jna.ToNativeConverter","java.lang.Object"] }] }, { "name":"com.sun.jna.Native$ffi_callback", "methods":[{"name":"invoke","parameterTypes":["long","long","long"] }] }, { "name":"com.sun.jna.NativeMapped", "methods":[{"name":"toNative","parameterTypes":[] }] }, { "name":"com.sun.jna.Pointer", "fields":[{"name":"peer"}], "methods":[{"name":"","parameterTypes":["long"] }] }, { "name":"com.sun.jna.PointerType", "fields":[{"name":"pointer"}] }, { "name":"com.sun.jna.Structure", "fields":[{"name":"memory"}, {"name":"typeInfo"}], "methods":[{"name":"autoRead","parameterTypes":[] }, {"name":"autoWrite","parameterTypes":[] }, {"name":"getTypeInfo","parameterTypes":[] }, {"name":"newInstance","parameterTypes":["java.lang.Class","long"] }] }, { "name":"com.sun.jna.Structure$ByValue" }, { "name":"com.sun.jna.Structure$FFIType$FFITypes", "fields":[{"name":"ffi_type_double"}, {"name":"ffi_type_float"}, {"name":"ffi_type_longdouble"}, {"name":"ffi_type_pointer"}, {"name":"ffi_type_sint16"}, {"name":"ffi_type_sint32"}, {"name":"ffi_type_sint64"}, {"name":"ffi_type_sint8"}, {"name":"ffi_type_uint16"}, {"name":"ffi_type_uint32"}, {"name":"ffi_type_uint64"}, {"name":"ffi_type_uint8"}, {"name":"ffi_type_void"}] }, { "name":"com.sun.jna.WString", "methods":[{"name":"","parameterTypes":["java.lang.String"] }] }, { "name":"java.lang.Boolean", "fields":[{"name":"TYPE"}, {"name":"value"}], "methods":[{"name":"","parameterTypes":["boolean"] }, {"name":"getBoolean","parameterTypes":["java.lang.String"] }] }, { "name":"java.lang.Byte", "fields":[{"name":"TYPE"}, {"name":"value"}], "methods":[{"name":"","parameterTypes":["byte"] }] }, { "name":"java.lang.Character", "fields":[{"name":"TYPE"}, {"name":"value"}], "methods":[{"name":"","parameterTypes":["char"] }] }, { "name":"java.lang.Class", "methods":[{"name":"getComponentType","parameterTypes":[] }] }, { "name":"java.lang.Double", "fields":[{"name":"TYPE"}, {"name":"value"}], "methods":[{"name":"","parameterTypes":["double"] }] }, { "name":"java.lang.Float", "fields":[{"name":"TYPE"}, {"name":"value"}], "methods":[{"name":"","parameterTypes":["float"] }] }, { "name":"java.lang.Integer", "fields":[{"name":"TYPE"}, {"name":"value"}], "methods":[{"name":"","parameterTypes":["int"] }] }, { "name":"java.lang.Long", "fields":[{"name":"TYPE"}, {"name":"value"}], "methods":[{"name":"","parameterTypes":["long"] }] }, { "name":"java.lang.Object", "methods":[{"name":"toString","parameterTypes":[] }] }, { "name":"java.lang.Short", "fields":[{"name":"TYPE"}, {"name":"value"}], "methods":[{"name":"","parameterTypes":["short"] }] }, { "name":"java.lang.String", "methods":[{"name":"","parameterTypes":["byte[]"] }, {"name":"","parameterTypes":["byte[]","java.lang.String"] }, {"name":"getBytes","parameterTypes":[] }, {"name":"getBytes","parameterTypes":["java.lang.String"] }, {"name":"lastIndexOf","parameterTypes":["int"] }, {"name":"substring","parameterTypes":["int"] }, {"name":"toCharArray","parameterTypes":[] }] }, { "name":"java.lang.System", "methods":[{"name":"getProperty","parameterTypes":["java.lang.String"] }, {"name":"setProperty","parameterTypes":["java.lang.String","java.lang.String"] }] }, { "name":"java.lang.UnsatisfiedLinkError", "methods":[{"name":"","parameterTypes":["java.lang.String"] }] }, { "name":"java.lang.Void", "fields":[{"name":"TYPE"}] }, { "name":"java.lang.reflect.Method", "methods":[{"name":"getParameterTypes","parameterTypes":[] }, {"name":"getReturnType","parameterTypes":[] }] }, { "name":"java.nio.Buffer", "methods":[{"name":"position","parameterTypes":[] }] }, { "name":"java.nio.ByteBuffer", "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] }, { "name":"java.nio.CharBuffer", "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] }, { "name":"java.nio.DoubleBuffer", "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] }, { "name":"java.nio.FloatBuffer", "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] }, { "name":"java.nio.IntBuffer", "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] }, { "name":"java.nio.LongBuffer", "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] }, { "name":"java.nio.ShortBuffer", "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] } ] reflect-config.json000066400000000000000000000074621465326363200343620ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/main/resources/META-INF/native-image[ { "name":"com.mongodb.crypt.capi.CAPI", "allPublicFields":true, "queryAllDeclaredMethods":true }, { "name":"com.mongodb.crypt.capi.CAPI$cstring", "methods":[{"name":"","parameterTypes":[] }] }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_binary_t", "methods":[{"name":"","parameterTypes":[] }] }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_crypto_fn", "queryAllDeclaredMethods":true, "queryAllPublicMethods":true }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_ctx_t", "methods":[{"name":"","parameterTypes":[] }] }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_hash_fn", "queryAllDeclaredMethods":true, "queryAllPublicMethods":true }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_hmac_fn", "queryAllDeclaredMethods":true, "queryAllPublicMethods":true }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_kms_ctx_t", "methods":[{"name":"","parameterTypes":[] }] }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_log_fn_t", "queryAllDeclaredMethods":true, "queryAllPublicMethods":true }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_random_fn", "queryAllDeclaredMethods":true, "queryAllPublicMethods":true }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_status_t", "methods":[{"name":"","parameterTypes":[] }] }, { "name":"com.mongodb.crypt.capi.CAPI$mongocrypt_t", "methods":[{"name":"","parameterTypes":[] }] }, { "name":"com.sun.jna.CallbackProxy", "methods":[{"name":"callback","parameterTypes":["java.lang.Object[]"] }] }, { "name":"com.sun.jna.Pointer", "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}] }, { "name":"com.sun.jna.Structure$FFIType", "allDeclaredFields":true, "queryAllPublicConstructors":true, "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}], "methods":[{"name":"","parameterTypes":[] }] }, { "name":"com.sun.jna.Structure$FFIType$size_t", "methods":[{"name":"","parameterTypes":[] }] }, { "name":"com.sun.jna.ptr.PointerByReference", "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}], "methods":[{"name":"","parameterTypes":[] }] }, { "name":"boolean", "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}] }, { "name":"com.sun.crypto.provider.AESCipher$General", "methods":[{"name":"","parameterTypes":[] }] }, { "name":"com.sun.crypto.provider.HmacCore$HmacSHA256", "methods":[{"name":"","parameterTypes":[] }] }, { "name":"com.sun.crypto.provider.HmacCore$HmacSHA512", "methods":[{"name":"","parameterTypes":[] }] }, { "name":"int", "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}] }, { "name":"java.lang.Throwable", "methods":[{"name":"addSuppressed","parameterTypes":["java.lang.Throwable"] }] }, { "name":"java.lang.reflect.Method", "methods":[{"name":"isVarArgs","parameterTypes":[] }] }, { "name":"java.nio.Buffer" }, { "name":"long", "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}] }, { "name":"sun.security.provider.NativePRNG", "methods":[{"name":"","parameterTypes":[] }, {"name":"","parameterTypes":["java.security.SecureRandomParameters"] }] }, { "name":"sun.security.provider.SHA2$SHA256", "methods":[{"name":"","parameterTypes":[] }] }, { "name":"sun.security.provider.SHA5$SHA512", "methods":[{"name":"","parameterTypes":[] }] }, { "name":"void", "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}] }, { "name":"org.slf4j.Logger" } ] libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/000077500000000000000000000000001465326363200231615ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/java/000077500000000000000000000000001465326363200241025ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/java/com/000077500000000000000000000000001465326363200246605ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/java/com/mongodb/000077500000000000000000000000001465326363200263055ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/java/com/mongodb/crypt/000077500000000000000000000000001465326363200274465ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/java/com/mongodb/crypt/capi/000077500000000000000000000000001465326363200303625ustar00rootroot00000000000000MongoCryptTest.java000066400000000000000000000371401465326363200341140ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/java/com/mongodb/crypt/capi/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.mongodb.crypt.capi; import com.mongodb.crypt.capi.MongoCryptContext.State; import org.bson.BsonBinary; import org.bson.BsonBinarySubType; import org.bson.BsonDocument; import org.bson.BsonString; import org.bson.RawBsonDocument; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.net.URISyntaxException; import java.net.URL; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.Arrays; import java.util.Base64; import java.util.List; import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertIterableEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; @SuppressWarnings("SameParameterValue") public class MongoCryptTest { @Test public void testEncrypt() throws URISyntaxException, IOException { MongoCrypt mongoCrypt = createMongoCrypt(); assertNotNull(mongoCrypt); MongoCryptContext encryptor = mongoCrypt.createEncryptionContext("test", getResourceAsDocument("command.json")); assertEquals(State.NEED_MONGO_COLLINFO, encryptor.getState()); BsonDocument listCollectionsFilter = encryptor.getMongoOperation(); assertEquals(getResourceAsDocument("list-collections-filter.json"), listCollectionsFilter); encryptor.addMongoOperationResult(getResourceAsDocument("collection-info.json")); encryptor.completeMongoOperation(); assertEquals(State.NEED_MONGO_MARKINGS, encryptor.getState()); BsonDocument jsonSchema = encryptor.getMongoOperation(); assertEquals(getResourceAsDocument("mongocryptd-command.json"), jsonSchema); encryptor.addMongoOperationResult(getResourceAsDocument("mongocryptd-reply.json")); encryptor.completeMongoOperation(); assertEquals(State.NEED_MONGO_KEYS, encryptor.getState()); testKeyDecryptor(encryptor); assertEquals(State.READY, encryptor.getState()); RawBsonDocument encryptedDocument = encryptor.finish(); assertEquals(State.DONE, encryptor.getState()); assertEquals(getResourceAsDocument("encrypted-command.json"), encryptedDocument); encryptor.close(); mongoCrypt.close(); } @Test public void testDecrypt() throws IOException, URISyntaxException { MongoCrypt mongoCrypt = createMongoCrypt(); assertNotNull(mongoCrypt); MongoCryptContext decryptor = mongoCrypt.createDecryptionContext(getResourceAsDocument("encrypted-command-reply.json")); assertEquals(State.NEED_MONGO_KEYS, decryptor.getState()); testKeyDecryptor(decryptor); assertEquals(State.READY, decryptor.getState()); RawBsonDocument decryptedDocument = decryptor.finish(); assertEquals(State.DONE, decryptor.getState()); assertEquals(getResourceAsDocument("command-reply.json"), decryptedDocument); decryptor.close(); mongoCrypt.close(); } @Test public void testEmptyAwsCredentials() throws URISyntaxException, IOException { MongoCrypt mongoCrypt = MongoCrypts.create(MongoCryptOptions .builder() .kmsProviderOptions(new BsonDocument("aws", new BsonDocument())) .needsKmsCredentialsStateEnabled(true) .build()); MongoCryptContext decryptor = mongoCrypt.createDecryptionContext(getResourceAsDocument("encrypted-command-reply.json")); assertEquals(State.NEED_KMS_CREDENTIALS, decryptor.getState()); BsonDocument awsCredentials = new BsonDocument(); awsCredentials.put("accessKeyId", new BsonString("example")); awsCredentials.put("secretAccessKey", new BsonString("example")); decryptor.provideKmsProviderCredentials(new BsonDocument("aws", awsCredentials)); assertEquals(State.NEED_MONGO_KEYS, decryptor.getState()); mongoCrypt.close(); } @Test public void testMultipleCloseCalls() { MongoCrypt mongoCrypt = createMongoCrypt(); assertNotNull(mongoCrypt); mongoCrypt.close(); mongoCrypt.close(); } @Test public void testDataKeyCreation() { MongoCrypt mongoCrypt = createMongoCrypt(); assertNotNull(mongoCrypt); List keyAltNames = Arrays.asList("first", "second"); MongoCryptContext dataKeyContext = mongoCrypt.createDataKeyContext("local", MongoDataKeyOptions.builder().masterKey(new BsonDocument()) .keyAltNames(keyAltNames) .build()); assertEquals(State.READY, dataKeyContext.getState()); RawBsonDocument dataKeyDocument = dataKeyContext.finish(); assertEquals(State.DONE, dataKeyContext.getState()); assertNotNull(dataKeyDocument); List actualKeyAltNames = dataKeyDocument.getArray("keyAltNames").stream() .map(bsonValue -> bsonValue.asString().getValue()) .sorted() .collect(Collectors.toList()); assertIterableEquals(keyAltNames, actualKeyAltNames); dataKeyContext.close(); mongoCrypt.close(); } @Test public void testExplicitEncryptionDecryption() { MongoCrypt mongoCrypt = createMongoCrypt(); assertNotNull(mongoCrypt); BsonDocument documentToEncrypt = new BsonDocument("v", new BsonString("hello")); MongoExplicitEncryptOptions options = MongoExplicitEncryptOptions.builder() .keyId(new BsonBinary(BsonBinarySubType.UUID_STANDARD, Base64.getDecoder().decode("YWFhYWFhYWFhYWFhYWFhYQ=="))) .algorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic") .build(); MongoCryptContext encryptor = mongoCrypt.createExplicitEncryptionContext(documentToEncrypt, options); assertEquals(State.NEED_MONGO_KEYS, encryptor.getState()); testKeyDecryptor(encryptor); assertEquals(State.READY, encryptor.getState()); RawBsonDocument encryptedDocument = encryptor.finish(); assertEquals(State.DONE, encryptor.getState()); assertEquals(getResourceAsDocument("encrypted-value.json"), encryptedDocument); MongoCryptContext decryptor = mongoCrypt.createExplicitDecryptionContext(encryptedDocument); assertEquals(State.READY, decryptor.getState()); RawBsonDocument decryptedDocument = decryptor.finish(); assertEquals(State.DONE, decryptor.getState()); assertEquals(documentToEncrypt, decryptedDocument); encryptor.close(); mongoCrypt.close(); } @Test public void testExplicitExpressionEncryption() { MongoCrypt mongoCrypt = createMongoCrypt(); assertNotNull(mongoCrypt); BsonDocument valueToEncrypt = getResourceAsDocument("fle2-find-range-explicit-v2/int32/value-to-encrypt.json"); BsonDocument rangeOptions = getResourceAsDocument("fle2-find-range-explicit-v2/int32/rangeopts.json"); BsonDocument expectedEncryptedPayload = getResourceAsDocument("fle2-find-range-explicit-v2/int32/encrypted-payload.json"); MongoExplicitEncryptOptions options = MongoExplicitEncryptOptions.builder() .keyId(new BsonBinary(BsonBinarySubType.UUID_STANDARD, Base64.getDecoder().decode("q83vqxI0mHYSNBI0VniQEg=="))) .algorithm("Range") .queryType("range") .contentionFactor(4L) .rangeOptions(rangeOptions) .build(); MongoCryptContext encryptor = mongoCrypt.createEncryptExpressionContext(valueToEncrypt, options); assertEquals(State.NEED_MONGO_KEYS, encryptor.getState()); testKeyDecryptor(encryptor, "fle2-find-range-explicit-v2/int32/key-filter.json", "keys/ABCDEFAB123498761234123456789012-local-document.json"); assertEquals(State.READY, encryptor.getState()); RawBsonDocument actualEncryptedPayload = encryptor.finish(); assertEquals(State.DONE, encryptor.getState()); assertEquals(expectedEncryptedPayload, actualEncryptedPayload); encryptor.close(); mongoCrypt.close(); } @Test public void testRangePreviewQueryTypeIsNotSupported() { MongoCrypt mongoCrypt = createMongoCrypt(); assertNotNull(mongoCrypt); BsonDocument valueToEncrypt = getResourceAsDocument("fle2-find-range-explicit-v2/int32/value-to-encrypt.json"); BsonDocument rangeOptions = getResourceAsDocument("fle2-find-range-explicit-v2/int32/rangeopts.json"); MongoExplicitEncryptOptions options = MongoExplicitEncryptOptions.builder() .keyId(new BsonBinary(BsonBinarySubType.UUID_STANDARD, Base64.getDecoder().decode("q83vqxI0mHYSNBI0VniQEg=="))) .algorithm("Range") .queryType("rangePreview") .contentionFactor(4L) .rangeOptions(rangeOptions) .build(); MongoCryptException exp = assertThrows(MongoCryptException.class, () -> mongoCrypt.createEncryptExpressionContext(valueToEncrypt, options)); assertEquals("Query type 'rangePreview' is deprecated, please use 'range'", exp.getMessage()); mongoCrypt.close(); } @Test public void testRangePreviewAlgorithmIsNotSupported() { MongoCrypt mongoCrypt = createMongoCrypt(); assertNotNull(mongoCrypt); BsonDocument rangeOptions = getResourceAsDocument("fle2-find-range-explicit-v2/int32/rangeopts.json"); IllegalStateException illegalStateException = assertThrows(IllegalStateException.class, () -> MongoExplicitEncryptOptions.builder() .keyId(new BsonBinary(BsonBinarySubType.UUID_STANDARD, Base64.getDecoder().decode("q83vqxI0mHYSNBI0VniQEg=="))) .algorithm("RangePreview") .queryType("range") .contentionFactor(4L) .rangeOptions(rangeOptions) .build()); assertEquals("Invalid configuration, contentionFactor can only be set if algorithm is 'Indexed' or 'Range'", illegalStateException.getMessage()); mongoCrypt.close(); } @Test public void testExplicitEncryptionDecryptionKeyAltName() throws IOException, URISyntaxException { MongoCrypt mongoCrypt = createMongoCrypt(); assertNotNull(mongoCrypt); BsonDocument documentToEncrypt = new BsonDocument("v", new BsonString("hello")); MongoExplicitEncryptOptions options = MongoExplicitEncryptOptions.builder() .keyAltName("altKeyName") .algorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic") .build(); MongoCryptContext encryptor = mongoCrypt.createExplicitEncryptionContext(documentToEncrypt, options); assertEquals(State.NEED_MONGO_KEYS, encryptor.getState()); testKeyDecryptor(encryptor, "key-filter-keyAltName.json", "key-document.json"); assertEquals(State.READY, encryptor.getState()); RawBsonDocument encryptedDocument = encryptor.finish(); assertEquals(State.DONE, encryptor.getState()); assertEquals(getResourceAsDocument("encrypted-value.json"), encryptedDocument); MongoCryptContext decryptor = mongoCrypt.createExplicitDecryptionContext(encryptedDocument); assertEquals(State.READY, decryptor.getState()); RawBsonDocument decryptedDocument = decryptor.finish(); assertEquals(State.DONE, decryptor.getState()); assertEquals(documentToEncrypt, decryptedDocument); encryptor.close(); mongoCrypt.close(); } private void testKeyDecryptor(final MongoCryptContext context) { testKeyDecryptor(context, "key-filter.json", "key-document.json"); } private void testKeyDecryptor(final MongoCryptContext context, final String keyFilterPath, final String keyDocumentPath) { BsonDocument keyFilter = context.getMongoOperation(); assertEquals(getResourceAsDocument(keyFilterPath), keyFilter); context.addMongoOperationResult(getResourceAsDocument(keyDocumentPath)); context.completeMongoOperation(); if (context.getState() == State.READY) { return; } assertEquals(State.NEED_KMS, context.getState()); MongoKeyDecryptor keyDecryptor = context.nextKeyDecryptor(); assertEquals("aws", keyDecryptor.getKmsProvider()); assertEquals("kms.us-east-1.amazonaws.com:443", keyDecryptor.getHostName()); ByteBuffer keyDecryptorMessage = keyDecryptor.getMessage(); assertEquals(790, keyDecryptorMessage.remaining()); int bytesNeeded = keyDecryptor.bytesNeeded(); assertEquals(1024, bytesNeeded); keyDecryptor.feed(getHttpResourceAsByteBuffer("kms-reply.txt")); bytesNeeded = keyDecryptor.bytesNeeded(); assertEquals(0, bytesNeeded); assertNull(context.nextKeyDecryptor()); context.completeKeyDecryptors(); } private MongoCrypt createMongoCrypt() { return MongoCrypts.create(MongoCryptOptions .builder() .awsKmsProviderOptions(MongoAwsKmsProviderOptions.builder() .accessKeyId("example") .secretAccessKey("example") .build()) .localKmsProviderOptions(MongoLocalKmsProviderOptions.builder() .localMasterKey(ByteBuffer.wrap(new byte[96])) .build()) .build()); } private static BsonDocument getResourceAsDocument(final String fileName) { return BsonDocument.parse(getFileAsString(fileName, System.getProperty("line.separator"))); } private static ByteBuffer getHttpResourceAsByteBuffer(final String fileName) { return ByteBuffer.wrap(getFileAsString(fileName, "\r\n").getBytes(StandardCharsets.UTF_8)); } private static String getFileAsString(final String fileName, String lineSeparator) { try { URL resource = MongoCryptTest.class.getResource("/" + fileName); if (resource == null) { throw new RuntimeException("Could not find file " + fileName); } File file = new File(resource.toURI()); StringBuilder stringBuilder = new StringBuilder(); String line; try (BufferedReader reader = new BufferedReader( new InputStreamReader(Files.newInputStream(file.toPath()), StandardCharsets.UTF_8))) { boolean first = true; while ((line = reader.readLine()) != null) { if (!first) { stringBuilder.append(lineSeparator); } first = false; stringBuilder.append(line); } } return stringBuilder.toString(); } catch (Throwable t) { throw new RuntimeException("Could not parse file " + fileName, t); } } } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/000077500000000000000000000000001465326363200251735ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/collection-info.json000066400000000000000000000017241465326363200311560ustar00rootroot00000000000000{ "type": "collection", "name": "test", "idIndex": { "ns": "test.test", "name": "_id_", "key": { "_id": { "$numberInt": "1" } }, "v": { "$numberInt": "2" } }, "options": { "validator": { "$jsonSchema": { "properties": { "ssn": { "encrypt": { "keyId": { "$binary": { "base64": "YWFhYWFhYWFhYWFhYWFhYQ==", "subType": "04" } }, "type": "string", "algorithm": "AEAD_AES_CBC_HMAC_SHA512-Deterministic" } } }, "bsonType": "object" } } } }libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/command-reply.json000066400000000000000000000002361465326363200306360ustar00rootroot00000000000000{ "cursor": { "firstBatch": [ { "_id": 1, "ssn": "457-55-5462" } ], "id": 0, "ns": "test.test" }, "ok": 1 } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/command.json000066400000000000000000000001121465326363200274760ustar00rootroot00000000000000{ "find": "test", "filter": { "ssn": "457-55-5462" } }libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/encrypted-command-reply.json000066400000000000000000000005251465326363200326320ustar00rootroot00000000000000{ "cursor" : { "firstBatch" : [ { "_id": 1, "ssn": { "$binary": "AWFhYWFhYWFhYWFhYWFhYWECRTOW9yZzNDn5dGwuqsrJQNLtgMEKaujhs9aRWRp+7Yo3JK8N8jC8P0Xjll6C1CwLsE/iP5wjOMhVv1KMMyOCSCrHorXRsb2IKPtzl2lKTqQ=", "$type": "06" } } ], "id" : 0, "ns" : "test.test" }, "ok" : 1 }libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/encrypted-command.json000066400000000000000000000004101465326363200314720ustar00rootroot00000000000000{ "filter": { "ssn": { "$binary": { "base64": "AWFhYWFhYWFhYWFhYWFhYWECRTOW9yZzNDn5dGwuqsrJQNLtgMEKaujhs9aRWRp+7Yo3JK8N8jC8P0Xjll6C1CwLsE/iP5wjOMhVv1KMMyOCSCrHorXRsb2IKPtzl2lKTqQ=", "subType": "06" } } }, "find": "test" } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/encrypted-value.json000066400000000000000000000002461465326363200311770ustar00rootroot00000000000000{ "v": { "$binary": "AWFhYWFhYWFhYWFhYWFhYWECW+zDjR/69eS6VtuMD5+O2lZw6JyiWOw3avI7mnUkdpKzPfvy8F/nlZrgZa2cGmQsb0TmLZuk5trldosnGKD91w==", "$type": "06" } } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/fle2-find-range-explicit-v2/000077500000000000000000000000001465326363200321775ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/fle2-find-range-explicit-v2/int32/000077500000000000000000000000001465326363200331365ustar00rootroot00000000000000encrypted-payload.json000066400000000000000000000025221465326363200373770ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/fle2-find-range-explicit-v2/int32{ "v": { "$and": [ { "age": { "$gte": { "$binary": { "base64": "DQECAAADcGF5bG9hZACZAQAABGcAhQEAAAMwAH0AAAAFZAAgAAAAAInd0noBhIiJMv8QTjcfgRqnnVhxRJRRACLfvgT+CTR/BXMAIAAAAADm0EjqF/T4EmR6Dw6NaPLrL0OuzS4AFvm90czFluAAygVsACAAAAAA5MXcYWjYlzhPFUDebBEa17B5z2bupmaW9uCdtLjc7RkAAzEAfQAAAAVkACAAAAAA7lkNtT6RLw91aJ07K/blwlFs5wi9pQjqUXDcaCTxe98FcwAgAAAAAPwySffuLQihmF70Ot93KtaUMNU8KpmA+niyPRcvarNMBWwAIAAAAACDv6fJXXwRqwZH3O2kO+hdeLZ36U6bMZSui8kv0PsPtAADMgB9AAAABWQAIAAAAACcMWVTbZC4ox5VdjWeYKLgf4oBjpPlbTTAkucm9JPK0wVzACAAAAAA3tIww4ZTytkxFsUKyJbc3zwQ2w7DhkOqaNvX9g8pi3gFbAAgAAAAAGs9XR3Q1JpxV+HPW8P2GvCuCBF5bGZ8Kl1zHqzZcd5/AAASY20ABAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAgAAABBzZWNvbmRPcGVyYXRvcgAEAAAAEnNwAAEAAAAAAAAAEHRmAAEAAAAQbW4AAAAAABBteADIAAAAAA==", "subType": "06" } } } }, { "age": { "$lte": { "$binary": { "base64": "DTsAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgACAAAAEHNlY29uZE9wZXJhdG9yAAQAAAAA", "subType": "06" } } } } ] } } key-filter.json000066400000000000000000000003631465326363200360270ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/fle2-find-range-explicit-v2/int32{ "$or": [ { "_id": { "$in": [ { "$binary": "q83vqxI0mHYSNBI0VniQEg==", "$type": "04" } ] } }, { "keyAltNames": { "$in": [] } } ] }rangeopts.json000066400000000000000000000003121465326363200357500ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/fle2-find-range-explicit-v2/int32{ "min": { "$numberInt": "0" }, "max": { "$numberInt": "200" }, "sparsity": { "$numberLong": "1" }, "trimFactor": { "$numberInt": "1" } } value-to-encrypt.json000066400000000000000000000005761465326363200372000ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/fle2-find-range-explicit-v2/int32{ "v": { "$and": [ { "age": { "$gte": { "$numberInt": "23" } } }, { "age": { "$lte": { "$numberInt": "35" } } } ] } } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/json-schema.json000066400000000000000000000004361465326363200303000ustar00rootroot00000000000000{ "properties": { "ssn": { "encrypt": { "keyId": { "$binary": "YWFhYWFhYWFhYWFhYWFhYQ==", "$type": "04" }, "type": "string", "algorithm": "AEAD_AES_CBC_HMAC_SHA512-Deterministic" } } }, "bsonType": "object" }libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/key-document.json000066400000000000000000000020731465326363200304740ustar00rootroot00000000000000{ "status": { "$numberInt": "1" }, "_id": { "$binary": { "base64": "YWFhYWFhYWFhYWFhYWFhYQ==", "subType": "04" } }, "masterKey": { "region": "us-east-1", "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", "provider": "aws" }, "updateDate": { "$date": { "$numberLong": "1557827033449" } }, "keyMaterial": { "$binary": { "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", "subType": "00" } }, "creationDate": { "$date": { "$numberLong": "1557827033449" } }, "keyAltNames": [ "altKeyName", "another_altname" ] } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/key-filter-keyAltName.json000066400000000000000000000002221465326363200321650ustar00rootroot00000000000000{ "$or": [ { "_id": { "$in": [] } }, { "keyAltNames": { "$in": ["altKeyName"] } } ] } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/key-filter.json000066400000000000000000000003631465326363200301430ustar00rootroot00000000000000{ "$or": [ { "_id": { "$in": [ { "$binary": "YWFhYWFhYWFhYWFhYWFhYQ==", "$type": "04" } ] } }, { "keyAltNames": { "$in": [] } } ] }libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/keys/000077500000000000000000000000001465326363200261465ustar00rootroot00000000000000ABCDEFAB123498761234123456789012-local-document.json000066400000000000000000000013741465326363200353440ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/keys{ "_id": { "$binary": { "base64": "q83vqxI0mHYSNBI0VniQEg==", "subType": "04" } }, "keyMaterial": { "$binary": { "base64": "27OBvUqHAuYFy60nwCdvq2xmZ4kFzVySphXzBGq+HEot13comCoydEfnltBzLTuXLbV9cnREFJIO5f0jMqrlkxIuvAV8yO84p5VJTEa8j/xSNe7iA594rx7UeKT0fOt4VqM47fht8h+8PZYc5JVezvEMvwk115IBCwENxDjLtT0g+y8Hf+aTUEGtxrYToH8zf1/Y7S16mHiIc4jK3/vxHw==", "subType": "00" } }, "creationDate": { "$date": { "$numberLong": "1648915408923" } }, "updateDate": { "$date": { "$numberLong": "1648915408923" } }, "status": { "$numberInt": "0" }, "masterKey": { "provider": "local" } } libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/kms-reply.txt000066400000000000000000000005561465326363200276650ustar00rootroot00000000000000HTTP/1.1 200 OK x-amzn-RequestId: deeb35e5-4ecb-4bf1-9af5-84a54ff0af0e Content-Type: application/x-amz-json-1.1 Content-Length: 233 {"KeyId": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", "Plaintext": "TqhXy3tKckECjy4/ZNykMWG8amBF46isVPzeOgeusKrwheBmYaU8TMG5AHR/NeUDKukqo8hBGgogiQOVpLPkqBQHD8YkLsNbDmHoGOill5QAHnniF/Lz405bGucB5TfR"}libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/list-collections-filter.json000066400000000000000000000000241465326363200326340ustar00rootroot00000000000000{ "name": "test" }libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/mongocryptd-command.json000066400000000000000000000006461465326363200320550ustar00rootroot00000000000000{ "find": "test", "filter": { "ssn": "457-55-5462" }, "jsonSchema": { "properties": { "ssn": { "encrypt": { "keyId": { "$binary": "YWFhYWFhYWFhYWFhYWFhYQ==", "$type": "04" }, "type": "string", "algorithm": "AEAD_AES_CBC_HMAC_SHA512-Deterministic" } } }, "bsonType": "object" }, "isRemoteSchema": true }libmongocrypt-1.11.0/bindings/java/mongocrypt/src/test/resources/mongocryptd-reply.json000066400000000000000000000006541465326363200315710ustar00rootroot00000000000000{ "schemaRequiresEncryption": true, "ok": { "$numberInt": "1" }, "result": { "filter": { "ssn": { "$binary": { "base64": "ADgAAAAQYQABAAAABWtpABAAAAAEYWFhYWFhYWFhYWFhYWFhYQJ2AAwAAAA0NTctNTUtNTQ2MgAA", "subType": "06" } } }, "find": "test" }, "hasEncryptedPlaceholders": true }libmongocrypt-1.11.0/bindings/node/000077500000000000000000000000001465326363200172165ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/node/README.md000066400000000000000000000003201465326363200204700ustar00rootroot00000000000000### The Node.js Bindings Have Moved! #### https://github.com/mongodb-js/mongodb-client-encryption They can still be found at the same npm package: - https://www.npmjs.com/package/mongodb-client-encryption libmongocrypt-1.11.0/bindings/python/000077500000000000000000000000001465326363200176125ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/.evergreen/000077500000000000000000000000001465326363200216525ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/.evergreen/integ-setup.sh000077500000000000000000000024671465326363200244660ustar00rootroot00000000000000#!/usr/bin/bash set -eux DRIVERS_TOOLS="$(pwd)/drivers-tools" PROJECT_DIRECTORY="${project_directory}" PYMONGO_DIR="$(pwd)/mongo-python-driver" # Python has cygwin path problems on Windows. if [ "Windows_NT" = "${OS:-}" ]; then DRIVERS_TOOLS=$(cygpath -m $DRIVERS_TOOLS) PROJECT_DIRECTORY=$(cygpath -m $PROJECT_DIRECTORY) fi export PROJECT_DIRECTORY export DRIVERS_TOOLS export MONGO_ORCHESTRATION_HOME="$DRIVERS_TOOLS/.evergreen/orchestration" export MONGODB_BINARIES="$DRIVERS_TOOLS/mongodb/bin" export MONGOCRYPT_DIR=${PROJECT_DIRECTORY}/all/${variant_name} cat < expansion.yml DRIVERS_TOOLS: "$DRIVERS_TOOLS" MONGO_ORCHESTRATION_HOME: "$MONGO_ORCHESTRATION_HOME" MONGODB_BINARIES: "$MONGODB_BINARIES" PROJECT_DIRECTORY: "$PROJECT_DIRECTORY" PYMONGO_DIR: "$PYMONGO_DIR" MONGOCRYPT_DIR: "$MONGOCRYPT_DIR" EOT # Set up drivers-tools with a .env file. git clone https://github.com/mongodb-labs/drivers-evergreen-tools.git ${DRIVERS_TOOLS} cat < ${DRIVERS_TOOLS}/.env DRIVERS_TOOLS="$DRIVERS_TOOLS" MONGO_ORCHESTRATION_HOME="$MONGO_ORCHESTRATION_HOME" MONGODB_BINARIES="$MONGODB_BINARIES" PROJECT_DIRECTORY="$PROJECT_DIRECTORY" EOT # Get the secrets bash $DRIVERS_TOOLS/.evergreen/csfle/setup-secrets.sh # Clone mongo-python-driver git clone https://github.com/mongodb/mongo-python-driver.git ${PYMONGO_DIR} libmongocrypt-1.11.0/bindings/python/.evergreen/integ-teardown.sh000077500000000000000000000003541465326363200251420ustar00rootroot00000000000000#! /bin/bash set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail bash ${DRIVERS_TOOLS}/.evergreen/csfle/teardown.sh bash ${DRIVERS_TOOLS}/.evergreen/teardown.sh libmongocrypt-1.11.0/bindings/python/.evergreen/integ-test.sh000077500000000000000000000026771465326363200243100ustar00rootroot00000000000000#! /bin/bash set -eux pushd $(pwd)/libmongocrypt/bindings/python # For createvirtualenv and find_python3 . .evergreen/utils.sh BASE_PYTHON=$(find_python3) # MONGOCRYPT_DIR is set by libmongocrypt/.evergreen/config.yml MONGOCRYPT_DIR="$MONGOCRYPT_DIR" MACHINE=$(uname -m) if [ $MACHINE == "aarch64" ]; then PYTHON="/opt/mongodbtoolchain/v4/bin/python3" TARGET=rhel82 else TARGET=rhel80 PYTHON="/opt/python/3.8/bin/python3" fi CRYPT_SHARED_DIR="$(pwd)/crypt_shared" /opt/mongodbtoolchain/v3/bin/python3 $DRIVERS_TOOLS/.evergreen/mongodl.py --component \ crypt_shared --version latest --out $CRYPT_SHARED_DIR --target $TARGET if [ -e "${MONGOCRYPT_DIR}/lib64/" ]; then export PYMONGOCRYPT_LIB=${MONGOCRYPT_DIR}/nocrypto/lib64/libmongocrypt.so PYMONGOCRYPT_LIB_CRYPTO=${MONGOCRYPT_DIR}/lib64/libmongocrypt.so else export PYMONGOCRYPT_LIB=${MONGOCRYPT_DIR}/nocrypto/lib/libmongocrypt.so PYMONGOCRYPT_LIB_CRYPTO=${MONGOCRYPT_DIR}/lib/libmongocrypt.so fi createvirtualenv $PYTHON .venv pip install -e . pushd $PYMONGO_DIR pip install -e ".[test,encryption]" source ${DRIVERS_TOOLS}/.evergreen/csfle/secrets-export.sh set -x TEST_CRYPT_SHARED=1 DYLD_FALLBACK_LIBRARY_PATH=$CRYPT_SHARED_DIR/lib/:${DYLD_FALLBACK_LIBRARY_PATH:-} \ LD_LIBRARY_PATH=$CRYPT_SHARED_DIR/lib:${LD_LIBRARY_PATH-} \ PATH=$CRYPT_SHARED_DIR/bin:$PATH \ AUTH=auth SSL=ssl \ .evergreen/run-tests.sh -m encryption popd deactivate rm -rf .venv popd libmongocrypt-1.11.0/bindings/python/.evergreen/test.sh000077500000000000000000000102151465326363200231670ustar00rootroot00000000000000#!/bin/bash # Test the Python bindings for libmongocrypt set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail # For createvirtualenv and find_python3 . .evergreen/utils.sh BASE_PYTHON=$(find_python3) # MONGOCRYPT_DIR is set by libmongocrypt/.evergreen/config.yml MONGOCRYPT_DIR="$MONGOCRYPT_DIR" git clone https://github.com/mongodb-labs/drivers-evergreen-tools.git if [ "Windows_NT" = "$OS" ]; then # Magic variable in cygwin PYMONGOCRYPT_LIB=${MONGOCRYPT_DIR}/nocrypto/bin/mongocrypt.dll PYMONGOCRYPT_LIB_CRYPTO=$(cygpath -m ${MONGOCRYPT_DIR}/bin/mongocrypt.dll) export PYMONGOCRYPT_LIB=$(cygpath -m $PYMONGOCRYPT_LIB) PYTHONS=("C:/python/Python38/python.exe" "C:/python/Python39/python.exe" "C:/python/Python310/python.exe" "C:/python/Python311/python.exe" "C:/python/Python312/python.exe") export CRYPT_SHARED_PATH=../crypt_shared/bin/mongo_crypt_v1.dll C:/python/Python310/python.exe drivers-evergreen-tools/.evergreen/mongodl.py --component crypt_shared \ --version latest --out ../crypt_shared/ elif [ "Darwin" = "$(uname -s)" ]; then export PYMONGOCRYPT_LIB=${MONGOCRYPT_DIR}/nocrypto/lib/libmongocrypt.dylib PYMONGOCRYPT_LIB_CRYPTO=${MONGOCRYPT_DIR}/lib/libmongocrypt.dylib PYTHONS=( "/Library/Frameworks/Python.framework/Versions/3.9/bin/python3" "/Library/Frameworks/Python.framework/Versions/3.10/bin/python3" "/Library/Frameworks/Python.framework/Versions/3.11/bin/python3" "/Library/Frameworks/Python.framework/Versions/3.12/bin/python3" ) export CRYPT_SHARED_PATH="../crypt_shared/lib/mongo_crypt_v1.dylib" python3 drivers-evergreen-tools/.evergreen/mongodl.py --component crypt_shared \ --version latest --out ../crypt_shared/ else if [ -e "${MONGOCRYPT_DIR}/lib64/" ]; then export PYMONGOCRYPT_LIB=${MONGOCRYPT_DIR}/nocrypto/lib64/libmongocrypt.so PYMONGOCRYPT_LIB_CRYPTO=${MONGOCRYPT_DIR}/lib64/libmongocrypt.so else export PYMONGOCRYPT_LIB=${MONGOCRYPT_DIR}/nocrypto/lib/libmongocrypt.so PYMONGOCRYPT_LIB_CRYPTO=${MONGOCRYPT_DIR}/lib/libmongocrypt.so fi export CRYPT_SHARED_PATH="../crypt_shared/lib/mongo_crypt_v1.so" MACHINE=$(uname -m) if [ $MACHINE == "aarch64" ]; then TARGET=rhel82 PYTHONS=("/opt/mongodbtoolchain/v3/bin/python3" "/opt/mongodbtoolchain/v4/bin/python3" ) else TARGET=rhel80 PYTHONS=("/opt/python/3.8/bin/python3" "/opt/python/3.9/bin/python3" "/opt/python/3.10/bin/python3" "/opt/python/3.11/bin/python3" "/opt/python/3.12/bin/python3" ) fi /opt/mongodbtoolchain/v3/bin/python3 drivers-evergreen-tools/.evergreen/mongodl.py --component \ crypt_shared --version latest --out ../crypt_shared/ --target $TARGET fi for PYTHON_BINARY in "${PYTHONS[@]}"; do echo "Running test with python: $PYTHON_BINARY" $PYTHON_BINARY -c 'import sys; print(sys.version)' git clean -dffx createvirtualenv $PYTHON_BINARY .venv python -m pip install --prefer-binary -v -e ".[test]" echo "Running tests with crypto enabled libmongocrypt..." PYMONGOCRYPT_LIB=$PYMONGOCRYPT_LIB_CRYPTO python -c 'from pymongocrypt.binding import lib;assert lib.mongocrypt_is_crypto_available(), "mongocrypt_is_crypto_available() returned False"' PYMONGOCRYPT_LIB=$PYMONGOCRYPT_LIB_CRYPTO python -m pytest -v --ignore=test/performance . echo "Running tests with crypt_shared on dynamic library path..." TEST_CRYPT_SHARED=1 DYLD_FALLBACK_LIBRARY_PATH=../crypt_shared/lib/:$DYLD_FALLBACK_LIBRARY_PATH \ LD_LIBRARY_PATH=../crypt_shared/lib:$LD_LIBRARY_PATH \ PATH=../crypt_shared/bin:$PATH \ python -m pytest -v --ignore=test/performance . deactivate rm -rf .venv done # Verify the sbom file LIBMONGOCRYPT_VERSION=$(cat ./libmongocrypt-version.txt) EXPECTED="pkg:github/mongodb/libmongocrypt@$LIBMONGOCRYPT_VERSION" if grep -q $EXPECTED sbom.json; then echo "SBOM is up to date!" else echo "SBOM is out of date! Run the \"update-sbom.sh\" script." exit 1 fi libmongocrypt-1.11.0/bindings/python/.evergreen/utils.sh000077500000000000000000000055501465326363200233560ustar00rootroot00000000000000#!/bin/bash -ex # Usage: # createvirtualenv /path/to/python /output/path/for/venv # * param1: Python binary to use for the virtualenv # * param2: Path to the virtualenv to create createvirtualenv () { PYTHON=$1 VENVPATH=$2 # Prefer venv VENV="$PYTHON -m venv" if [ "$(uname -s)" = "Darwin" ]; then VIRTUALENV="$PYTHON -m virtualenv" else VIRTUALENV=$(command -v virtualenv 2>/dev/null || echo "$PYTHON -m virtualenv") VIRTUALENV="$VIRTUALENV -p $PYTHON" fi if ! $VENV $VENVPATH 2>/dev/null; then # Workaround for bug in older versions of virtualenv. $VIRTUALENV $VENVPATH 2>/dev/null || $VIRTUALENV $VENVPATH fi if [ "Windows_NT" = "${OS:-}" ]; then # Workaround https://bugs.python.org/issue32451: # mongovenv/Scripts/activate: line 3: $'\r': command not found dos2unix $VENVPATH/Scripts/activate || true . $VENVPATH/Scripts/activate else . $VENVPATH/bin/activate fi export PIP_QUIET=1 python -m pip install --upgrade pip } # Usage: # PYTHON = find_python3 find_python3() { PYTHON="" # Add a fallback system python3 if it is available and Python 3.8+. if is_python_38 "$(command -v python3)"; then PYTHON="$(command -v python3)" fi # Find a suitable toolchain version, if available. if [ "$(uname -s)" = "Darwin" ]; then # macos 11.00 if [ -d "/Library/Frameworks/Python.Framework/Versions/3.10" ]; then PYTHON="/Library/Frameworks/Python.Framework/Versions/3.10/bin/python3" # macos 10.14 elif [ -d "/Library/Frameworks/Python.Framework/Versions/3.8" ]; then PYTHON="/Library/Frameworks/Python.Framework/Versions/3.8/bin/python3" fi elif [ "Windows_NT" = "${OS:-}" ]; then # Magic variable in cygwin PYTHON="C:/python/Python38/python.exe" else # Prefer our own toolchain, fall back to mongodb toolchain if it has Python 3.8+. if [ -f "/opt/python/3.8/bin/python3" ]; then PYTHON="/opt/python/3.8/bin/python3" elif is_python_38 "$(command -v /opt/mongodbtoolchain/v4/bin/python3)"; then PYTHON="/opt/mongodbtoolchain/v4/bin/python3" elif is_python_38 "$(command -v /opt/mongodbtoolchain/v3/bin/python3)"; then PYTHON="/opt/mongodbtoolchain/v3/bin/python3" fi fi if [ -z "$PYTHON" ]; then echo "Cannot run pre-commit without python3.8+ installed!" exit 1 fi echo "$PYTHON" } # Function that returns success if the provided Python binary is version 3.8 or later # Usage: # is_python_38 /path/to/python # * param1: Python binary is_python_38() { if [ -z "$1" ]; then return 1 elif $1 -c "import sys; exit(sys.version_info[:2] < (3, 8))"; then # runs when sys.version_info[:2] >= (3, 8) return 0 else return 1 fi } libmongocrypt-1.11.0/bindings/python/.gitignore000066400000000000000000000001501465326363200215760ustar00rootroot00000000000000*~ *#* .DS* *.cm *.class *.pyc *.pyd build/ doc/_build/ dist/ *.so *.egg .tox .eggs/ .idea/ *.egg-info/ libmongocrypt-1.11.0/bindings/python/CHANGELOG.rst000066400000000000000000000157171465326363200216460ustar00rootroot00000000000000Changelog ========= Changes in Version 1.10.1 ------------------------ - Bundle libmongocrypt 1.10.1 in release wheels. Changes in Version 1.10.0 ------------------------ - Add Python async support. - Drop support for Python 3.7 and PyPy 3.8. Python >=3.8 or PyPy >=3.9 is now required. - Add support for range-based Queryable Encryption with the new "range" algorithm on MongoDB 8.0+. This replaces the experimental "rangePreview" algorithm. - Add Secure Software Development Life Cycle automation to release process. GitHub Releases for pymongocrypt now include a Software Bill of Materials, and signature files corresponding to the distribution files released on PyPI. Changes in Version 1.9.2 ------------------------ - Fix support for building source distributions with setuptools >= 70. Changes in Version 1.9.1 ------------------------ - Fix bug in our release process which blocked uploading 1.9.0. Changes in Version 1.9.0 ------------------------ - Add support for named KMS providers like "local:name1". This feature requires libmongocrypt >= 1.9.0. - Use libmongocrypt native crypto when available which results in 10-50x better performance. On Linux, it is recommended to download the platform specific build and set PYMONGOCRYPT_LIB to the crypto-enabled libmongocrypt.so. - Bundle the crypto-enabled libmongocrypt builds in macOS and Windows wheels for better performance. - Bundle libmongocrypt 1.9.0 in release wheels. Changes in Version 1.8.0 ------------------------ - Update from manylinux2010 to manylinux2014 wheels. - Bundle libmongocrypt 1.8.4 in release wheels. - Add support for manylinux_2_28_aarch64 wheels. Changes in Version 1.7.0 ------------------------ - Add support for Python 3.12 on MacOS and Linux. - Update required cryptography version to >=2.5. Changes in Version 1.6.1 ------------------------ - Bundle libmongocrypt 1.8.1 in release wheels. Changes in Version 1.6.0 ------------------------ - Drop support for Python 2 and Python <3.7. Python >=3.7 is now required. - Bundle libmongocrypt 1.8.0 in release wheels. - **Remove support for libmongocrypt <=1.8.0, libmongocrypt >=1.8.0 is now required.** Note this is only relevant for users that install from source or use the ``PYMONGOCRYPT_LIB`` environment variable. Changes in Version 1.5.2 ------------------------ - Bundle libmongocrypt 1.7.3 in release wheels. Changes in Version 1.5.1 ------------------------ - Bundle libmongocrypt 1.7.1 in release wheels. Changes in Version 1.5.0 ------------------------ - Add support for range-based Queryable Encryption with the new "rangePreview" algorithm. NOTE: The "rangePreview" algorithm is experimental only. It is not intended for public use. - Bundle libmongocrypt 1.7.0 in release wheels. - **Remove support for libmongocrypt <=1.7.0, libmongocrypt >=1.7.0 is now required.** Note this is only relevant for users that install from source or use the ``PYMONGOCRYPT_LIB`` environment variable. Changes in Version 1.4.1 ------------------------ - Fixed spurious exception traceback at interpreter shutdown: ``AttributeError: 'NoneType' object has no attribute 'mongocrypt_destroy'`` Changes in Version 1.4.0 ------------------------ - Bundle libmongocrypt 1.6.1 in release wheels. - Support GCP attached service accounts when using GCP KMS. - Support Azure VM-assigned Managed Identity for Automatic KMS Credentials. - Support obtaining AWS credentials for CSFLE in the same way as for MONGODB-AWS. Changes in Version 1.3.1 ------------------------ 1.3.1 is a recommended upgrade for all users of 1.3.0. - Fix a potential data corruption bug in RewrapManyDataKey (ClientEncryption.rewrap_many_data_key) when rotating encrypted data encryption keys backed by GCP or Azure key services. The following conditions will trigger this bug: - A GCP-backed or Azure-backed data encryption key being rewrapped requires fetching an access token for decryption of the data encryption key. The result of this bug is that the key material for all data encryption keys being rewrapped is replaced by new randomly generated material, destroying the original key material. To mitigate potential data corruption, upgrade to this version or higher before using RewrapManyDataKey to rotate Azure-backed or GCP-backed data encryption keys. A backup of the key vault collection should always be taken before key rotation. - Bundle libmongocrypt 1.5.2 in release wheels. - **Remove support for libmongocrypt <=1.5.1, libmongocrypt >=1.5.2 is now required.** Note this is only relevant for users that install from source or use the ``PYMONGOCRYPT_LIB`` environment variable. Changes in Version 1.3.0 ------------------------ - Bundle libmongocrypt 1.5.0 in release wheels. - Add support for Queryable Encryption with MongoDB 6.0. - Add support for the crypt_shared library which can be used instead of mongocryptd. - **Remove support for libmongocrypt 1.3, libmongocrypt >=1.5 is now required.** Note this is only relevant for users that install from source or use the ``PYMONGOCRYPT_LIB`` environment variable. Changes in Version 1.2.0 ------------------------ - Add support for the "kmip" KMS provider. - Add MongoCryptKmsContext.kms_provider property. - Bundle libmongocrypt 1.3.0 in release wheels. - **Remove support for libmongocrypt 1.2, libmongocrypt >=1.3 is now required.** Note this is only relevant for users that install from source or use the ``PYMONGOCRYPT_LIB`` environment variable. Changes in Version 1.1.2 ------------------------ - Fix a bug where decrypting from a memoryview was not supported. - Bundle libmongocrypt 1.2.2 in release wheels. Changes in Version 1.1.1 ------------------------ - Bundle libmongocrypt 1.2.1 in release wheels. Changes in Version 1.1.0 ------------------------ - Add support for Azure and GCP KMS providers. - Add support for temporary AWS credentials via the "sessionToken" option. - Bundle libmongocrypt 1.2.0 in release wheels. - **Remove support for libmongocrypt 1.0 and 1.1, libmongocrypt >=1.2 is now required.** Note this is only relevant for users that install from source or use the ``PYMONGOCRYPT_LIB`` environment variable. Changes in Version 1.0.1 ------------------------ - Bundle libmongocrypt 1.0.4 in release wheels. Changes in Version 1.0.0 ------------------------ - The first stable version. - Bundle libmongocrypt 1.0.0 in release wheels. Changes in Version 0.1b3 ------------------------ - Add support for custom KMS endpoints with the AWS masterkey provider. - Bundle libmongocrypt 1.0.0 in release wheels. Changes in Version 0.1b2 ------------------------ - Document that pip 19 is required for manylinux2010 wheel installation. - Bundle libmongocrypt 1.0.0-beta5 in release wheels. Changes in Version 0.1b1 ------------------------ - Make pymongocrypt compatible with manylinux2010 releases. - Bundle libmongocrypt 1.0.0-beta4 in release wheels. Changes in Version 0.1b0 ------------------------ - Initial Python binding for libmongocrypt. - Bundle libmongocrypt 1.0.0-beta4 in release wheels. libmongocrypt-1.11.0/bindings/python/LICENSE000066400000000000000000000261351465326363200206260ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. libmongocrypt-1.11.0/bindings/python/README.rst000066400000000000000000000206201465326363200213010ustar00rootroot00000000000000============ PyMongoCrypt ============ :Info: Python bindings for libmongocrypt. See `GitHub `_ for the latest source. :Author: Shane Harvey About ===== Python wrapper library for libmongocrypt that supports client side encryption in drivers. PyMongoCrypt uses `cffi `_ and `cryptography `_. PyMongoCrypt supports Python 3.8+ and PyPy3.9+. Support / Feedback ================== For issues with, questions about, or feedback for PyMongoCrypt, please look into our `support channels `_. Please do not email any of the PyMongoCrypt developers directly with issues or questions - you're more likely to get an answer on the `mongodb-user `_ list on Google Groups. Bugs / Feature Requests ======================= Think you’ve found a bug? Want to see a new feature in PyMongoCrypt? Please open a case in our issue management tool, JIRA: - `Create an account and login `_. - Navigate to `the PYTHON project `_. - Click **Create Issue** - Please provide as much information as possible about the issue type and how to reproduce it. Bug reports in JIRA for all driver projects (i.e. PYTHON, CSHARP, JAVA) and the Core Server (i.e. SERVER) project are **public**. How To Ask For Help ------------------- Please include all of the following information when opening an issue: - Detailed steps to reproduce the problem, including full traceback, if possible. - The exact python version used, with patch level:: $ python -c "import sys; print(sys.version)" - The exact version of PyMongoCrypt used:: $ python -c "import pymongocrypt; print(pymongocrypt.__version__)" - The exact version of libbmongocrypt used by PyMongoCrypt:: $ python -c "import pymongocrypt; print(pymongocrypt.libmongocrypt_version())" - The exact version of PyMongo used (if applicable), with patch level:: $ python -c "import pymongo; print(pymongo.version); print(pymongo.has_c())" - The operating system and version (e.g. Windows 7, OSX 10.8, ...) - Web framework or asynchronous network library used, if any, with version (e.g. Django 1.7, mod_wsgi 4.3.0, gevent 1.0.1, Tornado 4.0.2, ...) Security Vulnerabilities ------------------------ If you've identified a security vulnerability in a driver or any other MongoDB project, please report it according to the `instructions here `_. Installation ============ PyMongoCrypt can be installed with `pip `_:: $ python -m pip install pymongocrypt $ python -c "import pymongocrypt; print(pymongocrypt.libmongocrypt_version())" 1.9.0 PyMongoCrypt ships wheels for macOS, Windows, and manylinux2010 that include an embedded libmongocrypt build. Installing from wheels on Linux requires pip 19 or later because it adds `support for manylinux2010 wheels `_. Older versions of pip will attempt installation using the pymongocrypt-X.Y.tar.gz source distribution which requires the extra step of downloading and installing libmongocrypt as described below. Users can upgrade to pip 19 by running:: $ python -m pip install --upgrade 'pip>=19' Installing from source ---------------------- Installing from source (or the pymongocrypt-X.Y.tar.gz source distribution, or pip < 19 on Linux) requires an extra step of installing libmongocrypt. First, install PyMongoCrypt from source:: $ git clone git@github.com:mongodb/libmongocrypt.git $ python -m pip install ./libmongocrypt/bindings/python Next, install libmongocrypt: Installing libmongocrypt ^^^^^^^^^^^^^^^^^^^^^^^^ libmongocrypt is continuously built and published on evergreen. The latest tarball containing libmongocrypt built on all supported variants is `published here `_. Download and extract ``libmongocrypt-all.tar.gz`` and set ``PYMONGOCRYPT_LIB`` to the path to your operating system's libmongocrypt.so file. For example:: $ curl -O https://s3.amazonaws.com/mciuploads/libmongocrypt/all/master/latest/libmongocrypt-all.tar.gz $ mkdir libmongocrypt-all && tar xzf libmongocrypt-all.tar.gz -C libmongocrypt-all $ ls libmongocrypt-all amazon2 debian92 rhel-80-64-bit rhel72-zseries-test ubuntu1804-arm64 amazon2-arm64 linux-64-amazon-ami rhel-81-ppc64el suse12-64 ubuntu2004-64 amazon2023 macos rhel-82-arm64 suse15-64 ubuntu2004-arm64 amazon2023-arm64 rhel-62-64-bit rhel-83-zseries ubuntu1604 ubuntu2204-64 debian10 rhel-70-64-bit rhel-91-64-bit ubuntu1604-arm64 ubuntu2204-arm64 debian11 rhel-71-ppc64el rhel-91-arm64 ubuntu1804-64 windows-test macOS:: $ # Set PYMONGOCRYPT_LIB for macOS: $ export PYMONGOCRYPT_LIB=$(pwd)/libmongocrypt-all/macos/lib/libmongocrypt.dylib $ python -c "import pymongocrypt; print(pymongocrypt.libmongocrypt_version())" 1.9.0 Windows:: $ # Set PYMONGOCRYPT_LIB for Windows: $ chmod +x $(pwd)/libmongocrypt-all/windows-test/bin/mongocrypt.dll $ export PYMONGOCRYPT_LIB=$(pwd)/libmongocrypt-all/windows-test/bin/mongocrypt.dll $ python -c "import pymongocrypt; print(pymongocrypt.libmongocrypt_version())" 1.9.0 Linux: set the libmongocrypt build for your platform, for example for Ubuntu 22.04 x86_64:: $ # Set PYMONGOCRYPT_LIB for Ubuntu 22.04 x86_64: $ export PYMONGOCRYPT_LIB=$(pwd)/libmongocrypt-all/ubuntu2204-64/lib/libmongocrypt.so $ python -c "import pymongocrypt; print(pymongocrypt.libmongocrypt_version())" 1.9.0 $ # Check that native crypto is enabled for better performance: $ python -c 'from pymongocrypt.binding import lib;print(lib.mongocrypt_is_crypto_available())' True Note if your Linux platform is not available, the generic RHEL 6.2 x86_64 "nocrypto" build should still be compatible however the "nocrypto" build will result in lower performance for encryption and decryption:: $ # Set PYMONGOCRYPT_LIB for RHEL 6.2 x86_64: $ export PYMONGOCRYPT_LIB=$(pwd)/libmongocrypt-all/rhel-62-64-bit/nocrypto/lib64/libmongocrypt.so $ python -c "import pymongocrypt; print(pymongocrypt.libmongocrypt_version())" 1.9.0 $ python -c 'from pymongocrypt.binding import lib;print(lib.mongocrypt_is_crypto_available())' False Other methods of installation (brew, rpm, yum, apt-get, deb, etc...) are documented here: https://www.mongodb.com/docs/manual/core/csfle/reference/libmongocrypt/#linux-installation Dependencies ============ PyMongoCrypt supports Python 3.8+ and PyPy3.9+. PyMongoCrypt requires `cffi `_ and `cryptography `_. If not installed using one of the official wheels, PyMongoCrypt also requires libmongocrypt to be installed on your system. If libmongocrypt is not installed you will see an error like this: .. code-block:: python >>> import pymongocrypt Traceback (most recent call last): File "", line 1, in File "pymongocrypt/__init__.py", line 15, in from pymongocrypt.binding import libmongocrypt_version, lib File "pymongocrypt/binding.py", line 803, in lib = ffi.dlopen(os.environ.get('PYMONGOCRYPT_LIB', 'mongocrypt')) File "/.../lib/python3.8/site-packages/cffi/api.py", line 146, in dlopen lib, function_cache = _make_ffi_library(self, name, flags) File "/.../lib/python3.8/site-packages/cffi/api.py", line 828, in _make_ffi_library backendlib = _load_backend_lib(backend, libname, flags) File "/.../lib/python3.8/site-packages/cffi/api.py", line 823, in _load_backend_lib raise OSError(msg) OSError: ctypes.util.find_library() did not manage to locate a library called 'mongocrypt' Use the ``PYMONGOCRYPT_LIB`` environment variable to load a locally installed libmongocrypt build without relying on platform specific library path environment variables, like ``LD_LIBRARY_PATH``. For example:: $ export PYMONGOCRYPT_LIB='/path/to/libmongocrypt.so' $ python -c "import pymongocrypt; print(pymongocrypt.libmongocrypt_version())" 1.9.0 Testing ======= The easiest way to run the tests is to run **python setup.py test** in the root of the distribution. libmongocrypt-1.11.0/bindings/python/RELEASE.rst000066400000000000000000000066361465326363200214370ustar00rootroot00000000000000===================== PyMongoCrypt Releases ===================== Versioning ---------- PyMongoCrypt's version numbers follow `semantic versioning`_: each version number is structured "major.minor.patch". Patch releases fix bugs, minor releases add features (and may fix bugs), and major releases include API changes that break backwards compatibility (and may add features and fix bugs). In between releases we add .devN to the version number to denote the version under development. So if we just released 1.0.0, then the current dev version might be 1.0.1.dev0 or 1.1.0.dev0. PyMongoCrypt's version numbers do not necessarily correspond to the embedded libmongocrypt library's version number. For example, assume the current PyMongoCrypt version is 1.0 and libmongocrypt is 1.0. Let's say that libmongocrypt 2.0.0 is released which has breaking changes to its API. If those 2.0.0 changes do not require any breaking changes to PyMongoCrypt, then the next version can be 1.1. .. _semantic versioning: http://semver.org/ Release Process --------------- PyMongoCrypt ships wheels for macOS, Windows, and manylinux2010 that include an embedded libmongocrypt build. Releasing a new version requires macOS with Docker and a Windows machine. #. Create a ticket for the release and create a PR. The PR needs to include the next steps including the version change because the branch is protected from directly pushing commits. #. Edit the release.sh script to embed the most recent libmongocrypt tag into our wheels, for example:: # The libmongocrypt git revision release to embed in our wheels. -REVISION=$(git rev-list -n 1 1.0.0) +REVISION=$(git rev-list -n 1 1.0.1) #. Add a changelog entry for this release in CHANGELOG.rst. #. Bump "__version__" in ``pymongocrypt/version.py``. #. After merging the PR, clone the repository and check out the commit with the version change. #. Create and push tag:: $ git tag -a "pymongocrypt-" -m "pymongocrypt-" $ MACOS_TARGET=macos_x86_64 PYTHON= ./release.sh $ PYTHON= ./release.sh Make sure to run using the official binaries for Python 3.8 and 3.10. You should end up with the same files created by Evergreen (except for the Windows wheel). #. To build the release package for Windows, launch a windows-64-vsMulti-small Evergreen spawn host, clone the repro, checkout the release tag, and run the release script:: $ git clone git@github.com:mongodb/libmongocrypt.git $ cd libmongocrypt/bindings/python $ git checkout "pymongocrypt " $ ./release.sh This will create the following distributions:: $ ls dist pymongocrypt--py2.py3-none-win_amd64.whl libmongocrypt-1.11.0/bindings/python/build-manylinux-wheel.sh000077500000000000000000000003261465326363200243750ustar00rootroot00000000000000#!/bin/bash -ex cd /python mkdir /tmp/wheelhouse /opt/python/cp38-cp38/bin/python -m build --wheel --outdir /tmp/wheelhouse # Audit wheels and repair manylinux tags auditwheel repair /tmp/wheelhouse/*.whl -w dist libmongocrypt-1.11.0/bindings/python/hatch_build.py000066400000000000000000000022021465326363200224260ustar00rootroot00000000000000"""A custom hatch build hook for pymongo.""" from __future__ import annotations import os import sys from pathlib import Path from hatchling.builders.hooks.plugin.interface import BuildHookInterface class CustomHook(BuildHookInterface): """The pymongocrypt build hook.""" def initialize(self, version, build_data): """Initialize the hook.""" if self.target_name == "sdist": return # Ensure wheel is marked as binary. # On linux, we use auditwheel to set the name. if sys.platform == "darwin": os.environ["MACOSX_DEPLOYMENT_TARGET"] = "11.0" build_data["tag"] = "py3-none-macosx_11_0_universal2" patt = ".dylib" elif os.name == "nt": build_data["tag"] = "py3-none-win_amd64" patt = ".dll" else: patt = ".so" here = Path(__file__).parent.resolve() dpath = here / "pymongocrypt" for fpath in dpath.glob(f"*{patt}"): relpath = os.path.relpath(fpath, here) build_data["artifacts"].append(relpath) build_data["force_include"][relpath] = relpath libmongocrypt-1.11.0/bindings/python/libmongocrypt-version.txt000066400000000000000000000000071465326363200247230ustar00rootroot000000000000001.10.1 libmongocrypt-1.11.0/bindings/python/pymongocrypt/000077500000000000000000000000001465326363200223645ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/pymongocrypt/__init__.py000066400000000000000000000013131465326363200244730ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from pymongocrypt.binding import lib, libmongocrypt_version # noqa: F401 from pymongocrypt.version import __version__ # noqa: F401 libmongocrypt-1.11.0/bindings/python/pymongocrypt/asynchronous/000077500000000000000000000000001465326363200251175ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/pymongocrypt/asynchronous/auto_encrypter.py000066400000000000000000000040631465326363200305370ustar00rootroot00000000000000# Copyright 2024-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from pymongocrypt.asynchronous.state_machine import run_state_machine from pymongocrypt.mongocrypt import MongoCrypt class AsyncAutoEncrypter: def __init__(self, callback, mongo_crypt_opts): """Encrypts and decrypts MongoDB commands. This class is used by a driver to support automatic encryption and decryption of MongoDB commands. :Parameters: - `callback`: A :class:`MongoCryptCallback`. - `mongo_crypt_opts`: A :class:`MongoCryptOptions`. """ self.callback = callback self.mongocrypt = MongoCrypt(mongo_crypt_opts, callback) async def encrypt(self, database, cmd): """Encrypt a MongoDB command. :Parameters: - `database`: The database for this command. - `cmd`: A MongoDB command as BSON. :Returns: The encrypted command. """ with self.mongocrypt.encryption_context(database, cmd) as ctx: return await run_state_machine(ctx, self.callback) async def decrypt(self, response): """Decrypt a MongoDB command response. :Parameters: - `response`: A MongoDB command response as BSON. :Returns: The decrypted command response. """ with self.mongocrypt.decryption_context(response) as ctx: return await run_state_machine(ctx, self.callback) async def close(self): """Cleanup resources.""" self.mongocrypt.close() await self.callback.close() libmongocrypt-1.11.0/bindings/python/pymongocrypt/asynchronous/credentials.py000066400000000000000000000126211465326363200277700ustar00rootroot00000000000000# Copyright 2024-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os from collections import namedtuple from datetime import datetime, timedelta, timezone try: from pymongo_auth_aws.auth import aws_temp_credentials _HAVE_AUTH_AWS = True except ImportError: _HAVE_AUTH_AWS = False import httpx from pymongocrypt.errors import MongoCryptError _azure_creds = namedtuple("_azure_creds", ["access_token", "expires_utc"]) _azure_creds_cache = None async def _get_gcp_credentials(): """Get on-demand GCP credentials""" metadata_host = os.getenv("GCE_METADATA_HOST") or "metadata.google.internal" url = ( "http://%s/computeMetadata/v1/instance/service-accounts/default/token" % metadata_host ) headers = {"Metadata-Flavor": "Google"} client = httpx.AsyncClient() try: response = await client.get(url, headers=headers) except Exception as e: msg = "unable to retrieve GCP credentials: %s" % e raise MongoCryptError(msg) from e finally: await client.aclose() if response.status_code != 200: msg = f"Unable to retrieve GCP credentials: expected StatusCode 200, got StatusCode: {response.status_code}. Response body:\n{response.content}" raise MongoCryptError(msg) try: data = response.json() except Exception as e: raise MongoCryptError( f"unable to retrieve GCP credentials: error reading response body\n{response.content}" ) from e if not data.get("access_token"): msg = ( "unable to retrieve GCP credentials: got unexpected empty accessToken from GCP Metadata Server. Response body: %s" % response.content ) raise MongoCryptError(msg) return {"accessToken": data["access_token"]} async def _get_azure_credentials(): """Get on-demand Azure credentials""" global _azure_creds_cache # Credentials are considered expired when: Expiration - now < 1 mins. creds = _azure_creds_cache if creds: if creds.expires_utc - datetime.now(tz=timezone.utc) < timedelta(seconds=60): _azure_creds_cache = None else: return {"accessToken": creds.access_token} url = "http://169.254.169.254/metadata/identity/oauth2/token" url += "?api-version=2018-02-01" url += "&resource=https://vault.azure.net" headers = {"Metadata": "true", "Accept": "application/json"} client = httpx.AsyncClient() try: response = await client.get(url, headers=headers) except Exception as e: msg = "Failed to acquire IMDS access token: %s" % e raise MongoCryptError(msg) from e finally: await client.aclose() if response.status_code != 200: msg = "Failed to acquire IMDS access token." raise MongoCryptError(msg) try: data = response.json() except Exception as e: raise MongoCryptError("Azure IMDS response must be in JSON format.") from e for key in ["access_token", "expires_in"]: if not data.get(key): msg = "Azure IMDS response must contain %s, but was %s." msg = msg % (key, response.content) raise MongoCryptError(msg) try: expires_in = int(data["expires_in"]) except ValueError as e: raise MongoCryptError( 'Azure IMDS response must contain "expires_in" integer, but was %s.' % response.content ) from e expires_utc = datetime.now(tz=timezone.utc) + timedelta(seconds=expires_in) _azure_creds_cache = _azure_creds(data["access_token"], expires_utc) return {"accessToken": data["access_token"]} async def _ask_for_kms_credentials(kms_providers): """Get on-demand kms credentials. This is a separate function so it can be overridden in unit tests.""" global _azure_creds_cache on_demand_aws = "aws" in kms_providers and not len(kms_providers["aws"]) on_demand_gcp = "gcp" in kms_providers and not len(kms_providers["gcp"]) on_demand_azure = "azure" in kms_providers and not len(kms_providers["azure"]) if not any([on_demand_aws, on_demand_gcp, on_demand_azure]): return {} creds = {} if on_demand_aws: if not _HAVE_AUTH_AWS: raise RuntimeError( "On-demand AWS credentials require pymongo-auth-aws: " "install with: python -m pip install 'pymongo[aws]'" ) aws_creds = aws_temp_credentials() creds_dict = { "accessKeyId": aws_creds.username, "secretAccessKey": aws_creds.password, } if aws_creds.token: creds_dict["sessionToken"] = aws_creds.token creds["aws"] = creds_dict if on_demand_gcp: creds["gcp"] = await _get_gcp_credentials() if on_demand_azure: try: creds["azure"] = await _get_azure_credentials() except Exception: _azure_creds_cache = None raise return creds libmongocrypt-1.11.0/bindings/python/pymongocrypt/asynchronous/explicit_encrypter.py000066400000000000000000000140171465326363200314100ustar00rootroot00000000000000# Copyright 2024-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from pymongocrypt.asynchronous.state_machine import run_state_machine from pymongocrypt.mongocrypt import MongoCrypt from pymongocrypt.options import DataKeyOpts, ExplicitEncryptOpts class AsyncExplicitEncrypter: def __init__(self, callback, mongo_crypt_opts): """Encrypts and decrypts BSON values. This class is used by a driver to support explicit encryption and decryption of individual fields in a BSON document. :Parameters: - `callback`: A :class:`MongoCryptCallback`. - `mongo_crypt_opts`: A :class:`MongoCryptOptions`. """ self.callback = callback if mongo_crypt_opts.schema_map is not None: raise ValueError("mongo_crypt_opts.schema_map must be None") self.mongocrypt = MongoCrypt(mongo_crypt_opts, callback) async def create_data_key( self, kms_provider, master_key=None, key_alt_names=None, key_material=None ): """Creates a data key used for explicit encryption. :Parameters: - `kms_provider`: The KMS provider to use. Supported values are "aws", "azure", "gcp", "kmip", "local", or a named provider like "kmip:name". - `master_key`: See class:`DataKeyOpts`. - `key_alt_names` (optional): An optional list of string alternate names used to reference a key. If a key is created with alternate names, then encryption may refer to the key by the unique alternate name instead of by ``_id``. - `key_material`: (optional) See class:`DataKeyOpts`. :Returns: The _id of the created data key document. """ # CDRIVER-3275 each key_alt_name needs to be wrapped in a bson # document. encoded_names = [] if key_alt_names is not None: for name in key_alt_names: encoded_names.append(self.callback.bson_encode({"keyAltName": name})) if key_material is not None: key_material = self.callback.bson_encode({"keyMaterial": key_material}) opts = DataKeyOpts(master_key, encoded_names, key_material) with self.mongocrypt.data_key_context(kms_provider, opts) as ctx: key = await run_state_machine(ctx, self.callback) return await self.callback.insert_data_key(key) async def rewrap_many_data_key(self, filter, provider=None, master_key=None): """Decrypts and encrypts all matching data keys with a possibly new `master_key` value. :Parameters: - `filter`: A document used to filter the data keys. - `provider`: (optional) The name of a different kms provider. - `master_key`: Optional document for the given provider. :Returns: A binary document with the rewrap data. """ with self.mongocrypt.rewrap_many_data_key_context( filter, provider, master_key ) as ctx: return await run_state_machine(ctx, self.callback) async def encrypt( self, value, algorithm, key_id=None, key_alt_name=None, query_type=None, contention_factor=None, range_opts=None, is_expression=False, ): """Encrypts a BSON value. Note that exactly one of ``key_id`` or ``key_alt_name`` must be provided. :Parameters: - `value` (bytes): The BSON value to encrypt. - `algorithm` (string): The encryption algorithm to use. See :class:`Algorithm` for some valid options. - `key_id` (bytes): The bytes of the binary subtype 4 ``_id`` data key. For example, ``uuid.bytes`` or ``bytes(bson_binary)``. - `key_alt_name` (string): Identifies a key vault document by 'keyAltName'. - `query_type` (str): The query type to execute. - `contention_factor` (int): The contention factor to use when the algorithm is "Indexed". - `range_opts` (bytes): Options for explicit encryption with the "range" algorithm encoded as a BSON document. - `is_expression` (boolean): True if this is an encryptExpression() context. Defaults to False. :Returns: The encrypted BSON value. .. versionchanged:: 1.3 Added the `query_type` and `contention_factor` parameters. .. versionchanged:: 1.5 Added the `range_opts` and `is_expression` parameters. """ # CDRIVER-3275 key_alt_name needs to be wrapped in a bson document. if key_alt_name is not None: key_alt_name = self.callback.bson_encode({"keyAltName": key_alt_name}) opts = ExplicitEncryptOpts( algorithm, key_id, key_alt_name, query_type, contention_factor, range_opts, is_expression, ) with self.mongocrypt.explicit_encryption_context(value, opts) as ctx: return await run_state_machine(ctx, self.callback) async def decrypt(self, value): """Decrypts a BSON value. :Parameters: - `value`: The encoded document to decrypt, which must be in the form { "v" : encrypted BSON value }}. :Returns: The decrypted BSON value. """ with self.mongocrypt.explicit_decryption_context(value) as ctx: return await run_state_machine(ctx, self.callback) def close(self): """Cleanup resources.""" self.mongocrypt.close() libmongocrypt-1.11.0/bindings/python/pymongocrypt/asynchronous/state_machine.py000066400000000000000000000114541465326363200303020ustar00rootroot00000000000000# Copyright 2024-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from abc import abstractmethod from pymongocrypt.asynchronous.credentials import _ask_for_kms_credentials from pymongocrypt.binding import lib from pymongocrypt.compat import ABC from pymongocrypt.errors import MongoCryptError class AsyncMongoCryptCallback(ABC): """Callback ABC to perform I/O on behalf of libbmongocrypt.""" @abstractmethod async def kms_request(self, kms_context): """Complete a KMS request. :Parameters: - `kms_context`: A :class:`MongoCryptKmsContext`. :Returns: None """ @abstractmethod async def collection_info(self, database, filter): """Get the collection info for a namespace. The returned collection info is passed to libmongocrypt which reads the JSON schema. :Parameters: - `database`: The database on which to run listCollections. - `filter`: The filter to pass to listCollections. :Returns: The first document from the listCollections command response as BSON. """ @abstractmethod async def mark_command(self, database, cmd): """Mark a command for encryption. :Parameters: - `database`: The database on which to run this command. - `cmd`: The BSON command to run. :Returns: The marked command response from mongocryptd. """ @abstractmethod async def fetch_keys(self, filter): """Yields one or more keys from the key vault. :Parameters: - `filter`: The filter to pass to find. :Returns: A generator which yields the requested keys from the key vault. """ @abstractmethod async def insert_data_key(self, data_key): """Insert a data key into the key vault. :Parameters: - `data_key`: The data key document to insert. :Returns: The _id of the inserted data key document. """ @abstractmethod def bson_encode(self, doc): """Encode a document to BSON. A document can be any mapping type (like :class:`dict`). :Parameters: - `doc`: mapping type representing a document :Returns: The encoded BSON bytes. """ @abstractmethod async def close(self): """Release resources.""" async def run_state_machine(ctx, callback): """Run the libmongocrypt state machine until completion. :Parameters: - `ctx`: A :class:`MongoCryptContext`. - `callback`: A :class:`AsyncMongoCryptCallback`. :Returns: The completed libmongocrypt operation. """ while True: state = ctx.state # Check for terminal states first. if state == lib.MONGOCRYPT_CTX_ERROR: ctx._raise_from_status() elif state == lib.MONGOCRYPT_CTX_READY: return ctx.finish() elif state == lib.MONGOCRYPT_CTX_DONE: return None if state == lib.MONGOCRYPT_CTX_NEED_MONGO_COLLINFO: list_colls_filter = ctx.mongo_operation() coll_info = await callback.collection_info(ctx.database, list_colls_filter) if coll_info: ctx.add_mongo_operation_result(coll_info) ctx.complete_mongo_operation() elif state == lib.MONGOCRYPT_CTX_NEED_MONGO_MARKINGS: mongocryptd_cmd = ctx.mongo_operation() result = await callback.mark_command(ctx.database, mongocryptd_cmd) ctx.add_mongo_operation_result(result) ctx.complete_mongo_operation() elif state == lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS: key_filter = ctx.mongo_operation() for key in await callback.fetch_keys(key_filter): ctx.add_mongo_operation_result(key) ctx.complete_mongo_operation() elif state == lib.MONGOCRYPT_CTX_NEED_KMS: for kms_ctx in ctx.kms_contexts(): with kms_ctx: await callback.kms_request(kms_ctx) ctx.complete_kms() elif state == lib.MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS: creds = await _ask_for_kms_credentials(ctx.kms_providers) ctx.provide_kms_providers(callback.bson_encode(creds)) else: raise MongoCryptError(f"unknown state: {state}") libmongocrypt-1.11.0/bindings/python/pymongocrypt/auto_encrypter.py000066400000000000000000000012431465326363200260010ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Alias file for import compatibility from pymongocrypt.synchronous.auto_encrypter import * libmongocrypt-1.11.0/bindings/python/pymongocrypt/binary.py000066400000000000000000000055501465326363200242270ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Internal helpers for dealing with mongocrypt_binary_t.""" from pymongocrypt.binding import ffi, lib from pymongocrypt.errors import MongoCryptError def _to_bytes(mongocrypt_binary): """Returns this mongocrypt_binary_t as bytes.""" data = mongocrypt_binary.data if data == ffi.NULL: raise MongoCryptError("mongocrypt_binary_t.data returned NULL") return ffi.unpack(ffi.cast("char*", data), mongocrypt_binary.len) def _write_bytes(mongocrypt_binary, data): """Writes the given data to a mongocrypt_binary_t.""" buf = mongocrypt_binary.data if buf == ffi.NULL: raise MongoCryptError("mongocrypt_binary_t.data returned NULL") ffi.memmove(buf, data, len(data)) mongocrypt_binary.len = len(data) class _MongoCryptBinary: __slots__ = ("bin",) def __init__(self, binary): """Wraps a mongocrypt_binary_t.""" if binary == ffi.NULL: raise MongoCryptError("unable to create new mongocrypt_binary object") self.bin = binary def _close(self): """Cleanup resources.""" if self.bin: lib.mongocrypt_binary_destroy(self.bin) self.bin = None def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self._close() def to_bytes(self): """Returns this mongocrypt_binary_t as bytes.""" data = self.bin.data if data == ffi.NULL: return b"" return ffi.unpack(ffi.cast("char*", data), self.bin.len) class MongoCryptBinaryOut(_MongoCryptBinary): __slots__ = () def __init__(self): """Wraps a mongocrypt_binary_t.""" super().__init__(lib.mongocrypt_binary_new()) class MongoCryptBinaryIn(_MongoCryptBinary): __slots__ = ("cref",) def __init__(self, data): """Creates a mongocrypt_binary_t from binary data.""" # mongocrypt_binary_t does not own the data it is passed so we need to # create a separate reference to keep the data alive. self.cref = ffi.from_buffer("uint8_t[]", data) super().__init__(lib.mongocrypt_binary_new_from_data(self.cref, len(data))) def _close(self): """Cleanup resources.""" super()._close() if self.cref is not None: ffi.release(self.cref) self.cref = None libmongocrypt-1.11.0/bindings/python/pymongocrypt/binding.py000066400000000000000000001574171465326363200243670ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import os.path import sys from pathlib import Path import cffi from packaging.version import Version from pymongocrypt.version import _MIN_LIBMONGOCRYPT_VERSION def _parse_version(version): return Version(version) ffi = cffi.FFI() # Generated with strip_header.py ffi.cdef( """/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @file mongocrypt.h The top-level handle to libmongocrypt. */ /** * @mainpage libmongocrypt * See all public API documentation in: @ref mongocrypt.h */ /* clang-format off */ /* clang-format on */ /** * Returns the version string for libmongocrypt. * * @param[out] len An optional length of the returned string. May be NULL. * @returns a NULL terminated version string for libmongocrypt. */ const char *mongocrypt_version(uint32_t *len); /** * Returns true if libmongocrypt was built with native crypto support. * * If libmongocrypt was not built with native crypto support, setting crypto * hooks is required. * * @returns True if libmongocrypt was built with native crypto support. */ bool mongocrypt_is_crypto_available(void); /** * A non-owning view of a byte buffer. * * When constructing a mongocrypt_binary_t it is the responsibility of the * caller to maintain the lifetime of the viewed data. However, all public * functions that take a mongocrypt_binary_t as an argument will make a copy of * the viewed data. For example, the following is valid: * * @code{.c} * mongocrypt_binary_t bin = mongocrypt_binary_new_from_data(mydata, mylen); * assert (mongocrypt_setopt_kms_provider_local (crypt), bin); * // The viewed data of bin has been copied. Ok to free the view and the data. * mongocrypt_binary_destroy (bin); * my_free_fn (mydata); * @endcode * * Functions with a mongocrypt_binary_t* out guarantee the lifetime of the * viewed data to live as long as the parent object. For example, @ref * mongocrypt_ctx_mongo_op guarantees that the viewed data of * mongocrypt_binary_t is valid until the parent ctx is destroyed with @ref * mongocrypt_ctx_destroy. * * The `mongocrypt_binary_t` struct definition is public. * Consumers may rely on the struct layout. */ typedef struct _mongocrypt_binary_t { void *data; uint32_t len; } mongocrypt_binary_t; /** * Create a new non-owning view of a buffer (data + length). * * Use this to create a mongocrypt_binary_t used for output parameters. * * @returns A new mongocrypt_binary_t. */ mongocrypt_binary_t *mongocrypt_binary_new(void); /** * Create a new non-owning view of a buffer (data + length). * * @param[in] data A pointer to an array of bytes. This data is not copied. @p * data must outlive the binary object. * @param[in] len The length of the @p data byte array. * * @returns A new @ref mongocrypt_binary_t. */ mongocrypt_binary_t *mongocrypt_binary_new_from_data(uint8_t *data, uint32_t len); /** * Get a pointer to the viewed data. * * @param[in] binary The @ref mongocrypt_binary_t. * * @returns A pointer to the viewed data. */ uint8_t *mongocrypt_binary_data(const mongocrypt_binary_t *binary); /** * Get the length of the viewed data. * * @param[in] binary The @ref mongocrypt_binary_t. * * @returns The length of the viewed data. */ uint32_t mongocrypt_binary_len(const mongocrypt_binary_t *binary); /** * Free the @ref mongocrypt_binary_t. * * This does not free the viewed data. * * @param[in] binary The mongocrypt_binary_t destroy. */ void mongocrypt_binary_destroy(mongocrypt_binary_t *binary); /** * Indicates success or contains error information. * * Functions like @ref mongocrypt_ctx_encrypt_init follow a pattern to expose a * status. A boolean is returned. True indicates success, and false indicates * failure. On failure a status on the handle is set, and is accessible with a * corresponding (handle)_status function. E.g. @ref mongocrypt_ctx_status. */ typedef struct _mongocrypt_status_t mongocrypt_status_t; /** * Indicates the type of error. */ typedef enum { MONGOCRYPT_STATUS_OK = 0, MONGOCRYPT_STATUS_ERROR_CLIENT = 1, MONGOCRYPT_STATUS_ERROR_KMS = 2, MONGOCRYPT_STATUS_ERROR_CRYPT_SHARED = 3, } mongocrypt_status_type_t; /** * Create a new status object. * * Use a new status object to retrieve the status from a handle by passing * this as an out-parameter to functions like @ref mongocrypt_ctx_status. * When done, destroy it with @ref mongocrypt_status_destroy. * * @returns A new status object. */ mongocrypt_status_t *mongocrypt_status_new(void); /** * Set a status object with message, type, and code. * * Use this to set the @ref mongocrypt_status_t given in the crypto hooks. * * @param[in] type The status type. * @param[in] code The status code. * @param[in] message The message. * @param[in] message_len Due to historical behavior, pass 1 + the string length * of @p message (which differs from other functions accepting string * arguments). * Alternatively, if message is NULL terminated this may be -1 to tell * mongocrypt * to determine the string's length with strlen. * */ void mongocrypt_status_set(mongocrypt_status_t *status, mongocrypt_status_type_t type, uint32_t code, const char *message, int32_t message_len); /** * Indicates success or the type of error. * * @param[in] status The status object. * * @returns A @ref mongocrypt_status_type_t. */ mongocrypt_status_type_t mongocrypt_status_type(mongocrypt_status_t *status); /** * Get an error code or 0. * * @param[in] status The status object. * * @returns An error code. */ uint32_t mongocrypt_status_code(mongocrypt_status_t *status); /** * Get the error message associated with a status or NULL. * * @param[in] status The status object. * @param[out] len An optional length of the returned string (excluding the * trailing NULL byte). May be NULL. * * @returns A NULL terminated error message or NULL. */ const char *mongocrypt_status_message(mongocrypt_status_t *status, uint32_t *len); /** * Returns true if the status indicates success. * * @param[in] status The status to check. * * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_status_ok(mongocrypt_status_t *status); /** * Free the memory for a status object. * * @param[in] status The status to destroy. */ void mongocrypt_status_destroy(mongocrypt_status_t *status); /** * Indicates the type of log message. */ typedef enum { MONGOCRYPT_LOG_LEVEL_FATAL = 0, MONGOCRYPT_LOG_LEVEL_ERROR = 1, MONGOCRYPT_LOG_LEVEL_WARNING = 2, MONGOCRYPT_LOG_LEVEL_INFO = 3, MONGOCRYPT_LOG_LEVEL_TRACE = 4 } mongocrypt_log_level_t; /** * A log callback function. Set a custom log callback with @ref * mongocrypt_setopt_log_handler. * * @param[in] message A NULL terminated message. * @param[in] message_len The length of message. * @param[in] ctx A context provided by the caller of @ref * mongocrypt_setopt_log_handler. */ typedef void (*mongocrypt_log_fn_t)(mongocrypt_log_level_t level, const char *message, uint32_t message_len, void *ctx); /** * The top-level handle to libmongocrypt. * * Create a mongocrypt_t handle to perform operations within libmongocrypt: * encryption, decryption, registering log callbacks, etc. * * Functions on a mongocrypt_t are thread safe, though functions on derived * handles (e.g. mongocrypt_ctx_t) are not and must be owned by a single * thread. See each handle's documentation for thread-safety considerations. * * Multiple mongocrypt_t handles may be created. */ typedef struct _mongocrypt_t mongocrypt_t; /** * Allocate a new @ref mongocrypt_t object. * * Set options using mongocrypt_setopt_* functions, then initialize with @ref * mongocrypt_init. When done with the @ref mongocrypt_t, free with @ref * mongocrypt_destroy. * * @returns A new @ref mongocrypt_t object. */ mongocrypt_t *mongocrypt_new(void); /** * Set a handler on the @ref mongocrypt_t object to get called on every log * message. * * @param[in] crypt The @ref mongocrypt_t object. * @param[in] log_fn The log callback. * @param[in] log_ctx A context passed as an argument to the log callback every * invocation. * @pre @ref mongocrypt_init has not been called on @p crypt. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_setopt_log_handler(mongocrypt_t *crypt, mongocrypt_log_fn_t log_fn, void *log_ctx); /** * Configure an AWS KMS provider on the @ref mongocrypt_t object. * * This has been superseded by the more flexible: * @ref mongocrypt_setopt_kms_providers * * @param[in] crypt The @ref mongocrypt_t object. * @param[in] aws_access_key_id The AWS access key ID used to generate KMS * messages. * @param[in] aws_access_key_id_len The string length (in bytes) of @p * aws_access_key_id. Pass -1 to determine the string length with strlen (must * be NULL terminated). * @param[in] aws_secret_access_key The AWS secret access key used to generate * KMS messages. * @param[in] aws_secret_access_key_len The string length (in bytes) of @p * aws_secret_access_key. Pass -1 to determine the string length with strlen * (must be NULL terminated). * @pre @ref mongocrypt_init has not been called on @p crypt. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_setopt_kms_provider_aws(mongocrypt_t *crypt, const char *aws_access_key_id, int32_t aws_access_key_id_len, const char *aws_secret_access_key, int32_t aws_secret_access_key_len); /** * Configure a local KMS provider on the @ref mongocrypt_t object. * * This has been superseded by the more flexible: * @ref mongocrypt_setopt_kms_providers * * @param[in] crypt The @ref mongocrypt_t object. * @param[in] key A 96 byte master key used to encrypt and decrypt key vault * keys. The viewed data is copied. It is valid to destroy @p key with @ref * mongocrypt_binary_destroy immediately after. * @pre @ref mongocrypt_init has not been called on @p crypt. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_setopt_kms_provider_local(mongocrypt_t *crypt, mongocrypt_binary_t *key); /** * Configure KMS providers with a BSON document. * * @param[in] crypt The @ref mongocrypt_t object. * @param[in] kms_providers A BSON document mapping the KMS provider names * to credentials. Set a KMS provider value to an empty document to supply * credentials on-demand with @ref mongocrypt_ctx_provide_kms_providers. * @pre @ref mongocrypt_init has not been called on @p crypt. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_setopt_kms_providers(mongocrypt_t *crypt, mongocrypt_binary_t *kms_providers); /** * Set a local schema map for encryption. * * @param[in] crypt The @ref mongocrypt_t object. * @param[in] schema_map A BSON document representing the schema map supplied by * the user. The keys are collection namespaces and values are JSON schemas. The * viewed data copied. It is valid to destroy @p schema_map with @ref * mongocrypt_binary_destroy immediately after. * @pre @p crypt has not been initialized. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_status */ bool mongocrypt_setopt_schema_map(mongocrypt_t *crypt, mongocrypt_binary_t *schema_map); /** * Set a local EncryptedFieldConfigMap for encryption. * * @param[in] crypt The @ref mongocrypt_t object. * @param[in] efc_map A BSON document representing the EncryptedFieldConfigMap * supplied by the user. The keys are collection namespaces and values are * EncryptedFieldConfigMap documents. The viewed data copied. It is valid to * destroy @p efc_map with @ref mongocrypt_binary_destroy immediately after. * @pre @p crypt has not been initialized. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_status */ bool mongocrypt_setopt_encrypted_field_config_map(mongocrypt_t *crypt, mongocrypt_binary_t *efc_map); /** * @brief Append an additional search directory to the search path for loading * the crypt_shared dynamic library. * * @param[in] crypt The @ref mongocrypt_t object to update * @param[in] path A null-terminated sequence of bytes for the search path. On * some filesystems, this may be arbitrary bytes. On other filesystems, this may * be required to be a valid UTF-8 code unit sequence. If the leading element of * the path is the literal string "$ORIGIN", that substring will be replaced * with the directory path containing the executable libmongocrypt module. If * the path string is literal "$SYSTEM", then libmongocrypt will defer to the * system's library resolution mechanism to find the crypt_shared library. * * @note If no crypt_shared dynamic library is found in any of the directories * specified by the search paths loaded here, @ref mongocrypt_init() will still * succeed and continue to operate without crypt_shared. * * @note The search paths are searched in the order that they are appended. This * allows one to provide a precedence in how the library will be discovered. For * example, appending known directories before appending "$SYSTEM" will allow * one to supersede the system's installed library, but still fall-back to it if * the library wasn't found otherwise. If one does not ever append "$SYSTEM", * then the system's library-search mechanism will never be consulted. * * @note If an absolute path to the library is specified using * @ref mongocrypt_setopt_set_crypt_shared_lib_path_override, then paths * appended here will have no effect. */ void mongocrypt_setopt_append_crypt_shared_lib_search_path(mongocrypt_t *crypt, const char *path); /** * @brief Set a single override path for loading the crypt_shared dynamic * library. * * @param[in] crypt The @ref mongocrypt_t object to update * @param[in] path A null-terminated sequence of bytes for a path to the * crypt_shared dynamic library. On some filesystems, this may be arbitrary * bytes. On other filesystems, this may be required to be a valid UTF-8 code * unit sequence. If the leading element of the path is the literal string * `$ORIGIN`, that substring will be replaced with the directory path containing * the executable libmongocrypt module. * * @note This function will do no IO nor path validation. All validation will * occur during the call to @ref mongocrypt_init. * * @note If a crypt_shared library path override is specified here, then no * paths given to @ref mongocrypt_setopt_append_crypt_shared_lib_search_path * will be consulted when opening the crypt_shared library. * * @note If a path is provided via this API and @ref mongocrypt_init fails to * initialize a valid crypt_shared library instance for the path specified, then * the initialization of mongocrypt_t will fail with an error. */ void mongocrypt_setopt_set_crypt_shared_lib_path_override(mongocrypt_t *crypt, const char *path); /** * @brief Opt-into handling the MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS state. * * If set, before entering the MONGOCRYPT_CTX_NEED_KMS state, * contexts may enter the MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS state * and then wait for credentials to be supplied through * @ref mongocrypt_ctx_provide_kms_providers. * * A context will only enter MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS * if an empty document was set for a KMS provider in @ref * mongocrypt_setopt_kms_providers. * * @param[in] crypt The @ref mongocrypt_t object to update */ void mongocrypt_setopt_use_need_kms_credentials_state(mongocrypt_t *crypt); /** * @brief Opt-into handling the MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB state. * * A context enters the MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB state when * processing a `bulkWrite` command. The target database of the `bulkWrite` may differ from the command database * ("admin"). * * @param[in] crypt The @ref mongocrypt_t object to update */ void mongocrypt_setopt_use_need_mongo_collinfo_with_db_state(mongocrypt_t *crypt); /** * Initialize new @ref mongocrypt_t object. * * Set options before using @ref mongocrypt_setopt_kms_provider_local, @ref * mongocrypt_setopt_kms_provider_aws, or @ref mongocrypt_setopt_log_handler. * * @param[in] crypt The @ref mongocrypt_t object. * * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status Failure may occur if previously * set * options are invalid. */ bool mongocrypt_init(mongocrypt_t *crypt); /** * Get the status associated with a @ref mongocrypt_t object. * * @param[in] crypt The @ref mongocrypt_t object. * @param[out] status Receives the status. * * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_status(mongocrypt_t *crypt, mongocrypt_status_t *status); /** * Destroy the @ref mongocrypt_t object. * * @param[in] crypt The @ref mongocrypt_t object to destroy. */ void mongocrypt_destroy(mongocrypt_t *crypt); /** * Obtain a nul-terminated version string of the loaded crypt_shared dynamic * library, if available. * * If no crypt_shared was successfully loaded, this function returns NULL. * * @param[in] crypt The mongocrypt_t object after a successful call to * mongocrypt_init. * @param[out] len An optional output parameter to which the length of the * returned string is written. If provided and no crypt_shared library was * loaded, zero is written to *len. * * @return A nul-terminated string of the dynamically loaded crypt_shared * library. * * @note For a numeric value that can be compared against, use * @ref mongocrypt_crypt_shared_lib_version. */ const char *mongocrypt_crypt_shared_lib_version_string(const mongocrypt_t *crypt, uint32_t *len); /** * @brief Obtain a 64-bit constant encoding the version of the loaded * crypt_shared library, if available. * * @param[in] crypt The mongocrypt_t object after a successful call to * mongocrypt_init. * * @return A 64-bit encoded version number, with the version encoded as four * sixteen-bit integers, or zero if no crypt_shared library was loaded. * * The version is encoded as four 16-bit numbers, from high to low: * * - Major version * - Minor version * - Revision * - Reserved * * For example, version 6.2.1 would be encoded as: 0x0006'0002'0001'0000 */ uint64_t mongocrypt_crypt_shared_lib_version(const mongocrypt_t *crypt); /** * Manages the state machine for encryption or decryption. */ typedef struct _mongocrypt_ctx_t mongocrypt_ctx_t; /** * Create a new uninitialized @ref mongocrypt_ctx_t. * * Initialize the context with functions like @ref mongocrypt_ctx_encrypt_init. * When done, destroy it with @ref mongocrypt_ctx_destroy. * * @param[in] crypt The @ref mongocrypt_t object. * @returns A new context. */ mongocrypt_ctx_t *mongocrypt_ctx_new(mongocrypt_t *crypt); /** * Get the status associated with a @ref mongocrypt_ctx_t object. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[out] status Receives the status. * * @returns True if the output is an ok status, false if it is an error * status. * * @see mongocrypt_status_ok */ bool mongocrypt_ctx_status(mongocrypt_ctx_t *ctx, mongocrypt_status_t *status); /** * Set the key id to use for explicit encryption. * * It is an error to set both this and the key alt name. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] key_id The binary corresponding to the _id (a UUID) of the data * key to use from the key vault collection. Note, the UUID must be encoded with * RFC-4122 byte order. The viewed data is copied. It is valid to destroy * @p key_id with @ref mongocrypt_binary_destroy immediately after. * @pre @p ctx has not been initialized. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_setopt_key_id(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *key_id); /** * Set the keyAltName to use for explicit encryption or * data key creation. * * Pass the binary encoding a BSON document like the following: * * { "keyAltName" : (BSON UTF8 value) } * * For explicit encryption, it is an error to set both the keyAltName * and the key id. * * For creating data keys, call this function repeatedly to set * multiple keyAltNames. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] key_alt_name The name to use. The viewed data is copied. It is * valid to destroy @p key_alt_name with @ref mongocrypt_binary_destroy * immediately after. * @pre @p ctx has not been initialized. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_setopt_key_alt_name(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *key_alt_name); /** * Set the keyMaterial to use for encrypting data. * * Pass the binary encoding of a BSON document like the following: * * { "keyMaterial" : (BSON BINARY value) } * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] key_material The data encryption key to use. The viewed data is * copied. It is valid to destroy @p key_material with @ref * mongocrypt_binary_destroy immediately after. * @pre @p ctx has not been initialized. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_setopt_key_material(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *key_material); /** * Set the algorithm used for encryption to either * deterministic or random encryption. This value * should only be set when using explicit encryption. * * If -1 is passed in for "len", then "algorithm" is * assumed to be a null-terminated string. * * Valid values for algorithm are: * "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" * "AEAD_AES_256_CBC_HMAC_SHA_512-Random" * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] algorithm A string specifying the algorithm to * use for encryption. * @param[in] len The length of the algorithm string. * @pre @p ctx has not been initialized. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_setopt_algorithm(mongocrypt_ctx_t *ctx, const char *algorithm, int len); /// String constant for setopt_algorithm "Deterministic" encryption /// String constant for setopt_algorithm "Random" encryption /// String constant for setopt_algorithm "Indexed" explicit encryption /// String constant for setopt_algorithm "Unindexed" explicit encryption // DEPRECATED: support "RangePreview" has been removed in favor of "range". // NOTE: "Range" is currently unstable API and subject to backwards breaking changes. /** * Identify the AWS KMS master key to use for creating a data key. * * This has been superseded by the more flexible: * @ref mongocrypt_ctx_setopt_key_encryption_key * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] region The AWS region. * @param[in] region_len The string length of @p region. Pass -1 to determine * the string length with strlen (must be NULL terminated). * @param[in] cmk The Amazon Resource Name (ARN) of the customer master key * (CMK). * @param[in] cmk_len The string length of @p cmk_len. Pass -1 to determine the * string length with strlen (must be NULL terminated). * @pre @p ctx has not been initialized. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_setopt_masterkey_aws(mongocrypt_ctx_t *ctx, const char *region, int32_t region_len, const char *cmk, int32_t cmk_len); /** * Identify a custom AWS endpoint when creating a data key. * This is used internally to construct the correct HTTP request * (with the Host header set to this endpoint). This endpoint * is persisted in the new data key, and will be returned via * @ref mongocrypt_kms_ctx_endpoint. * * This has been superseded by the more flexible: * @ref mongocrypt_ctx_setopt_key_encryption_key * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] endpoint The endpoint. * @param[in] endpoint_len The string length of @p endpoint. Pass -1 to * determine the string length with strlen (must be NULL terminated). * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_setopt_masterkey_aws_endpoint(mongocrypt_ctx_t *ctx, const char *endpoint, int32_t endpoint_len); /** * Set the master key to "local" for creating a data key. * This has been superseded by the more flexible: * @ref mongocrypt_ctx_setopt_key_encryption_key * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @pre @p ctx has not been initialized. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_setopt_masterkey_local(mongocrypt_ctx_t *ctx); /** * Set key encryption key document for creating a data key or for rewrapping * datakeys. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] bin BSON representing the key encryption key document with * an additional "provider" field. The following forms are accepted: * * AWS * { * provider: "aws", * region: , * key: , * endpoint: * } * * Azure * { * provider: "azure", * keyVaultEndpoint: , * keyName: , * keyVersion: * } * * GCP * { * provider: "gcp", * projectId: , * location: , * keyRing: , * keyName: , * keyVersion: , * endpoint: * } * * Local * { * provider: "local" * } * * KMIP * { * provider: "kmip", * keyId: * endpoint: * } * * @pre @p ctx has not been initialized. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status. */ bool mongocrypt_ctx_setopt_key_encryption_key(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *bin); /** * Initialize a context to create a data key. * * Associated options: * - @ref mongocrypt_ctx_setopt_masterkey_aws * - @ref mongocrypt_ctx_setopt_masterkey_aws_endpoint * - @ref mongocrypt_ctx_setopt_masterkey_local * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status * @pre A master key option has been set, and an associated KMS provider * has been set on the parent @ref mongocrypt_t. */ bool mongocrypt_ctx_datakey_init(mongocrypt_ctx_t *ctx); /** * Initialize a context for encryption. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] db The database name. * @param[in] db_len The byte length of @p db. Pass -1 to determine the string * length with strlen (must * be NULL terminated). * @param[in] cmd The BSON command to be encrypted. The viewed data is copied. * It is valid to destroy @p cmd with @ref mongocrypt_binary_destroy immediately * after. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_encrypt_init(mongocrypt_ctx_t *ctx, const char *db, int32_t db_len, mongocrypt_binary_t *cmd); /** * Explicit helper method to encrypt a single BSON object. Contexts * created for explicit encryption will not go through mongocryptd. * * To specify a key_id, algorithm, or iv to use, please use the * corresponding mongocrypt_setopt methods before calling this. * * This method expects the passed-in BSON to be of the form: * { "v" : BSON value to encrypt } * * The value of "v" is expected to be the BSON value passed to a driver * ClientEncryption.encrypt helper. * * Associated options for FLE 1: * - @ref mongocrypt_ctx_setopt_key_id * - @ref mongocrypt_ctx_setopt_key_alt_name * - @ref mongocrypt_ctx_setopt_algorithm * * Associated options for Queryable Encryption: * - @ref mongocrypt_ctx_setopt_key_id * - @ref mongocrypt_ctx_setopt_index_key_id * - @ref mongocrypt_ctx_setopt_contention_factor * - @ref mongocrypt_ctx_setopt_query_type * - @ref mongocrypt_ctx_setopt_algorithm_range * * An error is returned if FLE 1 and Queryable Encryption incompatible options * are set. * * @param[in] ctx A @ref mongocrypt_ctx_t. * @param[in] msg A @ref mongocrypt_binary_t the plaintext BSON value. The * viewed data is copied. It is valid to destroy @p msg with @ref * mongocrypt_binary_destroy immediately after. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *msg); /** * Explicit helper method to encrypt a Match Expression or Aggregate Expression. * Contexts created for explicit encryption will not go through mongocryptd. * Requires query_type to be "range". * * NOTE: "range" is currently unstable API and subject to backwards breaking changes. * * This method expects the passed-in BSON to be of the form: * { "v" : FLE2RangeFindDriverSpec } * * FLE2RangeFindDriverSpec is a BSON document with one of these forms: * * 1. A Match Expression of this form: * {$and: [{: {: , {: {: }}]} * 2. An Aggregate Expression of this form: * {$and: [{: [, ]}, {: [, ]}] * * may be $lt, $lte, $gt, or $gte. * * The value of "v" is expected to be the BSON value passed to a driver * ClientEncryption.encryptExpression helper. * * Associated options for FLE 1: * - @ref mongocrypt_ctx_setopt_key_id * - @ref mongocrypt_ctx_setopt_key_alt_name * - @ref mongocrypt_ctx_setopt_algorithm * * Associated options for Queryable Encryption: * - @ref mongocrypt_ctx_setopt_key_id * - @ref mongocrypt_ctx_setopt_index_key_id * - @ref mongocrypt_ctx_setopt_contention_factor * - @ref mongocrypt_ctx_setopt_query_type * - @ref mongocrypt_ctx_setopt_algorithm_range * * An error is returned if FLE 1 and Queryable Encryption incompatible options * are set. * * @param[in] ctx A @ref mongocrypt_ctx_t. * @param[in] msg A @ref mongocrypt_binary_t the plaintext BSON value. The * viewed data is copied. It is valid to destroy @p msg with @ref * mongocrypt_binary_destroy immediately after. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_explicit_encrypt_expression_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *msg); /** * Initialize a context for decryption. * * This method expects the passed-in BSON to be of the form: * { "v" : BSON value to encrypt } * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] doc The document to be decrypted. The viewed data is copied. It is * valid to destroy @p doc with @ref mongocrypt_binary_destroy immediately * after. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_decrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *doc); /** * Explicit helper method to decrypt a single BSON object. * * Pass the binary encoding of a BSON document containing the BSON value to * encrypt like the following: * * { "v" : (BSON BINARY value of subtype 6) } * * @param[in] ctx A @ref mongocrypt_ctx_t. * @param[in] msg A @ref mongocrypt_binary_t the encrypted BSON. The viewed data * is copied. It is valid to destroy @p msg with @ref mongocrypt_binary_destroy * immediately after. */ bool mongocrypt_ctx_explicit_decrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *msg); /** * @brief Initialize a context to rewrap datakeys. * * Associated options: * - @ref mongocrypt_ctx_setopt_key_encryption_key * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] filter The filter to use for the find command on the key vault * collection to retrieve datakeys to rewrap. * @return A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status. */ bool mongocrypt_ctx_rewrap_many_datakey_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *filter); /** * Indicates the state of the @ref mongocrypt_ctx_t. Each state requires * different handling. See [the integration * guide](https://github.com/mongodb/libmongocrypt/blob/master/integrating.md#state-machine) * for information on what to do for each state. */ typedef enum { MONGOCRYPT_CTX_ERROR = 0, MONGOCRYPT_CTX_NEED_MONGO_COLLINFO = 1, /* run on main MongoClient */ MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB = 8, /* run on main MongoClient */ MONGOCRYPT_CTX_NEED_MONGO_MARKINGS = 2, /* run on mongocryptd. */ MONGOCRYPT_CTX_NEED_MONGO_KEYS = 3, /* run on key vault */ MONGOCRYPT_CTX_NEED_KMS = 4, MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS = 7, /* fetch/renew KMS credentials */ MONGOCRYPT_CTX_READY = 5, /* ready for encryption/decryption */ MONGOCRYPT_CTX_DONE = 6, } mongocrypt_ctx_state_t; /** * Get the current state of a context. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @returns A @ref mongocrypt_ctx_state_t. */ mongocrypt_ctx_state_t mongocrypt_ctx_state(mongocrypt_ctx_t *ctx); /** * Get BSON necessary to run the mongo operation when mongocrypt_ctx_t * is in MONGOCRYPT_CTX_NEED_MONGO_* states. * * @p op_bson is a BSON document to be used for the operation. * - For MONGOCRYPT_CTX_NEED_MONGO_COLLINFO(_WITH_DB) it is a listCollections filter. * - For MONGOCRYPT_CTX_NEED_MONGO_KEYS it is a find filter. * - For MONGOCRYPT_CTX_NEED_MONGO_MARKINGS it is a command to send to * mongocryptd. * * The lifetime of @p op_bson is tied to the lifetime of @p ctx. It is valid * until @ref mongocrypt_ctx_destroy is called. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[out] op_bson A BSON document for the MongoDB operation. The data * viewed by @p op_bson is guaranteed to be valid until @p ctx is destroyed with * @ref mongocrypt_ctx_destroy. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_mongo_op(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *op_bson); /** * Get the database to run the mongo operation. * * Only applies when mongocrypt_ctx_t is in the state: * MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB. * * The lifetime of the returned string is tied to the lifetime of @p ctx. It is * valid until @ref mongocrypt_ctx_destroy is called. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @returns A string or NULL. If NULL, an error status is set. Retrieve it with * @ref mongocrypt_ctx_status */ const char *mongocrypt_ctx_mongo_db(mongocrypt_ctx_t *ctx); /** * Feed a BSON reply or result when mongocrypt_ctx_t is in * MONGOCRYPT_CTX_NEED_MONGO_* states. This may be called multiple times * depending on the operation. * * reply is a BSON document result being fed back for this operation. * - For MONGOCRYPT_CTX_NEED_MONGO_COLLINFO(_WITH_DB) it is a doc from a listCollections * cursor. (Note, if listCollections returned no result, do not call this * function.) * - For MONGOCRYPT_CTX_NEED_MONGO_KEYS it is a doc from a find cursor. * (Note, if find returned no results, do not call this function. reply must * not * be NULL.) * - For MONGOCRYPT_CTX_NEED_MONGO_MARKINGS it is a reply from mongocryptd. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] reply A BSON document for the MongoDB operation. The viewed data * is copied. It is valid to destroy @p reply with @ref * mongocrypt_binary_destroy immediately after. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_mongo_feed(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *reply); /** * Call when done feeding the reply (or replies) back to the context. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_mongo_done(mongocrypt_ctx_t *ctx); /** * Manages a single KMS HTTP request/response. */ typedef struct _mongocrypt_kms_ctx_t mongocrypt_kms_ctx_t; /** * Get the next KMS handle. * * Multiple KMS handles may be retrieved at once. Drivers may do this to fan * out multiple concurrent KMS HTTP requests. Feeding multiple KMS requests * is thread-safe. * * If KMS handles are being handled synchronously, the driver can reuse the same * TLS socket to send HTTP requests and receive responses. * * @param[in] ctx A @ref mongocrypt_ctx_t. * @returns a new @ref mongocrypt_kms_ctx_t or NULL. */ mongocrypt_kms_ctx_t *mongocrypt_ctx_next_kms_ctx(mongocrypt_ctx_t *ctx); /** * Get the HTTP request message for a KMS handle. * * The lifetime of @p msg is tied to the lifetime of @p kms. It is valid * until @ref mongocrypt_ctx_kms_done is called. * * @param[in] kms A @ref mongocrypt_kms_ctx_t. * @param[out] msg The HTTP request to send to KMS. The data viewed by @p msg is * guaranteed to be valid until the call of @ref mongocrypt_ctx_kms_done of the * parent @ref mongocrypt_ctx_t. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_kms_ctx_status */ bool mongocrypt_kms_ctx_message(mongocrypt_kms_ctx_t *kms, mongocrypt_binary_t *msg); /** * Get the hostname from which to connect over TLS. * * The storage for @p endpoint is not owned by the caller, but * is valid until calling @ref mongocrypt_ctx_kms_done. * * @param[in] kms A @ref mongocrypt_kms_ctx_t. * @param[out] endpoint The output endpoint as a NULL terminated string. * The endpoint consists of a hostname and port separated by a colon. * E.g. "example.com:123". A port is always present. * * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_kms_ctx_status */ bool mongocrypt_kms_ctx_endpoint(mongocrypt_kms_ctx_t *kms, const char **endpoint); /** * Indicates how many bytes to feed into @ref mongocrypt_kms_ctx_feed. * * @param[in] kms The @ref mongocrypt_kms_ctx_t. * @returns The number of requested bytes. */ uint32_t mongocrypt_kms_ctx_bytes_needed(mongocrypt_kms_ctx_t *kms); /** * Feed bytes from the HTTP response. * * Feeding more bytes than what has been returned in @ref * mongocrypt_kms_ctx_bytes_needed is an error. * * @param[in] kms The @ref mongocrypt_kms_ctx_t. * @param[in] bytes The bytes to feed. The viewed data is copied. It is valid to * destroy @p bytes with @ref mongocrypt_binary_destroy immediately after. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_kms_ctx_status */ bool mongocrypt_kms_ctx_feed(mongocrypt_kms_ctx_t *kms, mongocrypt_binary_t *bytes); /** * Get the status associated with a @ref mongocrypt_kms_ctx_t object. * * @param[in] kms The @ref mongocrypt_kms_ctx_t object. * @param[out] status Receives the status. * * @returns A boolean indicating success. If false, an error status is set. */ bool mongocrypt_kms_ctx_status(mongocrypt_kms_ctx_t *kms, mongocrypt_status_t *status); /** * Get the KMS provider identifier associated with this KMS request. * * This is used to conditionally configure TLS connections based on the KMS * request. It is useful for KMIP, which authenticates with a client * certificate. * * @param[in] kms The @ref mongocrypt_kms_ctx_t object. * @param[out] len Receives the length of the returned string. It may be NULL. * If it is not NULL, it is set to the length of the returned string without * the NULL terminator. * * @returns One of the NULL terminated static strings: "aws", "azure", "gcp", or * "kmip". */ const char *mongocrypt_kms_ctx_get_kms_provider(mongocrypt_kms_ctx_t *kms, uint32_t *len); /** * Call when done handling all KMS contexts. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_kms_done(mongocrypt_ctx_t *ctx); /** * Call in response to the MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS state * to set per-context KMS provider settings. These follow the same format * as @ref mongocrypt_setopt_kms_providers. If no keys are present in the * BSON input, the KMS provider settings configured for the @ref mongocrypt_t * at initialization are used. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] kms_providers_definition A BSON document mapping the KMS provider * names to credentials. * * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status. */ bool mongocrypt_ctx_provide_kms_providers(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *kms_providers_definition); /** * Perform the final encryption or decryption. * * @param[in] ctx A @ref mongocrypt_ctx_t. * @param[out] out The final BSON. The data viewed by @p out is guaranteed * to be valid until @p ctx is destroyed with @ref mongocrypt_ctx_destroy. * The meaning of this BSON depends on the type of @p ctx. * * If @p ctx was initialized with @ref mongocrypt_ctx_encrypt_init, then * this BSON is the (possibly) encrypted command to send to the server. * * If @p ctx was initialized with @ref mongocrypt_ctx_decrypt_init, then * this BSON is the decrypted result to return to the user. * * If @p ctx was initialized with @ref mongocrypt_ctx_explicit_encrypt_init, * then this BSON has the form { "v": (BSON binary) } where the BSON binary * is the resulting encrypted value. * * If @p ctx was initialized with @ref mongocrypt_ctx_explicit_decrypt_init, * then this BSON has the form { "v": (BSON value) } where the BSON value * is the resulting decrypted value. * * If @p ctx was initialized with @ref mongocrypt_ctx_datakey_init, then * this BSON is the document containing the new data key to be inserted into * the key vault collection. * * If @p ctx was initialized with @ref mongocrypt_ctx_rewrap_many_datakey_init, * then this BSON has the form: * { "v": [{ "_id": ..., "keyMaterial": ..., "masterKey": ... }, ...] } * where each BSON document in the array contains the updated fields of a * rewrapped datakey to be bulk-updated into the key vault collection. * Note: the updateDate field should be updated using the $currentDate operator. * * @returns a bool indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out); /** * Destroy and free all memory associated with a @ref mongocrypt_ctx_t. * * @param[in] ctx A @ref mongocrypt_ctx_t. */ void mongocrypt_ctx_destroy(mongocrypt_ctx_t *ctx); /** * An crypto AES-256-CBC encrypt or decrypt function. * * Note, @p in is already padded. Encrypt with padding disabled. * @param[in] ctx An optional context object that may have been set when hooks * were enabled. * @param[in] key An encryption key (32 bytes for AES_256). * @param[in] iv An initialization vector (16 bytes for AES_256); * @param[in] in The input. * @param[out] out A preallocated byte array for the output. See @ref * mongocrypt_binary_data. * @param[out] bytes_written Set this to the number of bytes written to @p out. * @param[out] status An optional status to pass error messages. See @ref * mongocrypt_status_set. * @returns A boolean indicating success. If returning false, set @p status * with a message indicating the error using @ref mongocrypt_status_set. */ typedef bool (*mongocrypt_crypto_fn)(void *ctx, mongocrypt_binary_t *key, mongocrypt_binary_t *iv, mongocrypt_binary_t *in, mongocrypt_binary_t *out, uint32_t *bytes_written, mongocrypt_status_t *status); /** * A crypto signature or HMAC function. * * Currently used in callbacks for HMAC SHA-512, HMAC SHA-256, and RSA SHA-256 * signature. * * @param[in] ctx An optional context object that may have been set when hooks * were enabled. * @param[in] key An encryption key (32 bytes for HMAC_SHA512). * @param[in] in The input. * @param[out] out A preallocated byte array for the output. See @ref * mongocrypt_binary_data. * @param[out] status An optional status to pass error messages. See @ref * mongocrypt_status_set. * @returns A boolean indicating success. If returning false, set @p status * with a message indicating the error using @ref mongocrypt_status_set. */ typedef bool (*mongocrypt_hmac_fn)(void *ctx, mongocrypt_binary_t *key, mongocrypt_binary_t *in, mongocrypt_binary_t *out, mongocrypt_status_t *status); /** * A crypto hash (SHA-256) function. * * @param[in] ctx An optional context object that may have been set when hooks * were enabled. * @param[in] in The input. * @param[out] out A preallocated byte array for the output. See @ref * mongocrypt_binary_data. * @param[out] status An optional status to pass error messages. See @ref * mongocrypt_status_set. * @returns A boolean indicating success. If returning false, set @p status * with a message indicating the error using @ref mongocrypt_status_set. */ typedef bool (*mongocrypt_hash_fn)(void *ctx, mongocrypt_binary_t *in, mongocrypt_binary_t *out, mongocrypt_status_t *status); /** * A crypto secure random function. * * @param[in] ctx An optional context object that may have been set when hooks * were enabled. * @param[out] out A preallocated byte array for the output. See @ref * mongocrypt_binary_data. * @param[in] count The number of random bytes requested. * @param[out] status An optional status to pass error messages. See @ref * mongocrypt_status_set. * @returns A boolean indicating success. If returning false, set @p status * with a message indicating the error using @ref mongocrypt_status_set. */ typedef bool (*mongocrypt_random_fn)(void *ctx, mongocrypt_binary_t *out, uint32_t count, mongocrypt_status_t *status); bool mongocrypt_setopt_crypto_hooks(mongocrypt_t *crypt, mongocrypt_crypto_fn aes_256_cbc_encrypt, mongocrypt_crypto_fn aes_256_cbc_decrypt, mongocrypt_random_fn random, mongocrypt_hmac_fn hmac_sha_512, mongocrypt_hmac_fn hmac_sha_256, mongocrypt_hash_fn sha_256, void *ctx); /** * Set a crypto hook for the AES256-CTR operations. * * @param[in] crypt The @ref mongocrypt_t object. * @param[in] aes_256_ctr_encrypt The crypto callback function for encrypt * operation. * @param[in] aes_256_ctr_decrypt The crypto callback function for decrypt * operation. * @param[in] ctx Unused. * @pre @ref mongocrypt_init has not been called on @p crypt. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_status * */ bool mongocrypt_setopt_aes_256_ctr(mongocrypt_t *crypt, mongocrypt_crypto_fn aes_256_ctr_encrypt, mongocrypt_crypto_fn aes_256_ctr_decrypt, void *ctx); /** * Set an AES256-ECB crypto hook for the AES256-CTR operations. If CTR hook was * configured using @ref mongocrypt_setopt_aes_256_ctr, ECB hook will be * ignored. * * @param[in] crypt The @ref mongocrypt_t object. * @param[in] aes_256_ecb_encrypt The crypto callback function for encrypt * operation. * @param[in] ctx Unused. * @pre @ref mongocrypt_init has not been called on @p crypt. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_status * */ bool mongocrypt_setopt_aes_256_ecb(mongocrypt_t *crypt, mongocrypt_crypto_fn aes_256_ecb_encrypt, void *ctx); /** * Set a crypto hook for the RSASSA-PKCS1-v1_5 algorithm with a SHA-256 hash. * * See: https://tools.ietf.org/html/rfc3447#section-8.2 * * Note: this function has the wrong name. It should be: * mongocrypt_setopt_crypto_hook_sign_rsassa_pkcs1_v1_5 * * @param[in] crypt The @ref mongocrypt_t object. * @param[in] sign_rsaes_pkcs1_v1_5 The crypto callback function. * @param[in] sign_ctx A context passed as an argument to the crypto callback * every invocation. * @pre @ref mongocrypt_init has not been called on @p crypt. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_status * */ bool mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5(mongocrypt_t *crypt, mongocrypt_hmac_fn sign_rsaes_pkcs1_v1_5, void *sign_ctx); /** * @brief Opt-into skipping query analysis. * * If opted in: * - The crypt_shared library will not attempt to be loaded. * - A mongocrypt_ctx_t will never enter the MONGOCRYPT_CTX_NEED_MARKINGS state. * * @param[in] crypt The @ref mongocrypt_t object to update */ void mongocrypt_setopt_bypass_query_analysis(mongocrypt_t *crypt); /** * DEPRECATED: Use of `mongocrypt_setopt_use_range_v2` is deprecated. Range V2 is always enabled. * NOTE: "range" is currently unstable API and subject to backwards breaking changes. * * @param[in] crypt The @ref mongocrypt_t object. * * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_status */ bool mongocrypt_setopt_use_range_v2(mongocrypt_t *crypt); /** * Set the contention factor used for explicit encryption. * The contention factor is only used for indexed Queryable Encryption. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] contention_factor * @pre @p ctx has not been initialized. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status. */ bool mongocrypt_ctx_setopt_contention_factor(mongocrypt_ctx_t *ctx, int64_t contention_factor); /** * Set the index key id to use for explicit Queryable Encryption. * * If the index key id not set, the key id from @ref * mongocrypt_ctx_setopt_key_id is used. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] key_id The binary corresponding to the _id (a UUID) of the data * key to use from the key vault collection. Note, the UUID must be encoded with * RFC-4122 byte order. The viewed data is copied. It is valid to destroy * @p key_id with @ref mongocrypt_binary_destroy immediately after. * @pre @p ctx has not been initialized. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_setopt_index_key_id(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *key_id); /** * Set the query type to use for explicit Queryable Encryption. * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] query_type The query type string * @param[in] len The length of query_type, or -1 for automatic * @pre @p ctx has not been initialized. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_setopt_query_type(mongocrypt_ctx_t *ctx, const char *query_type, int len); /** * Set options for explicit encryption with the "range" algorithm. * NOTE: "range" is currently unstable API and subject to backwards breaking changes. * * @p opts is a BSON document of the form: * { * "min": Optional, * "max": Optional, * "sparsity": Int64, * "precision": Optional, * "trimFactor": Optional * } * * @param[in] ctx The @ref mongocrypt_ctx_t object. * @param[in] opts BSON. * @pre @p ctx has not been initialized. * @returns A boolean indicating success. If false, an error status is set. * Retrieve it with @ref mongocrypt_ctx_status */ bool mongocrypt_ctx_setopt_algorithm_range(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *opts); /// String constants for setopt_query_type // DEPRECATED: Support "rangePreview" has been removed in favor of "range". /// NOTE: "range" is currently unstable API and subject to backwards breaking changes. """ ) def _to_string(cdata): """Decode a cdata c-string to a Python str.""" return ffi.string(cdata).decode() def libmongocrypt_version(): """Returns the version of libmongocrypt.""" return _to_string(lib.mongocrypt_version(ffi.NULL)) # Use the PYMONGOCRYPT_LIB environment variable to load a custom libmongocrypt # build without relying on platform specific library path environment # variables, like LD_LIBRARY_PATH. For example: # export PYMONGOCRYPT_LIB='/path/to/libmongocrypt.so' # If the PYMONGOCRYPT_LIB is not set then load the embedded library and # fallback to the relying on a system installed library. _base = Path(os.path.realpath(__file__)).parent if sys.platform == "win32": _path = Path(_base) / "mongocrypt.dll" elif sys.platform == "darwin": _path = Path(_base) / "libmongocrypt.dylib" else: _path = Path(_base) / "libmongocrypt.so" class _Library: """Helper class for delaying errors that would usually be raised at import time until the library is actually used.""" def __init__(self, error): self._error = error def __getattr__(self, name): raise self._error _PYMONGOCRYPT_LIB = os.environ.get("PYMONGOCRYPT_LIB") try: if _PYMONGOCRYPT_LIB: lib = ffi.dlopen(_PYMONGOCRYPT_LIB) else: try: lib = ffi.dlopen(str(_path)) except OSError: # Fallback to libmongocrypt installed on the system. lib = ffi.dlopen("mongocrypt") except OSError as exc: # dlopen raises OSError when the library cannot be found. # Delay the error until the library is actually used. lib = _Library(exc) else: _limongocrypt_version = Version(libmongocrypt_version()) if _limongocrypt_version < Version(_MIN_LIBMONGOCRYPT_VERSION): exc = RuntimeError( f"Expected libmongocrypt version %s or greater, found {_MIN_LIBMONGOCRYPT_VERSION, libmongocrypt_version()}" ) lib = _Library(exc) libmongocrypt-1.11.0/bindings/python/pymongocrypt/compat.py000066400000000000000000000020071465326363200242200ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Utility functions and definitions for Python compatibility.""" import sys PY3 = sys.version_info[0] >= 3 if PY3: from abc import ABC unicode_type = str else: from abc import ABCMeta as _ABCMeta ABC = _ABCMeta("ABC", (object,), {}) unicode_type = "unicode" def str_to_bytes(string): """Convert a str (or unicode) to bytes.""" if isinstance(string, bytes): return string return string.encode("utf-8") libmongocrypt-1.11.0/bindings/python/pymongocrypt/credentials.py000066400000000000000000000012401465326363200252300ustar00rootroot00000000000000# Copyright 2022-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Alias file for import compatibility from pymongocrypt.synchronous.credentials import * libmongocrypt-1.11.0/bindings/python/pymongocrypt/crypto.py000066400000000000000000000140231465326363200242560ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Internal crypto callbacks for libmongocrypt.""" import os import traceback from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.hashes import SHA256, SHA512, Hash from cryptography.hazmat.primitives.hmac import HMAC from cryptography.hazmat.primitives.serialization import load_der_private_key from pymongocrypt.binary import _to_bytes, _write_bytes from pymongocrypt.binding import ffi, lib from pymongocrypt.compat import str_to_bytes def _callback_error_handler(exception, exc_value, tb): """Set the mongocrypt_status_t on error.""" # From cffi docs: "First check if traceback is not None (it is None e.g. # if the whole function ran successfully but there was an error converting # the value returned: this occurs after the call)." if tb is not None: status = tb.tb_frame.f_locals["status"] msg = str_to_bytes( "".join(traceback.format_exception(exception, exc_value, tb)) ) lib.mongocrypt_status_set( status, lib.MONGOCRYPT_STATUS_ERROR_CLIENT, 1, msg, -1 ) return False def _aes_256_encrypt(key, mode, input, output, bytes_written): cipher = Cipher(algorithms.AES(_to_bytes(key)), mode, backend=default_backend()) encryptor = cipher.encryptor() data = encryptor.update(_to_bytes(input)) + encryptor.finalize() _write_bytes(output, data) bytes_written[0] = len(data) def _aes_256_decrypt(key, mode, input, output, bytes_written): cipher = Cipher(algorithms.AES(_to_bytes(key)), mode, backend=default_backend()) decryptor = cipher.decryptor() data = decryptor.update(_to_bytes(input)) + decryptor.finalize() _write_bytes(output, data) bytes_written[0] = len(data) @ffi.callback( "bool(void *, mongocrypt_binary_t *, mongocrypt_binary_t *," " mongocrypt_binary_t *, mongocrypt_binary_t *, uint32_t *," " mongocrypt_status_t *)", onerror=_callback_error_handler, ) def aes_256_cbc_encrypt(ctx, key, iv, input, output, bytes_written, status): # Note that libmongocrypt pads the input before calling this method. _aes_256_encrypt(key, modes.CBC(_to_bytes(iv)), input, output, bytes_written) return True @ffi.callback( "bool(void *, mongocrypt_binary_t *, mongocrypt_binary_t *," " mongocrypt_binary_t *, mongocrypt_binary_t *, uint32_t *," " mongocrypt_status_t *)", onerror=_callback_error_handler, ) def aes_256_cbc_decrypt(ctx, key, iv, input, output, bytes_written, status): # Note that libmongocrypt pads the input before calling this method. _aes_256_decrypt(key, modes.CBC(_to_bytes(iv)), input, output, bytes_written) return True @ffi.callback( "bool(void *, mongocrypt_binary_t *, mongocrypt_binary_t *," " mongocrypt_binary_t *, mongocrypt_binary_t *, uint32_t *," " mongocrypt_status_t *)", onerror=_callback_error_handler, ) def aes_256_ctr_encrypt(ctx, key, iv, input, output, bytes_written, status): _aes_256_encrypt(key, modes.CTR(_to_bytes(iv)), input, output, bytes_written) return True @ffi.callback( "bool(void *, mongocrypt_binary_t *, mongocrypt_binary_t *," " mongocrypt_binary_t *, mongocrypt_binary_t *, uint32_t *," " mongocrypt_status_t *)", onerror=_callback_error_handler, ) def aes_256_ctr_decrypt(ctx, key, iv, input, output, bytes_written, status): _aes_256_decrypt(key, modes.CTR(_to_bytes(iv)), input, output, bytes_written) return True @ffi.callback( "bool(void *, mongocrypt_binary_t *, mongocrypt_binary_t *, " " mongocrypt_binary_t *, mongocrypt_status_t *)", onerror=_callback_error_handler, ) def hmac_sha_256(ctx, key, input, output, status): h = HMAC(_to_bytes(key), SHA256(), backend=default_backend()) h.update(_to_bytes(input)) data = h.finalize() _write_bytes(output, data) return True @ffi.callback( "bool(void *, mongocrypt_binary_t *, mongocrypt_binary_t *, " " mongocrypt_binary_t *, mongocrypt_status_t *)", onerror=_callback_error_handler, ) def hmac_sha_512(ctx, key, input, output, status): h = HMAC(_to_bytes(key), SHA512(), backend=default_backend()) h.update(_to_bytes(input)) data = h.finalize() _write_bytes(output, data) return True @ffi.callback( "bool(void *, mongocrypt_binary_t *, mongocrypt_binary_t *, " " mongocrypt_status_t *)", onerror=_callback_error_handler, ) def sha_256(ctx, input, output, status): digest = Hash(SHA256(), backend=default_backend()) digest.update(_to_bytes(input)) data = digest.finalize() _write_bytes(output, data) return True @ffi.callback( "bool(void *, mongocrypt_binary_t *, uint32_t, mongocrypt_status_t *)", onerror=_callback_error_handler, ) def secure_random(ctx, output, count, status): data = os.urandom(int(count)) _write_bytes(output, data) return True @ffi.callback( "bool(void *, mongocrypt_binary_t *, mongocrypt_binary_t *, " " mongocrypt_binary_t *, mongocrypt_status_t *)", onerror=_callback_error_handler, ) def sign_rsaes_pkcs1_v1_5(ctx, key, input, output, status): rsa_private_key = load_der_private_key( _to_bytes(key), password=None, backend=default_backend() ) signature = rsa_private_key.sign( _to_bytes(input), padding=padding.PKCS1v15(), algorithm=SHA256() ) _write_bytes(output, signature) return True libmongocrypt-1.11.0/bindings/python/pymongocrypt/errors.py000066400000000000000000000025341465326363200242560ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from pymongocrypt.binding import _to_string, ffi, lib class MongoCryptError(Exception): def __init__(self, msg, code=-1): """Top level Exception for all MongoCrypt errors. :Parameters: - `msg`: An error message. - `code`: The mongocrypt_status_t code. """ super().__init__(msg) self.code = code @classmethod def from_status(cls, status): """Constructs an error from a mongocrypt_status_t. :Parameters: - `status`: A CFFI mongocrypt_status_t. """ if lib.mongocrypt_status_ok(status): raise ValueError("status must not be ok") msg = _to_string(lib.mongocrypt_status_message(status, ffi.NULL)) return cls(msg, lib.mongocrypt_status_code(status)) libmongocrypt-1.11.0/bindings/python/pymongocrypt/explicit_encrypter.py000066400000000000000000000012471465326363200266560ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Alias file for import compatibility from pymongocrypt.synchronous.explicit_encrypter import * libmongocrypt-1.11.0/bindings/python/pymongocrypt/mongocrypt.py000066400000000000000000000632411465326363200251450ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import platform import sys from packaging.version import Version from pymongocrypt.asynchronous.state_machine import AsyncMongoCryptCallback from pymongocrypt.binary import MongoCryptBinaryIn, MongoCryptBinaryOut from pymongocrypt.binding import _to_string, ffi, lib from pymongocrypt.compat import str_to_bytes from pymongocrypt.crypto import ( aes_256_cbc_decrypt, aes_256_cbc_encrypt, aes_256_ctr_decrypt, aes_256_ctr_encrypt, hmac_sha_256, hmac_sha_512, secure_random, sha_256, sign_rsaes_pkcs1_v1_5, ) from pymongocrypt.errors import MongoCryptError from pymongocrypt.options import MongoCryptOptions from pymongocrypt.synchronous.state_machine import MongoCryptCallback class MongoCrypt: def __init__(self, options, callback): """Abstracts libmongocrypt's mongocrypt_t type. :Parameters: - `options`: A :class:`MongoCryptOptions`. - `callback`: A :class:`MongoCryptCallback`. """ self.__opts = options # type: MongoCryptOptions self.__callback = callback self.__crypt = None if not isinstance(options, MongoCryptOptions): raise TypeError("options must be a MongoCryptOptions") if not isinstance(callback, (AsyncMongoCryptCallback, MongoCryptCallback)): raise TypeError( "callback must be a MongoCryptCallback or AsyncMongoCryptCallback" ) self.__crypt = lib.mongocrypt_new() if self.__crypt == ffi.NULL: raise MongoCryptError("unable to create new mongocrypt object") try: self.__init() except Exception: # Destroy the mongocrypt object on error. self.close() raise def __init(self): """Internal init helper.""" kms_providers = self.__opts.kms_providers with MongoCryptBinaryIn(self.__callback.bson_encode(kms_providers)) as kmsopt: if not lib.mongocrypt_setopt_kms_providers(self.__crypt, kmsopt.bin): self.__raise_from_status() schema_map = self.__opts.schema_map if schema_map is not None: with MongoCryptBinaryIn(schema_map) as binary_schema_map: if not lib.mongocrypt_setopt_schema_map( self.__crypt, binary_schema_map.bin ): self.__raise_from_status() encrypted_fields_map = self.__opts.encrypted_fields_map if encrypted_fields_map is not None: with MongoCryptBinaryIn( encrypted_fields_map ) as binary_encrypted_fields_map: if not lib.mongocrypt_setopt_encrypted_field_config_map( self.__crypt, binary_encrypted_fields_map.bin ): self.__raise_from_status() if self.__opts.bypass_query_analysis: lib.mongocrypt_setopt_bypass_query_analysis(self.__crypt) # Prefer using the native crypto binding when we know it's available. try: crypto_available = lib.mongocrypt_is_crypto_available() except AttributeError: # libmongocrypt < 1.9 crypto_available = False if not crypto_available: if not lib.mongocrypt_setopt_crypto_hooks( self.__crypt, aes_256_cbc_encrypt, aes_256_cbc_decrypt, secure_random, hmac_sha_512, hmac_sha_256, sha_256, ffi.NULL, ): self.__raise_from_status() if not lib.mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5( self.__crypt, sign_rsaes_pkcs1_v1_5, ffi.NULL ): self.__raise_from_status() if not lib.mongocrypt_setopt_aes_256_ctr( self.__crypt, aes_256_ctr_encrypt, aes_256_ctr_decrypt, ffi.NULL ): self.__raise_from_status() elif sys.platform == "darwin" and Version(platform.mac_ver()[0]) < Version( "10.15" ): # MONGOCRYPT-440 libmongocrypt does not support AES-CTR on macOS < 10.15. if not lib.mongocrypt_setopt_aes_256_ctr( self.__crypt, aes_256_ctr_encrypt, aes_256_ctr_decrypt, ffi.NULL ): self.__raise_from_status() if self.__opts.crypt_shared_lib_path is not None: lib.mongocrypt_setopt_set_crypt_shared_lib_path_override( self.__crypt, self.__opts.crypt_shared_lib_path.encode("utf-8") ) if not self.__opts.bypass_encryption: lib.mongocrypt_setopt_append_crypt_shared_lib_search_path( self.__crypt, b"$SYSTEM" ) on_demand_aws = "aws" in kms_providers and not len(kms_providers["aws"]) on_demand_gcp = "gcp" in kms_providers and not len(kms_providers["gcp"]) on_demand_azure = "azure" in kms_providers and not len(kms_providers["azure"]) if any([on_demand_aws, on_demand_gcp, on_demand_azure]): lib.mongocrypt_setopt_use_need_kms_credentials_state(self.__crypt) if not lib.mongocrypt_init(self.__crypt): self.__raise_from_status() if ( self.__opts.crypt_shared_lib_required and self.crypt_shared_lib_version is None ): raise MongoCryptError( "crypt_shared_lib_required=True but the crypt_shared library could not be loaded " f"from crypt_shared_lib_path={self.__opts.crypt_shared_lib_path}" + " or the operating system's dynamic library search path" ) def __raise_from_status(self): status = lib.mongocrypt_status_new() try: lib.mongocrypt_status(self.__crypt, status) exc = MongoCryptError.from_status(status) finally: lib.mongocrypt_status_destroy(status) raise exc @property def crypt_shared_lib_version(self): ver = lib.mongocrypt_crypt_shared_lib_version_string(self.__crypt, ffi.NULL) if ver == ffi.NULL: return None return ver def close(self): """Cleanup resources.""" if self.__crypt is None: return # Since close is called by __del__, we need to be sure to guard # against the case where global variables are set to None at # interpreter shutdown, see PYTHON-3530. if lib is not None: lib.mongocrypt_destroy(self.__crypt) self.__crypt = None def __del__(self): self.close() def _create_context(self): """Returns a new mongocrypt_ctx_t""" ctx = lib.mongocrypt_ctx_new(self.__crypt) if ctx == ffi.NULL: self.__raise_from_status() return ctx def encryption_context(self, database, command): """Creates a context to use for encryption. :Parameters: - `database`: The database name. - `command`: The encoded BSON command to encrypt. :Returns: A :class:`EncryptionContext`. """ return EncryptionContext( self._create_context(), self.__opts.kms_providers, database, command ) def decryption_context(self, command): """Creates a context to use for decryption. :Parameters: - `command`: The encoded BSON command to decrypt. :Returns: A :class:`DecryptionContext`. """ return DecryptionContext( self._create_context(), self.__opts.kms_providers, command ) def explicit_encryption_context(self, value, opts): """Creates a context to use for explicit encryption. :Parameters: - `value`: The encoded document to encrypt, which must be in the form { "v" : BSON value to encrypt }}. - `opts`: A :class:`ExplicitEncryptOpts`. :Returns: A :class:`ExplicitEncryptionContext`. """ return ExplicitEncryptionContext( self._create_context(), self.__opts.kms_providers, value, opts ) def explicit_decryption_context(self, value): """Creates a context to use for explicit decryption. :Parameters: - `value`: The encoded document to decrypt, which must be in the form { "v" : encrypted BSON value }}. :Returns: A :class:`ExplicitDecryptionContext`. """ return ExplicitDecryptionContext( self._create_context(), self.__opts.kms_providers, value ) def data_key_context(self, kms_provider, opts=None): """Creates a context to use for key generation. :Parameters: - `kms_provider`: The KMS provider. - `opts`: An optional class:`DataKeyOpts`. :Returns: A :class:`DataKeyContext`. """ return DataKeyContext( self._create_context(), self.__opts.kms_providers, kms_provider, opts, self.__callback, ) def rewrap_many_data_key_context(self, filter, provider, master_key): """Creates a context to use for rewrapping many data keys. :Parameters: - `filter`: A document used to filter the data keys. - `provider`: (optional) The name of a different kms provider. - `master_key`: Optional document for the given provider. MUST have the fields corresponding to the given provider as specified in master_key. master_key MUST NOT be given if it is not applicable for the given provider. :Returns: A :class:`RewrapManyDataKeyContext`. """ return RewrapManyDataKeyContext( self._create_context(), self.__opts.kms_providers, filter, provider, master_key, self.__callback, ) class MongoCryptContext: __slots__ = ("__ctx", "kms_providers") def __init__(self, ctx, kms_providers): """Abstracts libmongocrypt's mongocrypt_ctx_t type. :Parameters: - `ctx`: A mongocrypt_ctx_t. This MongoCryptContext takes ownership of the underlying mongocrypt_ctx_t. - `kms_providers`: The KMS provider map. """ self.__ctx = ctx self.kms_providers = kms_providers def _close(self): """Cleanup resources.""" if self.__ctx is None: return lib.mongocrypt_ctx_destroy(self.__ctx) self.__ctx = None def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self._close() @property def state(self): """The current state of the mongocrypt_ctx_t.""" return lib.mongocrypt_ctx_state(self.__ctx) def _raise_from_status(self): status = lib.mongocrypt_status_new() try: lib.mongocrypt_ctx_status(self.__ctx, status) exc = MongoCryptError.from_status(status) finally: lib.mongocrypt_status_destroy(status) raise exc def mongo_operation(self): """Returns the mongo operation to execute as bson bytes.""" with MongoCryptBinaryOut() as binary: if not lib.mongocrypt_ctx_mongo_op(self.__ctx, binary.bin): self._raise_from_status() return binary.to_bytes() def add_mongo_operation_result(self, document): """Adds the mongo operation's command response. :Parameters: - `document`: A raw BSON command response document. """ with MongoCryptBinaryIn(document) as binary: if not lib.mongocrypt_ctx_mongo_feed(self.__ctx, binary.bin): self._raise_from_status() def complete_mongo_operation(self): """Completes the mongo operation.""" if not lib.mongocrypt_ctx_mongo_done(self.__ctx): self._raise_from_status() def provide_kms_providers(self, providers): """Provide a map of KMS providers.""" with MongoCryptBinaryIn(providers) as binary: if not lib.mongocrypt_ctx_provide_kms_providers(self.__ctx, binary.bin): self._raise_from_status() def kms_contexts(self): """Yields the MongoCryptKmsContexts.""" ctx = lib.mongocrypt_ctx_next_kms_ctx(self.__ctx) while ctx != ffi.NULL: yield MongoCryptKmsContext(ctx) ctx = lib.mongocrypt_ctx_next_kms_ctx(self.__ctx) def complete_kms(self): """Indicates that all MongoCryptKmsContexts have been completed""" if not lib.mongocrypt_ctx_kms_done(self.__ctx): self._raise_from_status() def finish(self): """Returns the finished mongo operation as bson bytes.""" with MongoCryptBinaryOut() as binary: if not lib.mongocrypt_ctx_finalize(self.__ctx, binary.bin): self._raise_from_status() return binary.to_bytes() class EncryptionContext(MongoCryptContext): __slots__ = ("database",) def __init__(self, ctx, kms_providers, database, command): """Abstracts libmongocrypt's mongocrypt_ctx_t type. :Parameters: - `ctx`: A mongocrypt_ctx_t. This MongoCryptContext takes ownership of the underlying mongocrypt_ctx_t. - `kms_providers`: The KMS provider map. - `database`: Optional, the name of the database. - `command`: The BSON command to encrypt. """ super().__init__(ctx, kms_providers) self.database = database try: with MongoCryptBinaryIn(command) as binary: database = str_to_bytes(database) if not lib.mongocrypt_ctx_encrypt_init( ctx, database, len(database), binary.bin ): self._raise_from_status() except Exception: # Destroy the context on error. self._close() raise class DecryptionContext(MongoCryptContext): __slots__ = () def __init__(self, ctx, kms_providers, command): """Abstracts libmongocrypt's mongocrypt_ctx_t type. :Parameters: - `ctx`: A mongocrypt_ctx_t. This MongoCryptContext takes ownership of the underlying mongocrypt_ctx_t. - `kms_providers`: The KMS provider map. - `command`: The encoded BSON command to decrypt. """ super().__init__(ctx, kms_providers) try: with MongoCryptBinaryIn(command) as binary: if not lib.mongocrypt_ctx_decrypt_init(ctx, binary.bin): self._raise_from_status() except Exception: # Destroy the context on error. self._close() raise class ExplicitEncryptionContext(MongoCryptContext): __slots__ = () def __init__(self, ctx, kms_providers, value, opts): """Abstracts libmongocrypt's mongocrypt_ctx_t type. :Parameters: - `ctx`: A mongocrypt_ctx_t. This MongoCryptContext takes ownership of the underlying mongocrypt_ctx_t. - `kms_providers`: The KMS provider map. - `value`: The encoded document to encrypt, which must be in the form { "v" : BSON value to encrypt }}. - `opts`: A :class:`ExplicitEncryptOpts`. """ super().__init__(ctx, kms_providers) try: algorithm = str_to_bytes(opts.algorithm) if not lib.mongocrypt_ctx_setopt_algorithm(ctx, algorithm, -1): self._raise_from_status() if opts.key_id is not None: with MongoCryptBinaryIn(opts.key_id) as binary: if not lib.mongocrypt_ctx_setopt_key_id(ctx, binary.bin): self._raise_from_status() if opts.key_alt_name is not None: with MongoCryptBinaryIn(opts.key_alt_name) as binary: if not lib.mongocrypt_ctx_setopt_key_alt_name(ctx, binary.bin): self._raise_from_status() if opts.query_type is not None: qt = str_to_bytes(opts.query_type) if not lib.mongocrypt_ctx_setopt_query_type(ctx, qt, -1): self._raise_from_status() if opts.contention_factor is not None: if not lib.mongocrypt_ctx_setopt_contention_factor( ctx, opts.contention_factor ): self._raise_from_status() if opts.range_opts is not None: with MongoCryptBinaryIn(opts.range_opts) as range_opts: if not lib.mongocrypt_ctx_setopt_algorithm_range( ctx, range_opts.bin ): self._raise_from_status() with MongoCryptBinaryIn(value) as binary: if opts.is_expression: if not lib.mongocrypt_ctx_explicit_encrypt_expression_init( ctx, binary.bin ): self._raise_from_status() else: if not lib.mongocrypt_ctx_explicit_encrypt_init(ctx, binary.bin): self._raise_from_status() except Exception: # Destroy the context on error. self._close() raise class ExplicitDecryptionContext(MongoCryptContext): __slots__ = () def __init__(self, ctx, kms_providers, value): """Abstracts libmongocrypt's mongocrypt_ctx_t type. :Parameters: - `ctx`: A mongocrypt_ctx_t. This MongoCryptContext takes ownership of the underlying mongocrypt_ctx_t. - `kms_providers`: The KMS provider map. - `value`: The encoded BSON value to decrypt. """ super().__init__(ctx, kms_providers) try: with MongoCryptBinaryIn(value) as binary: if not lib.mongocrypt_ctx_explicit_decrypt_init(ctx, binary.bin): self._raise_from_status() except Exception: # Destroy the context on error. self._close() raise class DataKeyContext(MongoCryptContext): __slots__ = () def __init__(self, ctx, kms_providers, kms_provider, opts, callback): """Abstracts libmongocrypt's mongocrypt_ctx_t type. :Parameters: - `ctx`: A mongocrypt_ctx_t. This MongoCryptContext takes ownership of the underlying mongocrypt_ctx_t. - `kms_providers`: The KMS provider map. - `kms_provider`: The KMS provider. - `opts`: An optional class:`DataKeyOpts`. - `callback`: A :class:`MongoCryptCallback`. """ super().__init__(ctx, kms_providers) try: if kms_provider not in kms_providers: raise ValueError(f"unknown kms_provider: {kms_provider}") # Account for provider names like "local:myname". provider_type = kms_provider.split(":")[0] if opts is None or opts.master_key is None: if provider_type in ["kmip", "local"]: master_key = {} else: raise ValueError( f"master_key is required for kms_provider: {kms_provider!r}" ) else: master_key = opts.master_key.copy() if provider_type == "aws": if "region" not in master_key or "key" not in master_key: raise ValueError( 'master_key must include "region" and "key" for ' f"kms_provider: {kms_provider!r}" ) elif provider_type == "azure": if "keyName" not in master_key or "keyVaultEndpoint" not in master_key: raise ValueError( 'master key must include "keyName" and ' f'"keyVaultEndpoint" for kms_provider: {kms_provider!r}' ) elif provider_type == "gcp": if ( "projectId" not in master_key or "location" not in master_key or "keyRing" not in master_key or "keyName" not in master_key ): raise ValueError( 'master key must include "projectId", "location",' f'"keyRing", and "keyName" for kms_provider: {kms_provider!r}' ) master_key["provider"] = kms_provider with MongoCryptBinaryIn(callback.bson_encode(master_key)) as mkey: if not lib.mongocrypt_ctx_setopt_key_encryption_key(ctx, mkey.bin): self._raise_from_status() if opts.key_alt_names: for key_alt_name in opts.key_alt_names: with MongoCryptBinaryIn(key_alt_name) as binary: if not lib.mongocrypt_ctx_setopt_key_alt_name(ctx, binary.bin): self._raise_from_status() if opts.key_material: with MongoCryptBinaryIn(opts.key_material) as binary: if not lib.mongocrypt_ctx_setopt_key_material(ctx, binary.bin): self._raise_from_status() if not lib.mongocrypt_ctx_datakey_init(ctx): self._raise_from_status() except Exception: # Destroy the context on error. self._close() raise class MongoCryptKmsContext: __slots__ = ("__ctx",) def __init__(self, ctx): """Abstracts libmongocrypt's mongocrypt_kms_ctx_t type. :Parameters: - `ctx`: A mongocrypt_kms_ctx_t. """ self.__ctx = ctx def _close(self): """Clear the mongocrypt_kms_ctx_t.""" self.__ctx = None def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self._close() @property def endpoint(self): """The kms hostname to connect over TLS.""" p = ffi.new("char *[]", 1) try: if not lib.mongocrypt_kms_ctx_endpoint(self.__ctx, p): self.__raise_from_status() return _to_string(p[0]) finally: ffi.release(p) @property def message(self): """The HTTP request message to send to the given endpoint.""" with MongoCryptBinaryOut() as binary: if not lib.mongocrypt_kms_ctx_message(self.__ctx, binary.bin): self.__raise_from_status() return binary.to_bytes() @property def bytes_needed(self): """Indicates how many bytes to send to :meth:`feed`.""" return lib.mongocrypt_kms_ctx_bytes_needed(self.__ctx) @property def kms_provider(self): """The KMS provider identifier associated with this KMS request. :Returns: The KMS provider as a string, eg "aws", "azure", "gcp", or "kmip". .. versionadded:: 1.2 """ return _to_string(lib.mongocrypt_kms_ctx_get_kms_provider(self.__ctx, ffi.NULL)) def feed(self, data): """Feed bytes from the HTTP response. :Parameters: - `data`: The bytes of the HTTP response. Must not exceed :attr:`bytes_needed`. """ with MongoCryptBinaryIn(data) as binary: if not lib.mongocrypt_kms_ctx_feed(self.__ctx, binary.bin): self.__raise_from_status() def __raise_from_status(self): status = lib.mongocrypt_status_new() try: lib.mongocrypt_kms_ctx_status(self.__ctx, status) exc = MongoCryptError.from_status(status) finally: lib.mongocrypt_status_destroy(status) raise exc class RewrapManyDataKeyContext(MongoCryptContext): __slots__ = () def __init__(self, ctx, kms_providers, filter, provider, master_key, callback): """Abstracts libmongocrypt's mongocrypt_ctx_t type. :Parameters: - `ctx`: A mongocrypt_ctx_t. This MongoCryptContext takes ownership of the underlying mongocrypt_ctx_t. - `kms_providers`: The KMS provider map. - `filter`: The filter to use when finding data keys to rewrap in the key vault collection.. - `provider`: (optional) The name of a different kms provider. - `master_key`: Optional document for the given provider. - `callback`: A :class:`MongoCryptCallback`. """ super().__init__(ctx, kms_providers) key_encryption_key_bson = None if provider is not None: data = dict(provider=provider) if master_key: data.update(master_key) key_encryption_key_bson = callback.bson_encode(data) try: if key_encryption_key_bson: with MongoCryptBinaryIn(key_encryption_key_bson) as binary: if not lib.mongocrypt_ctx_setopt_key_encryption_key( ctx, binary.bin ): self._raise_from_status() filter_bson = callback.bson_encode(filter) with MongoCryptBinaryIn(filter_bson) as binary: if not lib.mongocrypt_ctx_rewrap_many_datakey_init(ctx, binary.bin): self._raise_from_status() except Exception: # Destroy the context on error. self._close() raise libmongocrypt-1.11.0/bindings/python/pymongocrypt/options.py000066400000000000000000000277531465326363200244470ustar00rootroot00000000000000from pymongocrypt.compat import unicode_type class MongoCryptOptions: def __init__( self, kms_providers, schema_map=None, encrypted_fields_map=None, bypass_query_analysis=False, crypt_shared_lib_path=None, crypt_shared_lib_required=False, bypass_encryption=False, ): """Options for :class:`MongoCrypt`. :Parameters: - `kms_providers`: Map of KMS provider options. The kms_providers map values differ by provider: - `aws`: Map with "accessKeyId" and "secretAccessKey" as strings, and optionally a "sessionToken" for temporary credentials. - `azure`: Map with "clientId" and "clientSecret" as strings. - `gcp`: Map with "email" as a string and "privateKey" as a byte array or a base64-encoded string. - `kmip`: Map with "endpoint" as a string. - `local`: Map with "key" as a 96-byte array or the equivalent base64-encoded string. KMS providers may be specified with an optional name suffix separated by a colon, for example "kmip:name". Named KMS providers do not support automatic credential lookup. - `schema_map`: Optional map of collection namespace ("db.coll") to JSON Schema. By default, a collection's JSONSchema is periodically polled with the listCollections command. But a JSONSchema may be specified locally with the schemaMap option. Supplying a `schema_map` provides more security than relying on JSON Schemas obtained from the server. It protects against a malicious server advertising a false JSON Schema, which could trick the client into sending unencrypted data that should be encrypted. Schemas supplied in the schemaMap only apply to configuring automatic encryption for client side encryption. Other validation rules in the JSON schema will not be enforced by the driver and will result in an error. - `encrypted_fields_map`: Optional map encoded to BSON `bytes`. - `bypass_query_analysis`: If ``True``, disable automatic analysis of outgoing commands. Set `bypass_query_analysis` to use explicit encryption on indexed fields without the MongoDB Enterprise Advanced licensed crypt_shared library. - `crypt_shared_lib_path`: Optional string path to the crypt_shared library. - `crypt_shared_lib_required`: Whether to require a crypt_shared library. - `bypass_encryption`: Whether to bypass encryption. .. versionremoved:: 1.11 Removed the ``enable_range_v2`` parameter. .. versionadded:: 1.10 Added the ``enable_range_v2`` parameter. .. versionadded:: 1.3 Added the ``crypt_shared_lib_path``, ``crypt_shared_lib_path``, and ``bypass_encryption`` parameters. .. versionadded:: 1.1 Support for "azure" and "gcp" kms_providers. Support for temporary AWS credentials via "sessionToken". .. versionchanged:: 1.1 For kmsProvider "local", the "key" field can now be specified as either a 96-byte array or the equivalent base64-encoded string. """ if not isinstance(kms_providers, dict): raise ValueError("kms_providers must be a dict") if not kms_providers: raise ValueError("at least one KMS provider must be configured") for name, provider in kms_providers.items(): # Account for provider names like "local:myname". provider_type = name.split(":")[0] if provider_type in ("aws", "gcp", "azure", "kmip", "local"): if not isinstance(provider, dict): raise ValueError(f"kms_providers[{name!r}] must be a dict") if provider_type == "aws": if len(provider): if ( "accessKeyId" not in provider or "secretAccessKey" not in provider ): raise ValueError( f"kms_providers[{name!r}] must contain " "'accessKeyId' and 'secretAccessKey'" ) elif provider_type == "azure": if len(provider): if "clientId" not in provider or "clientSecret" not in provider: raise ValueError( f"kms_providers[{name!r}] must contain " "'clientId' and 'clientSecret'" ) elif provider_type == "gcp": if len(provider): if "email" not in provider or "privateKey" not in provider: raise ValueError( f"kms_providers[{name!r}] must contain " "'email' and 'privateKey'" ) if not isinstance(provider["privateKey"], (bytes, unicode_type)): raise TypeError( f"kms_providers[{name!r}]['privateKey'] must " "be an instance of bytes or str" ) elif provider_type == "kmip": if "endpoint" not in provider: raise ValueError(f"kms_providers[{name!r}] must contain 'endpoint'") if not isinstance(provider["endpoint"], (str, unicode_type)): raise TypeError( f"kms_providers[{name!r}]['endpoint'] must " "be an instance of str" ) elif provider_type == "local": if "key" not in provider: raise ValueError(f"kms_providers[{name!r}] must contain 'key'") if not isinstance(provider["key"], (bytes, unicode_type)): raise TypeError( f"kms_providers[{name!r}]['key'] must be an " "instance of bytes or str" ) if schema_map is not None and not isinstance(schema_map, bytes): raise TypeError("schema_map must be bytes or None") if encrypted_fields_map is not None and not isinstance( encrypted_fields_map, bytes ): raise TypeError("encrypted_fields_map must be bytes or None") self.kms_providers = kms_providers self.schema_map = schema_map self.encrypted_fields_map = encrypted_fields_map self.bypass_query_analysis = bypass_query_analysis self.crypt_shared_lib_path = crypt_shared_lib_path self.crypt_shared_lib_required = crypt_shared_lib_required self.bypass_encryption = bypass_encryption class ExplicitEncryptOpts: def __init__( self, algorithm, key_id=None, key_alt_name=None, query_type=None, contention_factor=None, range_opts=None, is_expression=False, ): """Options for explicit encryption. :Parameters: - `algorithm` (str): The algorithm to use. - `key_id`: The data key _id. - `key_alt_name` (bytes): Identifies a key vault document by 'keyAltName'. Must be BSON encoded document in the form: { "keyAltName" : (BSON UTF8 value) } - `query_type` (str): The query type to execute. - `contention_factor` (int): The contention factor to use when the algorithm is "Indexed". - `range_opts` (bytes): Options for explicit encryption with the "range" algorithm encoded as a BSON document. - `is_expression` (boolean): True if this is an encryptExpression() context. Defaults to False. .. versionchanged:: 1.3 Added the `query_type` and `contention_factor` parameters. .. versionchanged:: 1.5 Added the `range_opts` and `is_expression` parameters. """ self.algorithm = algorithm self.key_id = key_id self.key_alt_name = key_alt_name if query_type is not None: if not isinstance(query_type, str): raise TypeError( f"query_type must be str or None, not: {type(query_type)}" ) self.query_type = query_type if contention_factor is not None and not isinstance(contention_factor, int): raise TypeError( f"contention_factor must be an int or None, not: {type(contention_factor)}" ) self.contention_factor = contention_factor if range_opts is not None and not isinstance(range_opts, bytes): raise TypeError( f"range_opts must be an bytes or None, not: {type(range_opts)}" ) self.range_opts = range_opts self.is_expression = is_expression class DataKeyOpts: def __init__(self, master_key=None, key_alt_names=None, key_material=None): """Options for creating encryption keys. :Parameters: - `master_key`: Identifies a KMS-specific key used to encrypt the new data key. If the kmsProvider is "local" the `master_key` is not applicable and may be omitted. If the `kms_provider` is "aws" it is required and has the following fields:: - `region` (string): Required. The AWS region, e.g. "us-east-1". - `key` (string): Required. The Amazon Resource Name (ARN) to the AWS customer. - `endpoint` (string): Optional. An alternate host to send KMS requests to. May include port number, e.g. "kms.us-east-1.amazonaws.com:443". If the `kms_provider` is "azure" it is required and has the following fields:: - `keyVaultEndpoint` (string): Required. Host with optional port, e.g. "example.vault.azure.net". - `keyName` (string): Required. Key name in the key vault. - `keyVersion` (string): Optional. Version of the key to use. If the `kms_provider` is "gcp" it is required and has the following fields:: - `projectId` (string): Required. The Google cloud project ID. - `location` (string): Required. The GCP location, e.g. "us-east1". - `keyRing` (string): Required. Name of the key ring that contains the key to use. - `keyName` (string): Required. Name of the key to use. - `keyVersion` (string): Optional. Version of the key to use. - `endpoint` (string): Optional. Host with optional port. Defaults to "cloudkms.googleapis.com". If the `kms_provider` is "kmip" it is optional and has the following fields:: - `keyId` (string): Optional. `keyId` is the KMIP Unique Identifier to a 96 byte KMIP Secret Data managed object. If keyId is omitted, the driver creates a random 96 byte KMIP Secret Data managed object. - `endpoint` (string): Optional. Host with optional port, e.g. "example.vault.azure.net:". - `key_alt_names`: An optional list of bytes suitable to be passed to mongocrypt_ctx_setopt_key_alt_name. Each element must be BSON encoded document in the form: { "keyAltName" : (BSON UTF8 value) } - `key_material`: An optional binary value of 96 bytes to use as custom key material for the data key being created. If ``key_material`` is given, the custom key material is used for encrypting and decrypting data. Otherwise, the key material for the new data key is generated from a cryptographically secure random device. """ self.master_key = master_key self.key_alt_names = key_alt_names self.key_material = key_material libmongocrypt-1.11.0/bindings/python/pymongocrypt/state_machine.py000066400000000000000000000012421465326363200255410ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Alias file for import compatibility from pymongocrypt.synchronous.state_machine import * libmongocrypt-1.11.0/bindings/python/pymongocrypt/synchronous/000077500000000000000000000000001465326363200247565ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/pymongocrypt/synchronous/auto_encrypter.py000066400000000000000000000040111465326363200303670ustar00rootroot00000000000000# Copyright 2024-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from pymongocrypt.mongocrypt import MongoCrypt from pymongocrypt.synchronous.state_machine import run_state_machine class AutoEncrypter: def __init__(self, callback, mongo_crypt_opts): """Encrypts and decrypts MongoDB commands. This class is used by a driver to support automatic encryption and decryption of MongoDB commands. :Parameters: - `callback`: A :class:`MongoCryptCallback`. - `mongo_crypt_opts`: A :class:`MongoCryptOptions`. """ self.callback = callback self.mongocrypt = MongoCrypt(mongo_crypt_opts, callback) def encrypt(self, database, cmd): """Encrypt a MongoDB command. :Parameters: - `database`: The database for this command. - `cmd`: A MongoDB command as BSON. :Returns: The encrypted command. """ with self.mongocrypt.encryption_context(database, cmd) as ctx: return run_state_machine(ctx, self.callback) def decrypt(self, response): """Decrypt a MongoDB command response. :Parameters: - `response`: A MongoDB command response as BSON. :Returns: The decrypted command response. """ with self.mongocrypt.decryption_context(response) as ctx: return run_state_machine(ctx, self.callback) def close(self): """Cleanup resources.""" self.mongocrypt.close() self.callback.close() libmongocrypt-1.11.0/bindings/python/pymongocrypt/synchronous/credentials.py000066400000000000000000000125171465326363200276330ustar00rootroot00000000000000# Copyright 2024-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os from collections import namedtuple from datetime import datetime, timedelta, timezone try: from pymongo_auth_aws.auth import aws_temp_credentials _HAVE_AUTH_AWS = True except ImportError: _HAVE_AUTH_AWS = False import httpx from pymongocrypt.errors import MongoCryptError _azure_creds = namedtuple("_azure_creds", ["access_token", "expires_utc"]) _azure_creds_cache = None def _get_gcp_credentials(): """Get on-demand GCP credentials""" metadata_host = os.getenv("GCE_METADATA_HOST") or "metadata.google.internal" url = ( "http://%s/computeMetadata/v1/instance/service-accounts/default/token" % metadata_host ) headers = {"Metadata-Flavor": "Google"} client = httpx.Client() try: response = client.get(url, headers=headers) except Exception as e: msg = "unable to retrieve GCP credentials: %s" % e raise MongoCryptError(msg) from e finally: client.close() if response.status_code != 200: msg = f"Unable to retrieve GCP credentials: expected StatusCode 200, got StatusCode: {response.status_code}. Response body:\n{response.content}" raise MongoCryptError(msg) try: data = response.json() except Exception as e: raise MongoCryptError( f"unable to retrieve GCP credentials: error reading response body\n{response.content}" ) from e if not data.get("access_token"): msg = ( "unable to retrieve GCP credentials: got unexpected empty accessToken from GCP Metadata Server. Response body: %s" % response.content ) raise MongoCryptError(msg) return {"accessToken": data["access_token"]} def _get_azure_credentials(): """Get on-demand Azure credentials""" global _azure_creds_cache # Credentials are considered expired when: Expiration - now < 1 mins. creds = _azure_creds_cache if creds: if creds.expires_utc - datetime.now(tz=timezone.utc) < timedelta(seconds=60): _azure_creds_cache = None else: return {"accessToken": creds.access_token} url = "http://169.254.169.254/metadata/identity/oauth2/token" url += "?api-version=2018-02-01" url += "&resource=https://vault.azure.net" headers = {"Metadata": "true", "Accept": "application/json"} client = httpx.Client() try: response = client.get(url, headers=headers) except Exception as e: msg = "Failed to acquire IMDS access token: %s" % e raise MongoCryptError(msg) from e finally: client.close() if response.status_code != 200: msg = "Failed to acquire IMDS access token." raise MongoCryptError(msg) try: data = response.json() except Exception as e: raise MongoCryptError("Azure IMDS response must be in JSON format.") from e for key in ["access_token", "expires_in"]: if not data.get(key): msg = "Azure IMDS response must contain %s, but was %s." msg = msg % (key, response.content) raise MongoCryptError(msg) try: expires_in = int(data["expires_in"]) except ValueError as e: raise MongoCryptError( 'Azure IMDS response must contain "expires_in" integer, but was %s.' % response.content ) from e expires_utc = datetime.now(tz=timezone.utc) + timedelta(seconds=expires_in) _azure_creds_cache = _azure_creds(data["access_token"], expires_utc) return {"accessToken": data["access_token"]} def _ask_for_kms_credentials(kms_providers): """Get on-demand kms credentials. This is a separate function so it can be overridden in unit tests.""" global _azure_creds_cache on_demand_aws = "aws" in kms_providers and not len(kms_providers["aws"]) on_demand_gcp = "gcp" in kms_providers and not len(kms_providers["gcp"]) on_demand_azure = "azure" in kms_providers and not len(kms_providers["azure"]) if not any([on_demand_aws, on_demand_gcp, on_demand_azure]): return {} creds = {} if on_demand_aws: if not _HAVE_AUTH_AWS: raise RuntimeError( "On-demand AWS credentials require pymongo-auth-aws: " "install with: python -m pip install 'pymongo[aws]'" ) aws_creds = aws_temp_credentials() creds_dict = { "accessKeyId": aws_creds.username, "secretAccessKey": aws_creds.password, } if aws_creds.token: creds_dict["sessionToken"] = aws_creds.token creds["aws"] = creds_dict if on_demand_gcp: creds["gcp"] = _get_gcp_credentials() if on_demand_azure: try: creds["azure"] = _get_azure_credentials() except Exception: _azure_creds_cache = None raise return creds libmongocrypt-1.11.0/bindings/python/pymongocrypt/synchronous/explicit_encrypter.py000066400000000000000000000137231465326363200312520ustar00rootroot00000000000000# Copyright 2024-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from pymongocrypt.mongocrypt import MongoCrypt from pymongocrypt.options import DataKeyOpts, ExplicitEncryptOpts from pymongocrypt.synchronous.state_machine import run_state_machine class ExplicitEncrypter: def __init__(self, callback, mongo_crypt_opts): """Encrypts and decrypts BSON values. This class is used by a driver to support explicit encryption and decryption of individual fields in a BSON document. :Parameters: - `callback`: A :class:`MongoCryptCallback`. - `mongo_crypt_opts`: A :class:`MongoCryptOptions`. """ self.callback = callback if mongo_crypt_opts.schema_map is not None: raise ValueError("mongo_crypt_opts.schema_map must be None") self.mongocrypt = MongoCrypt(mongo_crypt_opts, callback) def create_data_key( self, kms_provider, master_key=None, key_alt_names=None, key_material=None ): """Creates a data key used for explicit encryption. :Parameters: - `kms_provider`: The KMS provider to use. Supported values are "aws", "azure", "gcp", "kmip", "local", or a named provider like "kmip:name". - `master_key`: See class:`DataKeyOpts`. - `key_alt_names` (optional): An optional list of string alternate names used to reference a key. If a key is created with alternate names, then encryption may refer to the key by the unique alternate name instead of by ``_id``. - `key_material`: (optional) See class:`DataKeyOpts`. :Returns: The _id of the created data key document. """ # CDRIVER-3275 each key_alt_name needs to be wrapped in a bson # document. encoded_names = [] if key_alt_names is not None: for name in key_alt_names: encoded_names.append(self.callback.bson_encode({"keyAltName": name})) if key_material is not None: key_material = self.callback.bson_encode({"keyMaterial": key_material}) opts = DataKeyOpts(master_key, encoded_names, key_material) with self.mongocrypt.data_key_context(kms_provider, opts) as ctx: key = run_state_machine(ctx, self.callback) return self.callback.insert_data_key(key) def rewrap_many_data_key(self, filter, provider=None, master_key=None): """Decrypts and encrypts all matching data keys with a possibly new `master_key` value. :Parameters: - `filter`: A document used to filter the data keys. - `provider`: (optional) The name of a different kms provider. - `master_key`: Optional document for the given provider. :Returns: A binary document with the rewrap data. """ with self.mongocrypt.rewrap_many_data_key_context( filter, provider, master_key ) as ctx: return run_state_machine(ctx, self.callback) def encrypt( self, value, algorithm, key_id=None, key_alt_name=None, query_type=None, contention_factor=None, range_opts=None, is_expression=False, ): """Encrypts a BSON value. Note that exactly one of ``key_id`` or ``key_alt_name`` must be provided. :Parameters: - `value` (bytes): The BSON value to encrypt. - `algorithm` (string): The encryption algorithm to use. See :class:`Algorithm` for some valid options. - `key_id` (bytes): The bytes of the binary subtype 4 ``_id`` data key. For example, ``uuid.bytes`` or ``bytes(bson_binary)``. - `key_alt_name` (string): Identifies a key vault document by 'keyAltName'. - `query_type` (str): The query type to execute. - `contention_factor` (int): The contention factor to use when the algorithm is "Indexed". - `range_opts` (bytes): Options for explicit encryption with the "range" algorithm encoded as a BSON document. - `is_expression` (boolean): True if this is an encryptExpression() context. Defaults to False. :Returns: The encrypted BSON value. .. versionchanged:: 1.3 Added the `query_type` and `contention_factor` parameters. .. versionchanged:: 1.5 Added the `range_opts` and `is_expression` parameters. """ # CDRIVER-3275 key_alt_name needs to be wrapped in a bson document. if key_alt_name is not None: key_alt_name = self.callback.bson_encode({"keyAltName": key_alt_name}) opts = ExplicitEncryptOpts( algorithm, key_id, key_alt_name, query_type, contention_factor, range_opts, is_expression, ) with self.mongocrypt.explicit_encryption_context(value, opts) as ctx: return run_state_machine(ctx, self.callback) def decrypt(self, value): """Decrypts a BSON value. :Parameters: - `value`: The encoded document to decrypt, which must be in the form { "v" : encrypted BSON value }}. :Returns: The decrypted BSON value. """ with self.mongocrypt.explicit_decryption_context(value) as ctx: return run_state_machine(ctx, self.callback) def close(self): """Cleanup resources.""" self.mongocrypt.close() libmongocrypt-1.11.0/bindings/python/pymongocrypt/synchronous/state_machine.py000066400000000000000000000113311465326363200301330ustar00rootroot00000000000000# Copyright 2024-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from abc import abstractmethod from pymongocrypt.binding import lib from pymongocrypt.compat import ABC from pymongocrypt.errors import MongoCryptError from pymongocrypt.synchronous.credentials import _ask_for_kms_credentials class MongoCryptCallback(ABC): """Callback ABC to perform I/O on behalf of libbmongocrypt.""" @abstractmethod def kms_request(self, kms_context): """Complete a KMS request. :Parameters: - `kms_context`: A :class:`MongoCryptKmsContext`. :Returns: None """ @abstractmethod def collection_info(self, database, filter): """Get the collection info for a namespace. The returned collection info is passed to libmongocrypt which reads the JSON schema. :Parameters: - `database`: The database on which to run listCollections. - `filter`: The filter to pass to listCollections. :Returns: The first document from the listCollections command response as BSON. """ @abstractmethod def mark_command(self, database, cmd): """Mark a command for encryption. :Parameters: - `database`: The database on which to run this command. - `cmd`: The BSON command to run. :Returns: The marked command response from mongocryptd. """ @abstractmethod def fetch_keys(self, filter): """Yields one or more keys from the key vault. :Parameters: - `filter`: The filter to pass to find. :Returns: A generator which yields the requested keys from the key vault. """ @abstractmethod def insert_data_key(self, data_key): """Insert a data key into the key vault. :Parameters: - `data_key`: The data key document to insert. :Returns: The _id of the inserted data key document. """ @abstractmethod def bson_encode(self, doc): """Encode a document to BSON. A document can be any mapping type (like :class:`dict`). :Parameters: - `doc`: mapping type representing a document :Returns: The encoded BSON bytes. """ @abstractmethod def close(self): """Release resources.""" def run_state_machine(ctx, callback): """Run the libmongocrypt state machine until completion. :Parameters: - `ctx`: A :class:`MongoCryptContext`. - `callback`: A :class:`MongoCryptCallback`. :Returns: The completed libmongocrypt operation. """ while True: state = ctx.state # Check for terminal states first. if state == lib.MONGOCRYPT_CTX_ERROR: ctx._raise_from_status() elif state == lib.MONGOCRYPT_CTX_READY: return ctx.finish() elif state == lib.MONGOCRYPT_CTX_DONE: return None if state == lib.MONGOCRYPT_CTX_NEED_MONGO_COLLINFO: list_colls_filter = ctx.mongo_operation() coll_info = callback.collection_info(ctx.database, list_colls_filter) if coll_info: ctx.add_mongo_operation_result(coll_info) ctx.complete_mongo_operation() elif state == lib.MONGOCRYPT_CTX_NEED_MONGO_MARKINGS: mongocryptd_cmd = ctx.mongo_operation() result = callback.mark_command(ctx.database, mongocryptd_cmd) ctx.add_mongo_operation_result(result) ctx.complete_mongo_operation() elif state == lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS: key_filter = ctx.mongo_operation() for key in callback.fetch_keys(key_filter): ctx.add_mongo_operation_result(key) ctx.complete_mongo_operation() elif state == lib.MONGOCRYPT_CTX_NEED_KMS: for kms_ctx in ctx.kms_contexts(): with kms_ctx: callback.kms_request(kms_ctx) ctx.complete_kms() elif state == lib.MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS: creds = _ask_for_kms_credentials(ctx.kms_providers) ctx.provide_kms_providers(callback.bson_encode(creds)) else: raise MongoCryptError(f"unknown state: {state}") libmongocrypt-1.11.0/bindings/python/pymongocrypt/version.py000066400000000000000000000012101465326363200244150ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. __version__ = "1.11.0.dev0" _MIN_LIBMONGOCRYPT_VERSION = "1.8.0" libmongocrypt-1.11.0/bindings/python/pyproject.toml000066400000000000000000000104131465326363200225250ustar00rootroot00000000000000[build-system] requires = ["hatchling>1.24","hatch-requirements-txt>=0.4.1"] build-backend = "hatchling.build" [project] name = "pymongocrypt" dynamic = ["version", "dependencies", "optional-dependencies"] description = "Python bindings for libmongocrypt" readme = "README.rst" license = {file="LICENSE"} requires-python = ">=3.8" authors = [ { name = "Shane Harvey", email = "mongodb-user@googlegroups.com" }, ] keywords = [ "bson", "mongo", "mongocrypt", "mongodb", "pymongo", "pymongocrypt", ] classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Topic :: Database", ] [project.urls] Homepage = "https://github.com/mongodb/libmongocrypt/tree/master/bindings/python" [tool.hatch.version] path = "pymongocrypt/version.py" validate-bump = false # Used to call hatch_build.py [tool.hatch.build.hooks.custom] [tool.hatch.metadata.hooks.requirements_txt] files = ["requirements.txt"] [tool.hatch.metadata.hooks.requirements_txt.optional-dependencies] test = ["requirements-test.txt"] [tool.ruff.lint] select = [ "E", "F", "W", # flake8 "B", # flake8-bugbear "I", # isort "ARG", # flake8-unused-arguments "C4", # flake8-comprehensions "EM", # flake8-errmsg "ICN", # flake8-import-conventions "G", # flake8-logging-format "PGH", # pygrep-hooks "PIE", # flake8-pie "PL", # pylint "PT", # flake8-pytest-style "PTH", # flake8-use-pathlib "RET", # flake8-return "RUF", # Ruff-specific "S", # flake8-bandit "SIM", # flake8-simplify "T20", # flake8-print "UP", # pyupgrade "YTT", # flake8-2020 "EXE", # flake8-executable ] ignore = [ "PLR", # Design related pylint codes "E501", # Line too long "PT004", # Use underscore for non-returning fixture (use usefixture instead) "UP007", # Use `X | Y` for type annotation "EM101", # Exception must not use a string literal, assign to variable first "EM102", # Exception must not use an f-string literal, assign to variable first "G004", # Logging statement uses f-string" "UP006", # Use `type` instead of `Type` for type annotation" "RET505", # Unnecessary `elif` after `return` statement" "RET506", # Unnecessary `elif` after `raise` statement "SIM108", # Use ternary operator" "PTH123", # `open()` should be replaced by `Path.open()`" "SIM102", # Use a single `if` statement instead of nested `if` statements "SIM105", # Use `contextlib.suppress(OSError)` instead of `try`-`except`-`pass` "ARG002", # Unused method argument: "S101", # Use of `assert` detected "SIM114", # Combine `if` branches using logical `or` operator "PGH003", # Use specific rule codes when ignoring type issues "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar` "EM103", # Exception must not use a `.format()` string directly, assign to variable first "C408", # Unnecessary `dict` call (rewrite as a literal) "SIM117", # Use a single `with` statement with multiple contexts instead of nested `with` statements "PLW0603", # Using the global statement to update is discouraged "F403" # Unable to detect undefined names ] unfixable = [ "RUF100", # Unused noqa "T20", # Removes print statements "F841", # Removes unused variables ] [tool.ruff.lint.per-file-ignores] "test/*.py" = ["PT", "E402", "PLW", "SIM", "E741", "PTH", "S", "B904", "E722", "T201", "RET", "ARG", "F405", "B028", "PGH001", "B018", "F403", "RUF015", "E731", "B007", "UP031", "F401", "B023", "F811"] "pymongocrypt/crypto.py" = ["ARG001"] libmongocrypt-1.11.0/bindings/python/release.sh000077500000000000000000000110031465326363200215640ustar00rootroot00000000000000#!/bin/bash -ex # This script should be run on macOS and Cygwin on Windows. # On macOS it will create the following distributions # pymongocrypt-.tar.gz # pymongocrypt--py3-none-macosx_11_0_universal2.whl # pymongocrypt--py3-none-macosx_10_14_intel.whl # # On Windows it will create the following distribution: # pymongocrypt--py3-none-win_amd64.whl # # If docker is available on Linux or MacOS, it will also produce the following: # pymongocrypt--py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail # The libmongocrypt git revision release to embed in our wheels. LIBMONGOCRYPT_VERSION=$(cat ./libmongocrypt-version.txt) REVISION=$(git rev-list -n 1 $LIBMONGOCRYPT_VERSION) # The libmongocrypt release branch. BRANCH="r1.10" # The python executable to use. PYTHON=${PYTHON:-python} # Clean slate. rm -rf dist .venv build libmongocrypt pymongocrypt/*.so pymongocrypt/*.dll pymongocrypt/*.dylib function get_libmongocrypt() { TARGET=$1 MONGOCRYPT_SO=$2 rm -rf build libmongocrypt pymongocrypt/*.so pymongocrypt/*.dll pymongocrypt/*.dylib curl -O https://s3.amazonaws.com/mciuploads/libmongocrypt-release/$TARGET/${BRANCH}/${REVISION}/libmongocrypt.tar.gz mkdir libmongocrypt tar xzf libmongocrypt.tar.gz -C ./libmongocrypt chmod +x ${MONGOCRYPT_SO} cp ${MONGOCRYPT_SO} pymongocrypt/ rm -rf ./libmongocrypt libmongocrypt.tar.gz } function build_wheel() { python -m pip install unasync python -m pip install --upgrade pip build python -m build --wheel rm -rf build libmongocrypt pymongocrypt/*.so pymongocrypt/*.dll pymongocrypt/*.dylib } function build_manylinux_wheel() { python -m pip install unasync docker pull $1 docker run --rm -v `pwd`:/python $1 /python/build-manylinux-wheel.sh # Sudo is needed to remove the files created by docker. sudo rm -rf build libmongocrypt pymongocrypt/*.so pymongocrypt/*.dll pymongocrypt/*.dylib } function test_dist() { python -m pip uninstall -y pymongocrypt python -m pip install $1 pushd .. python -c "from pymongocrypt.binding import libmongocrypt_version, lib" popd } # Handle Windows dist. if [ "Windows_NT" = "$OS" ]; then # Magic variable in cygwin $PYTHON -m venv .venv # Workaround https://bugs.python.org/issue32451: # .venv/Scripts/activate: line 3: $'\r': command not found dos2unix .venv/Scripts/activate || true . ./.venv/Scripts/activate # Use crypto-enabled libmongocrypt. get_libmongocrypt windows-test libmongocrypt/bin/mongocrypt.dll build_wheel test_dist dist/*.whl fi # Handle MacOS dists. if [ "Darwin" = "$(uname -s)" ]; then $PYTHON -m venv .venv . .venv/bin/activate # Build universal2 wheel. get_libmongocrypt macos libmongocrypt/lib/libmongocrypt.dylib export MACOSX_DEPLOYMENT_TARGET=11.0 export _PYTHON_HOST_PLATFORM=macosx-11.0-universal2 build_wheel if [ "$(uname -m)" == "arm64" ]; then test_dist dist/*universal2.whl fi # Build and test sdist. python -m build --sdist test_dist dist/*.tar.gz fi # Handle manylinux dists. if [ $(command -v docker) ]; then if [ "Windows_NT" = "$OS" ]; then # docker: Error response from daemon: Windows does not support privileged mode # would be raised by the qemu command below. echo "Not supported on Windows" exit 0 fi # Set up qemu support using the method used in docker/setup-qemu-action # https://github.com/docker/setup-qemu-action/blob/2b82ce82d56a2a04d2637cd93a637ae1b359c0a7/README.md?plain=1#L46 docker run --rm --privileged tonistiigi/binfmt:latest --install all # Build the manylinux2014 x86_64 wheel. # https://github.com/pypa/manylinux # Supports CentOS 7 rh-python38, CentOS 8 python38, Fedora 32+, Ubuntu 20.04+. # When the rhel7 images go EOL we'll have to switch to the manylinux_x_y variants # and use rhel8. get_libmongocrypt rhel-70-64-bit libmongocrypt/nocrypto/lib64/libmongocrypt.so build_manylinux_wheel quay.io/pypa/manylinux2014_x86_64:2023-12-05-e9f0345 if [ "Linux" = "$(uname -s)" ]; then $PYTHON -m venv .venv . .venv/bin/activate test_dist dist/*linux*.whl fi # Build the manylinux_2_28 aarch64 wheel. get_libmongocrypt rhel-82-arm64 libmongocrypt/nocrypto/lib64/libmongocrypt.so build_manylinux_wheel quay.io/pypa/manylinux_2_28_aarch64:2024-01-01-0e91b08 fi ls -ltr dist libmongocrypt-1.11.0/bindings/python/requirements-test.txt000066400000000000000000000001251465326363200240510ustar00rootroot00000000000000pymongo[aws]>=4 cffi>=1.12.0,<2 cryptography>=2 pytest>=7.0 unasync respx setuptools libmongocrypt-1.11.0/bindings/python/requirements.txt000066400000000000000000000000771465326363200231020ustar00rootroot00000000000000cffi>=1.12.0,<2 cryptography>=40 packaging>=21.0 httpx>=0.25.0 libmongocrypt-1.11.0/bindings/python/sbom.json000066400000000000000000000042441465326363200214510ustar00rootroot00000000000000{ "components": [ { "bom-ref": "pkg:github/mongodb/libmongocrypt@1.10.1", "externalReferences": [ { "type": "distribution", "url": "https://github.com/mongodb/libmongocrypt/archive/refs/tags/1.10.1.tar.gz" }, { "type": "website", "url": "https://github.com/mongodb/libmongocrypt/tree/1.10.1" } ], "group": "mongodb", "name": "libmongocrypt", "purl": "pkg:github/mongodb/libmongocrypt@1.10.1", "type": "library", "version": "1.10.1" } ], "dependencies": [ { "ref": "pkg:github/mongodb/libmongocrypt@1.10.1" } ], "metadata": { "timestamp": "2024-06-28T19:11:17.100829+00:00", "tools": [ { "externalReferences": [ { "type": "build-system", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions" }, { "type": "distribution", "url": "https://pypi.org/project/cyclonedx-python-lib/" }, { "type": "documentation", "url": "https://cyclonedx-python-library.readthedocs.io/" }, { "type": "issue-tracker", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues" }, { "type": "license", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE" }, { "type": "release-notes", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md" }, { "type": "vcs", "url": "https://github.com/CycloneDX/cyclonedx-python-lib" }, { "type": "website", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/#readme" } ], "name": "cyclonedx-python-lib", "vendor": "CycloneDX", "version": "6.4.4" } ] }, "serialNumber": "urn:uuid:b09e93cf-eb1b-4d38-add5-86b01139769f", "version": 1, "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json", "bomFormat": "CycloneDX", "specVersion": "1.5" } libmongocrypt-1.11.0/bindings/python/strip_header.py000066400000000000000000000026721465326363200226440ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Generate a CFFI.cdef() string from a C header file Usage (on macOS):: python strip_header.py ../../src/mongocrypt.h | pbcopy """ import itertools import re import sys DROP_RE = re.compile(r"^\s*(#|MONGOCRYPT_EXPORT)") def strip_file(content): fold = content.replace("\\\n", " ") all_lines = [*fold.split("\n"), ""] keep_lines = (line for line in all_lines if not DROP_RE.match(line)) fin = "" for line, peek in itertools.pairwise(keep_lines): if peek == "" and line == "": # Drop adjacent empty lines continue yield line fin = peek yield fin def strip(hdr): with open(hdr) as fp: out = strip_file(fp.read()) print("\n".join(out)) # noqa: T201 if __name__ == "__main__": if len(sys.argv) != 2: raise Exception("Usage: strip_header.py header.h") strip(sys.argv[1]) libmongocrypt-1.11.0/bindings/python/synchro.py000066400000000000000000000034131465326363200216520ustar00rootroot00000000000000# Copyright 2024-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from os import listdir from pathlib import Path from unasync import Rule, unasync_files replacements = { "asynchronous": "synchronous", "AsyncMongoCryptCallback": "MongoCryptCallback", "AsyncExplicitEncrypter": "ExplicitEncrypter", "AsyncAutoEncrypter": "AutoEncrypter", "AsyncClient": "Client", "AsyncMongoCrypt": "MongoCrypt", "aclose": "close", } _base = "pymongocrypt" async_files = [ f"./{_base}/asynchronous/{f}" for f in listdir("pymongocrypt/asynchronous") if (Path(_base) / "asynchronous" / f).is_file() ] unasync_files( async_files, [ Rule( fromdir="/pymongocrypt/asynchronous/", todir="/pymongocrypt/synchronous/", additional_replacements=replacements, ) ], ) sync_files = [ f"./{_base}/synchronous/{f}" for f in listdir("pymongocrypt/synchronous") if (Path(_base) / "synchronous" / f).is_file() ] for file in sync_files: with open(file, "r+") as f: lines = f.readlines() for i in range(len(lines)): for s in replacements: lines[i] = lines[i].replace(s, replacements[s]) f.seek(0) f.truncate() f.writelines(lines) libmongocrypt-1.11.0/bindings/python/test/000077500000000000000000000000001465326363200205715ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/__init__.py000066400000000000000000000015141465326363200227030ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys import unittest sys.path[0:0] = [""] try: # Enable the fault handler to dump the traceback of each running thread # after a segfault. import faulthandler faulthandler.enable() except ImportError: pass from unittest import mock libmongocrypt-1.11.0/bindings/python/test/data/000077500000000000000000000000001465326363200215025ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/data/collection-info.json000066400000000000000000000020621465326363200254610ustar00rootroot00000000000000{ "type": "collection", "name": "test", "idIndex": { "ns": "test.test", "name": "_id_", "key": { "_id": { "$numberInt": "1" } }, "v": { "$numberInt": "2" } }, "options": { "validator": { "$jsonSchema": { "properties": { "ssn": { "encrypt": { "keyId": [ { "$binary": { "base64": "YWFhYWFhYWFhYWFhYWFhYQ==", "subType": "04" } } ], "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } } }, "bsonType": "object" } } } } libmongocrypt-1.11.0/bindings/python/test/data/command-reply.json000066400000000000000000000002361465326363200251450ustar00rootroot00000000000000{ "cursor": { "firstBatch": [ { "_id": 1, "ssn": "457-55-5462" } ], "id": 0, "ns": "test.test" }, "ok": 1 } libmongocrypt-1.11.0/bindings/python/test/data/command.json000066400000000000000000000001131465326363200240060ustar00rootroot00000000000000{ "find": "test", "filter": { "ssn": "457-55-5462" } } libmongocrypt-1.11.0/bindings/python/test/data/compact/000077500000000000000000000000001465326363200231305ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/data/compact/success/000077500000000000000000000000001465326363200246005ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/data/compact/success/cmd.json000066400000000000000000000000561465326363200262370ustar00rootroot00000000000000{ "compactStructuredEncryptionData": "test" } libmongocrypt-1.11.0/bindings/python/test/data/compact/success/encrypted-field-config-map.json000066400000000000000000000025011465326363200325650ustar00rootroot00000000000000{ "db.test": { "escCollection": "esc", "eccCollection": "ecc", "ecocCollection": "ecoc", "fields": [ { "keyId": { "$binary": { "base64": "EjRWeBI0mHYSNBI0VniQEg==", "subType": "04" } }, "path": "encrypted", "bsonType": "string", "queries": { "queryType": "equality", "contention": 0 } }, { "keyId": { "$binary": { "base64": "q83vqxI0mHYSNBI0VniQEg==", "subType": "04" } }, "path": "nested.encrypted", "bsonType": "string", "queries": { "queryType": "equality", "contention": 0 } }, { "keyId": { "$binary": { "base64": "EjRWeBI0mHYSNBI0VniQEw==", "subType": "04" } }, "path": "nested.notindexed", "bsonType": "string" } ] } } libmongocrypt-1.11.0/bindings/python/test/data/compact/success/encrypted-payload.json000066400000000000000000000010101465326363200311070ustar00rootroot00000000000000{ "compactStructuredEncryptionData": "test", "compactionTokens": { "nested.notindexed": { "$binary": { "base64": "27J6DZqcjkRzZ3lWEsxH7CsQHr4CZirrGmuPS8ZkRO0=", "subType": "00" } }, "nested.encrypted": { "$binary": { "base64": "SWO8WEoZ2r2Kx/muQKb7+COizy85nIIUFiHh4K9kcvA=", "subType": "00" } }, "encrypted": { "$binary": { "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=", "subType": "00" } } } } libmongocrypt-1.11.0/bindings/python/test/data/encrypted-command-reply.json000066400000000000000000000005261465326363200271420ustar00rootroot00000000000000{ "cursor" : { "firstBatch" : [ { "_id": 1, "ssn": { "$binary": "AWFhYWFhYWFhYWFhYWFhYWECRTOW9yZzNDn5dGwuqsrJQNLtgMEKaujhs9aRWRp+7Yo3JK8N8jC8P0Xjll6C1CwLsE/iP5wjOMhVv1KMMyOCSCrHorXRsb2IKPtzl2lKTqQ=", "$type": "06" } } ], "id" : 0, "ns" : "test.test" }, "ok" : 1 } libmongocrypt-1.11.0/bindings/python/test/data/encrypted-command.json000066400000000000000000000004471465326363200260130ustar00rootroot00000000000000{ "find": "test", "filter": { "ssn": { "$eq": { "$binary": { "base64": "AWFhYWFhYWFhYWFhYWFhYWECRTOW9yZzNDn5dGwuqsrJQNLtgMEKaujhs9aRWRp+7Yo3JK8N8jC8P0Xjll6C1CwLsE/iP5wjOMhVv1KMMyOCSCrHorXRsb2IKPtzl2lKTqQ=", "subType": "06" } } } } } libmongocrypt-1.11.0/bindings/python/test/data/encrypted-field-config-map.json000066400000000000000000000025401465326363200274720ustar00rootroot00000000000000{ "test.test": { "escCollection": "fle2.basic.esc", "eccCollection": "fle2.basic.ecc", "ecocCollection": "fle2.basic.ecoc", "fields": [ { "keyId": { "$binary": { "base64": "KEY1+AAAAAAAAAAAAAAAAA==", "subType": "04" } }, "path": "firstName", "bsonType": "string", "queries": { "queryType": "equality", "contention": { "$numberLong": "0" } } } ] }, "test.test2": { "escCollection": "fle2.basic.esc", "eccCollection": "fle2.basic.ecc", "ecocCollection": "fle2.basic.ecoc", "fields": [ { "keyId": { "$binary": { "base64": "KEY2+AAAAAAAAAAAAAAAAA==", "subType": "04" } }, "path": "firstName", "bsonType": "string", "queries": { "queryType": "equality", "contention": { "$numberLong": "0" } } } ] } } libmongocrypt-1.11.0/bindings/python/test/data/encrypted-value.json000066400000000000000000000002461465326363200255060ustar00rootroot00000000000000{ "v": { "$binary": "AWFhYWFhYWFhYWFhYWFhYWECW+zDjR/69eS6VtuMD5+O2lZw6JyiWOw3avI7mnUkdpKzPfvy8F/nlZrgZa2cGmQsb0TmLZuk5trldosnGKD91w==", "$type": "06" } } libmongocrypt-1.11.0/bindings/python/test/data/fle2-find-range-explicit-v2/000077500000000000000000000000001465326363200265065ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/data/fle2-find-range-explicit-v2/int32/000077500000000000000000000000001465326363200274455ustar00rootroot00000000000000encrypted-payload.json000066400000000000000000000025221465326363200337060ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/data/fle2-find-range-explicit-v2/int32{ "v": { "$and": [ { "age": { "$gte": { "$binary": { "base64": "DQECAAADcGF5bG9hZACZAQAABGcAhQEAAAMwAH0AAAAFZAAgAAAAAInd0noBhIiJMv8QTjcfgRqnnVhxRJRRACLfvgT+CTR/BXMAIAAAAADm0EjqF/T4EmR6Dw6NaPLrL0OuzS4AFvm90czFluAAygVsACAAAAAA5MXcYWjYlzhPFUDebBEa17B5z2bupmaW9uCdtLjc7RkAAzEAfQAAAAVkACAAAAAA7lkNtT6RLw91aJ07K/blwlFs5wi9pQjqUXDcaCTxe98FcwAgAAAAAPwySffuLQihmF70Ot93KtaUMNU8KpmA+niyPRcvarNMBWwAIAAAAACDv6fJXXwRqwZH3O2kO+hdeLZ36U6bMZSui8kv0PsPtAADMgB9AAAABWQAIAAAAACcMWVTbZC4ox5VdjWeYKLgf4oBjpPlbTTAkucm9JPK0wVzACAAAAAA3tIww4ZTytkxFsUKyJbc3zwQ2w7DhkOqaNvX9g8pi3gFbAAgAAAAAGs9XR3Q1JpxV+HPW8P2GvCuCBF5bGZ8Kl1zHqzZcd5/AAASY20ABAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAgAAABBzZWNvbmRPcGVyYXRvcgAEAAAAEnNwAAEAAAAAAAAAEHRmAAAAAAAQbW4AAAAAABBteADIAAAAAA==", "subType": "06" } } } }, { "age": { "$lte": { "$binary": { "base64": "DTsAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgACAAAAEHNlY29uZE9wZXJhdG9yAAQAAAAA", "subType": "06" } } } } ] } } libmongocrypt-1.11.0/bindings/python/test/data/fle2-find-range-explicit-v2/int32/rangeopts.json000066400000000000000000000003121465326363200323360ustar00rootroot00000000000000{ "min": { "$numberInt": "0" }, "max": { "$numberInt": "200" }, "sparsity": { "$numberLong": "1" }, "trimFactor": { "$numberInt": "0" } } value-to-encrypt.json000066400000000000000000000005761465326363200335070ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/data/fle2-find-range-explicit-v2/int32{ "v": { "$and": [ { "age": { "$gte": { "$numberInt": "23" } } }, { "age": { "$lte": { "$numberInt": "35" } } } ] } } libmongocrypt-1.11.0/bindings/python/test/data/fle2-find-rangePreview-explicit/000077500000000000000000000000001465326363200275235ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/data/fle2-find-rangePreview-explicit/int32/000077500000000000000000000000001465326363200304625ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/data/fle2-find-rangePreview-explicit/int32/rangeopts.json000066400000000000000000000002251465326363200333560ustar00rootroot00000000000000{ "min": { "$numberInt": "0" }, "max": { "$numberInt": "200" }, "sparsity": { "$numberLong": "1" } } value-to-encrypt.json000066400000000000000000000005761465326363200345240ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/data/fle2-find-rangePreview-explicit/int32{ "v": { "$and": [ { "age": { "$gte": { "$numberInt": "23" } } }, { "age": { "$lte": { "$numberInt": "35" } } } ] } } libmongocrypt-1.11.0/bindings/python/test/data/key-document-azure.json000066400000000000000000000017401465326363200261270ustar00rootroot00000000000000{ "status": { "$numberInt": "1" }, "_id": { "$binary": { "base64": "YWFhYWFhYWFhYWFhYWFhYQ==", "subType": "04" } }, "masterKey": { "provider": "azure", "keyVaultEndpoint": "example.com", "keyName": "foo" }, "updateDate": { "$date": { "$numberLong": "1557827033449" } }, "keyMaterial": { "$binary": { "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", "subType": "00" } }, "creationDate": { "$date": { "$numberLong": "1557827033449" } }, "keyAltNames": ["name1", "name2"] } libmongocrypt-1.11.0/bindings/python/test/data/key-document-gcp.json000066400000000000000000000020041465326363200255440ustar00rootroot00000000000000{ "status": { "$numberInt": "1" }, "_id": { "$binary": { "base64": "YWFhYWFhYWFhYWFhYWFhYQ==", "subType": "04" } }, "masterKey": { "provider": "gcp", "projectId": "foo", "location": "foo", "keyRing": "foo", "keyName": "foo" }, "updateDate": { "$date": { "$numberLong": "1557827033449" } }, "keyMaterial": { "$binary": { "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", "subType": "00" } }, "creationDate": { "$date": { "$numberLong": "1557827033449" } }, "keyAltNames": ["name1", "name2"] } libmongocrypt-1.11.0/bindings/python/test/data/key-document.json000066400000000000000000000020261465326363200250010ustar00rootroot00000000000000{ "status": { "$numberInt": "1" }, "_id": { "$binary": { "base64": "YWFhYWFhYWFhYWFhYWFhYQ==", "subType": "04" } }, "masterKey": { "region": "us-east-1", "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", "provider": "aws" }, "updateDate": { "$date": { "$numberLong": "1557827033449" } }, "keyMaterial": { "$binary": { "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", "subType": "00" } }, "creationDate": { "$date": { "$numberLong": "1557827033449" } }, "keyAltNames": ["name1", "name2"] } libmongocrypt-1.11.0/bindings/python/test/data/key-filter.json000066400000000000000000000003641465326363200244530ustar00rootroot00000000000000{ "$or": [ { "_id": { "$in": [ { "$binary": "YWFhYWFhYWFhYWFhYWFhYQ==", "$type": "04" } ] } }, { "keyAltNames": { "$in": [] } } ] } libmongocrypt-1.11.0/bindings/python/test/data/keys/000077500000000000000000000000001465326363200224555ustar00rootroot0000000000000012345678123498761234123456789012-local-document.json000066400000000000000000000013741465326363200314670ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/data/keys{ "_id": { "$binary": { "base64": "EjRWeBI0mHYSNBI0VniQEg==", "subType": "04" } }, "keyMaterial": { "$binary": { "base64": "1ZbBTB1i/z4LcmBKi9+nnWqkVB4Wl6P4G7/TFQvXATRF2fX0lhBLIM6rT1U547FX2YgMtaP7sid+jpd4Vhz5kS+UlgtmCFfjeO4qOnJ78KEXRzeIebzKWKQz1pMhYZ3OURDL4wCtNqt3tbSr11kfTADmCMuzgp8U8P8T21RWWBU0f2XDcxiIShYncOS3poKu7GJaPCTav4r3h5h2xRklDA==", "subType": "00" } }, "creationDate": { "$date": { "$numberLong": "1648914851981" } }, "updateDate": { "$date": { "$numberLong": "1648914851981" } }, "status": { "$numberInt": "0" }, "masterKey": { "provider": "local" } } 12345678123498761234123456789013-local-document.json000066400000000000000000000013741465326363200314700ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/data/keys{ "_id": { "$binary": { "base64": "EjRWeBI0mHYSNBI0VniQEw==", "subType": "04" } }, "keyMaterial": { "$binary": { "base64": "YQXu48YyDbXvVQ1OhPsodQQNA1gLVWZSV0udYVmCTpVrgyAZePHQmsWWnQzNZj+ZsTxRm02soje/FJCqWGLeth3gKdvIsRg15CDEUOqLdDEpHl46hadosXyJIfo0umZ/LVTkvxRhmDCDxAkd0+Dg4/vWSiG0FgNzGrlvOUsTLGbqWtNMuOdZ8pKAdnFRrqce5cwBGQmd2VVBA2OQ0/IMxQ==", "subType": "00" } }, "creationDate": { "$date": { "$numberLong": "1650631142512" } }, "updateDate": { "$date": { "$numberLong": "1650631142512" } }, "status": { "$numberInt": "0" }, "masterKey": { "provider": "local" } } ABCDEFAB123498761234123456789012-local-document.json000066400000000000000000000013741465326363200316530ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/data/keys{ "_id": { "$binary": { "base64": "q83vqxI0mHYSNBI0VniQEg==", "subType": "04" } }, "keyMaterial": { "$binary": { "base64": "27OBvUqHAuYFy60nwCdvq2xmZ4kFzVySphXzBGq+HEot13comCoydEfnltBzLTuXLbV9cnREFJIO5f0jMqrlkxIuvAV8yO84p5VJTEa8j/xSNe7iA594rx7UeKT0fOt4VqM47fht8h+8PZYc5JVezvEMvwk115IBCwENxDjLtT0g+y8Hf+aTUEGtxrYToH8zf1/Y7S16mHiIc4jK3/vxHw==", "subType": "00" } }, "creationDate": { "$date": { "$numberLong": "1648915408923" } }, "updateDate": { "$date": { "$numberLong": "1648915408923" } }, "status": { "$numberInt": "0" }, "masterKey": { "provider": "local" } } libmongocrypt-1.11.0/bindings/python/test/data/kms-encrypt-reply.txt000066400000000000000000000011251465326363200256470ustar00rootroot00000000000000HTTP/1.1 200 OK x-amzn-RequestId: deeb35e5-4ecb-4bf1-9af5-84a54ff0af0e Content-Type: application/x-amz-json-1.1 Content-Length: 446 Connection: close {"KeyId": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", "CiphertextBlob": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gHCPOT4UQIpMTvAVABLqnXlAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDLxAm0nO3rccdoWA6AIBEIB7HUe6+aPvgNu/4sLEXBQVDIJVBueI3q7zdOMBSkRKkgZWqEuQgA6iDuEZbhHhOVCUXPBaLX6QWRwyMmjvIy/2Bg5q+TmwnfRo6QKdw2vee1W32/FdPWIoQy1yKOoIhNy6XMWldS3JuWK8ffQOYkssEqx0V4LW6PKuFv7D"}libmongocrypt-1.11.0/bindings/python/test/data/kms-reply-azure.txt000066400000000000000000000007731465326363200253210ustar00rootroot00000000000000HTTP/1.1 200 OK x-amzn-RequestId: deeb35e5-4ecb-4bf1-9af5-84a54ff0af0e Content-Type: application/x-amz-json-1.1 Content-Length: 374 {"KeyId": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", "plaintext": "TqhXy3tKckECjy4/ZNykMWG8amBF46isVPzeOgeusKrwheBmYaU8TMG5AHR/NeUDKukqo8hBGgogiQOVpLPkqBQHD8YkLsNbDmHoGOill5QAHnniF/Lz405bGucB5TfR", "value": "TqhXy3tKckECjy4/ZNykMWG8amBF46isVPzeOgeusKrwheBmYaU8TMG5AHR/NeUDKukqo8hBGgogiQOVpLPkqBQHD8YkLsNbDmHoGOill5QAHnniF/Lz405bGucB5TfR"}libmongocrypt-1.11.0/bindings/python/test/data/kms-reply-gcp.txt000066400000000000000000000005561465326363200247430ustar00rootroot00000000000000HTTP/1.1 200 OK x-amzn-RequestId: deeb35e5-4ecb-4bf1-9af5-84a54ff0af0e Content-Type: application/x-amz-json-1.1 Content-Length: 233 {"KeyId": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", "plaintext": "TqhXy3tKckECjy4/ZNykMWG8amBF46isVPzeOgeusKrwheBmYaU8TMG5AHR/NeUDKukqo8hBGgogiQOVpLPkqBQHD8YkLsNbDmHoGOill5QAHnniF/Lz405bGucB5TfR"}libmongocrypt-1.11.0/bindings/python/test/data/kms-reply.txt000066400000000000000000000005561465326363200241740ustar00rootroot00000000000000HTTP/1.1 200 OK x-amzn-RequestId: deeb35e5-4ecb-4bf1-9af5-84a54ff0af0e Content-Type: application/x-amz-json-1.1 Content-Length: 233 {"KeyId": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", "Plaintext": "TqhXy3tKckECjy4/ZNykMWG8amBF46isVPzeOgeusKrwheBmYaU8TMG5AHR/NeUDKukqo8hBGgogiQOVpLPkqBQHD8YkLsNbDmHoGOill5QAHnniF/Lz405bGucB5TfR"}libmongocrypt-1.11.0/bindings/python/test/data/list-collections-filter.json000066400000000000000000000000251465326363200271440ustar00rootroot00000000000000{ "name": "test" } libmongocrypt-1.11.0/bindings/python/test/data/mongocryptd-command.json000066400000000000000000000012641465326363200263610ustar00rootroot00000000000000{ "find": "test", "filter": { "ssn": "457-55-5462" }, "jsonSchema": { "properties": { "ssn": { "encrypt": { "keyId": [ { "$binary": { "base64": "YWFhYWFhYWFhYWFhYWFhYQ==", "subType": "04" } } ], "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } } }, "bsonType": "object" }, "isRemoteSchema": true } libmongocrypt-1.11.0/bindings/python/test/data/mongocryptd-reply.json000066400000000000000000000007501465326363200260750ustar00rootroot00000000000000{ "schemaRequiresEncryption": true, "ok": { "$numberInt": "1" }, "result": { "find": "test", "filter": { "ssn": { "$eq": { "$binary": { "base64": "ADgAAAAQYQABAAAABWtpABAAAAAEYWFhYWFhYWFhYWFhYWFhYQJ2AAwAAAA0NTctNTUtNTQ2MgAA", "subType": "06" } } } } }, "hasEncryptedPlaceholders": true } libmongocrypt-1.11.0/bindings/python/test/data/schema-map.json000066400000000000000000000015051465326363200244110ustar00rootroot00000000000000{ "test.test": { "properties": { "ssn": { "encrypt": { "keyId": [ { "$binary": { "base64": "AAAAAAAAAAAAAAAAAAAAAA==", "subType": "04" } } ], "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } } }, "bsonType": "object" }, "test.test2": { "properties": { "ssn": { "encrypt": { "keyId": [ { "$binary": { "base64": "AAAAAAAAAAAAAAAAAAAAAA==", "subType": "04" } } ], "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" } } }, "bsonType": "object" } } libmongocrypt-1.11.0/bindings/python/test/performance/000077500000000000000000000000001465326363200230725ustar00rootroot00000000000000libmongocrypt-1.11.0/bindings/python/test/performance/keyDocument.json000066400000000000000000000011321465326363200262510ustar00rootroot00000000000000{ "_id": { "$binary": { "base64": "YWFhYWFhYWFhYWFhYWFhYQ==", "subType": "04" } }, "keyMaterial": { "$binary": { "base64": "ACR7Hm33dDOAAD7l2ubZhSpSUWK8BkALUY+qW3UgBAEcTV8sBwZnaAWnzDsmrX55dgmYHWfynDlJogC/e33u6pbhyXvFTs5ow9OLCuCWBJ39T/Ivm3kMaZJybkejY0V+uc4UEdHvVVz/SbitVnzs2WXdMGmo1/HmDRrxGYZjewFslquv8wtUHF5pyB+QDlQBd/al9M444/8bJZFbMSmtIg==", "subType": "00" } }, "creationDate": { "$date": "2023-08-21T14:28:20.875Z" }, "updateDate": { "$date": "2023-08-21T14:28:20.875Z" }, "status": 0, "masterKey": { "provider": "local" } } libmongocrypt-1.11.0/bindings/python/test/performance/perf_test.py000066400000000000000000000131101465326363200254330ustar00rootroot00000000000000# Copyright 2023-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Benchmark pymongocrypt performance.""" from __future__ import annotations import os import sys import time import unittest from concurrent.futures import ThreadPoolExecutor from typing import List try: import simplejson as json except ImportError: import json # type: ignore[no-redef] import bson from bson import json_util sys.path[0:0] = [""] from test.test_mongocrypt import MockCallback from pymongocrypt.binding import lib, libmongocrypt_version from pymongocrypt.mongocrypt import MongoCrypt, MongoCryptOptions from pymongocrypt.synchronous.explicit_encrypter import ExplicitEncrypter from pymongocrypt.version import __version__ NUM_ITERATIONS = 10 MAX_TIME = 1 NUM_FIELDS = 1500 LOCAL_MASTER_KEY = ( b"\x9d\x94K\r\x93\xd0\xc5D\xa5r\xfd2\x1b\x940\x90#5s|\xf0\xf6\xc2\xf4\xda#V\xe7\x8f\x04" b"\xcc\xfa\xdeu\xb4Q\x87\xf3\x8b\x97\xd7KD;\xac9\xa2\xc6M\x91\x00>\xd1\xfaJ0\xc1\xd2" b"\xc6^\xfb\xacA\xf2H\x13<\x9bP\xfc\xa7$z.\x02c\xa3\xc6\x16%QPx>\x0f\xd8n\x84\xa6\xec" b"\x8d-$G\xe5\xaf" ) OUTPUT_FILE = os.environ.get("OUTPUT_FILE") result_data: List = [] def read(filename, **kwargs): with open(os.path.join(os.path.dirname(__file__), filename), **kwargs) as fp: return fp.read() def json_data(filename): return json_util.loads(read(filename)) def bson_data(filename): return bson.encode(json_data(filename)) def tearDownModule(): output = json.dumps(result_data, indent=4) if OUTPUT_FILE: with open(OUTPUT_FILE, "w") as opf: opf.write(output) else: print(output) class TestBulkDecryption(unittest.TestCase): def setUp(self): opts = MongoCryptOptions({"local": {"key": LOCAL_MASTER_KEY}}) callback = MockCallback(key_docs=[bson_data("keyDocument.json")]) self.mongocrypt = MongoCrypt(opts, callback) self.encrypter = ExplicitEncrypter(callback, opts) self.addCleanup(self.mongocrypt.close) self.addCleanup(self.encrypter.close) def do_task(self, encrypted, duration=MAX_TIME): start = time.monotonic() ops = 0 while time.monotonic() - start < duration: with self.mongocrypt.decryption_context(encrypted) as ctx: if ctx.state == lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS: # Key is requested on the first operation, then expected to be cached for one minute. ctx.add_mongo_operation_result(bson_data("keyDocument.json")) ctx.complete_mongo_operation() self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_READY) decrypted = ctx.finish() ops += 1 # Assert that decryption actually occurred. self.assertGreater(ops, 0) doc = bson.decode(decrypted) for val in doc.values(): self.assertIsInstance(val, str) return ops def percentile(self, percentile): sorted_results = sorted(self.results) percentile_index = int(len(sorted_results) * percentile / 100) - 1 return sorted_results[percentile_index] def runTest(self): doc = {} key_id = json_data("keyDocument.json")["_id"] for i in range(NUM_FIELDS): val = f"value {i:04}" val_encrypted = bson.decode( self.encrypter.encrypt( bson.encode({"v": val}), "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", key_id=key_id, ) )["v"] doc[f"key{i:04}"] = val_encrypted encrypted = bson.encode(doc) # Warm up benchmark and discard the result. self.do_task(encrypted, duration=2) for n_threads in [1, 2, 8, 64]: with ThreadPoolExecutor(max_workers=n_threads) as executor: self.results = [] for _ in range(NUM_ITERATIONS): start = time.monotonic() thread_results = list( executor.map(self.do_task, [encrypted] * n_threads) ) interval = time.monotonic() - start self.results.append(sum(thread_results) / interval) median = self.percentile(50) print( f"Finished {self.__class__.__name__}, threads={n_threads}, median ops_per_second={median:.2f}" ) # Remove "Test" so that TestBulkDecryption is reported as "BulkDecryption". name = self.__class__.__name__[4:] result_data.append( { "info": { "test_name": name, "args": { "threads": n_threads, }, }, "metrics": [ {"name": "ops_per_second", "type": "MEDIAN", "value": median}, ], } ) if __name__ == "__main__": print( f"Running benchmark with pymongocrypt: {__version__} libmongocrypt: {libmongocrypt_version()}" ) unittest.main() libmongocrypt-1.11.0/bindings/python/test/test_binding.py000066400000000000000000000044261465326363200236220ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Test the binding module.""" import sys sys.path[0:0] = [""] from test import unittest import pymongocrypt from pymongocrypt.binding import _parse_version, ffi, lib class TestBinding(unittest.TestCase): def assertVersionLike(self, version): self.assertTrue(isinstance(version, str), msg=version) # There should be at least one dot: "1.0" or "1.0.0" not "1". self.assertGreaterEqual(len(version.split(".")), 2, msg=version) def test_pymongocrypt_version(self): self.assertVersionLike(pymongocrypt.__version__) def test_libmongocrypt_version(self): self.assertVersionLike(pymongocrypt.libmongocrypt_version()) def test_mongocrypt_new(self): data = lib.mongocrypt_new() self.assertNotEqual(data, ffi.NULL) lib.mongocrypt_destroy(data) def test_mongocrypt_binary_new(self): data = lib.mongocrypt_binary_new() self.assertNotEqual(data, ffi.NULL) lib.mongocrypt_binary_destroy(data) def test_mongocrypt_status_new(self): data = lib.mongocrypt_status_new() self.assertNotEqual(data, ffi.NULL) lib.mongocrypt_status_destroy(data) def test_parse_version(self): # Dev versions, betas, RCs should be less than stable releases. for v in ("1.1.0-beta1", "1.1.0-b2", "1.1.0-rc1", "1.1.0-beta1", "1.1.0-pre1"): self.assertLess(_parse_version(v), _parse_version("1.1.0")) # Dev versions should parse correctly. _parse_version("1.1.0-beta1+20201102git80202647fc") # Hyphenation in patch version should be disregarded. self.assertEqual(_parse_version("1.1.0-beta1"), _parse_version("1.1.0beta1")) if __name__ == "__main__": unittest.main() libmongocrypt-1.11.0/bindings/python/test/test_crypto.py000066400000000000000000000065651465326363200235360ustar00rootroot00000000000000# Copyright 2020-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Test the crypto module.""" import sys sys.path[0:0] = [""] import base64 from test import unittest from pymongocrypt.binary import MongoCryptBinaryIn from pymongocrypt.binding import ffi, lib from pymongocrypt.crypto import sign_rsaes_pkcs1_v1_5 class TestCrypto(unittest.TestCase): def test_sign_rsaes_pkcs1_v1_5(self): key_b64 = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC4JOyv5z05cL18ztpknRC7CFY2gYol4DAKerdVUoDJxCTmFMf39dVUEqD0WDiw/qcRtSO1/FRut08PlSPmvbyKetsLoxlpS8lukSzEFpFK7+L+R4miFOl6HvECyg7lbC1H/WGAhIz9yZRlXhRo9qmO/fB6PV9IeYtU+1xYuXicjCDPp36uuxBAnCz7JfvxJ3mdVc0vpSkbSb141nWuKNYR1mgyvvL6KzxO6mYsCo4hRAdhuizD9C4jDHk0V2gDCFBk0h8SLEdzStX8L0jG90/Og4y7J1b/cPo/kbYokkYisxe8cPlsvGBf+rZex7XPxc1yWaP080qeABJb+S88O//LAgMBAAECggEBAKVxP1m3FzHBUe2NZ3fYCc0Qa2zjK7xl1KPFp2u4CU+9sy0oZJUqQHUdm5CMprqWwIHPTftWboFenmCwrSXFOFzujljBO7Z3yc1WD3NJl1ZNepLcsRJ3WWFH5V+NLJ8Bdxlj1DMEZCwr7PC5+vpnCuYWzvT0qOPTl9RNVaW9VVjHouJ9Fg+s2DrShXDegFabl1iZEDdI4xScHoYBob06A5lw0WOCTayzw0Naf37lM8Y4psRAmI46XLiF/Vbuorna4hcChxDePlNLEfMipICcuxTcei1RBSlBa2t1tcnvoTy6cuYDqqImRYjp1KnMKlKQBnQ1NjS2TsRGm+F0FbreVCECgYEA4IDJlm8q/hVyNcPe4OzIcL1rsdYN3bNm2Y2O/YtRPIkQ446ItyxD06d9VuXsQpFp9jNACAPfCMSyHpPApqlxdc8z/xATlgHkcGezEOd1r4E7NdTpGg8y6Rj9b8kVlED6v4grbRhKcU6moyKUQT3+1B6ENZTOKyxuyDEgTwZHtFECgYEA0fqdv9h9s77d6eWmIioP7FSymq93pC4umxf6TVicpjpMErdD2ZfJGulN37dq8FOsOFnSmFYJdICj/PbJm6p1i8O21lsFCltEqVoVabJ7/0alPfdG2U76OeBqI8ZubL4BMnWXAB/VVEYbyWCNpQSDTjHQYs54qa2I0dJB7OgJt1sCgYEArctFQ02/7H5Rscl1yo3DBXO94SeiCFSPdC8f2Kt3MfOxvVdkAtkjkMACSbkoUsgbTVqTYSEOEc2jTgR3iQ13JgpHaFbbsq64V0QP3TAxbLIQUjYGVgQaF1UfLOBv8hrzgj45z/ST/G80lOl595+0nCUbmBcgG1AEWrmdF0/3RmECgYAKvIzKXXB3+19vcT2ga5Qq2l3TiPtOGsppRb2XrNs9qKdxIYvHmXo/9QP1V3SRW0XoD7ez8FpFabp42cmPOxUNk3FK3paQZABLxH5pzCWI9PzIAVfPDrm+sdnbgG7vAnwfL2IMMJSA3aDYGCbF9EgefG+STcpfqq7fQ6f5TBgLFwKBgCd7gn1xYL696SaKVSm7VngpXlczHVEpz3kStWR5gfzriPBxXgMVcWmcbajRser7ARpCEfbxM1UJyv6oAYZWVSNErNzNVb4POqLYcCNySuC6xKhs9FrEQnyKjyk8wI4VnrEMGrQ8e+qYSwYk9Gh6dKGoRMAPYVXQAO0fIsHF/T0a" ciphertext_b64 = "VocBRhpMmQ2XCzVehWSqheQLnU889gf3dhU4AnVnQTJjsKx/CM23qKDPkZDd2A/BnQsp99SN7ksIX5Raj0TPwyN5OCN/YrNFNGoOFlTsGhgP/hyE8X3Duiq6sNO0SMvRYNPFFGlJFsp1Fw3Z94eYMg4/Wpw5s4+Jo5Zm/qY7aTJIqDKDQ3CNHLeJgcMUOc9sz01/GzoUYKDVODHSxrYEk5ireFJFz9vP8P7Ha+VDUZuQIQdXer9NBbGFtYmWprY3nn4D3Dw93Sn0V0dIqYeIo91oKyslvMebmUM95S2PyIJdEpPb2DJDxjvX/0LLwSWlSXRWy9gapWoBkb4ynqZBsg==" value = b"data to sign" with MongoCryptBinaryIn(b"1" * 256) as output, MongoCryptBinaryIn( base64.b64decode(key_b64) ) as key, MongoCryptBinaryIn(value) as value: retval = sign_rsaes_pkcs1_v1_5( ffi.NULL, key.bin, value.bin, output.bin, lib.mongocrypt_status_new() ) self.assertTrue(retval) self.assertEqual(output.to_bytes(), base64.b64decode(ciphertext_b64)) if __name__ == "__main__": unittest.main() libmongocrypt-1.11.0/bindings/python/test/test_mongocrypt.py000066400000000000000000001645041465326363200244150ustar00rootroot00000000000000# Copyright 2019-present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Test the mongocrypt module.""" import base64 import copy import os import sys import bson import httpx from bson import json_util from bson.binary import Binary, UuidRepresentation from bson.codec_options import CodecOptions from bson.json_util import JSONOptions from bson.raw_bson import RawBSONDocument from bson.son import SON import pymongocrypt.mongocrypt from pymongocrypt.binary import MongoCryptBinaryIn, MongoCryptBinaryOut from pymongocrypt.options import MongoCryptOptions sys.path[0:0] = [""] import unittest import unittest.mock import respx from pymongo_auth_aws.auth import AwsCredential from pymongocrypt.asynchronous.auto_encrypter import AsyncAutoEncrypter from pymongocrypt.asynchronous.explicit_encrypter import AsyncExplicitEncrypter from pymongocrypt.asynchronous.state_machine import AsyncMongoCryptCallback from pymongocrypt.binding import lib from pymongocrypt.compat import PY3, unicode_type from pymongocrypt.errors import MongoCryptError from pymongocrypt.mongocrypt import MongoCrypt from pymongocrypt.synchronous.auto_encrypter import AutoEncrypter from pymongocrypt.synchronous.explicit_encrypter import ExplicitEncrypter from pymongocrypt.synchronous.state_machine import MongoCryptCallback # Data for testing libbmongocrypt binding. DATA_DIR = os.path.realpath(os.path.join(os.path.dirname(__file__), "data")) def to_base64(data): b64 = base64.b64encode(data) if not PY3: return unicode_type(b64) return b64.decode("utf-8") class TestMongoCryptBinary(unittest.TestCase): def test_mongocrypt_binary_in(self): with MongoCryptBinaryIn(b"1\x0023") as binary: self.assertIsNotNone(binary.bin) self.assertEqual(binary.to_bytes(), b"1\x0023") self.assertIsNone(binary.bin) with MongoCryptBinaryIn(b"") as binary: self.assertIsNotNone(binary.bin) self.assertEqual(binary.to_bytes(), b"") self.assertIsNone(binary.bin) # Memoryview with MongoCryptBinaryIn(memoryview(b"1\x0023")) as binary: self.assertIsNotNone(binary.bin) self.assertEqual(binary.to_bytes(), b"1\x0023") self.assertIsNone(binary.bin) def test_mongocrypt_binary_out(self): with MongoCryptBinaryOut() as binary: self.assertIsNotNone(binary.bin) self.assertEqual(binary.to_bytes(), b"") self.assertIsNone(binary.bin) class TestMongoCryptOptions(unittest.TestCase): def test_mongocrypt_options(self): schema_map = bson_data("schema-map.json") valid = [ ({"local": {"key": b"1" * 96}}, None), ({"aws": {}}, schema_map), ({"aws": {"accessKeyId": "", "secretAccessKey": ""}}, schema_map), ({"aws": {"accessKeyId": "foo", "secretAccessKey": "foo"}}, None), ( { "aws": { "accessKeyId": "foo", "secretAccessKey": "foo", "sessionToken": "token", } }, None, ), ( { "aws": {"accessKeyId": "foo", "secretAccessKey": "foo"}, "local": {"key": b"1" * 96}, }, None, ), ({"local": {"key": to_base64(b"1" * 96)}}, None), ({"local": {"key": Binary(b"1" * 96)}}, None), ({"azure": {}}, None), ({"azure": {"clientId": "foo", "clientSecret": "bar"}}, None), ({"gcp": {}}, None), ({"gcp": {"email": "foo@bar.baz", "privateKey": b"1"}}, None), ({"gcp": {"email": "foo@bar.baz", "privateKey": to_base64(b"1")}}, None), ({"gcp": {"email": "foo@bar.baz", "privateKey": Binary(b"1")}}, None), ({"kmip": {"endpoint": "localhost"}}, None), ] # Add tests for named KMS providers. for kms_providers, schema_map in valid: for name, val in list(kms_providers.items()): kms_providers[f"{name}:named"] = val for kms_providers, schema_map in valid: opts = MongoCryptOptions(kms_providers, schema_map) self.assertEqual(opts.kms_providers, kms_providers, msg=kms_providers) self.assertEqual(opts.schema_map, schema_map) self.assertIsNone(opts.encrypted_fields_map) self.assertFalse(opts.bypass_query_analysis) encrypted_fields_map = bson_data("encrypted-field-config-map.json") opts = MongoCryptOptions( valid[0][0], schema_map, encrypted_fields_map=encrypted_fields_map, bypass_query_analysis=True, ) self.assertEqual(opts.encrypted_fields_map, encrypted_fields_map) self.assertTrue(opts.bypass_query_analysis) def test_mongocrypt_options_validation(self): with self.assertRaisesRegex( ValueError, "at least one KMS provider must be configured" ): MongoCryptOptions({}) for invalid_kms_providers in [ {"aws": {"accessKeyId": "foo"}}, {"aws": {"secretAccessKey": "foo"}}, {"aws:foo": {"accessKeyId": "foo"}}, {"aws:foo": {"secretAccessKey": "foo"}}, ]: name = next(iter(invalid_kms_providers)) with self.assertRaisesRegex( ValueError, rf"kms_providers\[{name!r}\] must contain " "'accessKeyId' and 'secretAccessKey'", ): MongoCryptOptions(invalid_kms_providers) with self.assertRaisesRegex( TypeError, r"kms_providers\['local'\]\['key'\] must be an " r"instance of bytes or str", ): MongoCryptOptions({"local": {"key": None}}) with self.assertRaisesRegex( TypeError, r"kms_providers\['gcp'\]\['privateKey'\] must be an " r"instance of bytes or str", ): MongoCryptOptions({"gcp": {"email": "foo@bar.baz", "privateKey": None}}) with self.assertRaisesRegex( ValueError, r"kms_providers\['kmip'\] must contain 'endpoint'" ): MongoCryptOptions({"kmip": {}}) with self.assertRaisesRegex( TypeError, r"kms_providers\['kmip'\]\['endpoint'\] must be an instance of str", ): MongoCryptOptions({"kmip": {"endpoint": None}}) valid_kms = {"aws": {"accessKeyId": "", "secretAccessKey": ""}} with self.assertRaisesRegex(TypeError, "schema_map must be bytes or None"): MongoCryptOptions(valid_kms, schema_map={}) with self.assertRaisesRegex( TypeError, "encrypted_fields_map must be bytes or None" ): MongoCryptOptions(valid_kms, encrypted_fields_map={}) class TestMongoCrypt(unittest.TestCase): maxDiff = None def test_mongocrypt(self): kms_providers = {"aws": {"accessKeyId": "foo", "secretAccessKey": "foo"}} opts = MongoCryptOptions(kms_providers) mc = MongoCrypt(opts, MockCallback()) mc.close() mc.close() def test_mongocrypt_aws_session_token(self): kms_providers = { "aws": { "accessKeyId": "foo", "secretAccessKey": "foo", "sessionToken": "token", } } opts = MongoCryptOptions(kms_providers) mc = MongoCrypt(opts, MockCallback()) mc.close() def test_mongocrypt_validation(self): callback = MockCallback() options = MongoCryptOptions({"local": {"key": b"\x00" * 96}}) with self.assertRaisesRegex(TypeError, "options must be a MongoCryptOptions"): MongoCrypt({}, callback) with self.assertRaisesRegex(TypeError, "options must be a MongoCryptOptions"): MongoCrypt(None, callback) with self.assertRaisesRegex( TypeError, "callback must be a MongoCryptCallback or AsyncMongoCryptCallback", ): MongoCrypt(options, {}) with self.assertRaisesRegex( TypeError, "callback must be a MongoCryptCallback or AsyncMongoCryptCallback", ): MongoCrypt(options, None) invalid_key_len_opts = MongoCryptOptions({"local": {"key": b"1"}}) with self.assertRaisesRegex(MongoCryptError, "local key must be 96 bytes"): MongoCrypt(invalid_key_len_opts, callback) def test_setopt_kms_provider_base64_or_bytes(self): test_fields = [("local", "key"), ("gcp", "privateKey")] callback = MockCallback() base_kms_dict = { "local": {"key": b"\x00" * 96}, "gcp": {"email": "foo@bar.baz", "privateKey": b"\x00"}, } for f1, f2 in test_fields: kms_dict = copy.deepcopy(base_kms_dict) # Case 1: pass key as string containing bytes (valid) kms_dict[f1][f2] = b"\x00" * 96 options = MongoCryptOptions(kms_dict) mc = MongoCrypt(options, callback) mc.close() # Case 2: pass key as base64-encoded unicode literal (valid) kms_dict[f1][f2] = to_base64(b"\x00" * 96) options = MongoCryptOptions(kms_dict) mc = MongoCrypt(options, callback) mc.close() # Case 3: pass key as unicode string containing bytes (invalid) kms_dict[f1][f2] = unicode_type(b"\x00" * 96) options = MongoCryptOptions(kms_dict) with self.assertRaisesRegex( MongoCryptError, "unable to parse base64 from UTF-8 field" ): MongoCrypt(options, callback) # Case 4: pass key as base64-encoded string (invalid) # Only applicable to "local" as key length is not validated for gcp. kms_dict = copy.deepcopy(base_kms_dict) kms_dict["local"]["key"] = base64.b64encode(b"\x00" * 96) options = MongoCryptOptions(kms_dict) with self.assertRaisesRegex(MongoCryptError, "local key must be 96 bytes"): MongoCrypt(options, callback) @staticmethod def create_mongocrypt(**kwargs): return MongoCrypt( MongoCryptOptions( { "aws": {"accessKeyId": "example", "secretAccessKey": "example"}, "local": {"key": b"\x00" * 96}, }, **kwargs, ), MockCallback(), ) def _test_kms_context(self, ctx): key_filter = ctx.mongo_operation() self.assertEqual(key_filter, bson_data("key-filter.json")) ctx.add_mongo_operation_result(bson_data("key-document.json")) ctx.complete_mongo_operation() self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_KMS) km_contexts = list(ctx.kms_contexts()) self.assertEqual(len(km_contexts), 1) with km_contexts[0] as kms_ctx: self.assertEqual(kms_ctx.kms_provider, "aws") self.assertEqual(kms_ctx.endpoint, "kms.us-east-1.amazonaws.com:443") self.assertEqual(len(kms_ctx.message), 790) self.assertEqual(kms_ctx.bytes_needed, 1024) kms_ctx.feed(http_data("kms-reply.txt")) self.assertEqual(kms_ctx.bytes_needed, 0) self.assertEqual(kms_ctx.kms_provider, "aws") ctx.complete_kms() def test_encrypt(self): mc = self.create_mongocrypt() self.addCleanup(mc.close) if mc.crypt_shared_lib_version is not None: self.skipTest("this test must be skipped when crypt_shared is loaded") with mc.encryption_context("text", bson_data("command.json")) as ctx: self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_COLLINFO) list_colls_filter = ctx.mongo_operation() self.assertEqual( list_colls_filter, bson_data("list-collections-filter.json") ) ctx.add_mongo_operation_result(bson_data("collection-info.json")) ctx.complete_mongo_operation() self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_MARKINGS) mongocryptd_cmd = ctx.mongo_operation() self.assertEqual( bson.decode(mongocryptd_cmd, OPTS), json_data("mongocryptd-command.json"), ) self.assertEqual(mongocryptd_cmd, bson_data("mongocryptd-command.json")) ctx.add_mongo_operation_result(bson_data("mongocryptd-reply.json")) ctx.complete_mongo_operation() self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS) self._test_kms_context(ctx) self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_READY) encrypted = ctx.finish() self.assertEqual( bson.decode(encrypted, OPTS), json_data("encrypted-command.json") ) self.assertEqual(encrypted, bson_data("encrypted-command.json")) self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_DONE) def test_decrypt(self): mc = self.create_mongocrypt() self.addCleanup(mc.close) with mc.decryption_context(bson_data("encrypted-command-reply.json")) as ctx: self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS) self._test_kms_context(ctx) self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_READY) encrypted = ctx.finish() self.assertEqual( bson.decode(encrypted, OPTS), json_data("command-reply.json") ) self.assertEqual(encrypted, bson_data("command-reply.json")) self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_DONE) def test_encrypt_encrypted_fields_map(self): encrypted_fields_map = bson_data( "compact/success/encrypted-field-config-map.json" ) mc = self.create_mongocrypt(encrypted_fields_map=encrypted_fields_map) self.addCleanup(mc.close) with mc.encryption_context("db", bson_data("compact/success/cmd.json")) as ctx: self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS) ctx.mongo_operation() ctx.add_mongo_operation_result( bson_data("keys/12345678123498761234123456789012-local-document.json") ) self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS) ctx.mongo_operation() ctx.add_mongo_operation_result( bson_data("keys/ABCDEFAB123498761234123456789012-local-document.json") ) self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_NEED_MONGO_KEYS) ctx.mongo_operation() ctx.add_mongo_operation_result( bson_data("keys/12345678123498761234123456789013-local-document.json") ) ctx.complete_mongo_operation() self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_READY) encrypted = ctx.finish() self.assertEqual( bson.decode(encrypted, OPTS), json_data("compact/success/encrypted-payload.json"), ) self.assertEqual( encrypted, bson_data("compact/success/encrypted-payload.json") ) self.assertEqual(ctx.state, lib.MONGOCRYPT_CTX_DONE) def test_pymongo_imports(self): from pymongocrypt.auto_encrypter import AutoEncrypter # type:ignore[import] from pymongocrypt.errors import MongoCryptError # type:ignore[import] from pymongocrypt.explicit_encrypter import ( ExplicitEncrypter, # type:ignore[import] ) from pymongocrypt.mongocrypt import MongoCryptOptions # type:ignore[import] from pymongocrypt.state_machine import MongoCryptCallback # type:ignore[import] class MockCallback(MongoCryptCallback): def __init__( self, list_colls_result=None, mongocryptd_reply=None, key_docs=None, kms_reply=None, ): self.list_colls_result = list_colls_result self.mongocryptd_reply = mongocryptd_reply self.key_docs = key_docs self.kms_reply = kms_reply self.kms_endpoint = None def kms_request(self, kms_context): self.kms_endpoint = kms_context.endpoint kms_context.feed(self.kms_reply) def collection_info(self, ns, filter): return self.list_colls_result def mark_command(self, ns, cmd): return self.mongocryptd_reply def fetch_keys(self, filter): return self.key_docs def insert_data_key(self, data_key): raise NotImplementedError def bson_encode(self, doc): return bson.encode(doc) def close(self): pass class MockAsyncCallback(AsyncMongoCryptCallback): def __init__( self, list_colls_result=None, mongocryptd_reply=None, key_docs=None, kms_reply=None, ): self.list_colls_result = list_colls_result self.mongocryptd_reply = mongocryptd_reply self.key_docs = key_docs self.kms_reply = kms_reply self.kms_endpoint = None async def kms_request(self, kms_context): self.kms_endpoint = kms_context.endpoint kms_context.feed(self.kms_reply) async def collection_info(self, ns, filter): return self.list_colls_result async def mark_command(self, ns, cmd): return self.mongocryptd_reply async def fetch_keys(self, filter): return self.key_docs async def insert_data_key(self, data_key): raise NotImplementedError def bson_encode(self, doc): return bson.encode(doc) async def close(self): pass class TestMongoCryptCallback(unittest.TestCase): maxDiff = None @staticmethod def mongo_crypt_opts(): return MongoCryptOptions( { "aws": {"accessKeyId": "example", "secretAccessKey": "example"}, "local": {"key": b"\x00" * 96}, } ) @unittest.skipUnless( os.getenv("TEST_CRYPT_SHARED"), "this test requires TEST_CRYPT_SHARED=1" ) def test_crypt_shared(self): kms_providers = { "aws": {"accessKeyId": "example", "secretAccessKey": "example"}, "local": {"key": b"\x00" * 96}, } mc = MongoCrypt(MongoCryptOptions(kms_providers), MockCallback()) self.addCleanup(mc.close) self.assertIsNotNone(mc.crypt_shared_lib_version) # Test that we can pick up crypt_shared automatically encrypter = AutoEncrypter( MockCallback(), MongoCryptOptions( kms_providers, bypass_encryption=False, crypt_shared_lib_required=True ), ) self.addCleanup(encrypter.close) encrypter = AutoEncrypter( MockCallback(), MongoCryptOptions( kms_providers, crypt_shared_lib_path=os.environ["CRYPT_SHARED_PATH"], crypt_shared_lib_required=True, ), ) self.addCleanup(encrypter.close) with self.assertRaisesRegex(MongoCryptError, "/doesnotexist"): AutoEncrypter( MockCallback(), MongoCryptOptions( kms_providers, crypt_shared_lib_path="/doesnotexist", crypt_shared_lib_required=True, ), ) def test_encrypt(self): encrypter = AutoEncrypter( MockCallback( list_colls_result=bson_data("collection-info.json"), mongocryptd_reply=bson_data("mongocryptd-reply.json"), key_docs=[bson_data("key-document.json")], kms_reply=http_data("kms-reply.txt"), ), self.mongo_crypt_opts(), ) self.addCleanup(encrypter.close) encrypted = encrypter.encrypt("test", bson_data("command.json")) self.assertEqual( bson.decode(encrypted, OPTS), json_data("encrypted-command.json") ) self.assertEqual(encrypted, bson_data("encrypted-command.json")) def test_decrypt(self): encrypter = AutoEncrypter( MockCallback( list_colls_result=bson_data("collection-info.json"), mongocryptd_reply=bson_data("mongocryptd-reply.json"), key_docs=[bson_data("key-document.json")], kms_reply=http_data("kms-reply.txt"), ), self.mongo_crypt_opts(), ) self.addCleanup(encrypter.close) decrypted = encrypter.decrypt(bson_data("encrypted-command-reply.json")) self.assertEqual(bson.decode(decrypted, OPTS), json_data("command-reply.json")) self.assertEqual(decrypted, bson_data("command-reply.json")) def test_need_kms_aws_credentials(self): kms_providers = {"aws": {}} opts = MongoCryptOptions(kms_providers) callback = MockCallback( list_colls_result=bson_data("collection-info.json"), mongocryptd_reply=bson_data("mongocryptd-reply.json"), key_docs=[bson_data("key-document.json")], kms_reply=http_data("kms-reply.txt"), ) encrypter = AutoEncrypter(callback, opts) self.addCleanup(encrypter.close) with unittest.mock.patch( "pymongocrypt.synchronous.credentials.aws_temp_credentials" ) as m: m.return_value = AwsCredential("example", "example", None) decrypted = encrypter.decrypt(bson_data("encrypted-command-reply.json")) self.assertTrue(m.called) self.assertEqual(bson.decode(decrypted, OPTS), json_data("command-reply.json")) self.assertEqual(decrypted, bson_data("command-reply.json")) def test_need_kms_gcp_credentials(self): kms_providers = {"gcp": {}} opts = MongoCryptOptions(kms_providers) callback = MockCallback( list_colls_result=bson_data("collection-info.json"), mongocryptd_reply=bson_data("mongocryptd-reply.json"), key_docs=[bson_data("key-document-gcp.json")], kms_reply=http_data("kms-reply-gcp.txt"), ) encrypter = AutoEncrypter(callback, opts) self.addCleanup(encrypter.close) with respx.mock() as router: data = {"access_token": "foo"} url = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" router.add( respx.get(url=url).mock(return_value=httpx.Response(200, json=data)) ) decrypted = encrypter.decrypt(bson_data("encrypted-command-reply.json")) self.assertTrue(len(router.calls)) self.assertEqual(bson.decode(decrypted, OPTS), json_data("command-reply.json")) self.assertEqual(decrypted, bson_data("command-reply.json")) if sys.version_info >= (3, 8, 0): # noqa: UP036 class TestAsyncMongoCryptCallback(unittest.IsolatedAsyncioTestCase): maxDiff = None @staticmethod def mongo_crypt_opts(): return MongoCryptOptions( { "aws": {"accessKeyId": "example", "secretAccessKey": "example"}, "local": {"key": b"\x00" * 96}, } ) @unittest.skipUnless( os.getenv("TEST_CRYPT_SHARED"), "this test requires TEST_CRYPT_SHARED=1" ) async def test_crypt_shared(self): kms_providers = { "aws": {"accessKeyId": "example", "secretAccessKey": "example"}, "local": {"key": b"\x00" * 96}, } mc = MongoCrypt(MongoCryptOptions(kms_providers), MockAsyncCallback()) self.addCleanup(mc.close) self.assertIsNotNone(mc.crypt_shared_lib_version) # Test that we can pick up crypt_shared automatically encrypter = AsyncAutoEncrypter( MockAsyncCallback(), MongoCryptOptions( kms_providers, bypass_encryption=False, crypt_shared_lib_required=True, ), ) self.addAsyncCleanup(encrypter.close) encrypter = AsyncAutoEncrypter( MockAsyncCallback(), MongoCryptOptions( kms_providers, crypt_shared_lib_path=os.environ["CRYPT_SHARED_PATH"], crypt_shared_lib_required=True, ), ) self.addAsyncCleanup(encrypter.close) with self.assertRaisesRegex(MongoCryptError, "/doesnotexist"): AsyncAutoEncrypter( MockAsyncCallback(), MongoCryptOptions( kms_providers, crypt_shared_lib_path="/doesnotexist", crypt_shared_lib_required=True, ), ) async def test_encrypt(self): encrypter = AsyncAutoEncrypter( MockAsyncCallback( list_colls_result=bson_data("collection-info.json"), mongocryptd_reply=bson_data("mongocryptd-reply.json"), key_docs=[bson_data("key-document.json")], kms_reply=http_data("kms-reply.txt"), ), self.mongo_crypt_opts(), ) self.addAsyncCleanup(encrypter.close) encrypted = await encrypter.encrypt("test", bson_data("command.json")) self.assertEqual( bson.decode(encrypted, OPTS), json_data("encrypted-command.json") ) self.assertEqual(encrypted, bson_data("encrypted-command.json")) async def test_decrypt(self): encrypter = AsyncAutoEncrypter( MockAsyncCallback( list_colls_result=bson_data("collection-info.json"), mongocryptd_reply=bson_data("mongocryptd-reply.json"), key_docs=[bson_data("key-document.json")], kms_reply=http_data("kms-reply.txt"), ), self.mongo_crypt_opts(), ) self.addAsyncCleanup(encrypter.close) decrypted = await encrypter.decrypt( bson_data("encrypted-command-reply.json") ) self.assertEqual( bson.decode(decrypted, OPTS), json_data("command-reply.json") ) self.assertEqual(decrypted, bson_data("command-reply.json")) async def test_need_kms_aws_credentials(self): kms_providers = {"aws": {}} opts = MongoCryptOptions(kms_providers) callback = MockAsyncCallback( list_colls_result=bson_data("collection-info.json"), mongocryptd_reply=bson_data("mongocryptd-reply.json"), key_docs=[bson_data("key-document.json")], kms_reply=http_data("kms-reply.txt"), ) encrypter = AsyncAutoEncrypter(callback, opts) self.addAsyncCleanup(encrypter.close) with unittest.mock.patch( "pymongocrypt.asynchronous.credentials.aws_temp_credentials" ) as m: m.return_value = AwsCredential("example", "example", None) decrypted = await encrypter.decrypt( bson_data("encrypted-command-reply.json") ) self.assertTrue(m.called) self.assertEqual( bson.decode(decrypted, OPTS), json_data("command-reply.json") ) self.assertEqual(decrypted, bson_data("command-reply.json")) async def test_need_kms_gcp_credentials(self): kms_providers = {"gcp": {}} opts = MongoCryptOptions(kms_providers) callback = MockAsyncCallback( list_colls_result=bson_data("collection-info.json"), mongocryptd_reply=bson_data("mongocryptd-reply.json"), key_docs=[bson_data("key-document-gcp.json")], kms_reply=http_data("kms-reply-gcp.txt"), ) encrypter = AsyncAutoEncrypter(callback, opts) self.addAsyncCleanup(encrypter.close) with respx.mock() as router: data = {"access_token": "foo"} url = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" router.add( respx.get(url=url).mock(return_value=httpx.Response(200, json=data)) ) decrypted = await encrypter.decrypt( bson_data("encrypted-command-reply.json") ) self.assertTrue(len(router.calls)) self.assertEqual( bson.decode(decrypted, OPTS), json_data("command-reply.json") ) self.assertEqual(decrypted, bson_data("command-reply.json")) class TestAsyncExplicitEncryption(unittest.IsolatedAsyncioTestCase): maxDiff = None @staticmethod def mongo_crypt_opts(): return MongoCryptOptions( { "aws": {"accessKeyId": "example", "secretAccessKey": "example"}, "local": {"key": b"\x00" * 96}, } ) async def _test_encrypt_decrypt(self, key_id=None, key_alt_name=None): encrypter = AsyncExplicitEncrypter( MockAsyncCallback( key_docs=[bson_data("key-document.json")], kms_reply=http_data("kms-reply.txt"), ), self.mongo_crypt_opts(), ) self.addCleanup(encrypter.close) val = {"v": "hello"} encoded_val = bson.encode(val) algo = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" encrypted = await encrypter.encrypt( encoded_val, algo, key_id=key_id, key_alt_name=key_alt_name ) self.assertEqual( bson.decode(encrypted, OPTS), json_data("encrypted-value.json") ) self.assertEqual(encrypted, bson_data("encrypted-value.json")) decrypted = await encrypter.decrypt(encrypted) self.assertEqual(bson.decode(decrypted, OPTS), val) self.assertEqual(encoded_val, decrypted) async def test_encrypt_decrypt(self): key_id = json_data("key-document.json")["_id"] await self._test_encrypt_decrypt(key_id=key_id) async def test_encrypt_decrypt_key_alt_name(self): key_alt_name = json_data("key-document.json")["keyAltNames"][0] await self._test_encrypt_decrypt(key_alt_name=key_alt_name) async def test_encrypt_errors(self): key_id = json_data("key-document.json")["_id"] encrypter = AsyncExplicitEncrypter( MockAsyncCallback(key_docs=[]), self.mongo_crypt_opts() ) self.addCleanup(encrypter.close) val = {"v": "value123"} encoded_val = bson.encode(val) # Invalid algorithm. with self.assertRaisesRegex(MongoCryptError, "algorithm"): await encrypter.encrypt(encoded_val, "Invalid", key_id) # Invalid query_type type. with self.assertRaisesRegex(TypeError, "query_type"): await encrypter.encrypt(encoded_val, "Indexed", key_id, query_type=42) # Invalid query_type string. with self.assertRaisesRegex(MongoCryptError, "query_type"): await encrypter.encrypt( encoded_val, "Indexed", key_id, query_type="invalid query type string", ) # Invalid contention_factor type. with self.assertRaisesRegex(TypeError, "contention_factor"): await encrypter.encrypt( encoded_val, "Indexed", key_id, contention_factor="not an int" ) with self.assertRaisesRegex(MongoCryptError, "contention"): await encrypter.encrypt( encoded_val, "Indexed", key_id, contention_factor=-1 ) # Invalid: Unindexed + query_type is an error. with self.assertRaisesRegex(MongoCryptError, "query"): await encrypter.encrypt( encoded_val, "Unindexed", key_id, query_type="equality" ) # Invalid: Unindexed + contention_factor is an error. with self.assertRaisesRegex(MongoCryptError, "contention"): await encrypter.encrypt( encoded_val, "Unindexed", key_id, contention_factor=1 ) async def test_encrypt_indexed(self): key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json" key_id = json_data(key_path)["_id"] encrypter = AsyncExplicitEncrypter( MockAsyncCallback( key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt") ), self.mongo_crypt_opts(), ) self.addCleanup(encrypter.close) val = {"v": "value123"} encoded_val = bson.encode(val) for kwargs in [ dict(algorithm="Indexed", contention_factor=0), dict(algorithm="Indexed", query_type="equality", contention_factor=0), dict(algorithm="Indexed", contention_factor=100), dict(algorithm="Unindexed"), ]: kwargs["key_id"] = key_id encrypted = await encrypter.encrypt(encoded_val, **kwargs) encrypted_val = bson.decode(encrypted, OPTS)["v"] self.assertIsInstance(encrypted_val, Binary) self.assertEqual(encrypted_val.subtype, 6) # Queryable Encryption find payloads cannot be round-tripped. if "query_type" not in kwargs: decrypted = await encrypter.decrypt(encrypted) self.assertEqual(bson.decode(decrypted, OPTS), val) self.assertEqual(encoded_val, decrypted) async def test_data_key_creation(self): mock_key_vault = AsyncKeyVaultCallback( kms_reply=http_data("kms-encrypt-reply.txt") ) opts = MongoCryptOptions( { "aws": {"accessKeyId": "example", "secretAccessKey": "example"}, "aws:named": { "accessKeyId": "example", "secretAccessKey": "example", }, "local": {"key": b"\x00" * 96}, "local:named": {"key": b"\x01" * 96}, } ) encrypter = AsyncExplicitEncrypter(mock_key_vault, opts) self.addCleanup(encrypter.close) valid_args = [ ("local", None, ["first", "second"]), ("local:named", None, ["local:named"]), ("aws", {"region": "region", "key": "cmk"}, ["third", "forth"]), ("aws:named", {"region": "region", "key": "cmk"}, ["aws:named"]), # Unicode region and key ("aws", {"region": "region-unicode", "key": "cmk-unicode"}, []), # Endpoint ( "aws", { "region": "region", "key": "cmk", "endpoint": "kms.us-east-1.amazonaws.com:443", }, [], ), ] for kms_provider, master_key, key_alt_names in valid_args: key_id = await encrypter.create_data_key( kms_provider, master_key=master_key, key_alt_names=key_alt_names ) self.assertIsInstance(key_id, Binary) self.assertEqual(key_id.subtype, 4) data_key = bson.decode(mock_key_vault.data_key, OPTS) # CDRIVER-3277 The order of key_alt_names is not maintained. for name in key_alt_names: self.assertIn(name, data_key["keyAltNames"]) # Assert that the custom endpoint is passed to libmongocrypt. master_key = {"region": "region", "key": "key", "endpoint": "example.com"} key_material = base64.b64decode( "xPTAjBRG5JiPm+d3fj6XLi2q5DMXUS/f1f+SMAlhhwkhDRL0kr8r9GDLIGTAGlvC+HVjSIgdL+RKwZCvpXSyxTICWSXTUYsWYPyu3IoHbuBZdmw2faM3WhcRIgbMReU5" ) if not PY3: key_material = Binary(key_material) await encrypter.create_data_key( "aws", master_key=master_key, key_material=key_material ) self.assertEqual("example.com:443", mock_key_vault.kms_endpoint) async def test_data_key_creation_bad_key_material(self): mock_key_vault = AsyncKeyVaultCallback( kms_reply=http_data("kms-encrypt-reply.txt") ) encrypter = AsyncExplicitEncrypter(mock_key_vault, self.mongo_crypt_opts()) self.addCleanup(encrypter.close) key_material = Binary(b"0" * 97) with self.assertRaisesRegex( MongoCryptError, "keyMaterial should have length 96, but has length 97" ): await encrypter.create_data_key("local", key_material=key_material) async def test_rewrap_many_data_key(self): key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json" key_path2 = "keys/12345678123498761234123456789012-local-document.json" encrypter = AsyncExplicitEncrypter( MockAsyncCallback(key_docs=[bson_data(key_path), bson_data(key_path2)]), self.mongo_crypt_opts(), ) self.addCleanup(encrypter.close) result = await encrypter.rewrap_many_data_key({}) raw_doc = RawBSONDocument(result) assert len(raw_doc["v"]) == 2 async def test_range_query_int32(self): key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json" key_id = json_data(key_path)["_id"] encrypter = AsyncExplicitEncrypter( MockAsyncCallback( key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt") ), self.mongo_crypt_opts(), ) self.addCleanup(encrypter.close) range_opts = bson_data("fle2-find-range-explicit-v2/int32/rangeopts.json") value = bson_data("fle2-find-range-explicit-v2/int32/value-to-encrypt.json") expected = json_data( "fle2-find-range-explicit-v2/int32/encrypted-payload.json" ) encrypted = await encrypter.encrypt( value, "range", key_id=key_id, query_type="range", contention_factor=4, range_opts=range_opts, is_expression=True, ) encrypted_val = bson.decode(encrypted, OPTS) self.assertEqual( encrypted_val, adjust_range_counter(encrypted_val, expected) ) class TestNeedKMSAzureCredentials(unittest.TestCase): maxDiff = None def get_encrypter(self, clear_cache=True): if clear_cache: pymongocrypt.synchronous.credentials._azure_creds_cache = None kms_providers = {"azure": {}} opts = MongoCryptOptions(kms_providers) callback = MockCallback( list_colls_result=bson_data("collection-info.json"), mongocryptd_reply=bson_data("mongocryptd-reply.json"), key_docs=[bson_data("key-document-azure.json")], kms_reply=http_data("kms-reply-azure.txt"), ) encrypter = AutoEncrypter(callback, opts) self.addCleanup(encrypter.close) return encrypter def test_success(self): encrypter = self.get_encrypter() with respx.mock() as router: data = {"access_token": "foo", "expires_in": 4000} url = "http://169.254.169.254/metadata/identity/oauth2/token" router.add( respx.get(url=url).mock(return_value=httpx.Response(200, json=data)) ) decrypted = encrypter.decrypt(bson_data("encrypted-command-reply.json")) self.assertTrue(len(router.calls)) self.assertEqual(bson.decode(decrypted, OPTS), json_data("command-reply.json")) self.assertEqual(decrypted, bson_data("command-reply.json")) self.assertIsNotNone(pymongocrypt.synchronous.credentials._azure_creds_cache) def test_empty_json(self): encrypter = self.get_encrypter() with respx.mock() as router: url = "http://169.254.169.254/metadata/identity/oauth2/token" router.add( respx.get(url=url).mock(return_value=httpx.Response(200, json={})) ) with self.assertRaisesRegex( MongoCryptError, "Azure IMDS response must contain" ): encrypter.decrypt(bson_data("encrypted-command-reply.json")) self.assertTrue(len(router.calls)) self.assertIsNone(pymongocrypt.synchronous.credentials._azure_creds_cache) def test_bad_json(self): encrypter = self.get_encrypter() with respx.mock() as router: url = "http://169.254.169.254/metadata/identity/oauth2/token" router.add( respx.get(url=url).mock(return_value=httpx.Response(200, text="a'")) ) with self.assertRaisesRegex( MongoCryptError, "Azure IMDS response must be in JSON format" ): encrypter.decrypt(bson_data("encrypted-command-reply.json")) self.assertTrue(len(router.calls)) self.assertIsNone(pymongocrypt.synchronous.credentials._azure_creds_cache) def test_http_404(self): encrypter = self.get_encrypter() with respx.mock() as router: url = "http://169.254.169.254/metadata/identity/oauth2/token" router.add(respx.get(url=url).mock(return_value=httpx.Response(404))) with self.assertRaisesRegex( MongoCryptError, "Failed to acquire IMDS access token." ): encrypter.decrypt(bson_data("encrypted-command-reply.json")) self.assertTrue(len(router.calls)) self.assertIsNone(pymongocrypt.synchronous.credentials._azure_creds_cache) def test_http_500(self): encrypter = self.get_encrypter() with respx.mock() as router: url = "http://169.254.169.254/metadata/identity/oauth2/token" router.add(respx.get(url=url).mock(return_value=httpx.Response(500))) with self.assertRaisesRegex( MongoCryptError, "Failed to acquire IMDS access token." ): encrypter.decrypt(bson_data("encrypted-command-reply.json")) self.assertTrue(len(router.calls)) self.assertIsNone(pymongocrypt.synchronous.credentials._azure_creds_cache) def test_slow_response(self): encrypter = self.get_encrypter() with respx.mock() as router: url = "http://169.254.169.254/metadata/identity/oauth2/token" router.add( respx.get(url=url).mock(side_effect=httpx._exceptions.ConnectTimeout) ) with self.assertRaisesRegex( MongoCryptError, "Failed to acquire IMDS access token: " ): encrypter.decrypt(bson_data("encrypted-command-reply.json")) self.assertTrue(len(router.calls)) self.assertIsNone(pymongocrypt.synchronous.credentials._azure_creds_cache) def test_cache(self): encrypter = self.get_encrypter() with respx.mock() as router: data = {"access_token": "foo", "expires_in": 4000} url = "http://169.254.169.254/metadata/identity/oauth2/token" router.add( respx.get(url=url).mock( return_value=httpx.Response(status_code=200, json=data) ) ) encrypter.decrypt(bson_data("encrypted-command-reply.json")) self.assertTrue(len(router.calls)) self.assertIsNotNone(pymongocrypt.synchronous.credentials._azure_creds_cache) # Should use the cached value. decrypted = encrypter.decrypt(bson_data("encrypted-command-reply.json")) self.assertEqual(decrypted, bson_data("command-reply.json")) self.assertIsNotNone(pymongocrypt.synchronous.credentials._azure_creds_cache) def test_cache_expires_soon(self): encrypter = self.get_encrypter() with respx.mock() as router: data = {"access_token": "foo", "expires_in": 10} url = "http://169.254.169.254/metadata/identity/oauth2/token" router.add( respx.get(url=url).mock( return_value=httpx.Response(status_code=200, json=data) ) ) encrypter.decrypt(bson_data("encrypted-command-reply.json")) self.assertTrue(len(router.calls)) self.assertIsNotNone(pymongocrypt.synchronous.credentials._azure_creds_cache) # Should not use the cached value. encrypter = self.get_encrypter(False) self.assertIsNotNone(pymongocrypt.synchronous.credentials._azure_creds_cache) with respx.mock() as router: url = "http://169.254.169.254/metadata/identity/oauth2/token" router.add( respx.get(url=url).mock(side_effect=httpx._exceptions.ConnectTimeout) ) with self.assertRaisesRegex( MongoCryptError, "Failed to acquire IMDS access token: " ): encrypter.decrypt(bson_data("encrypted-command-reply.json")) self.assertTrue(len(router.calls)) self.assertIsNone(pymongocrypt.synchronous.credentials._azure_creds_cache) class KeyVaultCallback(MockCallback): def __init__(self, kms_reply=None): super().__init__(kms_reply=kms_reply) self.data_key = None def fetch_keys(self, filter): return self.data_key def insert_data_key(self, data_key): self.data_key = data_key return bson.decode(data_key, OPTS)["_id"] def adjust_range_counter(encrypted_val, expected): """Workaround for the internal range payload counter in libmongocrypt.""" if encrypted_val != expected: _payload1 = expected["v"]["$and"][0]["age"]["$gte"] _payload2 = expected["v"]["$and"][1]["age"]["$lte"] _decoded1 = bson.decode(_payload1[1:]) _decoded2 = bson.decode(_payload2[1:]) for _ in range(10): _decoded1["payloadId"] += 1 expected["v"]["$and"][0]["age"]["$gte"] = Binary( _payload1[0:1] + bson.encode(_decoded1), 6 ) _decoded2["payloadId"] += 1 expected["v"]["$and"][1]["age"]["$lte"] = Binary( _payload2[0:1] + bson.encode(_decoded2), 6 ) if encrypted_val == expected: break return expected class AsyncKeyVaultCallback(MockAsyncCallback): def __init__(self, kms_reply=None): super().__init__(kms_reply=kms_reply) self.data_key = None async def fetch_keys(self, filter): return self.data_key async def insert_data_key(self, data_key): self.data_key = data_key return bson.decode(data_key, OPTS)["_id"] class TestExplicitEncryption(unittest.TestCase): maxDiff = None @staticmethod def mongo_crypt_opts(): return MongoCryptOptions( { "aws": {"accessKeyId": "example", "secretAccessKey": "example"}, "local": {"key": b"\x00" * 96}, } ) def _test_encrypt_decrypt(self, key_id=None, key_alt_name=None): encrypter = ExplicitEncrypter( MockCallback( key_docs=[bson_data("key-document.json")], kms_reply=http_data("kms-reply.txt"), ), self.mongo_crypt_opts(), ) self.addCleanup(encrypter.close) val = {"v": "hello"} encoded_val = bson.encode(val) algo = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" encrypted = encrypter.encrypt( encoded_val, algo, key_id=key_id, key_alt_name=key_alt_name ) self.assertEqual( bson.decode(encrypted, OPTS), json_data("encrypted-value.json") ) self.assertEqual(encrypted, bson_data("encrypted-value.json")) decrypted = encrypter.decrypt(encrypted) self.assertEqual(bson.decode(decrypted, OPTS), val) self.assertEqual(encoded_val, decrypted) def test_encrypt_decrypt(self): key_id = json_data("key-document.json")["_id"] self._test_encrypt_decrypt(key_id=key_id) def test_encrypt_decrypt_key_alt_name(self): key_alt_name = json_data("key-document.json")["keyAltNames"][0] self._test_encrypt_decrypt(key_alt_name=key_alt_name) def test_encrypt_errors(self): key_id = json_data("key-document.json")["_id"] encrypter = ExplicitEncrypter( MockCallback(key_docs=[]), self.mongo_crypt_opts() ) self.addCleanup(encrypter.close) val = {"v": "value123"} encoded_val = bson.encode(val) # Invalid algorithm. with self.assertRaisesRegex(MongoCryptError, "algorithm"): encrypter.encrypt(encoded_val, "Invalid", key_id) # Invalid query_type type. with self.assertRaisesRegex(TypeError, "query_type"): encrypter.encrypt(encoded_val, "Indexed", key_id, query_type=42) # Invalid query_type string. with self.assertRaisesRegex(MongoCryptError, "query_type"): encrypter.encrypt( encoded_val, "Indexed", key_id, query_type="invalid query type string" ) # Invalid contention_factor type. with self.assertRaisesRegex(TypeError, "contention_factor"): encrypter.encrypt( encoded_val, "Indexed", key_id, contention_factor="not an int" ) with self.assertRaisesRegex(MongoCryptError, "contention"): encrypter.encrypt(encoded_val, "Indexed", key_id, contention_factor=-1) # Invalid: Unindexed + query_type is an error. with self.assertRaisesRegex(MongoCryptError, "query"): encrypter.encrypt(encoded_val, "Unindexed", key_id, query_type="equality") # Invalid: Unindexed + contention_factor is an error. with self.assertRaisesRegex(MongoCryptError, "contention"): encrypter.encrypt(encoded_val, "Unindexed", key_id, contention_factor=1) def test_encrypt_indexed(self): key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json" key_id = json_data(key_path)["_id"] encrypter = ExplicitEncrypter( MockCallback( key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt") ), self.mongo_crypt_opts(), ) self.addCleanup(encrypter.close) val = {"v": "value123"} encoded_val = bson.encode(val) for kwargs in [ dict(algorithm="Indexed", contention_factor=0), dict(algorithm="Indexed", query_type="equality", contention_factor=0), dict(algorithm="Indexed", contention_factor=100), dict(algorithm="Unindexed"), ]: kwargs["key_id"] = key_id encrypted = encrypter.encrypt(encoded_val, **kwargs) encrypted_val = bson.decode(encrypted, OPTS)["v"] self.assertIsInstance(encrypted_val, Binary) self.assertEqual(encrypted_val.subtype, 6) # Queryable Encryption find payloads cannot be round-tripped. if "query_type" not in kwargs: decrypted = encrypter.decrypt(encrypted) self.assertEqual(bson.decode(decrypted, OPTS), val) self.assertEqual(encoded_val, decrypted) def test_data_key_creation(self): mock_key_vault = KeyVaultCallback(kms_reply=http_data("kms-encrypt-reply.txt")) opts = MongoCryptOptions( { "aws": {"accessKeyId": "example", "secretAccessKey": "example"}, "aws:named": {"accessKeyId": "example", "secretAccessKey": "example"}, "local": {"key": b"\x00" * 96}, "local:named": {"key": b"\x01" * 96}, } ) encrypter = ExplicitEncrypter(mock_key_vault, opts) self.addCleanup(encrypter.close) valid_args = [ ("local", None, ["first", "second"]), ("local:named", None, ["local:named"]), ("aws", {"region": "region", "key": "cmk"}, ["third", "forth"]), ("aws:named", {"region": "region", "key": "cmk"}, ["aws:named"]), # Unicode region and key ("aws", {"region": "region-unicode", "key": "cmk-unicode"}, []), # Endpoint ( "aws", { "region": "region", "key": "cmk", "endpoint": "kms.us-east-1.amazonaws.com:443", }, [], ), ] for kms_provider, master_key, key_alt_names in valid_args: key_id = encrypter.create_data_key( kms_provider, master_key=master_key, key_alt_names=key_alt_names ) self.assertIsInstance(key_id, Binary) self.assertEqual(key_id.subtype, 4) data_key = bson.decode(mock_key_vault.data_key, OPTS) # CDRIVER-3277 The order of key_alt_names is not maintained. for name in key_alt_names: self.assertIn(name, data_key["keyAltNames"]) # Assert that the custom endpoint is passed to libmongocrypt. master_key = {"region": "region", "key": "key", "endpoint": "example.com"} key_material = base64.b64decode( "xPTAjBRG5JiPm+d3fj6XLi2q5DMXUS/f1f+SMAlhhwkhDRL0kr8r9GDLIGTAGlvC+HVjSIgdL+RKwZCvpXSyxTICWSXTUYsWYPyu3IoHbuBZdmw2faM3WhcRIgbMReU5" ) if not PY3: key_material = Binary(key_material) encrypter.create_data_key( "aws", master_key=master_key, key_material=key_material ) self.assertEqual("example.com:443", mock_key_vault.kms_endpoint) def test_data_key_creation_bad_key_material(self): mock_key_vault = KeyVaultCallback(kms_reply=http_data("kms-encrypt-reply.txt")) encrypter = ExplicitEncrypter(mock_key_vault, self.mongo_crypt_opts()) self.addCleanup(encrypter.close) key_material = Binary(b"0" * 97) with self.assertRaisesRegex( MongoCryptError, "keyMaterial should have length 96, but has length 97" ): encrypter.create_data_key("local", key_material=key_material) def test_rewrap_many_data_key(self): key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json" key_path2 = "keys/12345678123498761234123456789012-local-document.json" encrypter = ExplicitEncrypter( MockCallback(key_docs=[bson_data(key_path), bson_data(key_path2)]), self.mongo_crypt_opts(), ) self.addCleanup(encrypter.close) result = encrypter.rewrap_many_data_key({}) raw_doc = RawBSONDocument(result) assert len(raw_doc["v"]) == 2 def test_range_query_int32(self): key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json" key_id = json_data(key_path)["_id"] encrypter = ExplicitEncrypter( MockCallback( key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt") ), self.mongo_crypt_opts(), ) self.addCleanup(encrypter.close) range_opts = bson_data("fle2-find-range-explicit-v2/int32/rangeopts.json") value = bson_data("fle2-find-range-explicit-v2/int32/value-to-encrypt.json") expected = json_data("fle2-find-range-explicit-v2/int32/encrypted-payload.json") encrypted = encrypter.encrypt( value, "range", key_id=key_id, query_type="range", contention_factor=4, range_opts=range_opts, is_expression=True, ) encrypted_val = bson.decode(encrypted, OPTS) self.assertEqual(encrypted_val, adjust_range_counter(encrypted_val, expected)) def test_rangePreview_query_int32(self): # Expect error attempting to use 'rangePreview' with self.assertRaisesRegex( MongoCryptError, "Algorithm 'rangePreview' is deprecated, please use 'range'", ): key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json" key_id = json_data(key_path)["_id"] encrypter = ExplicitEncrypter( MockCallback( key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt") ), self.mongo_crypt_opts(), ) self.addCleanup(encrypter.close) range_opts = bson_data( "fle2-find-rangePreview-explicit/int32/rangeopts.json" ) value = bson_data( "fle2-find-rangePreview-explicit/int32/value-to-encrypt.json" ) encrypter.encrypt( value, "rangePreview", key_id=key_id, query_type="rangePreview", contention_factor=4, range_opts=range_opts, is_expression=True, ) def read(filename, **kwargs): with open(os.path.join(DATA_DIR, filename), **kwargs) as fp: return fp.read() OPTS = CodecOptions(uuid_representation=UuidRepresentation.UNSPECIFIED) JSON_OPTS = JSONOptions( document_class=dict, uuid_representation=UuidRepresentation.UNSPECIFIED ) def json_data(filename): return json_util.loads(read(filename), json_options=JSON_OPTS) def bson_data(filename): return bson.encode(json_data(filename), codec_options=OPTS) def http_data(filename): data = read(filename, mode="rb") return data.replace(b"\n", b"\r\n") if __name__ == "__main__": unittest.main() libmongocrypt-1.11.0/bindings/python/update-sbom.sh000077500000000000000000000007021465326363200223700ustar00rootroot00000000000000#!/bin/bash set -eux LIBMONGOCRYPT_VERSION=$(cat ./libmongocrypt-version.txt) if [ $(command -v podman) ]; then DOCKER=podman else DOCKER=docker fi echo "pkg:github/mongodb/libmongocrypt@$LIBMONGOCRYPT_VERSION" > purls.txt $DOCKER run --platform="linux/amd64" -it --rm -v $(pwd):$(pwd) artifactory.corp.mongodb.com/release-tools-container-registry-public-local/silkbomb:1.0 update --purls=$(pwd)/purls.txt -o $(pwd)/sbom.json rm purls.txt libmongocrypt-1.11.0/cmake/000077500000000000000000000000001465326363200155545ustar00rootroot00000000000000libmongocrypt-1.11.0/cmake/FetchMongoC.cmake000066400000000000000000000030211465326363200207060ustar00rootroot00000000000000include (FetchContent) # Set the tag that we will fetch. # When updating the version of libbson, also update the version in etc/purls.txt set (MONGOC_FETCH_TAG_FOR_LIBBSON "1.27.1" CACHE STRING "The Git tag of mongo-c-driver that will be fetched to obtain libbson") # Add an option to disable patching if a patch command is unavailable. option (LIBBSON_PATCH_ENABLED "Whether to apply patches to the libbson library" ON) set (patch_disabled OFF) if (NOT LIBBSON_PATCH_ENABLED) set (patch_disabled ON) endif () include (Patch) make_patch_command (patch_command STRIP_COMPONENTS 1 DIRECTORY "" DISABLED "${patch_disabled}" PATCHES ${PROJECT_SOURCE_DIR}/etc/libbson-remove-GCC-diagnostic-pragma.patch ) # Fetch the source archive for the requested tag from GitHub FetchContent_Declare ( embedded_mcd URL "https://github.com/mongodb/mongo-c-driver/archive/refs/tags/${MONGOC_FETCH_TAG_FOR_LIBBSON}.tar.gz" PATCH_COMMAND ${patch_command} --verbose ) # Populate it: FetchContent_GetProperties (embedded_mcd) if (NOT embedded_mcd_POPULATED) message (STATUS "Downloading mongo-c-driver ${MONGOC_FETCH_TAG_FOR_LIBBSON} for libbson") FetchContent_Populate (embedded_mcd) endif () # Store the directory path to the external mongoc project: get_filename_component (MONGOCRYPT_MONGOC_DIR "${embedded_mcd_SOURCE_DIR}" ABSOLUTE) # The project wants a VERSION_CURRENT file. We know that based on the tag. file (WRITE "${embedded_mcd_SOURCE_DIR}/VERSION_CURRENT" "${MONGOC_FETCH_TAG_FOR_LIBBSON}") libmongocrypt-1.11.0/cmake/ImportBSON.cmake000066400000000000000000000301731465326363200205160ustar00rootroot00000000000000#[[ This file defines, exports, and installs two INTERFACE targets: '_mongocrypt::libbson_for_static' and '_mongocrypt::libbson_for_shared', that are used to link libbson correctly for the build configuration of libmongocrypt. At find_package() time, we can resolve these interface targets to link to the appropriate libbson based on the build configurations of libmongocrypt. mongo::mongocrypt must link to _mongocrypt::libbson_for_shared, and mongo::mongocrypt_static must link to _mongocrypt::libbson_for_static. At configure+build time, these target will create BUILD_INTERFACE-only usage requirements appropriate for libmongocrypt to build against a libbson. Once these targets are installed, they retain no usage requirements defined here. Instead, the installed version of these targets will be manipulated in mongocrypt-config.cmake based on user settings and build configuration options of the installed libmongocrypt in order to ensure that users have satisfied the linking requirements of libmongocrypt. Refer to mongocrypt-config.cmake for more information This file calls add_subdirectory(EXCLUDE_FROM_ALL) on a mongo-c-driver project directory. This will expose libbson targets that we can link and use for the libmongocrypt build. The boolean option USE_SHARED_LIBBSON controls the behavior of libbson_for_shared: If USE_SHARED_LIBBSON=FALSE: - libbson_for_shared will transitively link the static libbson from the MONGOCRYPT_MONGOC_DIR. - The result is that mongo::mongocrypt (which is a SHARED library) will have the translation units of libbson directly embedded into the resulting binary. - The symbols from libbson that are merged into mongo::mongocrypt will be suppressed using linker scripts such that consumers of mongo::mongocrypt will not see the libbson symbols that were statically linked into the shared library. This allows consumers to link against a completely independent libbson without interfering with the libbson symbols that were merged into mongo::mongocrypt - The installed libbson_for_shared will have no usage requirements. If USE_SHARED_LIBBSON=TRUE: - libbson_for_shared will transitively use the shared libbson library from the MONGOCRYPT_MONGOC_DIR. - mongo::mongocrypt will be built with a dynamic link requirement on a libbson dynamic library, which must be resolved at runtime by consumers. The translation units from the MONGOCRYPT_MONGOC_DIR *will not* be included in the mongo::mongocrypt library. - The installed libbson_for_shared will dynamically link to a libbson on the user's system by using a find_library() call. In both of the above cases, libbson_for_static will require that the final consumer provide their own definitions of the libbson symbols, regardless of the value of USE_SHARED_LIBBSON. ]] include (CheckCSourceCompiles) include (CMakePushCheckState) cmake_push_check_state () # Even though we aren't going to use the system's libbson, try to detect whether it has # extra-alignment enabled. We want to match that setting as our default, for convenience # purposes only. find_path (SYSTEM_BSON_INCLUDE_DIR bson/bson.h PATH_SUFFIXES libbson-1.0) if (SYSTEM_BSON_INCLUDE_DIR AND NOT DEFINED ENABLE_EXTRA_ALIGNMENT) set (CMAKE_REQUIRED_INCLUDES "${SYSTEM_BSON_INCLUDE_DIR}") set (_extra_alignment_default OFF) check_c_source_compiles ([[ #include int main() { } ]] HAVE_SYSTEM_LIBBSON) if (HAVE_SYSTEM_LIBBSON) # We have a libbson, check for extra alignment check_c_source_compiles ([[ #include #ifndef BSON_EXTRA_ALIGN #error "Not extra-aligned" #endif int main() {} ]] SYSTEM_LIBBSON_IS_EXTRA_ALIGNED) if (SYSTEM_LIBBSON_IS_EXTRA_ALIGNED) # Extra aligned! We'll use extra alignment by default. set (_extra_alignment_default ON) endif () endif () endif () cmake_pop_check_state () set (init OFF) if (DEFINED ENABLED_SHARED_BSON) message (STATUS "ENABLE_SHARED_BSON is now named USE_SHARED_LIBBSON") set (init "${ENABLE_SHARED_BSON}") endif () option (USE_SHARED_LIBBSON "Dynamically link libbson for the libmongocrypt dynamic library (default is static)" ${init}) if (NOT DEFINED MONGOCRYPT_MONGOC_DIR) # The user did not provide a MONGOCRYPT_MONGOC_DIR, so we'll get one include (FetchContent OPTIONAL) if (NOT COMMAND FetchContent_Declare) # We need FetchContent in order to download the project. message (FATAL_ERROR "No MONGOCRYPT_MONGOC_DIR setting was defined, and the FetchContent.cmake " "module is not available. Upgrade your CMake version, or provide a " "MONGOCRYPT_MONGOC_DIR path to a mongo-c-driver directory (This is required " "for libmongocrypt to find a libbson to use and link against).") endif () include (FetchMongoC) # The FetchMongoC module defines a MONGOCRYPT_MONGOC_DIR for us to use endif () function (_import_bson) if (MONGOCRYPT_MONGOC_DIR STREQUAL "USE-SYSTEM" AND USE_SHARED_LIBBSON AND NOT ENABLE_ONLINE_TESTS) message (STATUS "NOTE: Using system-wide libbson library. This is intended only for package maintainers.") find_library (_MONGOCRYPT_SYSTEM_LIBBSON_SHARED "${CMAKE_SHARED_LIBRARY_PREFIX}bson-1.0${CMAKE_SHARED_LIBRARY_SUFFIX}") find_library (_MONGOCRYPT_SYSTEM_LIBBSON_STATIC "${CMAKE_STATIC_LIBRARY_PREFIX}bson-static-1.0${CMAKE_STATIC_LIBRARY_SUFFIX}") find_path (_MONGOCRYPT_SYSTEM_LIBBSON_INCLUDE_DIR bson/bson.h PATH_SUFFIXES libbson-1.0) add_library (bson_shared SHARED IMPORTED) add_library (bson_static STATIC IMPORTED) set_target_properties (bson_shared bson_static PROPERTIES IMPORTED_CONFIGURATIONS "Release" INTERFACE_INCLUDE_DIRECTORIES "${_MONGOCRYPT_SYSTEM_LIBBSON_INCLUDE_DIR}" ) set_property (TARGET bson_shared PROPERTY IMPORTED_LOCATION "${_MONGOCRYPT_SYSTEM_LIBBSON_SHARED}") set_property (TARGET bson_static PROPERTY IMPORTED_LOCATION "${_MONGOCRYPT_SYSTEM_LIBBSON_STATIC}") set_property ( CACHE _MONGOCRYPT_SYSTEM_LIBBSON_SHARED _MONGOCRYPT_SYSTEM_LIBBSON_INCLUDE_DIR PROPERTY ADVANCED TRUE ) else () message (STATUS "Using [${MONGOCRYPT_MONGOC_DIR}] as a sub-project for libbson") # Disable AWS_AUTH, to prevent it from building the kms-message symbols, which we build ourselves set (ENABLE_MONGODB_AWS_AUTH OFF CACHE BOOL "Disable kms-message content in mongoc for libmongocrypt" FORCE) # Disable install() for the libbson static library. We'll do it ourselves set (ENABLE_STATIC BUILD_ONLY) # Disable zlib, which isn't necessary for libmongocrypt and isn't necessarily available. set (ENABLE_ZLIB OFF CACHE BOOL "Toggle zlib for the mongoc subproject (not required by libmongocrypt)") # Disable libzstd, which isn't necessary for libmongocrypt and isn't necessarily available. set (ENABLE_ZSTD OFF CACHE BOOL "Toggle libzstd for the mongoc subproject (not required by libmongocrypt)") # Disable snappy, which isn't necessary for libmongocrypt and isn't necessarily available. set (ENABLE_SNAPPY OFF CACHE BOOL "Toggle snappy for the mongoc subproject (not required by libmongocrypt)") # Disable deprecated automatic init and cleanup. (May be overridden by the user) set (ENABLE_AUTOMATIC_INIT_AND_CLEANUP OFF CACHE BOOL "Enable automatic init and cleanup (GCC only)") # Disable over-alignment of bson types. (May be overridden by the user) set (ENABLE_EXTRA_ALIGNMENT ${_extra_alignment_default} CACHE BOOL "Toggle extra alignment of bson_t") # We don't want the subproject to find libmongocrypt set (ENABLE_CLIENT_SIDE_ENCRYPTION OFF CACHE BOOL "Disable client-side encryption for the libmongoc subproject") # Clear `BUILD_VERSION` so C driver does not use a `BUILD_VERSION` meant for libmongocrypt. # Both libmongocrypt and C driver support setting a `BUILD_VERSION` to override the version. if (DEFINED CACHE{BUILD_VERSION}) set (saved_cached_build_version "${BUILD_VERSION}") unset (BUILD_VERSION CACHE) # Undefine cache variable. endif () if (DEFINED BUILD_VERSION) set (saved_build_version "${BUILD_VERSION}") unset (BUILD_VERSION) # Undefine normal variable. endif () # Disable building tests in C driver: set (ENABLE_TESTS OFF) set (BUILD_TESTING OFF) # Disable counters in C driver. Counters are not supported on all platforms. set (ENABLE_SHM_COUNTERS OFF) # Add the subdirectory as a project. EXCLUDE_FROM_ALL to inhibit building and installing of components unless requested # SYSTEM (on applicable CMake versions) to prevent warnings (particularly from -Wconversion/-Wsign-conversion) from the C driver code if (CMAKE_VERSION VERSION_GREATER 3.25) add_subdirectory ("${MONGOCRYPT_MONGOC_DIR}" _mongo-c-driver EXCLUDE_FROM_ALL SYSTEM) else () add_subdirectory ("${MONGOCRYPT_MONGOC_DIR}" _mongo-c-driver EXCLUDE_FROM_ALL) endif () if (DEFINED saved_cached_build_version) set (BUILD_VERSION "${saved_cached_build_version}" CACHE STRING "Library version") endif () if (DEFINED saved_build_version) set (BUILD_VERSION "${saved_build_version}") endif () if (TARGET mongoc_static) # Workaround: Embedded mongoc_static does not set its INCLUDE_DIRECTORIES for user targets target_include_directories (mongoc_static PUBLIC "$" "$" ) endif () endif () endfunction () # Do the import in a function to isolate variable scope _import_bson () # Define interface targets to be used to control the libbson used at both build and import time. # Refer to mongocrypt-config.cmake to see how these targets are used by consumers add_library (_mongocrypt-libbson_for_static INTERFACE) add_library (_mongocrypt-libbson_for_shared INTERFACE) add_library (_mongocrypt::libbson_for_static ALIAS _mongocrypt-libbson_for_static) add_library (_mongocrypt::libbson_for_shared ALIAS _mongocrypt-libbson_for_shared) install ( TARGETS _mongocrypt-libbson_for_static _mongocrypt-libbson_for_shared EXPORT mongocrypt_targets ) # Link to the requested libbson, only exporting that usage for the local build tree. # The mongocrypt-config file will later add the appropriate link library for downstream # users during find_package() if (USE_SHARED_LIBBSON) target_link_libraries (_mongocrypt-libbson_for_shared INTERFACE $) else () target_link_libraries (_mongocrypt-libbson_for_shared INTERFACE $) endif () # libbson_for_static always links to the static libbson: target_link_libraries (_mongocrypt-libbson_for_static INTERFACE $) if (TARGET mongoc_static) # And an alias to the mongoc target for use in some test cases add_library (_mongocrypt::mongoc ALIAS mongoc_static) endif () # Put the libbson dynamic library into the current binary directory (plus possible config suffix). # This ensures that libbson DLL will resolve on Windows when it searches during tests set_property (TARGET bson_shared PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") if (ENABLE_STATIC) # We are going to build a static libmongocrypt. # We want the static libbson target from the embedded mongoc. Enable the static library as # part of "all", and install the archive alongside the rest of our static libraries. # (Useful for some users for convenience of static-linking libmongocrypt: CDRIVER-3187) set_target_properties (bson_static PROPERTIES EXCLUDE_FROM_ALL FALSE OUTPUT_NAME bson-static-for-libmongocrypt ) install ( FILES $ DESTINATION "${CMAKE_INSTALL_LIBDIR}" RENAME ${CMAKE_STATIC_LIBRARY_PREFIX}bson-static-for-libmongocrypt${CMAKE_STATIC_LIBRARY_SUFFIX} ) endif () libmongocrypt-1.11.0/cmake/ImportDFP.cmake000066400000000000000000000064771465326363200204000ustar00rootroot00000000000000#[[ This file handles importing the DFP (decimal floating point) library for decimal128 support. It is patterned after ImportBSON in this same directory. Initially, the only supported DFP implementation is Intel DFP. However, this module will allow for the future addition of support for libdfp. This file defines, exports, and installs one INTERFACE target: mongocrypt::intel_dfp. The target(s) from this file are used to link the DFP library correctly for the build configuration of libmongocrypt. At find_package() time, we can resolve these interface targets to link to the DFP library based on the build configurations of libmongocrypt. In the initial implementation both mongo::mongocrypt and mongo::mongocrypt_static must link to mongocrypt::intel_dfp (this is because if we link to the Intel DFP which is vendored with libmongocrypt then we will link the object files directly and if we use the system Intel DFP then we will be linking with .a static library archives). The default behavior is to use the Intel DFP which is vendored in this repository. By setting MONGOCRYPT_DFP_DIR=USE-SYSTEM the build will assume that an appropriate Intel DFP implementation can be found in a location where it has been installed system-wide (most likely under /usr or /usr/local). ]] if (DEFINED MONGOCRYPT_DFP_DIR AND NOT MONGOCRYPT_DFP_DIR STREQUAL "USE-SYSTEM") message (FATAL_ERROR "The only valid value for MONGOCRYPT_DFP_DIR is USE-SYSTEM") endif () function (_import_dfp) find_library (_MONGOCRYPT_SYSTEM_INTEL_DFP_STATIC "${CMAKE_STATIC_LIBRARY_PREFIX}bidgcc000${CMAKE_STATIC_LIBRARY_SUFFIX}") find_path (_MONGOCRYPT_SYSTEM_INTEL_DFP_INCLUDE_DIR bid_conf.h) add_library (intel_dfp STATIC IMPORTED) set_target_properties (intel_dfp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${_MONGOCRYPT_SYSTEM_INTEL_DFP_INCLUDE_DIR}" ) set_property (TARGET intel_dfp PROPERTY IMPORTED_LOCATION "${_MONGOCRYPT_SYSTEM_INTEL_DFP_STATIC}") set_property ( CACHE _MONGOCRYPT_SYSTEM_INTEL_DFP_INCLUDE_DIR PROPERTY ADVANCED TRUE ) endfunction () if (NOT DEFINED MONGOCRYPT_DFP_DIR) # The user did not provide a MONGOCRYPT_DFP_DIR, so we'll set one up include (IntelDFP) elseif (MONGOCRYPT_DFP_DIR STREQUAL "USE-SYSTEM") message (STATUS "NOTE: Using system-wide Intel DFP library. This is intended only for package maintainers.") set (USE_SYSTEM_INTEL_DFP "ON") # Do the import in a function to isolate variable scope _import_dfp () # Define interface targets to be used to control the DFP used at both build and import time. # Refer to mongocrypt-config.cmake to see how these targets are used by consumers add_library (_mongocrypt-intel_dfp INTERFACE) add_library (mongocrypt::intel_dfp ALIAS _mongocrypt-intel_dfp) install ( TARGETS _mongocrypt-intel_dfp EXPORT mongocrypt_targets ) # Link to Intel DFP, only exporting that usage for the local build tree. # The mongocrypt-config file will later add the appropriate link library for downstream # users during find_package() target_link_libraries (_mongocrypt-intel_dfp INTERFACE $) # Notify in-tree consumers that IntelDFP is available: target_compile_definitions (_mongocrypt-intel_dfp INTERFACE $) endif () libmongocrypt-1.11.0/cmake/IntelDFP.cmake000066400000000000000000000175111465326363200201700ustar00rootroot00000000000000 include (FetchContent) # When updating the version of IntelDFP, also update the version in etc/purls.txt set (_default_url "${PROJECT_SOURCE_DIR}/third-party/IntelRDFPMathLib20U2.tar.xz") set (INTEL_DFP_LIBRARY_URL "${_default_url}" CACHE STRING "The URL of an Intel DFP library to use") set (INTEL_DFP_LIBRARY_URL_HASH "SHA256=ac157e69c05556f3fa468ab34caeb1114a3b88ae18241bd41cc57b85a02dd314" CACHE STRING "The hash of the archive that lives at INTEL_DFP_LIBRARY_URL (Spelled: =)") option (INTEL_DFP_LIBRARY_PATCH_ENABLED "Whether to apply patches to the Intel DFP library" ON) set (_hash_arg) if (NOT INTEL_DFP_LIBRARY_URL_SHA256 STREQUAL "no-verify") set (_hash_arg URL_HASH "${INTEL_DFP_LIBRARY_URL_HASH}") endif () set (patch_disabled OFF) if (NOT INTEL_DFP_LIBRARY_PATCH_ENABLED) set (patch_disabled ON) endif () include (Patch) make_patch_command (patch_command STRIP_COMPONENTS 4 DIRECTORY "" DISABLED "${patch_disabled}" PATCHES "${PROJECT_SOURCE_DIR}/etc/mongo-inteldfp-s390x.patch" "${PROJECT_SOURCE_DIR}/etc/mongo-inteldfp-MONGOCRYPT-571.patch" "${PROJECT_SOURCE_DIR}/etc/mongo-inteldfp-libmongocrypt-pr-625.patch" "${PROJECT_SOURCE_DIR}/etc/mongo-inteldfp-alpine-arm-fix.patch" ) # NOTE: The applying of the patch expects the correct input directly from the # expanded archive. If the patch needs to be reapplied, you may see errors # about trying to update the intel_dfp component. If you are seeing such # errors, delete the `_deps/` subdirectory in the build tree and # re-run CMake the project. FetchContent_Declare ( intel_dfp URL "${_default_url}" ${_hash_arg} PATCH_COMMAND ${patch_command} --verbose ) FetchContent_GetProperties (intel_dfp) if (NOT intel_dfp_POPULATED) message (STATUS "Obtaining Intel Decimal FP library: ${INTEL_DFP_LIBRARY_URL}") FetchContent_Populate (intel_dfp) endif () # This list of sources was generated by copying the MongoDB server and removing any unnecessary. # Carefully add sources if more functionality is needed. Bundled sources are checked by static analysis, and may result in a larger binary. # The "" prefix is replaced below. # Refer: https://github.com/mongodb/mongo/blob/e9be40f47a77af1931773ad671d4927c0fe6969a/src/third_party/IntelRDFPMathLib20U1/SConscript set (_dfp_sources "/float128/dpml_exception.c" "/float128/dpml_ux_bid.c" "/float128/dpml_ux_log.c" "/float128/dpml_ux_ops.c" "/float128/dpml_ux_ops_64.c" "/src/bid128.c" "/src/bid128_2_str_tables.c" "/src/bid128_add.c" "/src/bid128_compare.c" "/src/bid128_div.c" "/src/bid128_fma.c" "/src/bid128_fmod.c" "/src/bid128_log10.c" "/src/bid128_log2.c" "/src/bid128_modf.c" "/src/bid128_mul.c" "/src/bid128_noncomp.c" "/src/bid128_round_integral.c" "/src/bid128_scalb.c" "/src/bid128_scalbl.c" "/src/bid128_string.c" "/src/bid128_to_int64.c" "/src/bid64_to_bid128.c" "/src/bid_binarydecimal.c" "/src/bid_convert_data.c" "/src/bid_decimal_data.c" "/src/bid_flag_operations.c" "/src/bid_round.c" ) # Put in the actual library path: string (REPLACE "" "${intel_dfp_SOURCE_DIR}/LIBRARY" _dfp_sources "${_dfp_sources}") #[[ Intel DFP gives us a very blunt yet powerful hammer to avoid symbol collision, since other library may also want a conflicting DFP version: Just rename everything! All function names are #defined with a `bid` or `binary` prefix, and are aliased to their "actual" names with a `__bid` or `__binary` prefix, respectively. So we can ship our own decimal library without worry, we'll rename those hidden symbols. ]] file (READ "${intel_dfp_SOURCE_DIR}/LIBRARY/src/bid_conf.h" dfp_conf_content) string (REGEX REPLACE #[[ Match every "#define X Y" where X begins with `"bid" or "binary", and Y begins with "__bid" or "__binary". X and Y must be separated by one or more spaces. ]] "#define ((bid|binary)[^ ]+ +)__(bid|binary)([^ +])" # Replace Y with "__mongocrypt_bid" or "__mongocrypt_binary" as the new prefix. "#define \\1 __mongocrypt_\\3\\4" new_content "${dfp_conf_content}" ) if (NOT new_content STREQUAL dfp_conf_content) # Only rewrite the file if we changed anything, otherwise we update build # input timestamps and will trigger a rebuild of DFP. file (WRITE "${intel_dfp_SOURCE_DIR}/LIBRARY/src/bid_conf.h" "${new_content}") endif () # Define the object library add_library (intel_dfp_obj OBJECT ${_dfp_sources}) # Build with -fPIC, since these objects may go into a static OR dynamic library. set_property (TARGET intel_dfp_obj PROPERTY POSITION_INDEPENDENT_CODE TRUE) # DFP needs information about the build target platform. Compute that: set (proc_lower $) set (ia32_list i386 i486 i586 i686 pentium3 pentium4 athlon geode emscripted x86 arm) set (efi2_list aarch64 arm64 x86_64 ppc64le riscv64) set (is_linux $) set (is_windows $) set (is_unix $) # These compiler definitions may seem a bit strange, but the whole DFP library's # config process is strange. These options match those used in MongoDB server. target_compile_definitions (intel_dfp_obj PUBLIC DECIMAL_CALL_BY_REFERENCE=0 DECIMAL_GLOBAL_ROUNDING=0 DECIMAL_GLOBAL_EXCEPTION_FLAGS=0 UNCHANGED_BINARY_STATUS_FLAGS=0 USE_COMPILER_F128_TYPE=0 USE_COMPILER_F80_TYPE=0 USE_NATIVE_QUAD_TYPE=0 $<${is_unix}:LINUX=1> $<$:mach=1> $<$:freebsd=1> $<$:linux=1> $<${is_windows}: WINDOWS=1 WNT=1 winnt=1 > $<$: IA32=1 ia32=1 > $<$: EFI2=1 efi2=1 > $<$: s390x=1 BID_BIG_ENDIAN=1 > ) # Suppress warnings in the Intel library, as it generates a lot that aren't of interest target_compile_options (intel_dfp_obj PRIVATE -w) target_include_directories(intel_dfp_obj PUBLIC ${intel_dfp_SOURCE_DIR}/LIBRARY/src) # Define an interface library that attaches the built TUs to the consumer add_library (_mongocrypt_intel_dfp INTERFACE) add_library (mongocrypt::intel_dfp ALIAS _mongocrypt_intel_dfp) # Notify in-tree consumers that IntelDFP is available: target_compile_definitions (_mongocrypt_intel_dfp INTERFACE $) target_sources (_mongocrypt_intel_dfp #[[ For targets *within this build* that link with mongocrypt::intel_dfp, inject the generated TUs (object files) from the intel_dfp_obj library. This will be stripped out of the interface library when it is installed, since we don't want to ship the DFP object separately. Instead, users will link to libmongocrypt, which will contain the necessary TUs for the library (because they link to this interface library). ]] INTERFACE $> ) target_link_libraries (_mongocrypt_intel_dfp INTERFACE $ # We do want to propagate an interface requirement: Some platforms need a # separate link library to support special math functions. $<$:m> ) # Give the installed target a name to indicate its hidden-ness set_property (TARGET _mongocrypt_intel_dfp PROPERTY EXPORT_NAME private::intel_dfp_interface) install (TARGETS _mongocrypt_intel_dfp EXPORT mongocrypt_targets) libmongocrypt-1.11.0/cmake/LTO.cmake000066400000000000000000000034651465326363200172240ustar00rootroot00000000000000 set (MONGO_LTO "OFF" CACHE STRING "Enable cross-translation unit optimizations (A.K.A. IPO/LTO/LTCG) [OFF/DEFAULT/FAT/THIN]" ) set_property (CACHE MONGO_LTO PROPERTY STRINGS OFF DEFAULT FAT THIN) if (MONGO_LTO STREQUAL "OFF") # Nothing to do return () endif () # CMake will know if LTO is supported at any basic level include (CheckIPOSupported) check_ipo_supported (RESULT supported OUTPUT out) if (NOT supported) message (SEND_ERROR "LTO is not supported by the compiler (requested by MONGO_LTO=${MONGO_LTO}):\n${out}") return () endif () # Set the appropriate compile/link flags for LTO: set (_c_flags) set (_link_flags) if (MONGO_LTO STREQUAL "DEFAULT") # Just use CMake's default INTERPROCEDURAL_OPTIMIZATION message (STATUS "Enabling INTERPROCEDURAL_OPTIMIZATION") set_property (DIRECTORY PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) elseif (MONGO_LTO STREQUAL "THIN") set (_c_flags -flto=thin) set (_link_flags -flto=thin) elseif (MONGO_LTO STREQUAL "FAT") set (_c_flags -flto -ffat-lto-objects) set (_link_flags -flto=auto) else () message (SEND_ERROR "Unknown MONGO_LTO setting '${MONGO_LTO}'") return () endif () # We need try_compile(), because we need more than one source file to accurately # check for LTO support try_compile ( MONGO_HAVE_LTO_${MONGO_LTO} "${CMAKE_CURRENT_BINARY_DIR}/_mongo-lto-check/${MONGO_LTO}" SOURCES "${CMAKE_CURRENT_LIST_DIR}/ltocheck-lib.c" "${CMAKE_CURRENT_LIST_DIR}/ltocheck-main.c" COMPILE_DEFINITIONS ${_c_flags} LINK_LIBRARIES ${_link_flags} OUTPUT_VARIABLE out ) if (NOT MONGO_HAVE_LTO_${MONGO_LTO}) message (SEND_ERROR "MONGO_LTO=${MONGO_LTO} is not supported by the current compiler:\n${out}") return () endif () add_compile_options (${_c_flags}) link_libraries (${_link_flags}) libmongocrypt-1.11.0/cmake/MongoC-Warnings.cmake000066400000000000000000000061711465326363200215330ustar00rootroot00000000000000#[[ This file sets warning options for the directories in which it is include()'d These warnings are intended to be ported to each supported platform, and especially for high-value warnings that are very likely to catch latent bugs early in the process before the code is even run. ]] set (__is_gnu "$") set (__is_clang "$,$>") set (__is_gnu_like "$") set (__is_msvc "$") # "Old" GNU is GCC < 5, which is missing several warning options set (__is_old_gnu "$,5>>") set (__not_old_gnu "$") #[[ Define additional compile options, conditional on the compiler being used. Each option should be prefixed by `gnu:`, `clang:`, `msvc:`, or `gnu-like:`. Those options will be conditionally enabled for GCC, Clang, or MSVC. These options are attached to the source directory and its children. ]] function (mongoc_add_platform_compile_options) foreach (opt IN LISTS ARGV) if (NOT opt MATCHES "^(gnu-like|gnu|clang|msvc):(.*)") message (SEND_ERROR "Invalid option '${opt}' (Should be prefixed by 'msvc:', 'gnu:', 'clang:', or 'gnu-like:'") continue () endif () if (CMAKE_MATCH_1 STREQUAL "gnu-like") add_compile_options ("$<${__is_gnu_like}:${CMAKE_MATCH_2}>") elseif (CMAKE_MATCH_1 STREQUAL gnu) add_compile_options ("$<${__is_gnu}:${CMAKE_MATCH_2}>") elseif (CMAKE_MATCH_1 STREQUAL clang) add_compile_options ("$<${__is_clang}:${CMAKE_MATCH_2}>") elseif (CMAKE_MATCH_1 STREQUAL "msvc") add_compile_options ("$<${__is_msvc}:${CMAKE_MATCH_2}>") else () message (SEND_ERROR "Invalid option to mongoc_add_platform_compile_options(): '${opt}'") endif () endforeach () endfunction () if (CMAKE_VERSION VERSION_LESS 3.3) # On older CMake versions, we'll just always pass the warning options, even # if the generate warnings for the C++ check file set (is_c_lang "1") else () # $ is only valid in CMake 3.3+ set (is_c_lang "$") endif () # These below warnings should always be unconditional hard errors, as the code is # almost definitely broken mongoc_add_platform_compile_options ( # Implicit function or variable declarations gnu-like:$<${is_c_lang}:-Werror=implicit> msvc:/we4013 msvc:/we4431 # Missing return types/statements gnu-like:-Werror=return-type msvc:/we4716 # Incompatible pointer types gnu-like:$<$:-Werror=incompatible-pointer-types> msvc:/we4113 # Integral/pointer conversions gnu-like:$<$:-Werror=int-conversion> msvc:/we4047 # Discarding qualifiers gnu:$<$:-Werror=discarded-qualifiers> clang:$<${is_c_lang}:-Werror=ignored-qualifiers> msvc:/we4090 # Definite use of uninitialized value gnu-like:-Werror=uninitialized msvc:/we4700 # Aside: Disable CRT insecurity warnings msvc:/D_CRT_SECURE_NO_WARNINGS ) libmongocrypt-1.11.0/cmake/Patch.cmake000066400000000000000000000034541465326363200176230ustar00rootroot00000000000000find_program(GIT_EXECUTABLE git) find_program(PATCH_EXECUTABLE patch) #[[ Form a new Patch-applying command for the given inputs make_patch_command( [DISABLED ] [DIRECTORY ] [STRIP_COMPONENTS ] PATCHES [ ...] ) ]] function(make_patch_command out) cmake_parse_arguments(PARSE_ARGV 1 patch "" "DIRECTORY;STRIP_COMPONENTS;DISABLED" "PATCHES") if(patch_DISABLED) # Use a placeholder "no-op" patch command. set(cmd "${CMAKE_COMMAND}" "-E" "true") elseif(GIT_EXECUTABLE) # git ... set(cmd ${GIT_EXECUTABLE}) if(patch_DIRECTORY) # git --work-tree=... list(APPEND cmd --work-tree=${patch_DIRECTORY}) endif() # git ... apply ... list(APPEND cmd apply) # git ... apply -pN ... if(patch_STRIP_COMPONENTS) list(APPEND cmd -p${patch_STRIP_COMPONENTS}) endif() # Ignore whitespace errors to fix patch errors on Windows: The patch file may be converted to \r\n by git, but libbson fetched with \n. list(APPEND cmd "--ignore-whitespace") # git accepts patch filepaths as positional arguments list(APPEND cmd ${patch_PATCHES}) else() # patch ... set(cmd ${PATCH_EXECUTABLE}) if(patch_DIRECTORY) # patch --dir=... list(APPEND cmd --dir=${patch_DIRECTORY}) endif() # patch ... -pN ... if(patch_STRIP_COMPONENTS) list(APPEND cmd -p${patch_STRIP_COMPONENTS}) endif() # Prepend "--input=" to each patch filepath and add them to the argv list(TRANSFORM patch_PATCHES PREPEND "--input=") list(APPEND cmd ${patch_PATCHES}) endif() set("${out}" "${cmd}" PARENT_SCOPE) endfunction() libmongocrypt-1.11.0/cmake/Platform.cmake000066400000000000000000000027311465326363200203450ustar00rootroot00000000000000#[[ Defines a platform-support target _mongocrypt::platform. This target sets certain internal-only compile definitions, and defines usage requirements on certain platform features required by libmongocrypt (Threads, dlopen(), math) ]] add_library (lmc-platform INTERFACE) add_library (mongocrypt::platform ALIAS lmc-platform) install (TARGETS lmc-platform EXPORT mongocrypt_targets) set_property ( TARGET lmc-platform PROPERTY EXPORT_NAME mongocrypt::platform ) # Threads: find_package (Threads REQUIRED) # Special math: if (NOT APPLE) find_library (M_LIBRARY m) endif () # Special runtime: find_library (RT_LIBRARY rt) # Endian detection: if (DEFINED CMAKE_C_BYTE_ORDER) # Newer CMake knows this immediately: set (MONGOCRYPT_ENDIAN_DEF "MONGOCRYPT_${CMAKE_C_BYTE_ORDER}") else () include (TestBigEndian) test_big_endian (_is_big) set (MONGOCRYPT_ENDIAN_DEF "MONGOCRYPT_$_ENDIAN") endif () target_compile_definitions (lmc-platform INTERFACE "$" ) target_link_libraries (lmc-platform INTERFACE Threads::Threads # These are build-interface libs, but still required. These will be added # to the platform library in mongocrypt-config.cmake using the same # find_library() calls: $ $:${M_LIBRARY}>> $:${RT_LIBRARY}>> ) libmongocrypt-1.11.0/cmake/libmongocrypt-hidden-symbols.map000066400000000000000000000001431465326363200240600ustar00rootroot00000000000000mongocrypt { local: bson*; bcon*; jsonsl*; _*; kms*; };libmongocrypt-1.11.0/cmake/libmongocrypt-hidden-symbols.txt000066400000000000000000000000401465326363200241160ustar00rootroot00000000000000_bson* _bcon* _jsonsl* __* _kms*libmongocrypt-1.11.0/cmake/libmongocrypt-static.pc.in000066400000000000000000000004411465326363200226610ustar00rootroot00000000000000Name: ${PROJECT_NAME} Description: ${PROJECT_DESCRIPTION} Version: ${PROJECT_VERSION} Requires: ${PKG_CONFIG_STATIC_REQUIRES} prefix=${CMAKE_INSTALL_PREFIX} includedir=${PKG_CONFIG_INCLUDEDIR} libdir=${PKG_CONFIG_LIBDIR} Libs: ${PKG_CONFIG_STATIC_LIBS} Cflags: ${PKG_CONFIG_STATIC_CFLAGS} libmongocrypt-1.11.0/cmake/libmongocrypt.pc.in000066400000000000000000000004751465326363200214030ustar00rootroot00000000000000Name: ${PROJECT_NAME} Description: ${PROJECT_DESCRIPTION} Version: ${PROJECT_VERSION} Requires: ${PKG_CONFIG_REQUIRES} Requires.private: ${PKG_CONFIG_REQUIRES_PRIVATE} prefix=${CMAKE_INSTALL_PREFIX} includedir=${PKG_CONFIG_INCLUDEDIR} libdir=${PKG_CONFIG_LIBDIR} Libs: ${PKG_CONFIG_LIBS} Cflags: ${PKG_CONFIG_CFLAGS} libmongocrypt-1.11.0/cmake/ltocheck-lib.c000066400000000000000000000000661465326363200202620ustar00rootroot00000000000000 extern int answer (int a, int b) { return a + b; }libmongocrypt-1.11.0/cmake/ltocheck-main.c000066400000000000000000000001331465326363200204330ustar00rootroot00000000000000extern int answer (int, int); int main () { int a = answer (3, 4); return a != 7; } libmongocrypt-1.11.0/cmake/mongocrypt-config.cmake000066400000000000000000000050571465326363200222310ustar00rootroot00000000000000include(CMakeFindDependencyMacro) find_dependency(kms_message 0.0.1) include("${CMAKE_CURRENT_LIST_DIR}/mongocrypt_targets.cmake") if (DEFINED MONGOCRYPT_LIBBSON_STATIC_USE) # The user has named a library that should be linked as the static libbson library set_property ( TARGET mongo::_mongocrypt-libbson_for_static APPEND PROPERTY INTERFACE_LINK_LIBRARIES "$" ) endif () # BOOL: Whether the libmongocrypt dynamic library in this package needs to link to an external libbson. # In the default configuration, the shared lib will include the TUs for a pinned version of libbson # and will use linker scripts to "hide" these symbols from the outside world. # # If the libmongocrypt package was built to link against a shared libbson library, then the # libmongocrypt dynamic library will contain pending references to libbson symbols that will # need to be resolved before the library can be used. # # (Note: static libmongocrypt *always* needs to link against an external libbson, as it does not # embed the libbson symbols.) set (_using_shared_libbson "@USE_SHARED_LIBBSON@") if (_using_shared_libbson AND DEFINED MONGOCRYPT_LIBBSON_SHARED_USE) # The user has named a library that should be linked as the shared libbson library set_property ( TARGET mongo::_mongocrypt-libbson_for_shared APPEND PROPERTY INTERFACE_LINK_LIBRARIES "$" ) endif () set (_using_system_intel_dfp "@USE_SYSTEM_INTEL_DFP@") if (_using_system_intel_dfp) find_library (_MONGOCRYPT_SYSTEM_INTEL_DFP_STATIC "${CMAKE_STATIC_LIBRARY_PREFIX}bidgcc000${CMAKE_STATIC_LIBRARY_SUFFIX}") set_property ( TARGET mongo::_mongocrypt-intel_dfp PROPERTY IMPORTED_LOCATION "${_MONGOCRYPT_SYSTEM_INTEL_DFP_STATIC}" ) endif () find_dependency(Threads) # Link for dlopen(): set_property (TARGET mongo::mongocrypt::platform APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS}) # Link for special math functions: if (NOT APPLE) find_library (_MONGOCRYPT_M_LIBRARY m) mark_as_advanced (_MONGOCRYPT_M_LIBRARY) if (_MONGOCRYPT_M_LIBRARY) set_property (TARGET mongo::mongocrypt::platform APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${_MONGOCRYPT_M_LIBRARY}") endif () endif () # Special runtime: find_library (_MONGOCRYPT_RT_LIBRARY rt) mark_as_advanced (_MONGOCRYPT_RT_LIBRARY) if (_MONGOCRYPT_RT_LIBRARY) set_property (TARGET mongo::mongocrypt::platform APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${_MONGOCRYPT_RT_LIBRARY}") endif () libmongocrypt-1.11.0/doc/000077500000000000000000000000001465326363200152415ustar00rootroot00000000000000libmongocrypt-1.11.0/doc/Doxygen000066400000000000000000003217451465326363200166150ustar00rootroot00000000000000# Doxyfile 1.8.13 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "libmongocrypt" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = ./doc # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. # Minimum value: 0, maximum value: 99, default value: 0. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 0 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete # parameter documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. # The default value is: NO. WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, # *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.idl \ *.ddl \ *.odl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.cs \ *.d \ *.php \ *.php4 \ *.php5 \ *.phtml \ *.inc \ *.m \ *.markdown \ *.md \ *.mm \ *.dox \ *.py \ *.pyw \ *.f90 \ *.f95 \ *.f03 \ *.f08 \ *.f \ *.for \ *.tcl \ *.vhd \ *.vhdl \ *.ucf \ *.qsf # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = *-private.h \ *.c # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to YES can help to show when doxygen was last run and thus if the # documentation is up to date. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /