From 56cd08a8df976e53a00318b1eaa942edc5de2909 Mon Sep 17 00:00:00 2001 From: K1 Date: Thu, 5 Dec 2024 16:10:46 +0800 Subject: [PATCH] Support shangmi crypto module for iOS Add start-up self test, including SM2/SM3/SM4/random. Add mod application, set admin password, reset on-demand self test and support entropy validation. Add entropy source, real-time clock(RTC). --- .github/workflows/ci.yml | 224 --- .github/workflows/cross-compiles.yml | 152 -- .github/workflows/gm.yml | 26 + .github/workflows/main.yml | 21 - .github/workflows/notify.yml | 21 - .github/workflows/windows.yml | 137 -- Configure | 8 +- apps/apps.c | 783 +++++++++++ apps/apps.h | 15 + apps/build.info | 4 + apps/mod.c | 128 ++ apps/openssl.c | 48 +- apps/speed.c | 2 +- apps/version.c | 27 +- apps/x509.c | 18 +- crypto/ec/curve448/field.h | 2 +- crypto/init.c | 12 + crypto/rand/rand_lib.c | 27 + crypto/rand/rand_self_test.c | 1911 ++++++++++++++++++++++++++ crypto/rand/rand_unix.c | 69 +- crypto/scm.c | 793 +++++++++++ crypto/sm2/sm2_crypt.c | 4 + crypto/sm2/sm2_sign.c | 8 + include/internal/cryptlib.h | 4 + include/openssl/opensslv.h | 2 +- ssl/s3_cbc.c | 2 +- ssl/s3_enc.c | 5 +- ssl/ssl_local.h | 2 +- ssl/statem_ntls/statem_ntls_clnt.c | 2 +- ssl/statem_ntls/statem_ntls_srvr.c | 6 +- test/recipes/25-test_x509.t | 30 +- 31 files changed, 3910 insertions(+), 583 deletions(-) delete mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/cross-compiles.yml create mode 100644 .github/workflows/gm.yml delete mode 100644 .github/workflows/main.yml delete mode 100644 .github/workflows/notify.yml delete mode 100644 .github/workflows/windows.yml create mode 100644 apps/mod.c create mode 100644 crypto/rand/rand_self_test.c create mode 100644 crypto/scm.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index cbdb3a1d8..000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,224 +0,0 @@ -name: GitHub CI - -on: [pull_request, push] - -# for some reason, this does not work: -# variables: -# BUILDOPTS: "-j4" - -# not implemented for v1.1.1: HARNESS_JOBS: "${HARNESS_JOBS:-4}" - -# for some reason, this does not work: -# before_script: -# - make="make -s" - -jobs: - check_update: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: config - run: ./config --strict-warnings && perl configdata.pm --dump - - name: make build_generated - run: make -s build_generated - - name: make update - run: make -s update - - name: git diff - run: git diff --exit-code - - check_docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: config - run: ./config --strict-warnings && perl configdata.pm --dump - - name: make build_generated - run: make -s build_generated - - name: make doc-nits - run: make doc-nits - - basic_gcc: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: config - run: ./config --strict-warnings && perl configdata.pm --dump - - name: make - run: make -s -j4 - - name: make test - run: make test - - name: make clean - run: make clean - - name: check dirty - run: test $(git status --porcelain | wc -l) -eq "0" - - basic_clang: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: config - run: CC=clang ./config --strict-warnings && perl configdata.pm --dump - - name: make - run: make -s -j4 - - name: make test - run: make test - - name: make clean - run: make clean - - name: check dirty - run: test $(git status --porcelain | wc -l) -eq "0" - - minimal: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: config - run: ./config --strict-warnings no-shared no-dso no-pic no-async no-autoload-config no-blake2 no-bf no-camellia no-cast no-chacha no-cmac no-cms no-comp no-ct no-des no-dgram no-dh no-dsa no-dtls no-ec2m no-engine no-filenames no-gost no-idea no-mdc2 no-md4 no-multiblock no-nextprotoneg no-ocsp no-ocb no-poly1305 no-psk no-rc2 no-rc4 no-rmd160 no-seed no-siphash no-sm2 no-sm3 no-sm4 no-srp no-srtp no-ssl3 no-ssl3-method no-ts no-ui-console no-whirlpool no-asm -DOPENSSL_NO_SECURE_MEMORY -DOPENSSL_SMALL_FOOTPRINT && perl configdata.pm --dump - - name: make - run: make -s -j4 - - name: make test - run: make test - - name: make clean - run: make clean - - name: check dirty - run: test $(git status --porcelain | wc -l) -eq "0" - - out-of-tree_build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: setup build dir - run: | - set -eux - mkdir -p ${myblddir:=../_build/nest/a/little/more} - echo "mysrcdir=$(realpath .)" | tee -a $GITHUB_ENV - echo "myblddir=$(realpath $myblddir)" | tee -a $GITHUB_ENV - - name: config - run: set -eux ; cd ${{ env.myblddir }} && ${{ env.mysrcdir }}/config --strict-warnings && perl configdata.pm --dump - - name: make build_generated - run: set -eux; cd ${{ env.myblddir }} && make -s build_generated - - name: make update - run: set -eux; cd ${{ env.myblddir }} && make update - - name: make - run: set -eux; cd ${{ env.myblddir }} && make -s -j4 - - name: make test (minimal subset) - run: set -eux; cd ${{ env.myblddir }} && make test TESTS='0[0-9]' - - no-deprecated: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: config - run: ./config --strict-warnings no-deprecated && perl configdata.pm --dump - - name: make - run: make -s -j4 - - name: make test - run: make test - - name: make clean - run: make clean - - name: check dirty - run: test $(git status --porcelain | wc -l) -eq "0" - - sanitizers: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: config - run: ./config --debug enable-asan enable-ubsan enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 && perl configdata.pm --dump - - name: make - run: make -s -j4 - - name: make test - run: make test OPENSSL_TEST_RAND_ORDER=0 - - name: make clean - run: make clean - - name: check dirty - run: test $(git status --porcelain | wc -l) -eq "0" - - enable_non-default_options: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: config - run: ./config --strict-warnings enable-asan enable-ubsan enable-ssl-trace enable-zlib enable-zlib-dynamic enable-crypto-mdebug enable-crypto-mdebug-backtrace enable-egd enable-ntls enable-delegated-credential enable-cert-compression && perl configdata.pm --dump - - name: make - run: make -s -j4 - - name: make test - run: make test - - name: make clean - run: make clean - - name: check dirty - run: test $(git status --porcelain | wc -l) -eq "0" - - legacy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: config - run: ./config -Werror --debug no-afalgeng no-shared enable-crypto-mdebug enable-rc5 enable-md2 enable-ssl3 enable-ssl3-method enable-weak-ssl-ciphers enable-zlib enable-ec_nistp_64_gcc_128 && perl configdata.pm --dump - - name: make - run: make -s -j4 - - name: make test - run: make test - - name: make clean - run: make clean - - name: check dirty - run: test $(git status --porcelain | wc -l) -eq "0" - - buildtest: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: config - run: ./config no-makedepend enable-buildtest-c++ --strict-warnings -D_DEFAULT_SOURCE && perl configdata.pm --dump - - name: make - run: make -s -j4 - - name: make test - run: make test - - name: make clean - run: make clean - - name: check dirty - run: test $(git status --porcelain | wc -l) -eq "0" - - ntls-without-sm234: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: config - run: ./config enable-ntls no-sm2 no-sm3 no-sm4 --strict-warnings && perl configdata.pm --dump - - name: make - run: make -s -j4 - - name: make test - run: make test - - name: make clean - run: make clean - - name: check dirty - run: test $(git status --porcelain | wc -l) -eq "0" - - ntls-sanitizers: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: config - run: ./config enable-ntls --strict-warnings enable-asan -fsanitize=address -static-libasan enable-crypto-mdebug enable-crypto-mdebug-backtrace && perl configdata.pm --dump - - name: make - run: make -s -j4 - - name: make test - run: make test - - name: make clean - run: make clean - - name: check dirty - run: test $(git status --porcelain | wc -l) -eq "0" - - ec_elgamal_test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: config - run: ./config --strict-warnings enable-asan enable-ubsan enable-ssl-trace enable-zlib enable-zlib-dynamic enable-ec_elgamal && perl configdata.pm --dump - - name: make - run: make -s -j4 - - name: make test - run: make test - - name: make clean - run: make clean - - name: check dirty - run: test $(git status --porcelain | wc -l) -eq "0" diff --git a/.github/workflows/cross-compiles.yml b/.github/workflows/cross-compiles.yml deleted file mode 100644 index 06ab7168a..000000000 --- a/.github/workflows/cross-compiles.yml +++ /dev/null @@ -1,152 +0,0 @@ ---- -name: Cross Compile - -on: [pull_request, push] - -jobs: - cross-compilation: - strategy: - fail-fast: false - matrix: - # The platform matrix specifies: - # arch: the architecture to build for, this defines the tool-chain - # prefix {arch}- and the Debian compiler package gcc-{arch} - # name. - # libs: the Debian package for the necessary link/runtime libraries. - # target: the OpenSSL configuration target to use, this is passed - # directly to the config command line. - # tests: omit this to run all the tests using QEMU, set it to "none" - # to never run the tests, otherwise it's value is passed to - # the "make test" command to allow selectiving disabling of - # tests. - platform: [ - { - arch: aarch64-linux-gnu, - libs: libc6-dev-arm64-cross, - target: linux-aarch64 - }, { - arch: alpha-linux-gnu, - libs: libc6.1-dev-alpha-cross, - target: linux-alpha-gcc - }, { - arch: arm-linux-gnueabi, - libs: libc6-dev-armel-cross, - target: linux-armv4, - tests: -test_includes -test_store -test_x509_store - }, { - arch: arm-linux-gnueabihf, - libs: libc6-dev-armhf-cross, - target: linux-armv4, - tests: -test_includes -test_store -test_x509_store - }, { - arch: hppa-linux-gnu, - libs: libc6-dev-hppa-cross, - target: -static linux-generic32, - tests: -test_includes -test_store -test_x509_store - }, { - arch: m68k-linux-gnu, - libs: libc6-dev-m68k-cross, - target: -static -m68040 linux-generic32, - tests: -test_includes -test_store -test_x509_store - }, { - arch: mips-linux-gnu, - libs: libc6-dev-mips-cross, - target: -static linux-mips32, - tests: -test_includes -test_store -test_x509_store - }, { - arch: mips64-linux-gnuabi64, - libs: libc6-dev-mips64-cross, - target: -static linux64-mips64, - }, { - arch: mipsel-linux-gnu, - libs: libc6-dev-mipsel-cross, - target: linux-mips32, - tests: -test_includes -test_store -test_x509_store - }, { - arch: powerpc64le-linux-gnu, - libs: libc6-dev-ppc64el-cross, - target: linux-ppc64le - }, { - arch: riscv64-linux-gnu, - libs: libc6-dev-riscv64-cross, - target: linux64-riscv64 - }, { - arch: s390x-linux-gnu, - libs: libc6-dev-s390x-cross, - target: linux64-s390x - }, { - arch: sh4-linux-gnu, - libs: libc6-dev-sh4-cross, - target: no-async linux-generic32, - tests: -test_includes -test_store -test_x509_store - }, - - # These build with shared libraries but they crash when run - # They mirror static builds above in order to cover more of the - # code base. - { - arch: hppa-linux-gnu, - libs: libc6-dev-hppa-cross, - target: linux-generic32, - tests: none - }, { - arch: m68k-linux-gnu, - libs: libc6-dev-m68k-cross, - target: -mcfv4e linux-generic32, - tests: none - }, { - arch: mips-linux-gnu, - libs: libc6-dev-mips-cross, - target: linux-mips32, - tests: none - }, { - arch: mips64-linux-gnuabi64, - libs: libc6-dev-mips64-cross, - target: linux64-mips64, - tests: none - }, - - # This build doesn't execute either with or without shared libraries. - { - arch: sparc64-linux-gnu, - libs: libc6-dev-sparc64-cross, - target: linux64-sparcv9, - tests: none - } - ] - runs-on: ubuntu-latest - steps: - - name: install packages - run: | - sudo apt-get update - sudo apt-get -yq --force-yes install \ - gcc-${{ matrix.platform.arch }} \ - ${{ matrix.platform.libs }} - - uses: actions/checkout@v2 - - - name: config - run: | - ./Configure --strict-warnings \ - --cross-compile-prefix=${{ matrix.platform.arch }}- \ - ${{ matrix.platform.target }} - - name: config dump - run: ./configdata.pm --dump - - - name: make - run: make -s -j4 - - - name: install qemu - if: github.event_name == 'push' && matrix.platform.tests != 'none' - run: sudo apt-get -yq --force-yes install qemu-user - - - name: make all tests - if: github.event_name == 'push' && matrix.platform.tests == '' - run: | - make test \ - QEMU_LD_PREFIX=/usr/${{ matrix.platform.arch }} - - name: make some tests - if: github.event_name == 'push' && matrix.platform.tests != 'none' && matrix.platform.tests != '' - run: | - make test \ - TESTS="${{ matrix.platform.tests }}" \ - QEMU_LD_PREFIX=/usr/${{ matrix.platform.arch }} diff --git a/.github/workflows/gm.yml b/.github/workflows/gm.yml new file mode 100644 index 000000000..626e00045 --- /dev/null +++ b/.github/workflows/gm.yml @@ -0,0 +1,26 @@ +name: GM CI +on: [pull_request, push] +jobs: + gm-ci: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: config + run: | + ./config no-shared enable-threads enable-tls1_3 enable-ssl3 enable-ssl3-method enable-weak-ssl-ciphers \ + no-evp-cipher-api-compat no-req-status no-status no-crypto-mdebug-count no-dynamic-ciphers \ + no-optimize-chacha no-rsa-multi-prime-key-compat no-session-lookup no-session-reused-type \ + no-global-session-cache no-verify-sni no-skip-scsv enable-ntls enable-crypto-mdebug-count \ + enable-crypto-mdebug-backtrace enable-ssl-trace --debug -fPIC --prefix=/opt/babassl enable-gm \ + --with-rand-seed=getrandom,egd,rtc -DSSL_DEBUG -DGM_DEBUG + - name: make + run: make -s -j4 + - name: make test + run: make test TESTS='test_rand test_internal_sm2 test_internal_sm3 test_internal_sm4 test_ssl_ntls_api' + - name: make install + run: make install + - name: print GM version + run: | + export OPENSSL_NO_INTEGRITY=1 + export OPENSSL_NO_AUTH=1 + /opt/babassl/bin/openssl version -g diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 740c09e43..000000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: CIFuzz -on: [pull_request, push] -jobs: - Fuzzing: - runs-on: ubuntu-latest - steps: - - name: Build Fuzzers - uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master - with: - dry-run: false - - name: Run Fuzzers - uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master - with: - fuzz-seconds: 600 - dry-run: false - - name: Upload Crash - uses: actions/upload-artifact@v1 - if: failure() - with: - name: artifacts - path: ./out/artifacts diff --git a/.github/workflows/notify.yml b/.github/workflows/notify.yml deleted file mode 100644 index 78856dcf2..000000000 --- a/.github/workflows/notify.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Notify CI - -on: - push: - branches: - - master - - 8.2-stable - -jobs: - check_update: - runs-on: ubuntu-latest - steps: - - name: Invoke build docs workflow - uses: benc-uk/workflow-dispatch@v1 - with: - workflow: Build docs - repo: BabaSSL/babassl.github.io - token: ${{ secrets.BUILD_DOCS_TOKEN }} - inputs: '{ "name": "build docs"}' - ref: ${{ github.event.pull_request.head.ref }} - diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml deleted file mode 100644 index 11f4454ce..000000000 --- a/.github/workflows/windows.yml +++ /dev/null @@ -1,137 +0,0 @@ ---- -name: Windows GitHub CI - -on: [pull_request, push] - -jobs: - shared: - # Run a job for each of the specified target architectures: - strategy: - matrix: - os: - - windows-2019 - - windows-2022 - platform: - - arch: win64 - config: VC-WIN64A - - arch: win32 - config: VC-WIN32 --strict-warnings - runs-on: ${{matrix.os}} - steps: - - uses: actions/checkout@v2 - - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: ${{ matrix.platform.arch }} - - uses: ilammy/setup-nasm@v1 - with: - platform: ${{ matrix.platform.arch }} - - uses: shogo82148/actions-setup-perl@v1 - - name: prepare the build directory - run: mkdir _build - - name: config - working-directory: _build - run: | - perl ..\Configure no-makedepend ${{ matrix.platform.config }} - perl configdata.pm --dump - - name: build - working-directory: _build - run: nmake /S - - name: test - working-directory: _build - run: nmake test VERBOSE_FAILURE=yes TESTS=-test_fuzz* - - name: install - # Run on 64 bit only as 32 bit is slow enough already - if: $${{ matrix.platform.arch == 'win64' }} - run: | - mkdir _dest - nmake install DESTDIR=_dest - working-directory: _build - plain: - strategy: - matrix: - os: - - windows-2019 - - windows-2022 - runs-on: ${{matrix.os}} - steps: - - uses: actions/checkout@v2 - - uses: ilammy/msvc-dev-cmd@v1 - - uses: shogo82148/actions-setup-perl@v1 - - name: prepare the build directory - run: mkdir _build - - name: config - working-directory: _build - run: | - perl ..\Configure no-makedepend no-shared VC-WIN64A-masm - perl configdata.pm --dump - - name: build - working-directory: _build - run: nmake /S - - name: test - working-directory: _build - run: nmake test VERBOSE_FAILURE=yes - minimal: - strategy: - matrix: - os: - - windows-2019 - - windows-2022 - runs-on: ${{matrix.os}} - steps: - - uses: actions/checkout@v2 - - uses: ilammy/msvc-dev-cmd@v1 - - uses: shogo82148/actions-setup-perl@v1 - - name: prepare the build directory - run: mkdir _build - - name: config - working-directory: _build - run: | - perl ..\Configure no-makedepend no-deprecated no-asm -DOPENSSL_SMALL_FOOTPRINT VC-WIN64A - perl configdata.pm --dump - - name: build - working-directory: _build - run: nmake # verbose, so no /S here - - name: test - working-directory: _build - run: nmake test VERBOSE_FAILURE=yes TESTS=-test_fuzz* - enable_non-default_options: - strategy: - matrix: - os: - - windows-2019 - - windows-2022 - platform: - - arch: win64 - config: VC-WIN64A - - arch: win32 - config: VC-WIN32 --strict-warnings - runs-on: ${{matrix.os}} - steps: - - uses: actions/checkout@v2 - - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: ${{ matrix.platform.arch }} - - uses: ilammy/setup-nasm@v1 - with: - platform: ${{ matrix.platform.arch }} - - uses: shogo82148/actions-setup-perl@v1 - - name: prepare the build directory - run: mkdir _build - - name: config - working-directory: _build - run: | - perl ..\Configure no-makedepend enable-ssl-trace enable-egd enable-ntls enable-delegated-credential enable-cert-compression ${{ matrix.platform.config }} - perl configdata.pm --dump - - name: build - working-directory: _build - run: nmake /S - - name: test - working-directory: _build - run: nmake test VERBOSE_FAILURE=yes TESTS=-test_fuzz* - - name: install - # Run on 64 bit only as 32 bit is slow enough already - if: $${{ matrix.platform.arch == 'win64' }} - run: | - mkdir _dest - nmake install DESTDIR=_dest - working-directory: _build diff --git a/Configure b/Configure index e912f6967..6be9d7527 100755 --- a/Configure +++ b/Configure @@ -389,6 +389,7 @@ my @disablables = ( "filenames", "fuzz-libfuzzer", "fuzz-afl", + "gm", "gost", "heartbeats", "hw(-.+)?", @@ -489,6 +490,7 @@ our %disabled = ( # "what" => "comment" "external-tests" => "default", "fuzz-libfuzzer" => "default", "fuzz-afl" => "default", + "gm" => "default", "heartbeats" => "default", "md2" => "default", "msan" => "default", @@ -675,7 +677,7 @@ my %cmdvars = (); # Stores FOO='blah' type arguments my %unsupported_options = (); my %deprecated_options = (); # If you change this, update apps/version.c -my @known_seed_sources = qw(getrandom devrandom os egd none rdcpu librandom); +my @known_seed_sources = qw(getrandom devrandom os egd none rdcpu librandom rtc); my @seed_sources = (); while (@argvcopy) { @@ -1589,6 +1591,10 @@ $config{CFLAGS} = [ map { $_ eq '--ossl-strict-warnings' ? @strict_warnings_collection : ( $_ ) } @{$config{CFLAGS}} ]; +# apps/mod.c depends libm +unless ($disabled{"gm"}) { + push @{$config{ex_libs}}, "-lm"; +} unless ($disabled{"crypto-mdebug-backtrace"}) { diff --git a/apps/apps.c b/apps/apps.c index 24155c319..07bcf5b64 100644 --- a/apps/apps.c +++ b/apps/apps.c @@ -45,7 +45,13 @@ #endif #include #include +#ifndef OPENSSL_NO_GM +#include +#include "../crypto/rand/rand_local.h" +#include "internal/cryptlib.h" +#endif #include "apps.h" +#include "crypto/rand.h" #ifdef _WIN32 static int WIN32_rename(const char *from, const char *to); @@ -2893,3 +2899,780 @@ int zlib_decompress(SSL *s, } # endif #endif + +#ifndef OPENSSL_NO_GM +#define SALT_LEN 64 + +static int entropy_source_startup_health_test(void) +{ + unsigned char *entropy = NULL; + RAND_DRBG *drbg = RAND_DRBG_get0_master(); + size_t entropylen = 0; + int total = 1000000 / 8; + unsigned int last = -1, cur; + unsigned int cnt = 1, max = 27; + int ret = 0; + size_t i, j; + + fprintf(stdout, "BEGIN { startup health test for entropy source }\n"); + + if (drbg == NULL) + goto end; + + while (total > 0) { + entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength, + drbg->min_entropylen, + drbg->max_entropylen, 0); + + if (entropylen < drbg->min_entropylen || + entropylen > drbg->max_entropylen) + goto end; + + for (i = 0; i < entropylen; i++) { + for (j = 0; j < 8; j++) { + cur = (entropy[i] >> j) & 0x01; + + if (last == cur) { + cnt++; + + if (cnt >= max) + goto end; + } else { + last = cur; + cnt = 1; + } + } + } + + total -= entropylen; + + if (drbg->cleanup_entropy != NULL) { + drbg->cleanup_entropy(drbg, entropy, entropylen); + entropy = NULL; + entropylen = 0; + } + } + + fprintf(stdout, "END { startup health test for entropy source }\n"); + + ret = 1; +end: + if (entropy != NULL && drbg->cleanup_entropy != NULL) + drbg->cleanup_entropy(drbg, entropy, entropylen); + + return ret; +} + +int scm_init(void) +{ + fprintf(stderr, "Init: SM2 module init success\n"); + fprintf(stderr, "Init: SM3 module init success\n"); + fprintf(stderr, "Init: SM4 module init success\n"); + + RAND_DRBG_set_defaults(NID_sm3, 0); + + if (entropy_source_startup_health_test()) + fprintf(stderr, "Init: Random module init success\n"); + else + return 0; + + fprintf(stderr, "------------------------------------------------------\n"); + + return 1; +} + +int scm_self_test_integrity(const char *exe) +{ + int ret = 0; + const char *pubkey = "-----BEGIN PUBLIC KEY-----\n" + "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE4DyCERSfDFCtzDYEzXwFGnPy7PBS\n" + "46vljnpWQKcgCkR3x+ZmzuXsabCZMfKPBNbAnSKlDwO9btRUzE19aRChLg==\n" + "-----END PUBLIC KEY-----"; + char *buf = NULL; + EVP_PKEY *pkey = NULL; + EVP_MD_CTX *mctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + BIO *keybio = NULL; + BIO *sigbio = NULL; + size_t siglen; + unsigned char *sigbuf = NULL; + BIO *in = NULL; + BIO *bmd = NULL; + BIO *inp = NULL; + int bufsize = 1024 * 8; + char *sighex = NULL; + int i; + + buf = app_malloc(bufsize, "I/O buffer"); + + keybio = BIO_new_mem_buf(pubkey, -1); + if (keybio == NULL) + goto end; + + pkey = PEM_read_bio_PUBKEY(keybio, NULL, NULL, NULL); + if (pkey == NULL) + goto end; + + in = BIO_new(BIO_s_file()); + if (in == NULL) + goto end; + + bmd = BIO_new(BIO_f_md()); + if (bmd == NULL) + goto end; + + if (!BIO_get_md_ctx(bmd, &mctx)) + goto end; + + if (!EVP_DigestVerifyInit(mctx, &pctx, EVP_sm3(), NULL, pkey)) + goto end; + + sigbio = BIO_new_file(OPENSSL_get_default_signature_file(), "rb"); + if (sigbio == NULL) + goto end; + + siglen = EVP_PKEY_size(pkey); + sigbuf = app_malloc(siglen, "signature buffer"); + siglen = BIO_read(sigbio, sigbuf, siglen); + if (siglen <= 0) { + goto end; + } + + BIO_free(sigbio); + sigbio = NULL; + + inp = BIO_push(bmd, in); + + if (BIO_read_filename(in, exe) <= 0) + goto end; + + while (BIO_pending(inp) || !BIO_eof(inp)) { + i = BIO_read(inp, (char *)buf, bufsize); + if (i < 0) { + BIO_printf(bio_err, "Read Error in %s\n", exe); + ERR_print_errors(bio_err); + goto end; + } + if (i == 0) + break; + } + + if (!EVP_DigestVerifyFinal(mctx, sigbuf, (unsigned int)siglen)) + goto end; + + sighex = OPENSSL_buf2hexstr(sigbuf, siglen); + if (sighex == NULL) + goto end; + + ret = 1; + + fprintf(stderr, "BEGIN { Self-test integrity test }\n"); + fprintf(stderr, "Self-test: integrity test\n"); + fprintf(stderr, "Pubkey=%s\n", pubkey); + fprintf(stderr, "Input=%s\n", sighex); +// fprintf(stderr, "Output=%s\n", tbs); + fprintf(stderr, "END { Self-test integrity test }\n"); +end: + OPENSSL_free(buf); + OPENSSL_free(sigbuf); + OPENSSL_free(sighex); + BIO_free(in); + BIO_free(bmd); + BIO_free(sigbio); + BIO_free(keybio); + EVP_PKEY_free(pkey); + + return ret; +} + +int scm_self_test_sm2_verify(void) +{ + int ret = 0; + unsigned char pubkey[] = "-----BEGIN PUBLIC KEY-----\n" + "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEOToq2eJ+Q6yqq4WhnTuFWR4UQGFX\n" + "F1rd03v3f/DK+e03/POotPVcA4UjJh/KZjav5qevoqFIKmBvXLOhiy4qHg==\n" + "-----END PUBLIC KEY-----"; + const char *sig = "D7AD397F6FFA5D4F7F11E7217F241607DC30618C236D2C09C1B9EA8FDADEE2E8"; + const char *tbs = "3046022100AB1DB64DE7C40EDBDE6651C9B8EBDB804673DB836E5D5C7FE15DCF9ED2725037022100EBA714451FF69B0BB930B379E192E7CD5FA6E3C41C7FBD8303B799AB54A54621"; + EVP_PKEY *pkey = NULL; + unsigned char *tbsbin = NULL; + unsigned char *sigbin = NULL; + EVP_MD_CTX *mctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + BIO *bio = NULL; + + bio = BIO_new_mem_buf(pubkey, -1); + if (bio == NULL) + goto end; + + pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + if (pkey == NULL) + goto end; + + tbsbin = OPENSSL_hexstr2buf(tbs, NULL); + if (tbsbin == NULL) + goto end; + + sigbin = OPENSSL_hexstr2buf(sig, NULL); + if (sigbin == NULL) + goto end; + + mctx = EVP_MD_CTX_new(); + if (mctx == NULL) + goto end; + + pctx = EVP_PKEY_CTX_new(pkey, NULL); + if (pctx == NULL) + goto end; + + EVP_MD_CTX_set_pkey_ctx(mctx, pctx); + + if (!EVP_DigestVerifyInit(mctx, NULL, EVP_sm3(), NULL, pkey) + || !EVP_DigestVerify(mctx, sigbin, strlen(sig)/2, + tbsbin, strlen(tbs)/2)) { + fprintf(stderr, "Self test: SM2 sign failed\n"); + goto end; + } + + ret = 1; + + fprintf(stderr, "BEGIN { Self-test SM2 verify test }\n"); + fprintf(stderr, "Pubkey=%s\n", pubkey); + fprintf(stderr, "Input=%s\n", sig); + fprintf(stderr, "Output=%s\n", tbs); + fprintf(stderr, "END { Self-test SM2 verify test }\n"); +end: + OPENSSL_free(tbsbin); + OPENSSL_free(sigbin); + EVP_PKEY_free(pkey); + EVP_MD_CTX_free(mctx); + EVP_PKEY_CTX_free(pctx); + BIO_free(bio); + return ret; +} + + +int scm_self_test_sm2_sign(void) +{ + int ret = 0; + unsigned char privkey[] = "-----BEGIN PRIVATE KEY-----\n" + "MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQg0JFWczAXva2An9m7\n" + "2MaT9gIwWTFptvlKrxyO4TjMmbWhRANCAAQ5OirZ4n5DrKqrhaGdO4VZHhRAYVcX\n" + "Wt3Te/d/8Mr57Tf886i09VwDhSMmH8pmNq/mp6+ioUgqYG9cs6GLLioe\n" + "-----END PRIVATE KEY-----"; + const char *tbs = "3046022100AB1DB64DE7C40EDBDE6651C9B8EBDB804673DB836E5D5C7FE15DCF9ED2725037022100EBA714451FF69B0BB930B379E192E7CD5FA6E3C41C7FBD8303B799AB54A54621"; + EVP_PKEY *pkey = NULL; + unsigned char *tbsbin = NULL; + EVP_MD_CTX *mctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + BIO *bio = NULL; + unsigned char *buf = NULL; + char *sig = NULL; + size_t tmplen; + + bio = BIO_new_mem_buf(privkey, -1); + if (bio == NULL) + goto end; + + pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + if (pkey == NULL) + goto end; + + tbsbin = OPENSSL_hexstr2buf(tbs, NULL); + if (tbsbin == NULL) + goto end; + + mctx = EVP_MD_CTX_new(); + if (mctx == NULL) + goto end; + + pctx = EVP_PKEY_CTX_new(pkey, NULL); + if (pctx == NULL) + goto end; + + EVP_MD_CTX_set_pkey_ctx(mctx, pctx); + + tmplen = ECDSA_size(EVP_PKEY_get0_EC_KEY(pkey)); + + buf = OPENSSL_malloc(tmplen); + if (buf == NULL) + goto end; + + if (!EVP_DigestSignInit(mctx, NULL, EVP_sm3(), NULL, pkey) + || !EVP_DigestSign(mctx, buf, &tmplen, + tbsbin, strlen(tbs)/2)) { + fprintf(stderr, "Self test: SM2 sign failed\n"); + goto end; + } + + if (!EVP_DigestVerifyInit(mctx, NULL, EVP_sm3(), NULL, pkey) + || !EVP_DigestVerify(mctx, buf, tmplen, tbsbin, strlen(tbs)/2)) + goto end; + + sig = OPENSSL_buf2hexstr(buf, tmplen); + if (sig == NULL) + goto end; + + ret = 1; + + fprintf(stderr, "BEGIN { Self-test SM2 sign test }\n"); + fprintf(stderr, "PrivKey=%s\n", privkey); + fprintf(stderr, "Input=%s\n", tbs); + fprintf(stderr, "Output=%s\n", sig); + fprintf(stderr, "END { Self-test SM2 sign test }\n"); +end: + OPENSSL_free(sig); + OPENSSL_free(buf); + OPENSSL_free(tbsbin); + EVP_PKEY_free(pkey); + EVP_MD_CTX_free(mctx); + EVP_PKEY_CTX_free(pctx); + BIO_free(bio); + return ret; +} + +int scm_self_test_sm4_decrypt(void) +{ + int ret = 0; + unsigned char buf[1024]; + EVP_CIPHER_CTX *ctx = NULL; + const char *key = "95F28D1231BB9EE5F01DDF2E3148CF41"; + const char *iv = "01020304050607080901020304050607"; + const char *input = "0A1D209300FD1D410E5C538F18D91299F6DE0ADD8A4212D88D7FC44A992EC795"; + const char *output = "A7009665F44878D3AE472FC8B9A3E0AD6DA9B0DC44331EA9D6CF95A3081D4117"; + unsigned char *keybin = NULL; + unsigned char *outputbin = NULL; + unsigned char *inputbin = NULL; + unsigned char *ivbin = NULL; + int tmplen; + int outlen; + + keybin = OPENSSL_hexstr2buf(key, NULL); + if (keybin == NULL) + goto end; + + ivbin = OPENSSL_hexstr2buf(iv, NULL); + if (ivbin == NULL) + goto end; + + inputbin = OPENSSL_hexstr2buf(input, NULL); + if (inputbin == NULL) + goto end; + + if ((ctx = EVP_CIPHER_CTX_new()) == NULL + || !EVP_DecryptInit_ex(ctx, EVP_sm4_cbc(), NULL, keybin, ivbin) + || !EVP_CIPHER_CTX_set_padding(ctx, 0) + || !EVP_DecryptUpdate(ctx, buf, &outlen, + inputbin, strlen(input)/2) + || !EVP_DecryptFinal_ex(ctx, buf + outlen, &tmplen)) + goto end; + + outlen += tmplen; + + outputbin = OPENSSL_hexstr2buf(output, NULL); + if (outputbin == NULL) + goto end; + + if (outlen != (int)strlen(output)/2 || + memcmp(buf, outputbin, outlen) != 0) + goto end; + + ret = 1; + + fprintf(stdout, "BEGIN { Self-test SM4 decrypt test }\n"); + fprintf(stderr, "Key=%s\n", key); + fprintf(stderr, "IV=%s\n", iv); + fprintf(stderr, "Input=%s\n", input); + fprintf(stderr, "Output=%s\n", output); + fprintf(stdout, "END { Self-test SM4 decrypt test }\n"); + +end: + OPENSSL_free(keybin); + OPENSSL_free(ivbin); + OPENSSL_free(inputbin); + OPENSSL_free(outputbin); + + EVP_CIPHER_CTX_free(ctx); + return ret; +} + +int scm_self_test_sm4_encrypt(void) +{ + int ret = 0; + unsigned char buf[1024]; + EVP_CIPHER_CTX *ctx = NULL; + const char *key = "95F28D1231BB9EE5F01DDF2E3148CF41"; + const char *iv = "01020304050607080901020304050607"; + const char *input = "A7009665F44878D3AE472FC8B9A3E0AD6DA9B0DC44331EA9D6CF95A3081D4117"; + const char *output = "0A1D209300FD1D410E5C538F18D91299F6DE0ADD8A4212D88D7FC44A992EC795"; + unsigned char *keybin = NULL; + unsigned char *outputbin = NULL; + unsigned char *inputbin = NULL; + unsigned char *ivbin = NULL; + int tmplen; + int outlen; + + keybin = OPENSSL_hexstr2buf(key, NULL); + if (keybin == NULL) + goto end; + + ivbin = OPENSSL_hexstr2buf(iv, NULL); + if (ivbin == NULL) + goto end; + + inputbin = OPENSSL_hexstr2buf(input, NULL); + if (inputbin == NULL) + goto end; + + if ((ctx = EVP_CIPHER_CTX_new()) == NULL + || !EVP_EncryptInit_ex(ctx, EVP_sm4_cbc(), NULL, keybin, ivbin) + || !EVP_CIPHER_CTX_set_padding(ctx, 0) + || !EVP_EncryptUpdate(ctx, buf, &outlen, + inputbin, strlen(input)/2) + || !EVP_EncryptFinal_ex(ctx, buf + outlen, &tmplen)) + goto end; + + outlen += tmplen; + + outputbin = OPENSSL_hexstr2buf(output, NULL); + if (outputbin == NULL) + goto end; + + if (outlen != (int)strlen(output)/2 || + memcmp(buf, outputbin, outlen) != 0) + goto end; + + ret = 1; + + fprintf(stdout, "BEGIN { Self-test SM4 encrypt test }\n"); + fprintf(stderr, "Key=%s\n", key); + fprintf(stderr, "IV=%s\n", iv); + fprintf(stderr, "Input=%s\n", input); + fprintf(stderr, "Output=%s\n", output); + fprintf(stdout, "END { Self-test SM4 encrypt test }\n"); + +end: + + OPENSSL_free(keybin); + OPENSSL_free(ivbin); + OPENSSL_free(inputbin); + OPENSSL_free(outputbin); + + EVP_CIPHER_CTX_free(ctx); + return ret; +} + +int scm_self_test_sm3(void) +{ + int ret = 0; + EVP_MD_CTX *mctx = NULL; + const char *input1[] = { + "c684788d8e3cb4eac0c680500c175e54", + "259909fe49ada2b1455b81a4e0a0f79912636ebaed96cb9d60c85cc2926e247e", + "217b5ebc849b8637cfd06121c9e0035ac887ab33d4736ffa6539e22b4daf839088d3c884001e97bf3351f11df69e1b9a4f2fa5929427f470e844de08b6434ffa", + "f66f79cb4f41fa491d0d6c7a78590545cb5a3850dc08f50b246bc365243ed5181c33f5d1f1f241a3cf1d38ae4077afebcc002a9302b01d4c3713ab855869ee7026d5fe3c2954bad913583526e0806f6272ae4a88e9d3fffb62ecac769419b23d81dec7b2de2ef6a7903e52ed6f5ed6aae804d0070896128633bf55c38e400a51", + "3c45817cfc093f18b4f8fb3ae9941e28e079b4d443e7e53cedc8aafe131b5ebfa3897fd61f49fed14e84006be0525347e570ec741a5a10a9bc28df9d13bc187530bd821dd74005e9a4226da97c8e7a409f8d1cf042ba4ba04ff1583e1d37c225ab6772f78e825c02f61799987cb2ce234262312d98e258f649e2a47fbc2777d91823a56b9354f85516d250c08b731cb87d905521de3ade205403bc5e237d83580a8612fd2af8858b4874fb434f90dafe0b1efa5de8e981f18e08a9fa38851fd63cd8b80e68275d425a45dc8bb3956d8aef77bf99e01ed3d467a03233a8739e90db50a03330cbc2ac28b64f73321996f9a089cfe17788c2a3544a93ac3be70af8", + }; + const char *output1[] = { + "f00f5012914600a3ec71c8e99526dc41e3b51bb82def800fbd7cb7992e54c322", + "804752ea387065b95cd46d108fa3d52d3657cfc0a9abb2d6f0bb8fbaf00b7c54", + "d82f2d501852941255ee2e11b2902982191717a365c48262d9239b30d85c58e9", + "ace600eb40c3d1506c10af1b3df6c51c9cf0389f61d98b29b24c89bd6256884f", + "26cd58cf6961a1cdfcc12f1bbb1ec4b97ca332151a640b7582b1c73ccac94b88", + }; + unsigned char buf[EVP_MAX_MD_SIZE]; + unsigned char *inputbin = NULL; + unsigned char *outputbin = NULL; + size_t i; + + fprintf(stdout, "BEGIN { Self-test SM3 test }\n"); + + for (i = 0; i < OSSL_NELEM(input1); i++) { + inputbin = OPENSSL_hexstr2buf(input1[i], NULL); + if (inputbin == NULL) + goto end; + + if ((mctx = EVP_MD_CTX_new()) == NULL + || !EVP_DigestInit_ex(mctx, EVP_sm3(), NULL) + || !EVP_DigestUpdate(mctx, inputbin, strlen(input1[i]) / 2) + || !EVP_DigestFinal_ex(mctx, buf, NULL)) + goto end; + + outputbin = OPENSSL_hexstr2buf(output1[i], NULL); + if (outputbin == NULL) + goto end; + + if (memcmp(buf, outputbin, strlen(output1[i]) / 2) != 0) + goto end; + + EVP_MD_CTX_free(mctx); + mctx = NULL; + OPENSSL_free(inputbin); + inputbin = NULL; + OPENSSL_free(outputbin); + outputbin = NULL; + + fprintf(stderr, "Self-test: SM3 test item %ld\n", i + 1); + fprintf(stderr, "Input=%s\n", input1[i]); + fprintf(stderr, "Output=%s\n", output1[i]); + } + + fprintf(stdout, "END { Self-test SM3 test }\n"); + + ret = 1; +end: + OPENSSL_free(outputbin); + EVP_MD_CTX_free(mctx); + OPENSSL_free(inputbin); + + return ret; +} + +static void hexdump(FILE *fp, const char *name, + const unsigned char *buf, size_t len) +{ + size_t i; + + fprintf(fp, "%s=", name); + + for (i = 0; i < len; i++) + fprintf(fp, "%02X", buf[i]); + + fprintf(fp, "\n"); +} + +static int self_test_drbg_data_index; + +typedef struct test_ctx_st { + const unsigned char *entropy; + size_t entropylen; + int entropycnt; + const unsigned char *nonce; + size_t noncelen; + int noncecnt; +} TEST_DRBG_CTX; + +static size_t self_test_get_entropy(RAND_DRBG *drbg, unsigned char **pout, + int entropy, size_t min_len, size_t max_len, + int prediction_resistance) +{ + TEST_DRBG_CTX *t = (TEST_DRBG_CTX *)RAND_DRBG_get_ex_data( + drbg, self_test_drbg_data_index); + + t->entropycnt++; + *pout = (unsigned char *)t->entropy; + return t->entropylen; +} + +static size_t self_test_get_nonce(RAND_DRBG *drbg, unsigned char **pout, + int entropy, size_t min_len, size_t max_len) +{ + TEST_DRBG_CTX *t = (TEST_DRBG_CTX *)RAND_DRBG_get_ex_data( + drbg, self_test_drbg_data_index); + + t->noncecnt++; + *pout = (unsigned char *)t->nonce; + return t->noncelen; +} + +int scm_self_test_sm3_drbg(void) +{ + RAND_DRBG *drbg = NULL; + TEST_DRBG_CTX t; + int ret = 0; + size_t request_len = 256 / 8; + unsigned char buff[1024]; + unsigned char pers[] = { + 0xc9, 0x80, 0xde, 0xdf, 0x98, 0x82, 0xed, 0x44, 0x64, 0xa6, 0x74, 0x96, + 0x78, 0x68, 0xf1, 0x43 + }; + unsigned char entropy[] = { + 0xE1, 0x0B, 0xC2, 0x8A, 0x0B, 0xFD, 0xDF, 0xE9, 0x3E, 0x7F, 0x51, 0x86, + 0xE0, 0xCA, 0x0B, 0x3B, 0x89, 0x0e, 0xb0, 0x67, 0xac, 0xf7, 0x38, 0x2e, + 0xff, 0x80, 0xb0, 0xc7, 0x3b, 0xc8, 0x72, 0xc6, + }; + unsigned char nonce[] = { + 0x9F, 0xF4, 0x77, 0xC1, 0x86, 0x73, 0x84, 0x0D, 0xaa, 0xd4, 0x71, 0xef, + 0x3e, 0xf1, 0xd2, 0x03, + }; + unsigned char adinreseed[] = { + 0x38, 0xBF, 0xEC, 0x9A, 0x10, 0xE6, 0xE4, 0x0C, 0x10, 0x68, 0x41, 0xDA, + 0xE4, 0x8D, 0xC3, 0xB8 + }; + unsigned char adin2[] = { + 0x7E, 0xAA, 0x1B, 0xBE, 0xC7, 0x93, 0x93, 0xA7, 0xF4, 0xA8, 0x22, 0x7B, + 0x69, 0x1E, 0xCB, 0x68 + }; + unsigned char expected[] = { + 0xFA, 0xAB, 0x8A, 0x9B, 0xA0, 0x16, 0x16, 0xB4, 0x0F, 0xD1, 0xD7, 0x3A, + 0x9F, 0x58, 0xA5, 0xEA, 0xC0, 0xF3, 0x74, 0x54, 0x5D, 0x74, 0x53, 0x09, + 0xA8, 0x73, 0x30, 0x92, 0xB4, 0x5F, 0xC1, 0xA9 + }; + int i; + + fprintf(stdout, "BEGIN { Self-test SM3-DRBG test }\n"); + + if ((drbg = RAND_DRBG_new(NID_sm3, 0, NULL)) == NULL) + return 0; + + if (!RAND_DRBG_set_callbacks(drbg, self_test_get_entropy, NULL, + self_test_get_nonce, NULL)) { + goto err; + } + memset(&t, 0, sizeof(t)); + t.entropy = entropy; + t.entropylen = sizeof(entropy); + t.nonce = nonce; + t.noncelen = sizeof(nonce); + + RAND_DRBG_set_ex_data(drbg, self_test_drbg_data_index, &t); + + hexdump(stdout, "entropy", entropy, sizeof(entropy)); + hexdump(stdout, "nonce", nonce, sizeof(nonce)); + hexdump(stdout, "personalization_str", pers, sizeof(pers)); + hexdump(stdout, "reseed additional_input", adinreseed, sizeof(adinreseed)); + hexdump(stdout, "generate additional_input", adin2, sizeof(adin2)); + fprintf(stdout, "requested_number_of_bits=%lu\n", request_len * 8); + hexdump(stdout, "returned_bits", buff, request_len); + + for (i = 0; i < 1000; i++) { + if (!RAND_DRBG_instantiate(drbg, pers, sizeof(pers)) + || !RAND_DRBG_reseed(drbg, adinreseed, sizeof(adinreseed), 0) + || !RAND_DRBG_generate(drbg, buff, request_len, 0, + adin2, sizeof(adin2)) + || memcmp(expected, buff, request_len) != 0) + goto err; + + RAND_DRBG_uninstantiate(drbg); + fprintf(stdout, "."); + } + + fprintf(stdout, "\n"); + + fprintf(stdout, "END { Self-test SM3-DRBG test }\n"); + + ret = 1; +err: + if (drbg != NULL) + RAND_DRBG_uninstantiate(drbg); + + RAND_DRBG_free(drbg); + return ret; +} + +int scm_do_passwd(const char *passphrase, int passphrase_len, + const char *salt, int salt_len, + char *result, int *res_len) +{ + int ret = 0; + unsigned char new_salt[SALT_LEN] = { + 0x17, 0xce, 0x14, 0x4c, 0x26, 0x64, 0xc3, 0x90, 0x44, 0x6b, 0x51, 0x1c, + 0x39, 0xa5, 0x27, 0x1f, 0xc7, 0x01, 0x67, 0x12, 0x7b, 0x54, 0xc9, 0x39, + 0xbe, 0x66, 0xda, 0x88, 0x2d, 0xd0, 0xf4, 0x58, 0x7e, 0x7e, 0x0f, 0x42, + 0x9a, 0x41, 0xdb, 0xb9, 0xd5, 0xea, 0x2a, 0x35, 0xc5, 0xa8, 0xac, 0x25, + 0x6f, 0x78, 0xc0, 0xe4, 0xb7, 0xf6, 0xd7, 0xfd, 0xb9, 0x0e, 0xf6, 0xbc, + 0xa0, 0x3e, 0xfd, 0x31}; + + EVP_MD_CTX *mctx = NULL; + unsigned char buf[EVP_MAX_MD_SIZE]; + + if (salt == NULL) { + salt = (const char *)new_salt; + salt_len = sizeof(new_salt); + } + + if ((mctx = EVP_MD_CTX_new()) == NULL + || !EVP_DigestInit_ex(mctx, EVP_sm3(), NULL) + || !EVP_DigestUpdate(mctx, salt, salt_len) + || !EVP_DigestUpdate(mctx, passphrase, passphrase_len) + || !EVP_DigestFinal_ex(mctx, buf, NULL)) + goto end; + + if (*res_len <= EVP_MD_size(EVP_sm3())) + goto end; + + memcpy(result, buf, EVP_MD_size(EVP_sm3())); + *res_len = EVP_MD_size(EVP_sm3()); + + ret = 1; +end: + EVP_MD_CTX_free(mctx); + return ret; +} + +int scm_setup_password(void) +{ + int ret = 0; + int templen; + BIO *out = NULL; + char passwd[512]; + char salt_pass[1024]; + + fprintf(stdout, "Setup admin password\n"); + + if (EVP_read_pw_string(passwd, sizeof(passwd), "Password: ", 1) != 0) + goto end; + + templen = sizeof(salt_pass); + + if (!scm_do_passwd(passwd, strlen(passwd), NULL, 0, salt_pass, &templen)) + goto end; + + out = bio_open_default(OPENSSL_get_default_passwd_file(), 'w', FORMAT_TEXT); + if (out == NULL) + goto end; + + BIO_hex_string(out, 0, 999999, (unsigned char *)salt_pass, templen); + + ret = 1; +end: + BIO_free_all(out); + return ret; +} + +int scm_verify_password(void) +{ + int ret = 0; + BIO *in = NULL; + char *buf = NULL; + long buf_len; + int templen; + char passwd[512]; + char calc_pass[1024]; + char read_pass[1024]; + + in = BIO_new_file(OPENSSL_get_default_passwd_file(), "r"); + if (in == NULL) + goto end; + + BIO_gets(in, read_pass, sizeof(read_pass)); + + buf = (char *)OPENSSL_hexstr2buf(read_pass, &buf_len); + if (buf == NULL) + goto end; + + if (buf_len != EVP_MD_size(EVP_sm3())) + goto end; + + if (EVP_read_pw_string(passwd, sizeof(passwd), "Password: ", 0) != 0) + goto end; + + templen = sizeof(calc_pass); + + if (!scm_do_passwd(passwd, strlen(passwd), NULL, 0, calc_pass, &templen)) + goto end; + + if (templen != EVP_MD_size(EVP_sm3())) + goto end; + + if (memcmp(buf, calc_pass, EVP_MD_size(EVP_sm3()))) + goto end; + + ret = 1; +end: + BIO_free(in); + OPENSSL_free(buf); + return ret; +} + +#endif diff --git a/apps/apps.h b/apps/apps.h index bdbcb216e..f076937ac 100644 --- a/apps/apps.h +++ b/apps/apps.h @@ -644,4 +644,19 @@ int zlib_decompress(SSL *s, # endif #endif +# ifndef OPENSSL_NO_GM +int scm_init(void); +int scm_self_test_integrity(const char *exe); +int scm_setup_password(void); +int scm_verify_password(void); +int scm_do_passwd(const char *passphrase, int passphrase_len, + const char *salt, int salt_len, + char *result, int *res_len); +int scm_self_test_sm3_drbg(void); +int scm_self_test_sm3(void); +int scm_self_test_sm4_encrypt(void); +int scm_self_test_sm4_decrypt(void); +int scm_self_test_sm2_sign(void); +int scm_self_test_sm2_verify(void); +# endif #endif diff --git a/apps/build.info b/apps/build.info index 9785ae47c..aed42cd05 100644 --- a/apps/build.info +++ b/apps/build.info @@ -67,6 +67,10 @@ IF[{- !$disabled{apps} -}] DEPEND[rsautl.o]=progs.h DEPEND[genrsa.o]=progs.h ENDIF + IF[{- !$disabled{'gm'} -}] + SOURCE[openssl]=mod.c + DEPEND[mod.o]=progs.h + ENDIF IF[{- $config{target} =~ /^(?:Cygwin|mingw|VC-)/ -}] GENERATE[openssl.rc]=../util/mkrc.pl openssl SOURCE[openssl]=openssl.rc diff --git a/apps/mod.c b/apps/mod.c new file mode 100644 index 000000000..ef7de9de0 --- /dev/null +++ b/apps/mod.c @@ -0,0 +1,128 @@ +#include + +#include "apps.h" +#include "progs.h" +#include +#include +#include +#include +#include +#include +#include +#include "internal/cryptlib.h" +#include "../crypto/rand/rand_local.h" + + +typedef enum OPTION_choice { + OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_PASS, + OPT_RESET, + OPT_TEST, + OPT_R_ENUM +} OPTION_CHOICE; + +const OPTIONS mod_options[] = { + {"help", OPT_HELP, '-', "Display this summary"}, + {"pass", OPT_PASS, '-', "Set password"}, + {"reset", OPT_RESET, '-', "Reset crypto module"}, + {"test", OPT_TEST, 's', "Self test, include random/sm2/sm3/sm4/all"}, + OPT_R_OPTIONS, + {NULL} +}; + +int mod_main(int argc, char **argv) +{ + int ret = 1; + char *prog; + OPTION_CHOICE o; + BIO *out = NULL; + int set_pass = 0; + int reset = 0; + char *arg = NULL; + int test_random = 0; + int test_sm2 = 0; + int test_sm3 = 0; + int test_sm4 = 0; + + prog = opt_init(argc, argv, mod_options); + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_EOF: + case OPT_ERR: + BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); + goto end; + case OPT_HELP: + opt_help(mod_options); + ret = 0; + goto end; + case OPT_PASS: + set_pass = 1; + break; + case OPT_RESET: + reset = 1; + break; + case OPT_TEST: + arg = opt_arg(); + break; + case OPT_R_CASES: + if (!opt_rand(o)) + goto end; + break; + } + } + argc = opt_num_rest(); + argv = opt_rest(); + + if (set_pass) { + if (!scm_setup_password()) + goto end; + + ret = 0; + goto end; + } + + if (reset) { + (void)remove(OPENSSL_get_default_passwd_file()); + /* return EXIT_THE_PROGRAM(-1) */ + ret = -1; + goto end; + } + + if (arg) { + if (!strcasecmp(arg, "random")) + test_random = 1; + else if (!strcasecmp(arg, "sm2")) + test_sm2 = 1; + else if (!strcasecmp(arg, "sm3")) + test_sm3 = 1; + else if (!strcasecmp(arg, "sm4")) + test_sm4 = 1; + else if (!strcasecmp(arg, "all")) + test_random = test_sm2 = test_sm3 = test_sm4 = 1; + else { + fprintf(stderr, "Error: invalid test item\n"); + goto end; + } + + if (test_random) + scm_self_test_sm3_drbg(); + + if (test_sm2) { + scm_self_test_sm2_sign(); + scm_self_test_sm2_verify(); + } + + if (test_sm3) + scm_self_test_sm3(); + + if (test_sm4) { + scm_self_test_sm4_encrypt(); + scm_self_test_sm4_decrypt(); + } + } + + ret = 0; +end: + BIO_free(out); + return ret; +} diff --git a/apps/openssl.c b/apps/openssl.c index d2ec5f8a3..964acf624 100644 --- a/apps/openssl.c +++ b/apps/openssl.c @@ -171,6 +171,52 @@ int main(int argc, char *argv[]) ret = 1; goto end; } + +#ifndef OPENSSL_NO_GM + if (!scm_init()) { + BIO_printf(bio_err, "Error: init failed\n"); + ret = 1; + goto end; + } + + if ( +# ifdef GM_DEBUG + getenv("OPENSSL_NO_INTEGRITY") == NULL && +# endif + !scm_self_test_integrity(argv[0])) + { + BIO_printf(bio_err, "Error: check integrity failed\n"); + ret = 1; + goto end; + } + + if (!scm_self_test_sm3_drbg() + || !scm_self_test_sm2_sign() + || !scm_self_test_sm2_verify() + || !scm_self_test_sm3() + || !scm_self_test_sm4_encrypt() + || !scm_self_test_sm4_decrypt()) + goto end; + +# ifdef GM_DEBUG + if (getenv("OPENSSL_NO_AUTH") == NULL) { +# endif + BIO *bio = bio_open_default_quiet(OPENSSL_get_default_passwd_file(), 'r', + FORMAT_TEXT); + if (bio == NULL) { + if (!scm_setup_password()) + goto end; + } else + BIO_free(bio); + + if (!scm_verify_password()) { + fprintf(stderr, "Error: auth failed\n"); + goto end; + } +# ifdef GM_DEBUG + } +# endif +#endif pname = opt_progname(argv[0]); /* first check the program name */ @@ -197,7 +243,7 @@ int main(int argc, char *argv[]) ret = 0; /* Read a line, continue reading if line ends with \ */ for (p = buf, n = sizeof(buf), i = 0, first = 1; n > 0; first = 0) { - prompt = first ? "OpenSSL> " : "> "; + prompt = first ? "BabaSSL> " : "> "; p[0] = '\0'; #ifndef READLINE fputs(prompt, stdout); diff --git a/apps/speed.c b/apps/speed.c index 91ad6eebb..aaac3a33c 100644 --- a/apps/speed.c +++ b/apps/speed.c @@ -3584,7 +3584,7 @@ int speed_main(int argc, char **argv) show_res: #endif if (!mr) { - printf("%s\n", OpenSSL_version(OPENSSL_VERSION)); + printf("%s\n", OpenSSL_version(BABASSL_VERSION)); printf("%s\n", OpenSSL_version(OPENSSL_BUILT_ON)); printf("options:"); printf("%s ", BN_options()); diff --git a/apps/version.c b/apps/version.c index 84473140c..8ac4afc38 100644 --- a/apps/version.c +++ b/apps/version.c @@ -33,7 +33,10 @@ typedef enum OPTION_choice { OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_B, OPT_D, OPT_E, OPT_F, OPT_O, OPT_P, OPT_V, OPT_A, OPT_R + OPT_B, OPT_D, OPT_E, OPT_F, OPT_O, OPT_P, OPT_V, OPT_A, OPT_R, +#ifndef OPENSSL_NO_GM + OPT_G, +#endif } OPTION_CHOICE; const OPTIONS version_options[] = { @@ -47,6 +50,9 @@ const OPTIONS version_options[] = { {"p", OPT_P, '-', "Show target build platform"}, {"r", OPT_R, '-', "Show random seeding options"}, {"v", OPT_V, '-', "Show library version"}, +#ifndef OPENSSL_NO_GM + {"g", OPT_G, '-', "Show GM info"}, +#endif {NULL} }; @@ -64,6 +70,9 @@ int version_main(int argc, char **argv) { int ret = 1, dirty = 0, seed = 0; int cflags = 0, version = 0, date = 0, options = 0, platform = 0, dir = 0; +#ifndef OPENSSL_NO_GM + int gm = 0; +#endif int engdir = 0, engines = 0; char *prog; OPTION_CHOICE o; @@ -104,6 +113,11 @@ int version_main(int argc, char **argv) case OPT_V: dirty = version = 1; break; +#ifndef OPENSSL_NO_GM + case OPT_G: + dirty = gm = 1; + break; +#endif case OPT_A: seed = options = cflags = version = date = platform = dir = engdir = engines = 1; @@ -186,6 +200,9 @@ int version_main(int argc, char **argv) printlist(" EGD", dev); } #endif +#ifdef OPENSSL_RAND_SEED_RTC + printf(" RTC ( real-time clock )"); +#endif #ifdef OPENSSL_RAND_SEED_NONE printf(" none"); #endif @@ -206,6 +223,14 @@ int version_main(int argc, char **argv) printf("\n"); #endif } +#ifndef OPENSSL_NO_GM + if (gm) { + printf("%s\n", OpenSSL_version(BABASSL_VERSION)); + printf("产品名称:BabaSSL IOS端软件密码模块\n"); + printf("型号:ANTGROUP-BabaSSL-MIOSC\n"); + printf("公司:蚂蚁科技集团股份有限公司\n"); + } +#endif ret = 0; end: return ret; diff --git a/apps/x509.c b/apps/x509.c index 9fd11d9f2..f6c1c3ebf 100644 --- a/apps/x509.c +++ b/apps/x509.c @@ -1128,15 +1128,6 @@ static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, const EVP_MD *digest, CONF *conf, const char *section, int preserve_dates, STACK_OF(OPENSSL_STRING) *sigopts) { -#ifndef OPENSSL_NO_SM2 - if (EVP_PKEY_is_sm2(pkey)) { - /* - * sm2 need to set sm2_id before sign, sm2_id should be set to - * EVP_PKEY_CTX, so use func do_X509_sign to do sm2 sign - */ - return do_X509_sign(x, pkey, digest, sigopts); - } -#endif if (!X509_set_issuer_name(x, X509_get_subject_name(x))) goto err; if (!preserve_dates && !set_cert_times(x, NULL, NULL, days)) @@ -1155,6 +1146,15 @@ static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, if (!X509V3_EXT_add_nconf(conf, &ctx, section, x)) goto err; } +#ifndef OPENSSL_NO_SM2 + if (EVP_PKEY_is_sm2(pkey)) { + /* + * sm2 need to set sm2_id before sign, sm2_id should be set to + * EVP_PKEY_CTX, so use func do_X509_sign to do sm2 sign + */ + return do_X509_sign(x, pkey, digest, sigopts); + } +#endif if (!X509_sign(x, pkey, digest)) goto err; return 1; diff --git a/crypto/ec/curve448/field.h b/crypto/ec/curve448/field.h index ccd04482d..4ce263d43 100644 --- a/crypto/ec/curve448/field.h +++ b/crypto/ec/curve448/field.h @@ -62,7 +62,7 @@ mask_t gf_eq(const gf x, const gf y); mask_t gf_lobit(const gf x); mask_t gf_hibit(const gf x); -void gf_serialize(uint8_t *serial, const gf x, int with_highbit); +void gf_serialize(uint8_t serial[SER_BYTES], const gf x, int with_highbit); mask_t gf_deserialize(gf x, const uint8_t serial[SER_BYTES], int with_hibit, uint8_t hi_nmask); diff --git a/crypto/init.c b/crypto/init.c index 1b0d523be..361915ad5 100644 --- a/crypto/init.c +++ b/crypto/init.c @@ -849,3 +849,15 @@ void OPENSSL_fork_child(void) { } #endif + +#ifndef OPENSSL_NO_GM +const char *OPENSSL_get_default_passwd_file(void) +{ + return OPENSSLDIR "/passwd.cnf"; +} + +const char *OPENSSL_get_default_signature_file(void) +{ + return OPENSSLDIR "/signature.bin"; +} +#endif \ No newline at end of file diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c index 40e9530b6..ed63f4322 100644 --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -210,6 +210,33 @@ size_t rand_drbg_get_entropy(RAND_DRBG *drbg, entropy_available = rand_pool_acquire_entropy(pool); } +#ifndef OPENSSL_NO_GM + /* + * continuous health test + * Adaptive Proportion Test (see GM/T 0105-2021 D.3) + */ + const unsigned char *buf = rand_pool_buffer(pool); + size_t len = rand_pool_length(pool); + int w = 1024 / 8, max = 690, cnt; + size_t i, j; + unsigned char sample; + + for (i = 0; i < len; i++) { + if (i % w == 0) { + sample = buf[i] & 0x01; + cnt = -1; + } + + for (j = 0; j < 8; j++) { + if (sample == ((buf[i] >> j) & 0x01)) { + cnt++; + + if (cnt >= max) + goto err; + } + } + } +#endif if (entropy_available > 0) { ret = rand_pool_length(pool); *pout = rand_pool_detach(pool); diff --git a/crypto/rand/rand_self_test.c b/crypto/rand/rand_self_test.c new file mode 100644 index 000000000..3cb54fb4e --- /dev/null +++ b/crypto/rand/rand_self_test.c @@ -0,0 +1,1911 @@ +/* + * Copyright 2022 The Tongsuo Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://github.com/Tongsuo-Project/Tongsuo/blob/master/LICENSE.txt + */ + +#include +#include +#include +#include +#include +#include "crypto/rand.h" + +#define MATRIX_FORWARD_ELIMINATION 0 +#define MATRIX_BACKWARD_ELIMINATION 1 + +/* SIGNIFICANCE LEVEL */ +static double alpha = 0.01; + +static double MACHEP = 1.11022302462515654042E-16; // 2**-53 +static double MAXLOG = 7.09782712893383996732224E2; // log(MAXNUM) +static double MAXNUM = 1.7976931348623158E308; // 2**1024*(1-MACHEP) +static double PI = 3.14159265358979323846; // pi, duh! + +static double big = 4.503599627370496e15; +static double biginv = 2.22044604925031308085e-16; + +static double cephes_igam(double a, double x); +static double cephes_igamc(double a, double x); +static double cephes_lgam(double x); +static double cephes_polevl(double x, double *coef, int N); +static double cephes_p1evl(double x, double *coef, int N); +static double psi2(const unsigned char *buf, size_t m, size_t n); +static int get_bit(const unsigned char *buf, int m); +static void set_bit(unsigned char *buf, int m, int bit); +static int compute_rank(int M, int Q, unsigned char **matrix); +static void perform_elementary_row_operations(int flag, int i, int M, int Q, + unsigned char **A); +static int find_unit_element_and_swap(int flag, int i, int M, int Q, + unsigned char **A); +static int determine_rank(int m, int M, int Q, unsigned char **A); +static double cephes_normal(double x); +static int swap_rows(int i, int index, int Q, unsigned char **A); +static void dradf4(int ido, int l1, double *cc, double *ch, double *wa1, + double *wa2, double *wa3); +static void dradf2(int ido, int l1, double *cc, double *ch, double *wa1); +static void dradfg(int ido, int ip, int l1, int idl1, double *cc, double *c1, + double *c2, double *ch, double *ch2, double *wa); + +static double cephes_normal(double x) +{ + double arg, result, sqrt2 = 1.414213562373095048801688724209698078569672; + + if (x > 0) { + arg = x / sqrt2; + result = 0.5 * (1 + erf(arg)); + } else { + arg = -x / sqrt2; + result = 0.5 * (1 - erf(arg)); + } + + return (result); +} + +static int compute_rank(int M, int Q, unsigned char **matrix) +{ + int i, rank, m = M < Q ? M : Q; + + /* FORWARD APPLICATION OF ELEMENTARY ROW OPERATIONS */ + for (i = 0; i < m - 1; i++) { + if (get_bit(matrix[i], i) == 1) + perform_elementary_row_operations(MATRIX_FORWARD_ELIMINATION, i, M, + Q, matrix); + else { /* matrix[i][i] = 0 */ + if (find_unit_element_and_swap(MATRIX_FORWARD_ELIMINATION, i, M, Q, + matrix) + == 1) + perform_elementary_row_operations(MATRIX_FORWARD_ELIMINATION, i, + M, Q, matrix); + } + } + + /* BACKWARD APPLICATION OF ELEMENTARY ROW OPERATIONS */ + for (i = m - 1; i > 0; i--) { + if (get_bit(matrix[i], i) == 1) + perform_elementary_row_operations(MATRIX_BACKWARD_ELIMINATION, i, M, + Q, matrix); + else { /* matrix[i][i] = 0 */ + if (find_unit_element_and_swap(MATRIX_BACKWARD_ELIMINATION, i, M, Q, + matrix) + == 1) + perform_elementary_row_operations(MATRIX_BACKWARD_ELIMINATION, + i, M, Q, matrix); + } + } + + rank = determine_rank(m, M, Q, matrix); + + return rank; +} + +static void perform_elementary_row_operations(int flag, int i, int M, int Q, + unsigned char **A) +{ + int j, k; + + if (flag == MATRIX_FORWARD_ELIMINATION) { + for (j = i + 1; j < M; j++) + if (get_bit(A[j], i) == 1) + for (k = i; k < Q; k++) + /* A[j][k] = (A[j][k] + A[i][k]) % 2 */ + set_bit(A[j], k, (get_bit(A[j], k) + get_bit(A[i], k)) % 2); + } else { + for (j = i - 1; j >= 0; j--) + if (get_bit(A[j], i) == 1) + for (k = 0; k < Q; k++) + /* A[j][k] = (A[j][k] + A[i][k]) % 2 */ + set_bit(A[j], k, (get_bit(A[j], k) + get_bit(A[i], k)) % 2); + } +} + +static int find_unit_element_and_swap(int flag, int i, int M, int Q, + unsigned char **A) +{ + int index, row_op = 0; + + if (flag == MATRIX_FORWARD_ELIMINATION) { + index = i + 1; + while ((index < M) && (get_bit(A[index], i) == 0)) + index++; + if (index < M) + row_op = swap_rows(i, index, Q, A); + } else { + index = i - 1; + while ((index >= 0) && (get_bit(A[index], i) == 0)) + index--; + if (index >= 0) + row_op = swap_rows(i, index, Q, A); + } + + return row_op; +} + +static int swap_rows(int i, int index, int Q, unsigned char **A) +{ + int p; + unsigned char temp; + + for (p = 0; p < Q; p++) { + temp = get_bit(A[i], p); + set_bit(A[i], p, get_bit(A[index], p)); + set_bit(A[index], p, temp); + } + + return 1; +} + +/* DETERMINE RANK, THAT IS, COUNT THE NUMBER OF NONZERO ROWS */ +static int determine_rank(int m, int M, int Q, unsigned char **A) +{ + int i, j, rank, allZeroes; + + rank = m; + for (i = 0; i < M; i++) { + allZeroes = 1; + for (j = 0; j < Q; j++) { + if (get_bit(A[i], j) == 1) { + allZeroes = 0; + break; + } + } + if (allZeroes == 1) + rank--; + } + + return rank; +} + +static void set_bit(unsigned char *buf, int m, int bit) +{ + if (m < 0) + return; + + if (bit) + buf[m / 8] |= 0x80 >> (m % 8); + else + buf[m / 8] &= ~(0x80 >> (m % 8)); +} + +static int get_bit(const unsigned char *buf, int m) +{ + if (m < 0) + return 0; + + return (buf[m / 8] << (m % 8) >> 7) & 1; +} + +static double cephes_igamc(double a, double x) +{ + double ans, ax, c, yc, r, t, y, z; + double pk, pkm1, pkm2, qk, qkm1, qkm2; + + if (x <= 0 || a <= 0) + return 1.0; + + if (x < 1.0 || x < a) + return 1.e0 - cephes_igam(a, x); + + ax = a * log(x) - x - cephes_lgam(a); + + if (ax < -MAXLOG) { + /* igamc: UNDERFLOW */ + return 0.0; + } + ax = exp(ax); + + /* continued fraction */ + y = 1.0 - a; + z = x + y + 1.0; + c = 0.0; + pkm2 = 1.0; + qkm2 = x; + pkm1 = x + 1.0; + qkm1 = z * x; + ans = pkm1 / qkm1; + + do { + c += 1.0; + y += 1.0; + z += 2.0; + yc = y * c; + pk = pkm1 * z - pkm2 * yc; + qk = qkm1 * z - qkm2 * yc; + if (qk != 0) { + r = pk / qk; + t = fabs((ans - r) / r); + ans = r; + } else + t = 1.0; + pkm2 = pkm1; + pkm1 = pk; + qkm2 = qkm1; + qkm1 = qk; + if (fabs(pk) > big) { + pkm2 *= biginv; + pkm1 *= biginv; + qkm2 *= biginv; + qkm1 *= biginv; + } + } while (t > MACHEP); + + return ans * ax; +} + +static double cephes_igam(double a, double x) +{ + double ans, ax, c, r; + + if ((x <= 0) || (a <= 0)) + return 0.0; + + if ((x > 1.0) && (x > a)) + return 1.e0 - cephes_igamc(a, x); + + /* Compute x**a * exp(-x) / gamma(a) */ + ax = a * log(x) - x - cephes_lgam(a); + if (ax < -MAXLOG) { + /* igam: UNDERFLOW */ + return 0.0; + } + ax = exp(ax); + + /* power series */ + r = a; + c = 1.0; + ans = 1.0; + + do { + r += 1.0; + c *= x / r; + ans += c; + } while (c / ans > MACHEP); + + return ans * ax / a; +} + +/* Logarithm of gamma function */ +static double cephes_lgam(double x) +{ +#define MAXLGM 2.556348e305 + /* A[]: Stirling's formula expansion of log gamma + * B[], C[]: log gamma function between 2 and 3 + */ + unsigned short A[] = {0x6661, 0x2733, 0x9850, 0x3f4a, 0xe943, + 0xb580, 0x7fbd, 0xbf43, 0x5ebb, 0x20dc, + 0x019f, 0x3f4a, 0xa5a1, 0x16b0, 0xc16c, + 0xbf66, 0x554b, 0x5555, 0x5555, 0x3fb5}; + unsigned short B[] = {0x6761, 0x8ff3, 0x8901, 0xc095, 0xb93e, 0x355b, + 0xf234, 0xc0e2, 0x89e5, 0xf890, 0x3d73, 0xc114, + 0xdb51, 0xf994, 0xbc82, 0xc131, 0xf20b, 0x0219, + 0x4589, 0xc13a, 0x055e, 0x5418, 0x0c67, 0xc12a}; + static unsigned short C[] = { + /*0x0000,0x0000,0x0000,0x3ff0,*/ + 0x12b2, 0x1cf3, 0xfd0d, 0xc075, 0xd757, 0x7b89, 0xaa0d, 0xc0d0, + 0x4c9b, 0xb974, 0xeb84, 0xc10a, 0x0043, 0x7195, 0x6286, 0xc131, + 0xf34c, 0x892f, 0x5255, 0xc143, 0xe14a, 0x6a11, 0xce4b, 0xc13e}; + double p, q, u, w, z; + int i; + int sgngam = 1; + + if (x < -34.0) { + q = -x; + w = cephes_lgam(q); + p = floor(q); + if (p == q) { + lgsing: + goto loverf; + } + i = (int)p; + if ((i & 1) == 0) + sgngam = -1; + else + sgngam = 1; + z = q - p; + if (z > 0.5) { + p += 1.0; + z = p - q; + } + z = q * sin(PI * z); + if (z == 0.0) + goto lgsing; + + z = log(PI) - log(z) - w; + return z; + } + + if (x < 13.0) { + z = 1.0; + p = 0.0; + u = x; + while (u >= 3.0) { + p -= 1.0; + u = x + p; + z *= u; + } + while (u < 2.0) { + if (u == 0.0) + goto lgsing; + z /= u; + p += 1.0; + u = x + p; + } + if (z < 0.0) { + sgngam = -1; + z = -z; + } else + sgngam = 1; + if (u == 2.0) + return (log(z)); + p -= 2.0; + x = x + p; + p = x * cephes_polevl(x, (double *)B, 5) + / cephes_p1evl(x, (double *)C, 6); + + return log(z) + p; + } + + if (x > MAXLGM) { + loverf: + /* lgam: OVERFLOW */ + return sgngam * MAXNUM; + } + + q = (x - 0.5) * log(x) - x + log(sqrt(2 * PI)); + if (x > 1.0e8) + return q; + + p = 1.0 / (x * x); + if (x >= 1000.0) + q += + ((7.9365079365079365079365e-4 * p - 2.7777777777777777777778e-3) * p + + 0.0833333333333333333333) + / x; + else + q += cephes_polevl(p, (double *)A, 4) / x; + + return q; +} + +static double cephes_polevl(double x, double *coef, int N) +{ + double ans; + int i; + double *p; + + p = coef; + ans = *p++; + i = N; + + do { + ans = ans * x + *p++; + } while (--i); + + return ans; +} + +static double cephes_p1evl(double x, double *coef, int N) +{ + double ans; + double *p; + int i; + + p = coef; + ans = x + *p++; + i = N - 1; + + do { + ans = ans * x + *p++; + } while (--i); + + return ans; +} + +static double psi2(const unsigned char *buf, size_t m, size_t n) +{ + size_t i, j, k, pow_len; + double sum; + unsigned int *P; + + if (m == 0) + return 0.0; + + pow_len = (size_t)pow(2, m + 1) - 1; + + if ((P = OPENSSL_zalloc(pow_len * sizeof(size_t))) == NULL) + return 0.0; + + for (i = 1; i < pow_len - 1; i++) + P[i] = 0; + for (i = 0; i < n; i++) { + k = 1; + for (j = 0; j < m; j++) { + int bit = get_bit(buf, (i + j) % n); + if (bit == 0) + k *= 2; + else + k = 2 * k + 1; + } + P[k - 1]++; + } + sum = 0.0; + for (i = (size_t)pow(2, m) - 1; i < (size_t)pow(2, m + 1) - 1; i++) + sum += pow(P[i], 2); + sum = (sum * pow(2, m) / (double)n) - (double)n; + + OPENSSL_free(P); + + return sum; +} + +static void drfti1(int n, double *wa, int *ifac) +{ + static int ntryh[4] = {4, 2, 3, 5}; + static double tpi = 6.28318530717958647692528676655900577; + double arg, argh, argld, fi; + int ntry = 0, i, j = -1; + int k1, l1, l2, ib; + int ld, ii, ip, is, nq, nr; + int ido, ipm, nfm1; + int nl = n; + int nf = 0; + +L101: + j++; + if (j < 4) + ntry = ntryh[j]; + else + ntry += 2; + +L104: + nq = nl / ntry; + nr = nl - ntry * nq; + if (nr != 0) + goto L101; + + nf++; + ifac[nf + 1] = ntry; + nl = nq; + if (ntry != 2) + goto L107; + if (nf == 1) + goto L107; + + for (i = 1; i < nf; i++) { + ib = nf - i + 1; + ifac[ib + 1] = ifac[ib]; + } + ifac[2] = 2; + +L107: + if (nl != 1) + goto L104; + ifac[0] = n; + ifac[1] = nf; + argh = tpi / n; + is = 0; + nfm1 = nf - 1; + l1 = 1; + + if (nfm1 == 0) + return; + + for (k1 = 0; k1 < nfm1; k1++) { + ip = ifac[k1 + 2]; + ld = 0; + l2 = l1 * ip; + ido = n / l2; + ipm = ip - 1; + + for (j = 0; j < ipm; j++) { + ld += l1; + i = is; + argld = (double)ld * argh; + fi = 0.0; + for (ii = 2; ii < ido; ii += 2) { + fi += 1.0; + arg = fi * argld; + wa[i++] = cos(arg); + wa[i++] = sin(arg); + } + is += ido; + } + l1 = l2; + } +} + +static void __ogg_fdrffti(int n, double *wsave, int *ifac) +{ + if (n == 1) + return; + drfti1(n, wsave + n, ifac); +} + +static void dradf2(int ido, int l1, double *cc, double *ch, double *wa1) +{ + int i, k; + double ti2, tr2; + int t0, t1, t2, t3, t4, t5, t6; + + t1 = 0; + t0 = (t2 = l1 * ido); + t3 = ido << 1; + for (k = 0; k < l1; k++) { + ch[t1 << 1] = cc[t1] + cc[t2]; + ch[(t1 << 1) + t3 - 1] = cc[t1] - cc[t2]; + t1 += ido; + t2 += ido; + } + + if (ido < 2) + return; + if (ido == 2) + goto L105; + + t1 = 0; + t2 = t0; + for (k = 0; k < l1; k++) { + t3 = t2; + t4 = (t1 << 1) + (ido << 1); + t5 = t1; + t6 = t1 + t1; + for (i = 2; i < ido; i += 2) { + t3 += 2; + t4 -= 2; + t5 += 2; + t6 += 2; + tr2 = wa1[i - 2] * cc[t3 - 1] + wa1[i - 1] * cc[t3]; + ti2 = wa1[i - 2] * cc[t3] - wa1[i - 1] * cc[t3 - 1]; + ch[t6] = cc[t5] + ti2; + ch[t4] = ti2 - cc[t5]; + ch[t6 - 1] = cc[t5 - 1] + tr2; + ch[t4 - 1] = cc[t5 - 1] - tr2; + } + t1 += ido; + t2 += ido; + } + + if (ido % 2 == 1) + return; + +L105: + t3 = (t2 = (t1 = ido) - 1); + t2 += t0; + for (k = 0; k < l1; k++) { + ch[t1] = -cc[t2]; + ch[t1 - 1] = cc[t3]; + t1 += ido << 1; + t2 += ido; + t3 += ido; + } +} + +static void dradf4(int ido, int l1, double *cc, double *ch, double *wa1, + double *wa2, double *wa3) +{ + static double hsqt2 = .70710678118654752440084436210485; + int i, k, t0, t1, t2, t3, t4, t5, t6; + double ci2, ci3, ci4, cr2, cr3, cr4; + double ti1, ti2, ti3, ti4, tr1, tr2, tr3, tr4; + + t0 = l1 * ido; + t1 = t0; + t4 = t1 << 1; + t2 = t1 + (t1 << 1); + t3 = 0; + + for (k = 0; k < l1; k++) { + tr1 = cc[t1] + cc[t2]; + tr2 = cc[t3] + cc[t4]; + ch[t5 = t3 << 2] = tr1 + tr2; + ch[(ido << 2) + t5 - 1] = tr2 - tr1; + ch[(t5 += (ido << 1)) - 1] = cc[t3] - cc[t4]; + ch[t5] = cc[t2] - cc[t1]; + + t1 += ido; + t2 += ido; + t3 += ido; + t4 += ido; + } + + if (ido < 2) + return; + if (ido == 2) + goto L105; + + t1 = 0; + for (k = 0; k < l1; k++) { + t2 = t1; + t4 = t1 << 2; + t5 = (t6 = ido << 1) + t4; + for (i = 2; i < ido; i += 2) { + t3 = (t2 += 2); + t4 += 2; + t5 -= 2; + + t3 += t0; + cr2 = wa1[i - 2] * cc[t3 - 1] + wa1[i - 1] * cc[t3]; + ci2 = wa1[i - 2] * cc[t3] - wa1[i - 1] * cc[t3 - 1]; + t3 += t0; + cr3 = wa2[i - 2] * cc[t3 - 1] + wa2[i - 1] * cc[t3]; + ci3 = wa2[i - 2] * cc[t3] - wa2[i - 1] * cc[t3 - 1]; + t3 += t0; + cr4 = wa3[i - 2] * cc[t3 - 1] + wa3[i - 1] * cc[t3]; + ci4 = wa3[i - 2] * cc[t3] - wa3[i - 1] * cc[t3 - 1]; + + tr1 = cr2 + cr4; + tr4 = cr4 - cr2; + ti1 = ci2 + ci4; + ti4 = ci2 - ci4; + ti2 = cc[t2] + ci3; + ti3 = cc[t2] - ci3; + tr2 = cc[t2 - 1] + cr3; + tr3 = cc[t2 - 1] - cr3; + + ch[t4 - 1] = tr1 + tr2; + ch[t4] = ti1 + ti2; + + ch[t5 - 1] = tr3 - ti4; + ch[t5] = tr4 - ti3; + + ch[t4 + t6 - 1] = ti4 + tr3; + ch[t4 + t6] = tr4 + ti3; + + ch[t5 + t6 - 1] = tr2 - tr1; + ch[t5 + t6] = ti1 - ti2; + } + t1 += ido; + } + if (ido % 2 == 1) + return; + +L105: + + t2 = (t1 = t0 + ido - 1) + (t0 << 1); + t3 = ido << 2; + t4 = ido; + t5 = ido << 1; + t6 = ido; + + for (k = 0; k < l1; k++) { + ti1 = -hsqt2 * (cc[t1] + cc[t2]); + tr1 = hsqt2 * (cc[t1] - cc[t2]); + ch[t4 - 1] = tr1 + cc[t6 - 1]; + ch[t4 + t5 - 1] = cc[t6 - 1] - tr1; + ch[t4] = ti1 - cc[t1 + t0]; + ch[t4 + t5] = ti1 + cc[t1 + t0]; + t1 += ido; + t2 += ido; + t4 += t3; + t6 += ido; + } +} + +static void dradfg(int ido, int ip, int l1, int idl1, double *cc, double *c1, + double *c2, double *ch, double *ch2, double *wa) +{ + static double tpi = 6.28318530717958647692528676655900577; + int idij, ipph, i, j, k, l, ic, ik, is; + int t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10; + double dc2, ai1, ai2, ar1, ar2, ds2; + int nbd; + double dcp, arg, dsp, ar1h, ar2h; + int idp2, ipp2; + + arg = tpi / (double)ip; + dcp = cos(arg); + dsp = sin(arg); + ipph = (ip + 1) >> 1; + ipp2 = ip; + idp2 = ido; + nbd = (ido - 1) >> 1; + t0 = l1 * ido; + t10 = ip * ido; + + if (ido == 1) + goto L119; + for (ik = 0; ik < idl1; ik++) + ch2[ik] = c2[ik]; + + t1 = 0; + for (j = 1; j < ip; j++) { + t1 += t0; + t2 = t1; + for (k = 0; k < l1; k++) { + ch[t2] = c1[t2]; + t2 += ido; + } + } + + is = -ido; + t1 = 0; + if (nbd > l1) { + for (j = 1; j < ip; j++) { + t1 += t0; + is += ido; + t2 = -ido + t1; + for (k = 0; k < l1; k++) { + idij = is - 1; + t2 += ido; + t3 = t2; + for (i = 2; i < ido; i += 2) { + idij += 2; + t3 += 2; + ch[t3 - 1] = wa[idij - 1] * c1[t3 - 1] + wa[idij] * c1[t3]; + ch[t3] = wa[idij - 1] * c1[t3] - wa[idij] * c1[t3 - 1]; + } + } + } + } else { + for (j = 1; j < ip; j++) { + is += ido; + idij = is - 1; + t1 += t0; + t2 = t1; + for (i = 2; i < ido; i += 2) { + idij += 2; + t2 += 2; + t3 = t2; + for (k = 0; k < l1; k++) { + ch[t3 - 1] = wa[idij - 1] * c1[t3 - 1] + wa[idij] * c1[t3]; + ch[t3] = wa[idij - 1] * c1[t3] - wa[idij] * c1[t3 - 1]; + t3 += ido; + } + } + } + } + + t1 = 0; + t2 = ipp2 * t0; + if (nbd < l1) { + for (j = 1; j < ipph; j++) { + t1 += t0; + t2 -= t0; + t3 = t1; + t4 = t2; + for (i = 2; i < ido; i += 2) { + t3 += 2; + t4 += 2; + t5 = t3 - ido; + t6 = t4 - ido; + for (k = 0; k < l1; k++) { + t5 += ido; + t6 += ido; + c1[t5 - 1] = ch[t5 - 1] + ch[t6 - 1]; + c1[t6 - 1] = ch[t5] - ch[t6]; + c1[t5] = ch[t5] + ch[t6]; + c1[t6] = ch[t6 - 1] - ch[t5 - 1]; + } + } + } + } else { + for (j = 1; j < ipph; j++) { + t1 += t0; + t2 -= t0; + t3 = t1; + t4 = t2; + for (k = 0; k < l1; k++) { + t5 = t3; + t6 = t4; + for (i = 2; i < ido; i += 2) { + t5 += 2; + t6 += 2; + c1[t5 - 1] = ch[t5 - 1] + ch[t6 - 1]; + c1[t6 - 1] = ch[t5] - ch[t6]; + c1[t5] = ch[t5] + ch[t6]; + c1[t6] = ch[t6 - 1] - ch[t5 - 1]; + } + t3 += ido; + t4 += ido; + } + } + } + +L119: + for (ik = 0; ik < idl1; ik++) + c2[ik] = ch2[ik]; + + t1 = 0; + t2 = ipp2 * idl1; + for (j = 1; j < ipph; j++) { + t1 += t0; + t2 -= t0; + t3 = t1 - ido; + t4 = t2 - ido; + for (k = 0; k < l1; k++) { + t3 += ido; + t4 += ido; + c1[t3] = ch[t3] + ch[t4]; + c1[t4] = ch[t4] - ch[t3]; + } + } + + ar1 = 1.0; + ai1 = 0.0; + t1 = 0; + t2 = ipp2 * idl1; + t3 = (ip - 1) * idl1; + for (l = 1; l < ipph; l++) { + t1 += idl1; + t2 -= idl1; + ar1h = dcp * ar1 - dsp * ai1; + ai1 = dcp * ai1 + dsp * ar1; + ar1 = ar1h; + t4 = t1; + t5 = t2; + t6 = t3; + t7 = idl1; + + for (ik = 0; ik < idl1; ik++) { + ch2[t4++] = c2[ik] + ar1 * c2[t7++]; + ch2[t5++] = ai1 * c2[t6++]; + } + + dc2 = ar1; + ds2 = ai1; + ar2 = ar1; + ai2 = ai1; + + t4 = idl1; + t5 = (ipp2 - 1) * idl1; + for (j = 2; j < ipph; j++) { + t4 += idl1; + t5 -= idl1; + + ar2h = dc2 * ar2 - ds2 * ai2; + ai2 = dc2 * ai2 + ds2 * ar2; + ar2 = ar2h; + + t6 = t1; + t7 = t2; + t8 = t4; + t9 = t5; + for (ik = 0; ik < idl1; ik++) { + ch2[t6++] += ar2 * c2[t8++]; + ch2[t7++] += ai2 * c2[t9++]; + } + } + } + + t1 = 0; + for (j = 1; j < ipph; j++) { + t1 += idl1; + t2 = t1; + for (ik = 0; ik < idl1; ik++) + ch2[ik] += c2[t2++]; + } + + if (ido < l1) + goto L132; + + t1 = 0; + t2 = 0; + for (k = 0; k < l1; k++) { + t3 = t1; + t4 = t2; + for (i = 0; i < ido; i++) + cc[t4++] = ch[t3++]; + t1 += ido; + t2 += t10; + } + + goto L135; + +L132: + for (i = 0; i < ido; i++) { + t1 = i; + t2 = i; + for (k = 0; k < l1; k++) { + cc[t2] = ch[t1]; + t1 += ido; + t2 += t10; + } + } + +L135: + t1 = 0; + t2 = ido << 1; + t3 = 0; + t4 = ipp2 * t0; + for (j = 1; j < ipph; j++) { + + t1 += t2; + t3 += t0; + t4 -= t0; + + t5 = t1; + t6 = t3; + t7 = t4; + + for (k = 0; k < l1; k++) { + cc[t5 - 1] = ch[t6]; + cc[t5] = ch[t7]; + t5 += t10; + t6 += ido; + t7 += ido; + } + } + + if (ido == 1) + return; + if (nbd < l1) + goto L141; + + t1 = -ido; + t3 = 0; + t4 = 0; + t5 = ipp2 * t0; + for (j = 1; j < ipph; j++) { + t1 += t2; + t3 += t2; + t4 += t0; + t5 -= t0; + t6 = t1; + t7 = t3; + t8 = t4; + t9 = t5; + for (k = 0; k < l1; k++) { + for (i = 2; i < ido; i += 2) { + ic = idp2 - i; + cc[i + t7 - 1] = ch[i + t8 - 1] + ch[i + t9 - 1]; + cc[ic + t6 - 1] = ch[i + t8 - 1] - ch[i + t9 - 1]; + cc[i + t7] = ch[i + t8] + ch[i + t9]; + cc[ic + t6] = ch[i + t9] - ch[i + t8]; + } + t6 += t10; + t7 += t10; + t8 += ido; + t9 += ido; + } + } + return; + +L141: + + t1 = -ido; + t3 = 0; + t4 = 0; + t5 = ipp2 * t0; + for (j = 1; j < ipph; j++) { + t1 += t2; + t3 += t2; + t4 += t0; + t5 -= t0; + for (i = 2; i < ido; i += 2) { + t6 = idp2 + t1 - i; + t7 = i + t3; + t8 = i + t4; + t9 = i + t5; + for (k = 0; k < l1; k++) { + cc[t7 - 1] = ch[t8 - 1] + ch[t9 - 1]; + cc[t6 - 1] = ch[t8 - 1] - ch[t9 - 1]; + cc[t7] = ch[t8] + ch[t9]; + cc[t6] = ch[t9] - ch[t8]; + t6 += t10; + t7 += t10; + t8 += ido; + t9 += ido; + } + } + } +} + +static void drftf1(int n, double *c, double *ch, double *wa, int *ifac) +{ + int i, k1, l1, l2; + int na, kh, nf; + int ip, iw, ido, idl1, ix2, ix3; + + nf = ifac[1]; + na = 1; + l2 = n; + iw = n; + + for (k1 = 0; k1 < nf; k1++) { + kh = nf - k1; + ip = ifac[kh + 1]; + l1 = l2 / ip; + ido = n / l2; + idl1 = ido * l1; + iw -= (ip - 1) * ido; + na = 1 - na; + + if (ip != 4) + goto L102; + + ix2 = iw + ido; + ix3 = ix2 + ido; + if (na != 0) + dradf4(ido, l1, ch, c, wa + iw - 1, wa + ix2 - 1, wa + ix3 - 1); + else + dradf4(ido, l1, c, ch, wa + iw - 1, wa + ix2 - 1, wa + ix3 - 1); + goto L110; + + L102: + if (ip != 2) + goto L104; + if (na != 0) + goto L103; + + dradf2(ido, l1, c, ch, wa + iw - 1); + goto L110; + + L103: + dradf2(ido, l1, ch, c, wa + iw - 1); + goto L110; + + L104: + if (ido == 1) + na = 1 - na; + if (na != 0) + goto L109; + + dradfg(ido, ip, l1, idl1, c, c, c, ch, ch, wa + iw - 1); + na = 1; + goto L110; + + L109: + dradfg(ido, ip, l1, idl1, ch, ch, ch, c, c, wa + iw - 1); + na = 0; + + L110: + l2 = l1; + } + + if (na == 1) + return; + + for (i = 0; i < n; i++) + c[i] = ch[i]; +} + +static void __ogg_fdrfftf(int n, double *r, double *wsave, int *ifac) +{ + if (n == 1) + return; + drftf1(n, r, wsave, wsave + n, ifac); +} + +/* + * 单比特频数检测, Frequency (Monobit) Test + */ +int rand_self_test_frequency(const unsigned char *buf, size_t nbit, double *P_value) +{ + size_t i, n = nbit; + double sum = 0; + double p_value; + + for (i = 0; i < n; i++) + sum += 2 * get_bit(buf, i) - 1; + + p_value = erfc(fabs(sum) / sqrt(n) / sqrt(2.0)); + + if (P_value) + *P_value = p_value; + + return p_value >= alpha; +} + +/* + * 块内频数检测, Frequency Test within a Block + */ +int rand_self_test_block_frequency(const unsigned char *buf, size_t nbit, + size_t m, double *P_value) +{ + size_t i, j, N, block_sum; + double p_value, sum, pi, V; + + N = nbit / m; + sum = 0.0; + + for (i = 0; i < N; i++) { + block_sum = 0; + for (j = 0; j < m; j++) + block_sum += get_bit(buf, i * m + j); + + pi = (double)block_sum / m; + sum += pow(pi - 0.5, 2); + } + + V = 4.0 * m * sum; + p_value = cephes_igamc(N / 2.0, V / 2.0); + + if (P_value) + *P_value = p_value; + + return p_value >= alpha; +} + +/* + * 扑克检测 + */ +int rand_self_test_poker(const unsigned char *buf, size_t nbit, size_t m, + double *P_value) +{ + size_t i, j, n = nbit, N, block_sum; + double p_value, sum = 0.0, V; + size_t *F = NULL; + + if (m != 4 && m != 8) + return 0; + + N = n / m; + + F = OPENSSL_zalloc((size_t)pow(2, m) * sizeof(size_t)); + if (F == NULL) + return 0; + + for (i = 0; i < N; i++) { + if (m == 8) + block_sum = (unsigned int)buf[i]; + else { + block_sum = 0; + for (j = 0; j < m; j++) + block_sum = (block_sum << 1) | get_bit(buf, i * m + j); + } + F[block_sum]++; + } + + for (i = 0; i < (size_t)pow(2, m); i++) + sum += F[i] * F[i]; + + V = pow(2, m) / N * sum - N; + + p_value = cephes_igamc((pow(2, m) - 1) / 2.0, V / 2.0); + if (P_value) + *P_value = p_value; + + OPENSSL_free(F); + return p_value >= alpha; +} + +/* + * 重叠子序列检测, Serial Test + */ +int rand_self_test_serial(const unsigned char *buf, size_t nbit, size_t m, + double *P1, double *P2) +{ + double p_value1, p_value2, psim0, psim1, psim2, del1, del2; + + psim0 = psi2(buf, m, nbit); + psim1 = psi2(buf, m - 1, nbit); + psim2 = psi2(buf, m - 2, nbit); + del1 = psim0 - psim1; + del2 = psim0 - 2.0 * psim1 + psim2; + p_value1 = cephes_igamc(pow(2, m - 1) / 2, del1 / 2.0); + p_value2 = cephes_igamc(pow(2, m - 2) / 2, del2 / 2.0); + + if (P1) + *P1 = p_value1; + if (P2) + *P2 = p_value2; + + return p_value1 >= alpha && p_value2 >= alpha; +} + +/* + * 游程总数检测, Runs Test + */ +int rand_self_test_runs(const unsigned char *buf, size_t nbit, double *P) +{ + size_t n = nbit, S = 0, k; + double pi, Vn, V, p_value; + + for (k = 0; k < n; k++) + if (get_bit(buf, k)) + S++; + + pi = (double)S / (double)n; + Vn = 1; + for (k = 1; k < n; k++) + if (get_bit(buf, k) != get_bit(buf, k - 1)) + Vn++; + + V = (Vn - 2.0 * n * pi * (1 - pi)) / (2.0 * pi * (1 - pi) * sqrt(n)); + p_value = erfc(fabs(V) / sqrt(2.0)); + + if (P) + *P = p_value; + + return p_value >= alpha; +} + +/* + * 游程分布检测 + */ +int rand_self_test_runs_distribution(const unsigned char *buf, size_t nbit, double *P) +{ + size_t n = nbit, i, k = 0, cnt, T = 0; + int cur, last; + size_t *B = NULL, *G = NULL; + double p_value, V = 0.0, e; + + for (i = 1; i <= n; i++) + if ((n - i + 3) / pow(2, i + 2) >= 5) + k = i; + + if ((B = OPENSSL_zalloc(k * sizeof(size_t))) == NULL + || (G = OPENSSL_zalloc(k * sizeof(size_t))) == NULL) { + if (B != NULL) + OPENSSL_free(B); + if (G != NULL) + OPENSSL_free(G); + + return 0; + } + + last = get_bit(buf, 0); + cnt = 1; + + for (i = 1; i < n; i++) { + cur = get_bit(buf, i); + + if (cur == last) { + cnt++; + } else { + if (cnt > k) + cnt = k; + + T++; + if (last == 1) + B[cnt - 1]++; + else + G[cnt - 1]++; + + cnt = 1; + } + + last = cur; + } + + if (cnt > k) + cnt = k; + + T++; + if (last == 1) + B[cnt - 1]++; + else + G[cnt - 1]++; + + for (i = 0; i < k; i++) { + if (i != k - 1) + e = T / pow(2, i + 2); + else + e = T / pow(2, k); + V += (pow(B[i] - e, 2) + pow(G[i] - e, 2)) / e; + } + + p_value = cephes_igamc(k - 1, V / 2.0); + + OPENSSL_free(B); + OPENSSL_free(G); + + if (P) + *P = p_value; + + return p_value >= alpha; +} + +/* + * 块内最大1游程检测, Test for the Longest Run of Ones in a Block + */ +int rand_self_test_longest_run_of_ones(const unsigned char *buf, size_t nbit, double *P) +{ + double pval, chi2, pi[7]; + int run, v_n_obs, V[7]; + size_t n = nbit, N, M, i, j, K; + unsigned int nu[7] = {0, 0, 0, 0, 0, 0, 0}; + + /* n is too short */ + if (n < 128) + return 0; + + if (n < 6272) { + K = 3; + M = 8; + V[0] = 1; + V[1] = 2; + V[2] = 3; + V[3] = 4; + pi[0] = 0.2148; + pi[1] = 0.3672; + pi[2] = 0.2305; + pi[3] = 0.1875; + } else if (n < 750000) { + K = 5; + M = 128; + V[0] = 4; + V[1] = 5; + V[2] = 6; + V[3] = 7; + V[4] = 8; + V[5] = 9; + pi[0] = 0.1174; + pi[1] = 0.2430; + pi[2] = 0.2494; + pi[3] = 0.1752; + pi[4] = 0.1027; + pi[5] = 0.1124; + } else { + K = 6; + M = 10000; + V[0] = 10; + V[1] = 11; + V[2] = 12; + V[3] = 13; + V[4] = 14; + V[5] = 15; + V[6] = 16; + pi[0] = 0.086632; + pi[1] = 0.208201; + pi[2] = 0.248419; + pi[3] = 0.193913; + pi[4] = 0.121458; + pi[5] = 0.068011; + pi[6] = 0.073366; + } + + N = n / M; + for (i = 0; i < N; i++) { + v_n_obs = 0; + run = 0; + for (j = 0; j < M; j++) { + if (get_bit(buf, i * M + j) == 1) { + run++; + if (run > v_n_obs) + v_n_obs = run; + } else + run = 0; + } + if (v_n_obs < V[0]) + nu[0]++; + for (j = 0; j <= K; j++) { + if (v_n_obs == V[j]) + nu[j]++; + } + if (v_n_obs > V[K]) + nu[K]++; + } + + chi2 = 0.0; + for (i = 0; i <= K; i++) + chi2 += ((nu[i] - N * pi[i]) * (nu[i] - N * pi[i])) / (N * pi[i]); + + pval = cephes_igamc((double)(K / 2.0), chi2 / 2.0); + if (P) + *P = pval; + + return pval >= alpha; +} + +/* + * 二元推导检测 + */ +int rand_self_test_binary_derivation(const unsigned char *buf, size_t nbit, + size_t k, double *P) +{ + size_t n = nbit, i, j; + double sum = 0; + unsigned char *buf1 = NULL, *buf2 = NULL, *tmp; + double p_value, V; + + if ((buf1 = OPENSSL_malloc((n + 7) / 8)) == NULL + || (buf2 = OPENSSL_malloc((n + 7) / 8)) == NULL) { + if (buf1 != NULL) + OPENSSL_free(buf1); + if (buf2 != NULL) + OPENSSL_free(buf2); + + return 0; + } + + memcpy(buf1, buf, (n + 7) / 8); + + for (i = 1; i <= k; i++) { + for (j = 0; j < n - i; j++) { + int b = get_bit(buf1, j) ^ get_bit(buf1, j + 1); + set_bit(buf2, j, b); + + if (i == k) + sum += 2 * b - 1; + } + + tmp = buf1; + buf1 = buf2; + buf2 = tmp; + } + + OPENSSL_free(buf1); + OPENSSL_free(buf2); + + V = fabs(sum) / sqrt(n - k); + + p_value = erfc(V / sqrt(2.0)); + if (P) + *P = p_value; + + return p_value >= alpha; +} + +/* + * 自相关检测 + */ +int rand_self_test_self_correlation(const unsigned char *buf, size_t nbit, + size_t d, double *P) +{ + size_t n = nbit, i, A = 0; + double p_value, V; + + if (d < 1 || d > n / 2 || d + 10 >= n) + return 0; + + for (i = 0; i < n - d; i++) + A += get_bit(buf, i) ^ get_bit(buf, i + d); + + V = 2.0 * (A - (n - d) / 2.0) / sqrt(n - d); + p_value = erfc(fabs(V) / sqrt(2.0)); + + if (P) + *P = p_value; + + return p_value >= alpha; +} + +/* + * 矩阵秩检测, Binary Matrix Rank Test + */ +int rand_self_test_binary_matrix_rank(const unsigned char *buf, size_t nbit, + double *P) +{ + int R, F_32 = 0, F_31 = 0; + size_t n = nbit, N, i, j; + double V, p_value; + unsigned char *matrix[32]; + unsigned char m[32][4]; + + for (i = 0; i < 32; i++) + matrix[i] = (unsigned char *)&m[i]; + + N = n / (32 * 32); + if (N == 0) { + p_value = 0.00; + } else { + for (i = 0; i < N; i++) { + + for (j = 0; j < 32; j++) + memcpy(matrix[j], buf + i * 32 * 4 + j * 4, 4); + + R = compute_rank(32, 32, (unsigned char **)matrix); + if (R == 32) + F_32++; + if (R == 31) + F_31++; + } + + V = pow(F_32 - 0.2888 * N, 2) / 0.2888 + + pow(F_31 - 0.5776 * N, 2) / 0.5776 + + pow(N - F_32 - F_31 - 0.1336 * N, 2) / 0.1336; + V = V / N; + + p_value = cephes_igamc(1, V / 2.0); + } + + if (P) + *P = p_value; + + return p_value >= alpha; +} + +/* + * 累加和检测, Cumulative Sums Test + * P1, 前向检测结果 + * P2, 后向检测结果 + */ +int rand_self_test_cumulative_sums(const unsigned char *buf, size_t nbit, + double *P1, double *P2) +{ + size_t n = nbit, i; + ssize_t S, k, sup, inf, z = 0, zrev = 0; + double sum1, sum2, p_value; + + S = 0; + sup = 0; + inf = 0; + for (i = 0; i < n; i++) { + get_bit(buf, i) ? S++ : S--; + if (S > sup) + sup++; + if (S < inf) + inf--; + z = (sup > -inf) ? sup : -inf; + zrev = (sup - S > S - inf) ? sup - S : S - inf; + } + + /* forward */ + sum1 = 0.0; + for (k = ((ssize_t)-n / z + 1) / 4; k <= (ssize_t)(n / z - 1) / 4; k++) { + sum1 += cephes_normal(((4 * k + 1) * z) / sqrt(n)); + sum1 -= cephes_normal(((4 * k - 1) * z) / sqrt(n)); + } + sum2 = 0.0; + for (k = ((ssize_t)-n / z - 3) / 4; k <= (ssize_t)(n / z - 1) / 4; k++) { + sum2 += cephes_normal(((4 * k + 3) * z) / sqrt(n)); + sum2 -= cephes_normal(((4 * k + 1) * z) / sqrt(n)); + } + + p_value = 1.0 - sum1 + sum2; + + if (P1) + *P1 = p_value; + + if (p_value < alpha) + return 0; + + /* backwards */ + sum1 = 0.0; + for (k = ((ssize_t)-n / zrev + 1) / 4;k <= (ssize_t)(n / zrev - 1) / 4; k++) + { + sum1 += cephes_normal(((4 * k + 1) * zrev) / sqrt(n)); + sum1 -= cephes_normal(((4 * k - 1) * zrev) / sqrt(n)); + } + sum2 = 0.0; + for (k = ((ssize_t)-n / zrev - 3) / 4; k <= (ssize_t)(n / zrev - 1) / 4; + k++) + { + sum2 += cephes_normal(((4 * k + 3) * zrev) / sqrt(n)); + sum2 -= cephes_normal(((4 * k + 1) * zrev) / sqrt(n)); + } + p_value = 1.0 - sum1 + sum2; + + if (P2) + *P2 = p_value; + + if (p_value < alpha) + return 0; + + return 1; +} + +/* + * 近似熵检测, Approximate Entropy Test + */ +int rand_self_test_approximate_entropy(const unsigned char *buf, size_t nbit, + size_t m, double *P) +{ + size_t block; + size_t n, i, j, k, r; + double sum, ApEn[2], apen, V, p_value; + size_t *C; + + n = nbit; + r = 0; + + for (block = m; block <= m + 1; block++) { + if (block == 0) { + ApEn[0] = 0.00; + r++; + } else { + if ((C = (size_t *)OPENSSL_zalloc(pow(2, block) * sizeof(size_t))) + == NULL) + return 0; + + for (i = 0; i < nbit; i++) { + k = 0; + for (j = 0; j < block; j++) { + k <<= 1; + if (get_bit(buf, (i + j) % n) == 1) + k++; + } + C[k]++; + } + + sum = 0.0; + for (i = 0; i < (size_t)pow(2, block); i++) { + if (C[i] > 0) + sum += C[i] * log((double)C[i] / n); + } + ApEn[r] = sum / n; + r++; + OPENSSL_free(C); + } + } + + apen = ApEn[0] - ApEn[1]; + V = 2.0 * n * (log(2) - apen); + p_value = cephes_igamc(pow(2, m - 1), V / 2.0); + + if (P) + *P = p_value; + + return p_value >= alpha; +} + +/* + * 线性复杂度检测, Linear Complexity Test + */ +int rand_self_test_linear_complexity(const unsigned char *buf, size_t nbit, + size_t M, double *P_value) +{ + size_t n = nbit, i, ii, j, d, N, L, N_, parity, K = 6; + int m, sign; + double p_value, T_, mean, nu[7], V = 0.0; + double pi[7] = {0.010417, 0.031250, 0.125, 0.500, + 0.250, 0.062500, 0.020833}; + size_t *T = NULL, *P = NULL, *B_ = NULL, *C = NULL; + + N = n / M; + if (((B_ = OPENSSL_malloc(M * sizeof(size_t))) == NULL) + || ((C = OPENSSL_malloc(M * sizeof(size_t))) == NULL) + || ((P = OPENSSL_malloc(M * sizeof(size_t))) == NULL) + || ((T = OPENSSL_malloc(M * sizeof(size_t))) == NULL)) { + if (B_ != NULL) + OPENSSL_free(B_); + if (C != NULL) + OPENSSL_free(C); + if (P != NULL) + OPENSSL_free(P); + if (T != NULL) + OPENSSL_free(T); + return 0; + } + + for (i = 0; i < K + 1; i++) + nu[i] = 0.00; + for (ii = 0; ii < N; ii++) { + for (i = 0; i < M; i++) { + B_[i] = 0; + C[i] = 0; + T[i] = 0; + P[i] = 0; + } + L = 0; + m = -1; + d = 0; + C[0] = 1; + B_[0] = 1; + N_ = 0; + while (N_ < M) { + d = get_bit(buf, ii * M + N_); + for (i = 1; i <= L; i++) + d += C[i] * get_bit(buf, ii * M + N_ - i); + d = d % 2; + if (d == 1) { + for (i = 0; i < M; i++) { + T[i] = C[i]; + P[i] = 0; + } + for (j = 0; j < M; j++) + if (B_[j] == 1) + P[j + N_ - m] = 1; + for (i = 0; i < M; i++) + C[i] = (C[i] + P[i]) % 2; + if (L <= N_ / 2) { + L = N_ + 1 - L; + m = N_; + for (i = 0; i < M; i++) + B_[i] = T[i]; + } + } + N_++; + } + if ((parity = (M + 1) % 2) == 0) + sign = -1; + else + sign = 1; + mean = M / 2.0 + (9.0 + sign) / 36.0 + - 1.0 / pow(2, M) * (M / 3.0 + 2.0 / 9.0); + if ((parity = M % 2) == 0) + sign = 1; + else + sign = -1; + T_ = sign * (L - mean) + 2.0 / 9.0; + + if (T_ <= -2.5) + nu[0]++; + else if (T_ > -2.5 && T_ <= -1.5) + nu[1]++; + else if (T_ > -1.5 && T_ <= -0.5) + nu[2]++; + else if (T_ > -0.5 && T_ <= 0.5) + nu[3]++; + else if (T_ > 0.5 && T_ <= 1.5) + nu[4]++; + else if (T_ > 1.5 && T_ <= 2.5) + nu[5]++; + else + nu[6]++; + } + + for (i = 0; i < K + 1; i++) + V += pow(nu[i] - N * pi[i], 2) / (N * pi[i]); + + p_value = cephes_igamc(3, V / 2.0); + + if (P_value) + *P_value = p_value; + + OPENSSL_free(B_); + OPENSSL_free(P); + OPENSSL_free(C); + OPENSSL_free(T); + + return p_value >= alpha; +} + +/* + * Maurer通用统计检测,Maurer's "Universal Statistical" Test + */ +int rand_self_test_maurer_universal_statistical(const unsigned char *buf, + size_t nbit, double *P) +{ + size_t n = nbit, i, j, t, L, Q, K; + double sigma, V, sum, p_value, c; + size_t *T; + double expected_value[17] = { + 0, 0, 0, 0, 0, 0, + 5.2177052, 6.1962507, 7.1836656, 8.1764248, 9.1723243, 10.170032, + 11.168765, 12.168070, 13.167693, 14.167488, 15.167379}; + double variance[17] = {0, 0, 0, 0, 0, 0, + 2.954, 3.125, 3.238, 3.311, 3.356, 3.384, + 3.401, 3.410, 3.416, 3.419, 3.421}; + + /* + * THE FOLLOWING REDEFINES L, SHOULD THE CONDITION: n >= 1010*2^L*L + * NOT BE MET, FOR THE BLOCK LENGTH L. + */ + L = 5; + if (n >= 387840) + L = 6; + if (n >= 904960) + L = 7; + if (n >= 2068480) + L = 8; + if (n >= 4654080) + L = 9; + if (n >= 10342400) + L = 10; + if (n >= 22753280) + L = 11; + if (n >= 49643520) + L = 12; + if (n >= 107560960) + L = 13; + if (n >= 231669760) + L = 14; + if (n >= 496435200) + L = 15; + if (n >= 1059061760) + L = 16; + + Q = 10 * (size_t)pow(2, L); + K = n / L - Q; + + if ((T = OPENSSL_zalloc(pow(2, L) * sizeof(size_t))) == NULL) { + return 0; + } + + /* COMPUTE THE EXPECTED: Formula 16, in Marsaglia's Paper */ + c = 0.7 - 0.8 / L + (4 + 32 / (double)L) * pow(K, -3 / (double)L) / 15; + sigma = c * sqrt(variance[L] / (double)K); + sum = 0.0; + + for (i = 1; i <= Q; i++) { + j = 0; + for (t = 0; t < L; t++) { + j <<= 1; + if (get_bit(buf, (i - 1) * L + t)) + j++; + } + T[j] = i; + } + for (i = Q + 1; i <= Q + K; i++) { + j = 0; + for (t = 0; t < L; t++) { + j <<= 1; + if (get_bit(buf, (i - 1) * L + t)) + j++; + } + sum += log2(i - T[j]); + T[j] = i; + } + + V = (sum / (double)K - expected_value[L]) / sigma; + p_value = erfc(fabs(V) / sqrt(2)); + + if (P) + *P = p_value; + + OPENSSL_free(T); + + return p_value >= alpha; +} + +/* + * 离散傅里叶检测, Discrete Fourier Transform (Spectral) Test + */ +int rand_self_test_discrete_fourier_transform(const unsigned char *buf, + size_t nbit, double *P) +{ + size_t n = nbit, i, count; + double p_value, T, N1, N0, V; + double *m = NULL, *X = NULL, *wsave = NULL; + int ifac[15]; + + if (((X = OPENSSL_zalloc((n + 1) * sizeof(double))) == NULL) + || ((wsave = OPENSSL_zalloc(2 * n * sizeof(double))) == NULL) + || ((m = OPENSSL_zalloc((n / 2 + 1) * sizeof(double))) == NULL)) { + if (X != NULL) + OPENSSL_free(X); + if (wsave != NULL) + OPENSSL_free(wsave); + if (m != NULL) + OPENSSL_free(m); + return 0; + } + + for (i = 0; i < n; i++) + X[i] = 2 * get_bit(buf, i) - 1; + + /* INITIALIZE WORK ARRAYS */ + __ogg_fdrffti(n, wsave, ifac); + /* APPLY FORWARD FFT */ + __ogg_fdrfftf(n, X, wsave, ifac); + + m[0] = sqrt(X[0] * X[0]); + for (i = 0; i < n / 2; i++) + m[i + 1] = sqrt(pow(X[2 * i + 1], 2) + pow(X[2 * i + 2], 2)); + + count = 0; + T = sqrt(2.995732274 * n); + + for (i = 0; i < n / 2; i++) + if (m[i] < T) + count++; + + N1 = (double)count; + N0 = 0.95 * n / 2.0; + V = (N1 - N0) / sqrt(0.95 * 0.05 * n / 3.8); + p_value = erfc(fabs(V) / sqrt(2.0)); + + if (P) + *P = p_value; + + OPENSSL_free(X); + OPENSSL_free(wsave); + OPENSSL_free(m); + + return p_value >= alpha; +} + +void rand_self_test_set_alpha(double a) +{ + alpha = a; +} + +double rand_self_test_get_alpha(void) +{ + return alpha; +} diff --git a/crypto/rand/rand_unix.c b/crypto/rand/rand_unix.c index fe457cab4..dd9a0d9f7 100644 --- a/crypto/rand/rand_unix.c +++ b/crypto/rand/rand_unix.c @@ -409,7 +409,8 @@ static struct random_device { } random_devices[OSSL_NELEM(random_device_paths)]; static int keep_random_devices_open = 1; -# if defined(__linux) && defined(DEVRANDOM_WAIT) +# if defined(__linux) && defined(DEVRANDOM_WAIT) \ + && defined(OPENSSL_RAND_SEED_GETRANDOM) static void *shm_addr; static void cleanup_shm(void) @@ -487,7 +488,7 @@ static int wait_random_seeded(void) } return seeded; } -# else /* defined __linux */ +# else /* defined __linux && DEVRANDOM_WAIT && OPENSSL_RAND_SEED_GETRANDOM */ static int wait_random_seeded(void) { return 1; @@ -598,6 +599,64 @@ void rand_pool_keep_random_devices_open(int keep) # endif /* defined(OPENSSL_RAND_SEED_DEVRANDOM) */ +# if defined(OPENSSL_RAND_SEED_RTC) +/* + * The following algorithm repeatedly samples the real-time clock (RTC) to + * generate a sequence of unpredictable data. The algorithm relies upon the + * uneven execution speed of the code (due to factors such as cache misses, + * interrupts, bus activity, and scheduling) and upon the rather large + * relative difference between the speed of the clock and the rate at which + * it can be read. If it is ported to an environment where execution speed + * is more constant or where the RTC ticks at a much slower rate, or the + * clock can be read with fewer instructions, it is likely that the results + * would be far more predictable. This should only be used for legacy + * platforms. + * + * As a precaution, we assume only 2 bits of entropy per byte. + */ +static size_t rand_acquire_entropy_from_rtc(RAND_POOL *pool) +{ + size_t i, k; + size_t bytes_needed; + struct timespec ts; + unsigned char v; +# ifdef OPENSSL_SYS_VOS_HPPA + short int code; + long duration; + extern void s$sleep(long *_duration, short int *_code); +# else + long long duration; +# endif + + bytes_needed = rand_pool_bytes_needed(pool, 4 /*entropy_factor*/); + + for (i = 0; i < bytes_needed; i++) { + /* + * burn some cpu; hope for interrupts, cache collisions, bus + * interference, etc. + */ + for (k = 0; k < 99; k++) + ts.tv_nsec = random(); + +# ifdef OPENSSL_SYS_VOS_HPPA + /* sleep for 1/1024 of a second (976 us). */ + duration = 1; + s$sleep(&duration, &code); +# else + /* sleep for 1/65536 of a second (15 us). */ + duration = 15; + usleep(duration); +# endif + + /* Get wall clock time, take 8 bits. */ + clock_gettime(CLOCK_REALTIME, &ts); + v = (unsigned char)(ts.tv_nsec & 0xFF); + rand_pool_add(pool, &v, sizeof(v) , 2); + } + return rand_pool_entropy_available(pool); +} +# endif + /* * Try the various seeding methods in turn, exit when successful. * @@ -733,6 +792,12 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool) } # endif +# if defined(OPENSSL_RAND_SEED_RTC) + entropy_available = rand_acquire_entropy_from_rtc(pool); + if (entropy_available > 0) + return entropy_available; +# endif + return rand_pool_entropy_available(pool); # endif } diff --git a/crypto/scm.c b/crypto/scm.c new file mode 100644 index 000000000..b02cc7e06 --- /dev/null +++ b/crypto/scm.c @@ -0,0 +1,793 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "crypto/rand.h" +#include "rand/rand_local.h" +#include "internal/cryptlib.h" + +#define SALT_LEN 64 + +static int entropy_source_startup_health_test(void) +{ + unsigned char *entropy = NULL; + RAND_DRBG *drbg = RAND_DRBG_get0_master(); + size_t entropylen = 0; + int total = 1000000 / 8; + unsigned int last = -1, cur; + unsigned int cnt = 1, max = 27; + int ret = 0; + size_t i, j; + + fprintf(stdout, "BEGIN { startup health test for entropy source }\n"); + + if (drbg == NULL) + goto end; + + while (total > 0) { + entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength, + drbg->min_entropylen, + drbg->max_entropylen, 0); + + if (entropylen < drbg->min_entropylen || + entropylen > drbg->max_entropylen) + goto end; + + for (i = 0; i < entropylen; i++) { + for (j = 0; j < 8; j++) { + cur = (entropy[i] >> j) & 0x01; + + if (last == cur) { + cnt++; + + if (cnt >= max) + goto end; + } else { + last = cur; + cnt = 1; + } + } + } + + total -= entropylen; + + if (drbg->cleanup_entropy != NULL) { + drbg->cleanup_entropy(drbg, entropy, entropylen); + entropy = NULL; + entropylen = 0; + } + } + + fprintf(stdout, "END { startup health test for entropy source }\n"); + + ret = 1; +end: + if (entropy != NULL && drbg->cleanup_entropy != NULL) + drbg->cleanup_entropy(drbg, entropy, entropylen); + + return ret; +} + +int scm_init(void) +{ + fprintf(stderr, "Init: SM2 module init success\n"); + fprintf(stderr, "Init: SM3 module init success\n"); + fprintf(stderr, "Init: SM4 module init success\n"); + + RAND_DRBG_set_defaults(NID_sm3, 0); + + if (entropy_source_startup_health_test()) + fprintf(stderr, "Init: Random module init success\n"); + else + return 0; + + fprintf(stderr, "------------------------------------------------------\n"); + + return 1; +} + +int scm_self_test_integrity(const char *exe) +{ + int ret = 0; + const char *pubkey = "-----BEGIN PUBLIC KEY-----\n" + "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE4DyCERSfDFCtzDYEzXwFGnPy7PBS\n" + "46vljnpWQKcgCkR3x+ZmzuXsabCZMfKPBNbAnSKlDwO9btRUzE19aRChLg==\n" + "-----END PUBLIC KEY-----"; + char *buf = NULL; + EVP_PKEY *pkey = NULL; + EVP_MD_CTX *mctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + BIO *keybio = NULL; + BIO *sigbio = NULL; + size_t siglen; + unsigned char *sigbuf = NULL; + BIO *in = NULL; + BIO *bmd = NULL; + BIO *inp = NULL; + int bufsize = 1024 * 8; + char *sighex = NULL; + int i; + + buf = app_malloc(bufsize, "I/O buffer"); + + keybio = BIO_new_mem_buf(pubkey, -1); + if (keybio == NULL) + goto end; + + pkey = PEM_read_bio_PUBKEY(keybio, NULL, NULL, NULL); + if (pkey == NULL) + goto end; + + in = BIO_new(BIO_s_file()); + if (in == NULL) + goto end; + + bmd = BIO_new(BIO_f_md()); + if (bmd == NULL) + goto end; + + if (!BIO_get_md_ctx(bmd, &mctx)) + goto end; + + if (!EVP_DigestVerifyInit(mctx, &pctx, EVP_sm3(), NULL, pkey)) + goto end; + + sigbio = BIO_new_file(OPENSSL_get_default_signature_file(), "rb"); + if (sigbio == NULL) + goto end; + + siglen = EVP_PKEY_size(pkey); + sigbuf = app_malloc(siglen, "signature buffer"); + siglen = BIO_read(sigbio, sigbuf, siglen); + if (siglen <= 0) { + goto end; + } + + BIO_free(sigbio); + sigbio = NULL; + + inp = BIO_push(bmd, in); + + if (BIO_read_filename(in, exe) <= 0) + goto end; + + while (BIO_pending(inp) || !BIO_eof(inp)) { + i = BIO_read(inp, (char *)buf, bufsize); + if (i < 0) { + BIO_printf(bio_err, "Read Error in %s\n", exe); + ERR_print_errors(bio_err); + goto end; + } + if (i == 0) + break; + } + + if (!EVP_DigestVerifyFinal(mctx, sigbuf, (unsigned int)siglen)) + goto end; + + sighex = OPENSSL_buf2hexstr(sigbuf, siglen); + if (sighex == NULL) + goto end; + + ret = 1; + + fprintf(stderr, "BEGIN { Self-test integrity test }\n"); + fprintf(stderr, "Self-test: integrity test\n"); + fprintf(stderr, "Pubkey=%s\n", pubkey); + fprintf(stderr, "Input=%s\n", sighex); +// fprintf(stderr, "Output=%s\n", tbs); + fprintf(stderr, "END { Self-test integrity test }\n"); +end: + OPENSSL_free(buf); + OPENSSL_free(sigbuf); + OPENSSL_free(sighex); + BIO_free(in); + BIO_free(bmd); + BIO_free(sigbio); + BIO_free(keybio); + EVP_PKEY_free(pkey); + + return ret; +} + +int scm_self_test_sm2_verify(void) +{ + int ret = 0; + unsigned char pubkey[] = "-----BEGIN PUBLIC KEY-----\n" + "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEOToq2eJ+Q6yqq4WhnTuFWR4UQGFX\n" + "F1rd03v3f/DK+e03/POotPVcA4UjJh/KZjav5qevoqFIKmBvXLOhiy4qHg==\n" + "-----END PUBLIC KEY-----"; + const char *sig = "D7AD397F6FFA5D4F7F11E7217F241607DC30618C236D2C09C1B9EA8FDADEE2E8"; + const char *tbs = "3046022100AB1DB64DE7C40EDBDE6651C9B8EBDB804673DB836E5D5C7FE15DCF9ED2725037022100EBA714451FF69B0BB930B379E192E7CD5FA6E3C41C7FBD8303B799AB54A54621"; + EVP_PKEY *pkey = NULL; + unsigned char *tbsbin = NULL; + unsigned char *sigbin = NULL; + EVP_MD_CTX *mctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + BIO *bio = NULL; + + bio = BIO_new_mem_buf(pubkey, -1); + if (bio == NULL) + goto end; + + pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + if (pkey == NULL) + goto end; + + tbsbin = OPENSSL_hexstr2buf(tbs, NULL); + if (tbsbin == NULL) + goto end; + + sigbin = OPENSSL_hexstr2buf(sig, NULL); + if (sigbin == NULL) + goto end; + + mctx = EVP_MD_CTX_new(); + if (mctx == NULL) + goto end; + + pctx = EVP_PKEY_CTX_new(pkey, NULL); + if (pctx == NULL) + goto end; + + EVP_MD_CTX_set_pkey_ctx(mctx, pctx); + + if (!EVP_DigestVerifyInit(mctx, NULL, EVP_sm3(), NULL, pkey) + || !EVP_DigestVerify(mctx, sigbin, strlen(sig)/2, + tbsbin, strlen(tbs)/2)) { + fprintf(stderr, "Self test: SM2 sign failed\n"); + goto end; + } + + ret = 1; + + fprintf(stderr, "BEGIN { Self-test SM2 verify test }\n"); + fprintf(stderr, "Pubkey=%s\n", pubkey); + fprintf(stderr, "Input=%s\n", sig); + fprintf(stderr, "Output=%s\n", tbs); + fprintf(stderr, "END { Self-test SM2 verify test }\n"); +end: + OPENSSL_free(tbsbin); + OPENSSL_free(sigbin); + EVP_PKEY_free(pkey); + EVP_MD_CTX_free(mctx); + EVP_PKEY_CTX_free(pctx); + BIO_free(bio); + return ret; +} + + +int scm_self_test_sm2_sign(void) +{ + int ret = 0; + unsigned char privkey[] = "-----BEGIN PRIVATE KEY-----\n" + "MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQg0JFWczAXva2An9m7\n" + "2MaT9gIwWTFptvlKrxyO4TjMmbWhRANCAAQ5OirZ4n5DrKqrhaGdO4VZHhRAYVcX\n" + "Wt3Te/d/8Mr57Tf886i09VwDhSMmH8pmNq/mp6+ioUgqYG9cs6GLLioe\n" + "-----END PRIVATE KEY-----"; + const char *tbs = "3046022100AB1DB64DE7C40EDBDE6651C9B8EBDB804673DB836E5D5C7FE15DCF9ED2725037022100EBA714451FF69B0BB930B379E192E7CD5FA6E3C41C7FBD8303B799AB54A54621"; + EVP_PKEY *pkey = NULL; + unsigned char *tbsbin = NULL; + EVP_MD_CTX *mctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + BIO *bio = NULL; + unsigned char *buf = NULL; + char *sig = NULL; + size_t tmplen; + + bio = BIO_new_mem_buf(privkey, -1); + if (bio == NULL) + goto end; + + pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + if (pkey == NULL) + goto end; + + tbsbin = OPENSSL_hexstr2buf(tbs, NULL); + if (tbsbin == NULL) + goto end; + + mctx = EVP_MD_CTX_new(); + if (mctx == NULL) + goto end; + + pctx = EVP_PKEY_CTX_new(pkey, NULL); + if (pctx == NULL) + goto end; + + EVP_MD_CTX_set_pkey_ctx(mctx, pctx); + + tmplen = ECDSA_size(EVP_PKEY_get0_EC_KEY(pkey)); + + buf = OPENSSL_malloc(tmplen); + if (buf == NULL) + goto end; + + if (!EVP_DigestSignInit(mctx, NULL, EVP_sm3(), NULL, pkey) + || !EVP_DigestSign(mctx, buf, &tmplen, + tbsbin, strlen(tbs)/2)) { + fprintf(stderr, "Self test: SM2 sign failed\n"); + goto end; + } + + if (!EVP_DigestVerifyInit(mctx, NULL, EVP_sm3(), NULL, pkey) + || !EVP_DigestVerify(mctx, buf, tmplen, tbsbin, strlen(tbs)/2)) + goto end; + + sig = OPENSSL_buf2hexstr(buf, tmplen); + if (sig == NULL) + goto end; + + ret = 1; + + fprintf(stderr, "BEGIN { Self-test SM2 sign test }\n"); + fprintf(stderr, "PrivKey=%s\n", privkey); + fprintf(stderr, "Input=%s\n", tbs); + fprintf(stderr, "Output=%s\n", sig); + fprintf(stderr, "END { Self-test SM2 sign test }\n"); +end: + OPENSSL_free(sig); + OPENSSL_free(buf); + OPENSSL_free(tbsbin); + EVP_PKEY_free(pkey); + EVP_MD_CTX_free(mctx); + EVP_PKEY_CTX_free(pctx); + BIO_free(bio); + return ret; +} + +int scm_self_test_sm4_decrypt(void) +{ + int ret = 0; + unsigned char buf[1024]; + EVP_CIPHER_CTX *ctx = NULL; + const char *key = "95F28D1231BB9EE5F01DDF2E3148CF41"; + const char *iv = "01020304050607080901020304050607"; + const char *input = "0A1D209300FD1D410E5C538F18D91299F6DE0ADD8A4212D88D7FC44A992EC795"; + const char *output = "A7009665F44878D3AE472FC8B9A3E0AD6DA9B0DC44331EA9D6CF95A3081D4117"; + unsigned char *keybin = NULL; + unsigned char *outputbin = NULL; + unsigned char *inputbin = NULL; + unsigned char *ivbin = NULL; + int tmplen; + int outlen; + + keybin = OPENSSL_hexstr2buf(key, NULL); + if (keybin == NULL) + goto end; + + ivbin = OPENSSL_hexstr2buf(iv, NULL); + if (ivbin == NULL) + goto end; + + inputbin = OPENSSL_hexstr2buf(input, NULL); + if (inputbin == NULL) + goto end; + + if ((ctx = EVP_CIPHER_CTX_new()) == NULL + || !EVP_DecryptInit_ex(ctx, EVP_sm4_cbc(), NULL, keybin, ivbin) + || !EVP_CIPHER_CTX_set_padding(ctx, 0) + || !EVP_DecryptUpdate(ctx, buf, &outlen, + inputbin, strlen(input)/2) + || !EVP_DecryptFinal_ex(ctx, buf + outlen, &tmplen)) + goto end; + + outlen += tmplen; + + outputbin = OPENSSL_hexstr2buf(output, NULL); + if (outputbin == NULL) + goto end; + + if (outlen != (int)strlen(output)/2 || + memcmp(buf, outputbin, outlen) != 0) + goto end; + + ret = 1; + + fprintf(stdout, "BEGIN { Self-test SM4 decrypt test }\n"); + fprintf(stderr, "Key=%s\n", key); + fprintf(stderr, "IV=%s\n", iv); + fprintf(stderr, "Input=%s\n", input); + fprintf(stderr, "Output=%s\n", output); + fprintf(stdout, "END { Self-test SM4 decrypt test }\n"); + +end: + OPENSSL_free(keybin); + OPENSSL_free(ivbin); + OPENSSL_free(inputbin); + OPENSSL_free(outputbin); + + EVP_CIPHER_CTX_free(ctx); + return ret; +} + +int scm_self_test_sm4_encrypt(void) +{ + int ret = 0; + unsigned char buf[1024]; + EVP_CIPHER_CTX *ctx = NULL; + const char *key = "95F28D1231BB9EE5F01DDF2E3148CF41"; + const char *iv = "01020304050607080901020304050607"; + const char *input = "A7009665F44878D3AE472FC8B9A3E0AD6DA9B0DC44331EA9D6CF95A3081D4117"; + const char *output = "0A1D209300FD1D410E5C538F18D91299F6DE0ADD8A4212D88D7FC44A992EC795"; + unsigned char *keybin = NULL; + unsigned char *outputbin = NULL; + unsigned char *inputbin = NULL; + unsigned char *ivbin = NULL; + int tmplen; + int outlen; + + keybin = OPENSSL_hexstr2buf(key, NULL); + if (keybin == NULL) + goto end; + + ivbin = OPENSSL_hexstr2buf(iv, NULL); + if (ivbin == NULL) + goto end; + + inputbin = OPENSSL_hexstr2buf(input, NULL); + if (inputbin == NULL) + goto end; + + if ((ctx = EVP_CIPHER_CTX_new()) == NULL + || !EVP_EncryptInit_ex(ctx, EVP_sm4_cbc(), NULL, keybin, ivbin) + || !EVP_CIPHER_CTX_set_padding(ctx, 0) + || !EVP_EncryptUpdate(ctx, buf, &outlen, + inputbin, strlen(input)/2) + || !EVP_EncryptFinal_ex(ctx, buf + outlen, &tmplen)) + goto end; + + outlen += tmplen; + + outputbin = OPENSSL_hexstr2buf(output, NULL); + if (outputbin == NULL) + goto end; + + if (outlen != (int)strlen(output)/2 || + memcmp(buf, outputbin, outlen) != 0) + goto end; + + ret = 1; + + fprintf(stdout, "BEGIN { Self-test SM4 encrypt test }\n"); + fprintf(stderr, "Key=%s\n", key); + fprintf(stderr, "IV=%s\n", iv); + fprintf(stderr, "Input=%s\n", input); + fprintf(stderr, "Output=%s\n", output); + fprintf(stdout, "END { Self-test SM4 encrypt test }\n"); + +end: + + OPENSSL_free(keybin); + OPENSSL_free(ivbin); + OPENSSL_free(inputbin); + OPENSSL_free(outputbin); + + EVP_CIPHER_CTX_free(ctx); + return ret; +} + +int scm_self_test_sm3(void) +{ + int ret = 0; + EVP_MD_CTX *mctx = NULL; + const char *input1[] = { + "c684788d8e3cb4eac0c680500c175e54", + "259909fe49ada2b1455b81a4e0a0f79912636ebaed96cb9d60c85cc2926e247e", + "217b5ebc849b8637cfd06121c9e0035ac887ab33d4736ffa6539e22b4daf839088d3c884001e97bf3351f11df69e1b9a4f2fa5929427f470e844de08b6434ffa", + "f66f79cb4f41fa491d0d6c7a78590545cb5a3850dc08f50b246bc365243ed5181c33f5d1f1f241a3cf1d38ae4077afebcc002a9302b01d4c3713ab855869ee7026d5fe3c2954bad913583526e0806f6272ae4a88e9d3fffb62ecac769419b23d81dec7b2de2ef6a7903e52ed6f5ed6aae804d0070896128633bf55c38e400a51", + "3c45817cfc093f18b4f8fb3ae9941e28e079b4d443e7e53cedc8aafe131b5ebfa3897fd61f49fed14e84006be0525347e570ec741a5a10a9bc28df9d13bc187530bd821dd74005e9a4226da97c8e7a409f8d1cf042ba4ba04ff1583e1d37c225ab6772f78e825c02f61799987cb2ce234262312d98e258f649e2a47fbc2777d91823a56b9354f85516d250c08b731cb87d905521de3ade205403bc5e237d83580a8612fd2af8858b4874fb434f90dafe0b1efa5de8e981f18e08a9fa38851fd63cd8b80e68275d425a45dc8bb3956d8aef77bf99e01ed3d467a03233a8739e90db50a03330cbc2ac28b64f73321996f9a089cfe17788c2a3544a93ac3be70af8", + }; + const char *output1[] = { + "f00f5012914600a3ec71c8e99526dc41e3b51bb82def800fbd7cb7992e54c322", + "804752ea387065b95cd46d108fa3d52d3657cfc0a9abb2d6f0bb8fbaf00b7c54", + "d82f2d501852941255ee2e11b2902982191717a365c48262d9239b30d85c58e9", + "ace600eb40c3d1506c10af1b3df6c51c9cf0389f61d98b29b24c89bd6256884f", + "26cd58cf6961a1cdfcc12f1bbb1ec4b97ca332151a640b7582b1c73ccac94b88", + }; + unsigned char buf[EVP_MAX_MD_SIZE]; + unsigned char *inputbin = NULL; + unsigned char *outputbin = NULL; + size_t i; + + fprintf(stdout, "BEGIN { Self-test SM3 test }\n"); + + for (i = 0; i < OSSL_NELEM(input1); i++) { + inputbin = OPENSSL_hexstr2buf(input1[i], NULL); + if (inputbin == NULL) + goto end; + + if ((mctx = EVP_MD_CTX_new()) == NULL + || !EVP_DigestInit_ex(mctx, EVP_sm3(), NULL) + || !EVP_DigestUpdate(mctx, inputbin, strlen(input1[i]) / 2) + || !EVP_DigestFinal_ex(mctx, buf, NULL)) + goto end; + + outputbin = OPENSSL_hexstr2buf(output1[i], NULL); + if (outputbin == NULL) + goto end; + + if (memcmp(buf, outputbin, strlen(output1[i]) / 2) != 0) + goto end; + + EVP_MD_CTX_free(mctx); + mctx = NULL; + OPENSSL_free(inputbin); + inputbin = NULL; + OPENSSL_free(outputbin); + outputbin = NULL; + + fprintf(stderr, "Self-test: SM3 test item %ld\n", i + 1); + fprintf(stderr, "Input=%s\n", input1[i]); + fprintf(stderr, "Output=%s\n", output1[i]); + } + + fprintf(stdout, "END { Self-test SM3 test }\n"); + + ret = 1; +end: + OPENSSL_free(outputbin); + EVP_MD_CTX_free(mctx); + OPENSSL_free(inputbin); + + return ret; +} + +static void hexdump(FILE *fp, const char *name, + const unsigned char *buf, size_t len) +{ + size_t i; + + fprintf(fp, "%s=", name); + + for (i = 0; i < len; i++) + fprintf(fp, "%02X", buf[i]); + + fprintf(fp, "\n"); +} + +static int self_test_drbg_data_index; + +typedef struct test_ctx_st { + const unsigned char *entropy; + size_t entropylen; + int entropycnt; + const unsigned char *nonce; + size_t noncelen; + int noncecnt; +} TEST_DRBG_CTX; + +static size_t self_test_get_entropy(RAND_DRBG *drbg, unsigned char **pout, + int entropy, size_t min_len, size_t max_len, + int prediction_resistance) +{ + TEST_DRBG_CTX *t = (TEST_DRBG_CTX *)RAND_DRBG_get_ex_data( + drbg, self_test_drbg_data_index); + + t->entropycnt++; + *pout = (unsigned char *)t->entropy; + return t->entropylen; +} + +static size_t self_test_get_nonce(RAND_DRBG *drbg, unsigned char **pout, + int entropy, size_t min_len, size_t max_len) +{ + TEST_DRBG_CTX *t = (TEST_DRBG_CTX *)RAND_DRBG_get_ex_data( + drbg, self_test_drbg_data_index); + + t->noncecnt++; + *pout = (unsigned char *)t->nonce; + return t->noncelen; +} + +int scm_self_test_sm3_drbg(void) +{ + RAND_DRBG *drbg = NULL; + TEST_DRBG_CTX t; + int ret = 0; + size_t request_len = 256 / 8; + unsigned char buff[1024]; + unsigned char pers[] = { + 0xc9, 0x80, 0xde, 0xdf, 0x98, 0x82, 0xed, 0x44, 0x64, 0xa6, 0x74, 0x96, + 0x78, 0x68, 0xf1, 0x43 + }; + unsigned char entropy[] = { + 0xE1, 0x0B, 0xC2, 0x8A, 0x0B, 0xFD, 0xDF, 0xE9, 0x3E, 0x7F, 0x51, 0x86, + 0xE0, 0xCA, 0x0B, 0x3B, 0x89, 0x0e, 0xb0, 0x67, 0xac, 0xf7, 0x38, 0x2e, + 0xff, 0x80, 0xb0, 0xc7, 0x3b, 0xc8, 0x72, 0xc6, + }; + unsigned char nonce[] = { + 0x9F, 0xF4, 0x77, 0xC1, 0x86, 0x73, 0x84, 0x0D, 0xaa, 0xd4, 0x71, 0xef, + 0x3e, 0xf1, 0xd2, 0x03, + }; + unsigned char adinreseed[] = { + 0x38, 0xBF, 0xEC, 0x9A, 0x10, 0xE6, 0xE4, 0x0C, 0x10, 0x68, 0x41, 0xDA, + 0xE4, 0x8D, 0xC3, 0xB8 + }; + unsigned char adin2[] = { + 0x7E, 0xAA, 0x1B, 0xBE, 0xC7, 0x93, 0x93, 0xA7, 0xF4, 0xA8, 0x22, 0x7B, + 0x69, 0x1E, 0xCB, 0x68 + }; + unsigned char expected[] = { + 0xFA, 0xAB, 0x8A, 0x9B, 0xA0, 0x16, 0x16, 0xB4, 0x0F, 0xD1, 0xD7, 0x3A, + 0x9F, 0x58, 0xA5, 0xEA, 0xC0, 0xF3, 0x74, 0x54, 0x5D, 0x74, 0x53, 0x09, + 0xA8, 0x73, 0x30, 0x92, 0xB4, 0x5F, 0xC1, 0xA9 + }; + int i; + + fprintf(stdout, "BEGIN { Self-test SM3-DRBG test }\n"); + + if ((drbg = RAND_DRBG_new(NID_sm3, 0, NULL)) == NULL) + return 0; + + if (!RAND_DRBG_set_callbacks(drbg, self_test_get_entropy, NULL, + self_test_get_nonce, NULL)) { + goto err; + } + memset(&t, 0, sizeof(t)); + t.entropy = entropy; + t.entropylen = sizeof(entropy); + t.nonce = nonce; + t.noncelen = sizeof(nonce); + + RAND_DRBG_set_ex_data(drbg, self_test_drbg_data_index, &t); + + hexdump(stdout, "entropy", entropy, sizeof(entropy)); + hexdump(stdout, "nonce", nonce, sizeof(nonce)); + hexdump(stdout, "personalization_str", pers, sizeof(pers)); + hexdump(stdout, "reseed additional_input", adinreseed, sizeof(adinreseed)); + hexdump(stdout, "generate additional_input", adin2, sizeof(adin2)); + fprintf(stdout, "requested_number_of_bits=%lu\n", request_len * 8); + hexdump(stdout, "returned_bits", buff, request_len); + + for (i = 0; i < 1000; i++) { + if (!RAND_DRBG_instantiate(drbg, pers, sizeof(pers)) + || !RAND_DRBG_reseed(drbg, adinreseed, sizeof(adinreseed), 0) + || !RAND_DRBG_generate(drbg, buff, request_len, 0, + adin2, sizeof(adin2)) + || memcmp(expected, buff, request_len) != 0) + goto err; + + RAND_DRBG_uninstantiate(drbg); + fprintf(stdout, "."); + } + + fprintf(stdout, "\n"); + + fprintf(stdout, "END { Self-test SM3-DRBG test }\n"); + + ret = 1; +err: + if (drbg != NULL) + RAND_DRBG_uninstantiate(drbg); + + RAND_DRBG_free(drbg); + return ret; +} + +int scm_do_passwd(const char *passphrase, int passphrase_len, + const char *salt, int salt_len, + char *result, int *res_len) +{ + int ret = 0; + unsigned char new_salt[SALT_LEN] = { + 0x17, 0xce, 0x14, 0x4c, 0x26, 0x64, 0xc3, 0x90, 0x44, 0x6b, 0x51, 0x1c, + 0x39, 0xa5, 0x27, 0x1f, 0xc7, 0x01, 0x67, 0x12, 0x7b, 0x54, 0xc9, 0x39, + 0xbe, 0x66, 0xda, 0x88, 0x2d, 0xd0, 0xf4, 0x58, 0x7e, 0x7e, 0x0f, 0x42, + 0x9a, 0x41, 0xdb, 0xb9, 0xd5, 0xea, 0x2a, 0x35, 0xc5, 0xa8, 0xac, 0x25, + 0x6f, 0x78, 0xc0, 0xe4, 0xb7, 0xf6, 0xd7, 0xfd, 0xb9, 0x0e, 0xf6, 0xbc, + 0xa0, 0x3e, 0xfd, 0x31}; + + EVP_MD_CTX *mctx = NULL; + unsigned char buf[EVP_MAX_MD_SIZE]; + + if (salt == NULL) { + salt = (const char *)new_salt; + salt_len = sizeof(new_salt); + } + + if ((mctx = EVP_MD_CTX_new()) == NULL + || !EVP_DigestInit_ex(mctx, EVP_sm3(), NULL) + || !EVP_DigestUpdate(mctx, salt, salt_len) + || !EVP_DigestUpdate(mctx, passphrase, passphrase_len) + || !EVP_DigestFinal_ex(mctx, buf, NULL)) + goto end; + + if (*res_len <= EVP_MD_size(EVP_sm3())) + goto end; + + memcpy(result, buf, EVP_MD_size(EVP_sm3())); + *res_len = EVP_MD_size(EVP_sm3()); + + ret = 1; +end: + EVP_MD_CTX_free(mctx); + return ret; +} + +int scm_setup_password(void) +{ + int ret = 0; + int templen; + BIO *out = NULL; + char passwd[512]; + char salt_pass[1024]; + + fprintf(stdout, "Setup admin password\n"); + + if (EVP_read_pw_string(passwd, sizeof(passwd), "Password: ", 1) != 0) + goto end; + + templen = sizeof(salt_pass); + + if (!scm_do_passwd(passwd, strlen(passwd), NULL, 0, salt_pass, &templen)) + goto end; + + out = bio_open_default(OPENSSL_get_default_passwd_file(), 'w', FORMAT_TEXT); + if (out == NULL) + goto end; + + BIO_hex_string(out, 0, 999999, (unsigned char *)salt_pass, templen); + + ret = 1; +end: + BIO_free_all(out); + return ret; +} + +int scm_verify_password(void) +{ + int ret = 0; + BIO *in = NULL; + char *buf = NULL; + long buf_len; + int templen; + char passwd[512]; + char calc_pass[1024]; + char read_pass[1024]; + + in = BIO_new_file(OPENSSL_get_default_passwd_file(), "r"); + if (in == NULL) + goto end; + + BIO_gets(in, read_pass, sizeof(read_pass)); + + buf = (char *)OPENSSL_hexstr2buf(read_pass, &buf_len); + if (buf == NULL) + goto end; + + if (buf_len != EVP_MD_size(EVP_sm3())) + goto end; + + if (EVP_read_pw_string(passwd, sizeof(passwd), "Password: ", 0) != 0) + goto end; + + templen = sizeof(calc_pass); + + if (!scm_do_passwd(passwd, strlen(passwd), NULL, 0, calc_pass, &templen)) + goto end; + + if (templen != EVP_MD_size(EVP_sm3())) + goto end; + + if (memcmp(buf, calc_pass, EVP_MD_size(EVP_sm3()))) + goto end; + + ret = 1; +end: + BIO_free(in); + OPENSSL_free(buf); + return ret; +} diff --git a/crypto/sm2/sm2_crypt.c b/crypto/sm2/sm2_crypt.c index 1188abfc6..00055a4e5 100644 --- a/crypto/sm2/sm2_crypt.c +++ b/crypto/sm2/sm2_crypt.c @@ -294,6 +294,10 @@ int sm2_decrypt(const EC_KEY *key, C2 = sm2_ctext->C2->data; C3 = sm2_ctext->C3->data; msg_len = sm2_ctext->C2->length; + if (*ptext_len < (size_t)msg_len) { + SM2err(SM2_F_SM2_DECRYPT, SM2_R_BUFFER_TOO_SMALL); + goto done; + } ctx = BN_CTX_new(); if (ctx == NULL) { diff --git a/crypto/sm2/sm2_sign.c b/crypto/sm2/sm2_sign.c index 683f03f93..557f20a9e 100644 --- a/crypto/sm2/sm2_sign.c +++ b/crypto/sm2/sm2_sign.c @@ -261,6 +261,10 @@ static ECDSA_SIG *sm2_sig_gen(const EC_KEY *key, const BIGNUM *e) goto done; } + /* try again if s == 0 */ + if (BN_is_zero(s)) + continue; + sig = ECDSA_SIG_new(); if (sig == NULL) { SM2err(SM2_F_SM2_SIG_GEN, ERR_R_MALLOC_FAILURE); @@ -421,6 +425,10 @@ int sm2_sign(const unsigned char *dgst, int dgstlen, } s = sm2_sig_gen(eckey, e); + if (s == NULL) { + SM2err(SM2_F_SM2_SIGN, ERR_R_INTERNAL_ERROR); + goto done; + } sigleni = i2d_ECDSA_SIG(s, &sig); if (sigleni < 0) { diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h index 6e7291ae4..95d443fc2 100644 --- a/include/internal/cryptlib.h +++ b/include/internal/cryptlib.h @@ -96,4 +96,8 @@ uint32_t OPENSSL_rdtsc(void); size_t OPENSSL_instrument_bus(unsigned int *, size_t); size_t OPENSSL_instrument_bus2(unsigned int *, size_t, size_t); +# ifndef OPENSSL_NO_GM +const char *OPENSSL_get_default_passwd_file(void); +const char *OPENSSL_get_default_signature_file(void); +# endif #endif diff --git a/include/openssl/opensslv.h b/include/openssl/opensslv.h index 81ab20f66..85320470a 100644 --- a/include/openssl/opensslv.h +++ b/include/openssl/opensslv.h @@ -108,7 +108,7 @@ extern "C" { * 1.9.5 0x1090500f */ -# define BABASSL_VERSION_NUMBER 0x8030000fL +# define BABASSL_VERSION_NUMBER 0x80300000L # define BABASSL_VERSION_TEXT "BabaSSL 8.3.0" #ifdef __cplusplus diff --git a/ssl/s3_cbc.c b/ssl/s3_cbc.c index aa7d63f84..ae2a330ba 100644 --- a/ssl/s3_cbc.c +++ b/ssl/s3_cbc.c @@ -128,7 +128,7 @@ char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx) int ssl3_cbc_digest_record(const EVP_MD_CTX *ctx, unsigned char *md_out, size_t *md_out_size, - const unsigned char header[13], + const unsigned char *header, const unsigned char *data, size_t data_plus_mac_size, size_t data_plus_mac_plus_padding_size, diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c index 8a89f512f..707cf74d8 100644 --- a/ssl/s3_enc.c +++ b/ssl/s3_enc.c @@ -20,7 +20,7 @@ static int ssl3_generate_key_block(SSL *s, unsigned char *km, int num) EVP_MD_CTX *s1; unsigned char buf[16], smd[SHA_DIGEST_LENGTH]; unsigned char c = 'A'; - unsigned int i, j, k; + unsigned int i, k; int ret = 0; #ifdef CHARSET_EBCDIC @@ -44,8 +44,7 @@ static int ssl3_generate_key_block(SSL *s, unsigned char *km, int num) goto err; } - for (j = 0; j < k; j++) - buf[j] = c; + memset(buf, c, k); c++; if (!EVP_DigestInit_ex(s1, EVP_sha1(), NULL) || !EVP_DigestUpdate(s1, buf, k) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index d937b8a27..66b61963b 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -2861,7 +2861,7 @@ __owur char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx); __owur int ssl3_cbc_digest_record(const EVP_MD_CTX *ctx, unsigned char *md_out, size_t *md_out_size, - const unsigned char header[13], + const unsigned char *header, const unsigned char *data, size_t data_plus_mac_size, size_t data_plus_mac_plus_padding_size, diff --git a/ssl/statem_ntls/statem_ntls_clnt.c b/ssl/statem_ntls/statem_ntls_clnt.c index 9bf76dfe0..aa56998d8 100644 --- a/ssl/statem_ntls/statem_ntls_clnt.c +++ b/ssl/statem_ntls/statem_ntls_clnt.c @@ -406,7 +406,7 @@ static int ntls_process_ske_rsa(SSL *s, PACKET *pkt) SSL3_RANDOM_SIZE) <= 0 || EVP_DigestVerifyUpdate(md_ctx, &(s->s3->server_random[0]), SSL3_RANDOM_SIZE) <= 0 - || EVP_DigestVerifyUpdate(md_ctx, buf, n) <= 0) { + || EVP_DigestVerifyUpdate(md_ctx, buf, n + 3) <= 0) { SSLfatal_ntls(s, SSL_AD_INTERNAL_ERROR, SSL_F_NTLS_PROCESS_SKE_RSA, ERR_R_INTERNAL_ERROR); goto end; diff --git a/ssl/statem_ntls/statem_ntls_srvr.c b/ssl/statem_ntls/statem_ntls_srvr.c index 5008cd650..02c5b9bcd 100644 --- a/ssl/statem_ntls/statem_ntls_srvr.c +++ b/ssl/statem_ntls/statem_ntls_srvr.c @@ -377,7 +377,8 @@ static int ntls_construct_ske_rsa(SSL *s, WPACKET *pkt) return 0; } - p = &(buf[3]); + p = buf; + l2n3(n, p); if ((n = i2d_X509(x509, &p)) <= 0) { SSLfatal_ntls(s, SSL_AD_INTERNAL_ERROR, SSL_F_NTLS_CONSTRUCT_SKE_RSA, @@ -385,8 +386,7 @@ static int ntls_construct_ske_rsa(SSL *s, WPACKET *pkt) goto end; } - l2n3(n, buf); - buf -= 3; + n += 3; siglen = EVP_PKEY_size(pkey); diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t index f5ef0f996..7e8c04d86 100644 --- a/test/recipes/25-test_x509.t +++ b/test/recipes/25-test_x509.t @@ -11,11 +11,12 @@ use strict; use warnings; use File::Spec; +use OpenSSL::Test::Utils; use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_x509"); -plan tests => 9; +plan tests => 10; require_ok(srctop_file('test','recipes','tconversion.pl')); @@ -46,4 +47,29 @@ subtest 'x509 -- second x.509 v3 certificate' => sub { subtest 'x509 -- pathlen' => sub { ok(run(test(["v3ext", srctop_file("test/certs", "pathlen.pem")]))); -} +}; + +subtest 'x509 -- sign sm2 cert' => sub { + plan tests => 2; + + SKIP: { + skip "SM2 is not supported by this OpenSSL build", 2 + if disabled("sm2"); + + # test x509 sign sm2 cert, should include X509v3 extensions + my $csr = srctop_file("test", "certs", "sm2-root.csr"); + my $key = srctop_file("test", "certs", "sm2-root.key"); + my $cert = "sm2-root.tmp"; + ok(run(app([ "openssl", "x509", "-req", "-in", $csr, "-extfile", + srctop_file("apps", "openssl.cnf"), "-extensions", "v3_ca", "-sm3", + "-signkey", $key, "-out", $cert ]))); + + my @output = run(app([ "openssl", "x509", "-in", $cert, "-text", + "-noout" ], stderr => undef), capture => 1); + + unlink $cert; + + my $count = grep /X509v3 Basic Constraints:/, @output; + ok($count == 1); + } +};