. "$BST_LIB" # libgcrypt is GnuPG's general-purpose crypto library: the symmetric ciphers, # the digests and MACs, the MPI (bignum) layer the public-key algorithms are # built on, an S-expression parser used to carry keys, and a CSPRNG. It links # libgpg-error (BRINTOS-308) for its error namespace, which is why that port # landed first on this Epic. # # The distro is static-only, so what the image gets is /usr/lib/libgcrypt.a, # /usr/include/gcrypt.h, libgcrypt.pc, the AM_PATH_LIBGCRYPT aclocal macro, and # three CLIs -- /usr/bin/hmac256, /usr/bin/dumpsexp and /usr/bin/mpicalc -- # plus /usr/bin/libgcrypt-config, which poky's binconfig-disabled class replaces # with a refusal stub. # # --------------------------------------------------------------------------- # THE ONE THING TO UNDERSTAND ABOUT THIS SUITE'S RESULT # # The three CLIs split cleanly in two, and the split is not arbitrary: # # hmac256, dumpsexp -- upstream builds these STANDALONE (-DSTANDALONE, and # LDADD = $(arch_gpg_error_libs), which is empty off # W32CE). They link NEITHER libgcrypt NOR libgpg-error, # carrying their own SHA-256 code. They RUN, and every # assertion over them below is green. # mpicalc, the probe -- these link libgcrypt.a, which links libgpg-error.a. # They trap before main's first instruction, every time, # with the "orphan at clear" violation that BRINTOS-308 # filed as hwjs-cc#26. Nothing at the port level can work # around it: the library cannot begin executing. # # So the reds in this suite are ONE platform defect, hwjs-cc#26, and they are # deliberately left FAILING rather than skipped -- they flip green by themselves # the day it is fixed, which is the regression evidence this lifecycle buys. # # WHAT IS STILL PROVEN GREEN, and it is more than it sounds: hmac256's start-up # path is libgcrypt's own SHA-256/HMAC implementation compiled for this arm, and # main() runs selftest() -- upstream's RFC 4231 vector set -- BEFORE it will hash # anything, exiting 2 with "fatal error: self-test failed" if any vector is # wrong. So hmac256 succeeding on target is a hard assertion that a start-up # self-test over real crypto passed here, not a presence check. The digests it # then produces are checked against RFC 4231 itself. # # EVERY EXPECTED VALUE BELOW IS EITHER A PUBLISHED CONSTANT (RFC 4231) OR THE # VALUE A NATIVE x86_64 BUILD OF THE IDENTICAL RELEASE PRODUCES, captured before # this suite was ever run on target. Where the target legitimately differs from # that control it is a Yocto packaging property and is called out at the case: # the version string carries an "-unknown" suffix in the cross build (the same # suffix libgpg-error 1.48 carries), and libgcrypt-config is poky's refusal stub. require hmac256 libgcrypt/present incd=/usr/include lib=/usr/lib/libgcrypt.a pc=/usr/lib/pkgconfig/libgcrypt.pc m4=/usr/share/aclocal/libgcrypt.m4 tmp=${TMPDIR:-/tmp} nl=' ' hasfile() { if [ -s "$2" ]; then bst_ok "$1"; else bst_notok "$1" "absent or empty: $2"; fi; } has() { case "$3" in *"$2"*) bst_ok "$1" ;; *) bst_notok "$1" "not found: $2" ;; esac; } hasnot() { case "$3" in *"$2"*) bst_notok "$1" "unexpectedly present: $2" ;; *) bst_ok "$1" ;; esac; } # check_out insists on rc 0 and check_rc discards the output, so neither fits a # case whose message AND exit status are both under test (the refusal stub, and # hmac256's usage error). out_rc() { _id=$1; _want=$2; _needle=$3; shift 3 _out=$("$@" 2>&1); _rc=$? case "$_out" in *"$_needle"*) _hit=1 ;; *) _hit=0 ;; esac if [ "$_rc" -eq "$_want" ] && [ "$_hit" -eq 1 ]; then bst_ok "$_id" else bst_notok "$_id" "rc=$_rc want=$_want want:'$_needle' got:'$(_bst_1line "$_out")'"; fi } # --- payload shape ----------------------------------------------------------- hasfile libgcrypt/header "$incd/gcrypt.h" hasfile libgcrypt/archive "$lib" hasfile libgcrypt/pkgconfig "$pc" hasfile libgcrypt/m4 "$m4" hasfile libgcrypt/bin-hmac256 /usr/bin/hmac256 hasfile libgcrypt/bin-dumpsexp /usr/bin/dumpsexp hasfile libgcrypt/bin-mpicalc /usr/bin/mpicalc hasfile libgcrypt/bin-config-stub /usr/bin/libgcrypt-config # --- libgcrypt.pc ------------------------------------------------------------ pctext=$(cat "$pc" 2>/dev/null) has libgcrypt/pc-name "Name: libgcrypt" "$pctext" has libgcrypt/pc-desc "Description: General purpose cryptographic library" "$pctext" has libgcrypt/pc-libs "Libs: -L\${libdir} -lgcrypt" "$pctext" has libgcrypt/pc-libdir "libdir=/usr/lib" "$pctext" has libgcrypt/pc-api "api_version=1" "$pctext" # libgcrypt links libgpg-error; the .pc must say so, or a consumer's static # link fails to resolve the gpg_err_* namespace. has libgcrypt/pc-requires "Requires.private: gpg-error" "$pctext" # The arm's own triple, as autoconf canonicalised it. has libgcrypt/pc-host "host=wasm32-hwjs-linux-gnu" "$pctext" # Yocto, not the platform: the cross build stamps an -unknown suffix where the # native control of the identical release says just "1.10.4". has libgcrypt/pc-version "Version: 1.10.4-unknown" "$pctext" # The algorithm inventory the build actually enabled, verbatim from configure. has libgcrypt/pc-ciphers 'symmetric_ciphers="arcfour blowfish cast5 des aes twofish serpent rfc2268 seed camellia idea salsa20 gost28147 chacha20 sm4"' "$pctext" has libgcrypt/pc-pubkey 'asymmetric_ciphers="dsa elgamal rsa ecc"' "$pctext" has libgcrypt/pc-digests 'digests="crc gostr3411-94 md4 md5 rmd160 sha1 sha256 sha512 sha3 tiger whirlpool stribog blake2 sm3"' "$pctext" # --- gcrypt.h ---------------------------------------------------------------- hdrtext=$(cat "$incd/gcrypt.h" 2>/dev/null) has libgcrypt/header-version '#define GCRYPT_VERSION "1.10.4-unknown"' "$hdrtext" # The ABI-relevant number, which is identical between the cross and native # builds even though the string above is not. has libgcrypt/header-vernum "#define GCRYPT_VERSION_NUMBER 0x010a04" "$hdrtext" has libgcrypt/header-selftest "GCRYCTL_SELFTEST" "$hdrtext" has libgcrypt/header-mpi "gcry_mpi_powm" "$hdrtext" has libgcrypt/m4-macro "AM_PATH_LIBGCRYPT" "$(cat "$m4" 2>/dev/null)" # --- THE --disable-asm BUILD, ASSERTED FROM THE ARCHIVE THAT SHIPS ----------- # BRINTOS-309 requires the hand-written assembly paths disabled on this arm. # configure recorded that at build time ("MPI and cipher assembler modules are # requested... no", "architecture and mpi assembler functions... disabled", # "Hardware detection module: none"), but a build log is not something a target # can be re-checked against. The archive is: an ar member table carries each # object's filename, so the accelerated translation units are observable by name # in the shipped .a. # # Two directions, and both matter. Absence alone would also be satisfied by an # archive that failed to build its cipher cores at all, so the portable C # members are asserted present in the same breath. # # Note mpih-mul1.o and friends are NOT usable as evidence either way: the MPI # layer compiles to the same member names from mpi/generic/*.c and from # mpi//*.S. The cipher and hash accelerators are what carry the arch in # their filenames, and hwf-.o is the CPU-feature-detection module that # "Hardware detection module: none" removes outright. arcobjs=$(grep -ao '[A-Za-z0-9_-]*\.o' "$lib" 2>/dev/null | sort -u) asm_absent="" for o in rijndael-aesni.o rijndael-ssse3-amd64.o rijndael-vaes-avx2-amd64.o \ rijndael-padlock.o rijndael-armv8-ce.o rijndael-ppc.o rijndael-s390x.o \ sha1-avx-amd64.o sha1-ssse3-amd64.o sha1-intel-shaext.o sha1-armv8-aarch64-ce.o \ sha256-avx2-bmi2-amd64.o sha256-ssse3-amd64.o sha256-intel-shaext.o sha256-ppc.o \ sha512-avx2-bmi2-amd64.o sha512-ssse3-amd64.o sha512-arm.o \ chacha20-amd64-avx2.o chacha20-amd64-ssse3.o chacha20-armv7-neon.o chacha20-s390x.o \ poly1305-amd64-avx2.o poly1305-s390x.o \ cipher-gcm-intel-pclmul.o cipher-gcm-armv8-aarch64-ce.o cipher-gcm-ppc.o \ des-amd64.o twofish-amd64.o twofish-avx2-amd64.o \ serpent-avx2-amd64.o serpent-sse2-amd64.o serpent-armv7-neon.o \ camellia-aesni-avx-amd64.o camellia-aesni-avx2-amd64.o camellia-arm.o \ blake2b-amd64-avx2.o blake2s-amd64-avx.o \ sm3-avx-bmi2-amd64.o sm4-aesni-avx-amd64.o \ keccak-amd64-avx512.o whirlpool-sse2-amd64.o \ hwf-x86.o hwf-arm.o hwf-ppc.o hwf-s390x.o ; do case "$nl$arcobjs$nl" in *"$nl$o$nl"*) asm_absent="$asm_absent $o" ;; esac done if [ -z "$asm_absent" ]; then bst_ok libgcrypt/asm-no-accel-members else bst_notok libgcrypt/asm-no-accel-members "assembly/hw members present in a --disable-asm archive:$asm_absent"; fi c_missing="" for o in rijndael.o sha1.o sha256.o sha512.o keccak.o chacha20.o poly1305.o \ twofish.o serpent.o camellia.o blowfish.o des.o sm3.o sm4.o blake2.o \ whirlpool.o md5.o rmd160.o mpih-mul1.o mpih-add1.o mpi-pow.o ; do case "$nl$arcobjs$nl" in *"$nl$o$nl"*) ;; *) c_missing="$c_missing $o" ;; esac done if [ -z "$c_missing" ]; then bst_ok libgcrypt/asm-portable-c-members else bst_notok libgcrypt/asm-portable-c-members "portable C members missing from the archive:$c_missing"; fi # --- every function gcrypt.h declares is in the archive ---------------------- # Read the header rather than compare against a hardcoded list, so a release # that adds or renames an entry point is checked rather than permanently # forgiven. Names introduced by a #define (macro wrappers and the deprecated # aliases gcrypt.h keeps) carry no archive symbol by design and are excluded by # reading those #define lines, not by naming them here. arcsyms=$(grep -ao 'gcry_[a-z0-9_]*' "$lib" 2>/dev/null | sort -u) macrosyms=$(grep -E '^[[:space:]]*#[[:space:]]*define' "$incd/gcrypt.h" 2>/dev/null \ | grep -oE '\bgcry_[a-z0-9_]+' | sort -u) # Four names -- gcry_err_make, gcry_error, gcry_err_code, gcry_err_source -- are # `static GPG_ERR_INLINE` wrappers that just forward to libgpg-error's gpg_err_*, # so they carry no archive symbol BY DESIGN. They are excluded by reading the # header for that shape, not by a hardcoded list, so a release that promotes one # of them to a real function is checked rather than permanently forgiven. inlinesyms=$(awk '/static GPG_ERR_INLINE/ { getline if (match($0, /^gcry_[A-Za-z0-9_]*/)) print substr($0, RSTART, RLENGTH) }' "$incd/gcrypt.h" 2>/dev/null | sort -u) hdrsyms=$(grep -vE '^[[:space:]]*#' "$incd/gcrypt.h" 2>/dev/null \ | grep -oE '\bgcry_[a-z0-9_]+[[:space:]]*\(' \ | sed -e 's/[[:space:]]*(//' | sort -u) nsym=0; nmiss=0; missing="" for f in $hdrsyms; do case "$nl$macrosyms$nl" in *"$nl$f$nl"*) continue ;; esac case "$nl$inlinesyms$nl" in *"$nl$f$nl"*) continue ;; esac nsym=$((nsym + 1)) case "$nl$arcsyms$nl" in *"$nl$f$nl"*) ;; *) nmiss=$((nmiss + 1)); missing="$missing $f" ;; esac done # A floor, not an exact count: the guard this case provides is that the header # parse yielded a real entry-point surface rather than silently returning none. # The number is lower than a naive grep of gcrypt.h because macros, preprocessor # lines and the inline forwarders above are all excluded first. if [ "$nsym" -gt 150 ]; then bst_ok libgcrypt/symbols-counted else bst_notok libgcrypt/symbols-counted "only $nsym gcry_* entry points parsed out of gcrypt.h (expected >150)"; fi if [ "$nmiss" -eq 0 ]; then bst_ok libgcrypt/symbols-complete else bst_notok libgcrypt/symbols-complete "$nmiss of $nsym header symbols absent from the archive:$missing"; fi for f in gcry_check_version gcry_control gcry_md_hash_buffer gcry_cipher_encrypt \ gcry_mpi_powm gcry_pk_sign gcry_sexp_build gcry_randomize; do case "$nl$arcsyms$nl" in *"$nl$f$nl"*) bst_ok "libgcrypt/sym-$f" ;; *) bst_notok "libgcrypt/sym-$f" "not in archive: $f" ;; esac done # --- hmac256: REAL CRYPTO RUNNING, AND ITS START-UP SELF-TEST --------------- # hmac256 is built -DSTANDALONE and links neither libgcrypt nor libgpg-error, so # it is unaffected by hwjs-cc#26 and these cases are green. Its main() runs # selftest() -- upstream's RFC 4231 vectors over its SHA-256/HMAC code -- before # it will hash a single byte, and exits 2 with "fatal error: self-test failed" # if any vector mismatches. Every case below therefore also asserts that # self-test passed: none of them could report a digest otherwise. printf 'abc' > "$tmp/bst-lgc-abc.$$" printf 'what do ya want for nothing?' > "$tmp/bst-lgc-jefe.$$" : > "$tmp/bst-lgc-empty.$$" # RFC 4231 test case 2 verbatim: key "Jefe", data "what do ya want for # nothing?". This is the published HMAC-SHA-256 value, not a self-comparison. check_out libgcrypt/hmac256-rfc4231-tc2 \ "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843" \ hmac256 Jefe "$tmp/bst-lgc-jefe.$$" # --stdkey uses libgcrypt's built-in binary-check key; both values below are the # native x86_64 control's, byte-identical there and here. check_out libgcrypt/hmac256-stdkey-abc \ "eade30a457d32f91c602dd74774f5cd6df35809a6d1d25f10667a7e54e3b64b5" \ hmac256 --stdkey "$tmp/bst-lgc-abc.$$" check_out libgcrypt/hmac256-stdkey-empty \ "f2353f4c2eae21f5a2113d024a70e9210736cd1663b3c655a3a1e243398baaf2" \ hmac256 --stdkey "$tmp/bst-lgc-empty.$$" # Reading from stdin must agree with reading the same bytes from a file. check_eq libgcrypt/hmac256-stdin \ "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843" \ "$(hmac256 Jefe < "$tmp/bst-lgc-jefe.$$" 2>/dev/null | cut -d' ' -f1)" # A different key must give a different MAC (guards a stub that ignores the key). check_eq libgcrypt/hmac256-key-matters "differ" \ "$(a=$(hmac256 Jefe "$tmp/bst-lgc-abc.$$" 2>/dev/null | cut -d' ' -f1); \ b=$(hmac256 Kefe "$tmp/bst-lgc-abc.$$" 2>/dev/null | cut -d' ' -f1); \ [ -n "$a" ] && [ "$a" != "$b" ] && echo differ || echo same)" # --binary writes the 32 raw bytes instead of hex. check_eq libgcrypt/hmac256-binary-len "32" \ "$(hmac256 --binary Jefe "$tmp/bst-lgc-jefe.$$" 2>/dev/null | wc -c | tr -d ' ')" # No key and no --stdkey is a usage error: rc 1 and the usage line on stderr. out_rc libgcrypt/hmac256-usage 1 "usage: hmac256" hmac256 # --- dumpsexp --------------------------------------------------------------- # Also STANDALONE, also green. It is the package's S-expression debug tool. printf '(3:abc3:def)' > "$tmp/bst-lgc-sexp.$$" check_out libgcrypt/dumpsexp-version "dumpsexp (Libgcrypt) 1.10.4-unknown" dumpsexp --help check_out libgcrypt/dumpsexp-hexdump "|(3:abc3:def)|" dumpsexp "$tmp/bst-lgc-sexp.$$" check_out libgcrypt/dumpsexp-offset "00000000" dumpsexp "$tmp/bst-lgc-sexp.$$" # --advanced is accepted and still hex-dumps for a short canonical input like # this one; the case pins that it is accepted and produces the same bytes, # rather than asserting a re-rendered form this input does not trigger. check_out libgcrypt/dumpsexp-advanced "|(3:abc3:def)|" dumpsexp --advanced "$tmp/bst-lgc-sexp.$$" # --- libgcrypt-config: poky's refusal stub ---------------------------------- # binconfig-disabled replaces the upstream script so a consumer's configure # cannot pick it up in preference to pkg-config. Refusing IS the contract here, # so the case asserts the refusal, not a version. out_rc libgcrypt/config-stub-refuses 1 \ "ERROR: /usr/bin/libgcrypt-config should not be used" libgcrypt-config --version # --- mpicalc: the first thing that links libgcrypt.a ------------------------ # Asserted rather than skipped, per this ticket. Expected RED until hwjs-cc#26 # is fixed: mpicalc traps in __wasm32_main_with_ctors before main, so it prints # no prompt and dies on SIGILL (rc 132). # "2 3 + p" pushes 2 and 3, adds, prints: mpicalc renders in hex with an even # digit count, so 5 comes out as "05" (the native control's exact output). out_rc libgcrypt/mpicalc-runs 0 "05" sh -c 'echo "2 3 + p" | mpicalc' # --- the library itself, via the cross-linked probe ------------------------- # data/libgcrypt-probe is cross-linked with wasmcc-glibc against THE VERY # ARCHIVE THAT SHIPS (/usr/lib/libgcrypt.a); its source is src/libgcrypt_probe.c # and the cross-link reported refused=0 skipped=0. It is the only thing here # that calls gcry_control(GCRYCTL_SELFTEST) -- libgcrypt's own start-up # self-test over its ciphers, digests, MAC, pubkey and RNG -- which is the # assertion BRINTOS-309 asks for by name. # # It scores 75/75 against a native x86_64 build of the identical release. On # target it traps before main, so all 75 cases below are reported not ok and # attributed to hwjs-cc#26. They are enumerated explicitly rather than derived # from the probe's output, so a probe that prints NOTHING still produces 75 # accounted-for reds instead of silently contributing no cases at all. P309_CASES="version-string version-atleast version-refuses-future init-disable-secmem init-finished init-is-initialized selftest md-sha1-abc md-sha256-abc md-sha256-empty md-sha512-abc md-sha224-abc md-sha384-abc md-sha3-256-abc md-sha3-512-abc md-md5-abc md-md4-abc md-rmd160-abc md-blake2b512-abc md-sm3-abc md-multipart md-dlen-sha256 md-dlen-sha512 md-algo-name-sha256 md-map-name-sha256 hmac-sha256-rfc4231-tc1 hmac-sha256-rfc4231-tc2 hmac-sha256-rfc4231-tc3 hmac-sha512-rfc4231-tc2 hmac-sha1-rfc2202-tc2 aes128-ecb-fips197 aes192-ecb-fips197 aes256-ecb-fips197 aes128-cbc-sp80038a aes128-ctr-sp80038a chacha20-rfc8439 aes128-gcm-nist-tc4-aad aes128-gcm-nist-tc4-ct aes128-gcm-nist-tc4-tag aes128-gcm-tag-binds-aad 3des-roundtrip 3des-not-identity cipher-blklen-aes cipher-keylen-aes256 cipher-algo-name-aes aes128-roundtrip mpi-scan mpi-print-roundtrip mpi-add mpi-sub mpi-mul mpi-cmp-gt mpi-nbits mpi-powm-fermat mpi-modp-nbits mpi-invm mpi-div-q mpi-div-r mpi-set-bit mpi-test-bit pk-genkey pk-key-parts pk-testkey pk-sign pk-verify pk-verify-rejects-wrong-hash sexp-build sexp-find-token sexp-sprint rng-nonzero rng-differs rng-nonce-differs config-string config-no-hwfeatures config-names-version" probe=$tmp/bst-libgcrypt-probe.$$ if cp "$BST_DATA/libgcrypt-probe" "$probe" 2>/dev/null && chmod +x "$probe" 2>/dev/null; then out=$("$probe" 2>&1); prc=$? # One line naming why the group failed, so a reader of the report does not # have to infer it from 75 identical details. case "$out" in *"orphan at clear"*) why="hwjs-cc#26: trapped in __wasm32_main_with_ctors before main (rc=$prc)" ;; *) why="probe produced no result for this case (rc=$prc)" ;; esac for c in $P309_CASES; do case "$out" in *"P309 ok $c"*) bst_ok "libgcrypt/probe-$c" ;; *"P309 FAIL $c :"*) bst_notok "libgcrypt/probe-$c" \ "$(printf '%s\n' "$out" | grep -m1 "P309 FAIL $c :" | sed 's/.*: //')" ;; *) bst_notok "libgcrypt/probe-$c" "$why" ;; esac done # The probe's own tally and exit status. 75/75 is what the same source scores # natively; both are red while hwjs-cc#26 stands. has libgcrypt/probe-summary "P309-SUMMARY pass=75 fail=0" "$out" check_rc libgcrypt/probe-exit0 0 "$probe" rm -f "$probe" else bst_notok libgcrypt/probe-stage "cannot stage $BST_DATA/libgcrypt-probe" fi rm -f "$tmp/bst-lgc-abc.$$" "$tmp/bst-lgc-jefe.$$" "$tmp/bst-lgc-empty.$$" "$tmp/bst-lgc-sexp.$$"